Add 100+ automated unit tests from .expect file specifications Add session system test Add rsx:constants:regenerate command test Add rsx:logrotate command test Add rsx:clean command test Add rsx:manifest:stats command test Add model enum system test Add model mass assignment prevention test Add rsx:check command test Add migrate:status command test 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
167 lines
5.4 KiB
PHP
167 lines
5.4 KiB
PHP
<?php
|
|
/**
|
|
* CODING CONVENTION:
|
|
* This file follows the coding convention where variable_names and function_names
|
|
* use snake_case (underscore_wherever_possible).
|
|
*/
|
|
|
|
namespace App\RSpade\Core;
|
|
|
|
use App\RSpade\Core\Dispatch\ApiHandler;
|
|
use App\RSpade\Core\Manifest\Manifest;
|
|
|
|
/**
|
|
* API helper class for internal API execution
|
|
*
|
|
* Provides static methods for executing API endpoints internally
|
|
* without making HTTP requests.
|
|
*/
|
|
class API
|
|
{
|
|
/**
|
|
* Execute an API endpoint internally
|
|
*
|
|
* @param string $endpoint Format: "ControllerClass.method" or "Namespace\Class.method"
|
|
* @param array $params Parameters to pass to the API method
|
|
* @param array $options Optional settings like authentication context
|
|
* @return mixed Raw PHP response (not JSON)
|
|
*
|
|
* @example
|
|
* // Simple internal API call
|
|
* $user = API::execute('UserApi.get_profile', ['user_id' => 123]);
|
|
*
|
|
* // With authentication context
|
|
* $data = API::execute('DataApi.export', [
|
|
* 'format' => 'csv'
|
|
* ], ['auth_token' => 'secret_key']);
|
|
*/
|
|
public static function execute($endpoint, array $params = [], array $options = [])
|
|
{
|
|
$api_handler = app(ApiHandler::class);
|
|
|
|
return $api_handler->execute_internal($endpoint, $params, $options);
|
|
}
|
|
|
|
/**
|
|
* Execute multiple API endpoints in parallel
|
|
*
|
|
* @param array $requests Array of [endpoint, params, options] arrays
|
|
* @return array Array of results keyed by endpoint
|
|
*
|
|
* @example
|
|
* $results = API::execute_batch([
|
|
* ['UserApi.get_profile', ['user_id' => 123]],
|
|
* ['PostApi.get_user_posts', ['user_id' => 123]],
|
|
* ['CommentApi.get_user_comments', ['user_id' => 123]]
|
|
* ]);
|
|
*/
|
|
public static function execute_batch(array $requests)
|
|
{
|
|
$api_handler = app(ApiHandler::class);
|
|
$results = [];
|
|
|
|
foreach ($requests as $request) {
|
|
$endpoint = $request[0];
|
|
$params = $request[1] ?? [];
|
|
$options = $request[2] ?? [];
|
|
|
|
try {
|
|
$results[$endpoint] = $api_handler->execute_internal($endpoint, $params, $options);
|
|
} catch (\Exception $e) {
|
|
$results[$endpoint] = [
|
|
'error' => true,
|
|
'message' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Check if an API endpoint exists
|
|
*
|
|
* @param string $endpoint
|
|
* @return bool
|
|
*/
|
|
public static function exists($endpoint)
|
|
{
|
|
try {
|
|
$api_handler = app(ApiHandler::class);
|
|
list($class, $method) = explode('.', $endpoint);
|
|
|
|
// Try to resolve the class using Manifest
|
|
if (!str_contains($class, '\\')) {
|
|
// Try to find the class by simple name
|
|
try {
|
|
$metadata = Manifest::php_get_metadata_by_class($class);
|
|
$class = $metadata['fqcn'];
|
|
} catch (\RuntimeException $e) {
|
|
// Try with common API namespaces
|
|
$namespaces = [
|
|
'App\\Http\\Controllers\\Api\\',
|
|
'App\\RSpade\\Api\\',
|
|
'App\\Api\\'
|
|
];
|
|
|
|
$found = false;
|
|
foreach ($namespaces as $namespace) {
|
|
try {
|
|
$metadata = Manifest::php_get_metadata_by_fqcn($namespace . $class);
|
|
$class = $metadata['fqcn'];
|
|
$found = true;
|
|
break;
|
|
} catch (\RuntimeException $e2) {
|
|
// Try next namespace
|
|
}
|
|
}
|
|
|
|
if (!$found) {
|
|
// Class not found in Manifest
|
|
shouldnt_happen("API class not found in Manifest: {$class}");
|
|
}
|
|
}
|
|
} else {
|
|
// Full namespace provided, verify it exists in Manifest
|
|
try {
|
|
$metadata = Manifest::php_get_metadata_by_fqcn($class);
|
|
$class = $metadata['fqcn'];
|
|
} catch (\RuntimeException $e) {
|
|
shouldnt_happen("API class not found in Manifest: {$class}");
|
|
}
|
|
}
|
|
|
|
return method_exists($class, $method);
|
|
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get available API endpoints
|
|
*
|
|
* @return array List of available endpoints
|
|
*/
|
|
public static function get_endpoints()
|
|
{
|
|
$manifest = app(Manifest::class);
|
|
$manifest_data = $manifest->get_manifest();
|
|
|
|
$endpoints = [];
|
|
|
|
if (isset($manifest_data['routes']['api'])) {
|
|
foreach ($manifest_data['routes']['api'] as $pattern => $methods) {
|
|
foreach ($methods as $method => $handler) {
|
|
$endpoints[] = [
|
|
'endpoint' => $handler['class'] . '.' . $handler['method'],
|
|
'http_method' => $method,
|
|
'pattern' => $pattern
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $endpoints;
|
|
}
|
|
} |