Implement JavaScript route generation and default route fallback system
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2088,7 +2088,7 @@ JS;
|
||||
console_debug('BUNDLE', "Found controller: {$class_name}");
|
||||
|
||||
// Process methods with Route attributes
|
||||
foreach ($file_info['methods'] ?? [] as $method_name => $method_data) {
|
||||
foreach ($file_info['public_static_methods'] ?? [] as $method_name => $method_data) {
|
||||
foreach ($method_data['attributes'] ?? [] as $attr_name => $attr_instances) {
|
||||
if ($attr_name === 'Route') {
|
||||
// Get the first route pattern (index 0 is the first argument)
|
||||
@@ -2143,7 +2143,7 @@ JS;
|
||||
}
|
||||
|
||||
// Process methods with Route attributes
|
||||
foreach ($file_info['methods'] ?? [] as $method_name => $method_data) {
|
||||
foreach ($file_info['public_static_methods'] ?? [] as $method_name => $method_data) {
|
||||
foreach ($method_data['attributes'] ?? [] as $attr_name => $attr_instances) {
|
||||
if ($attr_name === 'Route') {
|
||||
// Get the first route pattern (index 0 is the first argument)
|
||||
|
||||
@@ -115,43 +115,108 @@ class Dispatcher
|
||||
\Log::debug("Dispatcher: No route found for: $url");
|
||||
console_debug('DISPATCH', 'No route found for:', $url);
|
||||
|
||||
// No route found - try Main pre_dispatch and unhandled_route hooks
|
||||
$params = array_merge(request()->all(), $extra_params);
|
||||
// Check if this matches the default route pattern: /_/{controller}/{action}
|
||||
if (preg_match('#^/_/([A-Za-z_][A-Za-z0-9_]*)/([A-Za-z_][A-Za-z0-9_]*)/?$#', $url, $matches)) {
|
||||
$controller_name = $matches[1];
|
||||
$action_name = $matches[2];
|
||||
|
||||
// First try Main pre_dispatch
|
||||
$main_classes = Manifest::php_get_extending('Main_Abstract');
|
||||
foreach ($main_classes as $main_class) {
|
||||
if (isset($main_class['fqcn']) && $main_class['fqcn']) {
|
||||
$main_class_name = $main_class['fqcn'];
|
||||
if (method_exists($main_class_name, 'pre_dispatch')) {
|
||||
Debugger::console_debug('[DISPATCH]', 'Main::pre_dispatch');
|
||||
$result = $main_class_name::pre_dispatch($request, $params);
|
||||
if ($result !== null) {
|
||||
$response = static::__build_response($result);
|
||||
console_debug('DISPATCH', 'Matched default route pattern:', $controller_name, '::', $action_name);
|
||||
|
||||
return static::__transform_response($response, $original_method);
|
||||
}
|
||||
// Try to find the controller using manifest
|
||||
try {
|
||||
$metadata = Manifest::php_get_metadata_by_class($controller_name);
|
||||
$controller_fqcn = $metadata['fqcn'];
|
||||
|
||||
// Verify it extends Rsx_Controller_Abstract
|
||||
if (!Manifest::php_is_subclass_of($controller_name, 'Rsx_Controller_Abstract')) {
|
||||
console_debug('DISPATCH', 'Class does not extend Rsx_Controller_Abstract:', $controller_name);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify the method exists and has a Route attribute
|
||||
if (!isset($metadata['public_static_methods'][$action_name])) {
|
||||
console_debug('DISPATCH', 'Method not found:', $action_name);
|
||||
return null;
|
||||
}
|
||||
|
||||
$method_data = $metadata['public_static_methods'][$action_name];
|
||||
if (!isset($method_data['attributes']['Route'])) {
|
||||
console_debug('DISPATCH', 'Method does not have Route attribute:', $action_name);
|
||||
return null;
|
||||
}
|
||||
|
||||
// For POST requests: execute the action
|
||||
if ($route_method === 'POST') {
|
||||
// Collect parameters from POST data and query string
|
||||
$params = array_merge($request->query->all(), $request->request->all(), $extra_params);
|
||||
|
||||
// Create synthetic route match
|
||||
$route_match = [
|
||||
'class' => $controller_fqcn,
|
||||
'method' => $action_name,
|
||||
'params' => $params,
|
||||
'pattern' => "/_/{$controller_name}/{$action_name}",
|
||||
'require' => $method_data['attributes']['Auth'] ?? []
|
||||
];
|
||||
|
||||
// Continue with normal dispatch (will handle auth, pre_dispatch, etc.)
|
||||
// Fall through to normal route handling below
|
||||
} else {
|
||||
// For GET requests: redirect to the proper route
|
||||
$params = array_merge($request->query->all(), $extra_params);
|
||||
|
||||
// Generate proper URL using Rsx::Route
|
||||
$proper_url = Rsx::Route($controller_name, $action_name)->url($params);
|
||||
|
||||
console_debug('DISPATCH', 'Redirecting GET to proper route:', $proper_url);
|
||||
|
||||
return redirect($proper_url, 302);
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
console_debug('DISPATCH', 'Controller not found in manifest:', $controller_name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Then try unhandled_route hook
|
||||
foreach ($main_classes as $main_class) {
|
||||
if (isset($main_class['fqcn']) && $main_class['fqcn']) {
|
||||
$main_class_name = $main_class['fqcn'];
|
||||
if (method_exists($main_class_name, 'unhandled_route')) {
|
||||
$result = $main_class_name::unhandled_route($request, $params);
|
||||
if ($result !== null) {
|
||||
$response = static::__build_response($result);
|
||||
if (!$route_match) {
|
||||
// No route found - try Main pre_dispatch and unhandled_route hooks
|
||||
$params = array_merge(request()->all(), $extra_params);
|
||||
|
||||
return static::__transform_response($response, $original_method);
|
||||
// First try Main pre_dispatch
|
||||
$main_classes = Manifest::php_get_extending('Main_Abstract');
|
||||
foreach ($main_classes as $main_class) {
|
||||
if (isset($main_class['fqcn']) && $main_class['fqcn']) {
|
||||
$main_class_name = $main_class['fqcn'];
|
||||
if (method_exists($main_class_name, 'pre_dispatch')) {
|
||||
Debugger::console_debug('[DISPATCH]', 'Main::pre_dispatch');
|
||||
$result = $main_class_name::pre_dispatch($request, $params);
|
||||
if ($result !== null) {
|
||||
$response = static::__build_response($result);
|
||||
|
||||
return static::__transform_response($response, $original_method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default 404 - return null to let Laravel handle it
|
||||
return null;
|
||||
// Then try unhandled_route hook
|
||||
foreach ($main_classes as $main_class) {
|
||||
if (isset($main_class['fqcn']) && $main_class['fqcn']) {
|
||||
$main_class_name = $main_class['fqcn'];
|
||||
if (method_exists($main_class_name, 'unhandled_route')) {
|
||||
$result = $main_class_name::unhandled_route($request, $params);
|
||||
if ($result !== null) {
|
||||
$response = static::__build_response($result);
|
||||
|
||||
return static::__transform_response($response, $original_method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default 404 - return null to let Laravel handle it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract route information
|
||||
|
||||
@@ -156,6 +156,9 @@ class Rsx {
|
||||
* The proxy ensures all required route parameters are provided and handles extra parameters
|
||||
* as query string values.
|
||||
*
|
||||
* If the route is not found in the route definitions, a default pattern is used:
|
||||
* `/_/{controller}/{action}` with all parameters appended as query strings.
|
||||
*
|
||||
* Usage examples:
|
||||
* ```javascript
|
||||
* // Simple route without parameters (defaults to 'index' action)
|
||||
@@ -177,6 +180,10 @@ class Rsx {
|
||||
* });
|
||||
* // Returns: /clients/view/C001?tab=history
|
||||
*
|
||||
* // Route not found - uses default pattern
|
||||
* const url = Rsx.Route('Unimplemented_Controller', 'some_action').url({foo: 'bar'});
|
||||
* // Returns: /_/Unimplemented_Controller/some_action?foo=bar
|
||||
*
|
||||
* // Generate absolute URL
|
||||
* const absolute = Rsx.Route('Frontend_Index_Controller').absolute_url();
|
||||
* // Returns: https://example.com/dashboard
|
||||
@@ -194,20 +201,17 @@ class Rsx {
|
||||
* @param {string} class_name The controller class name (e.g., 'User_Controller')
|
||||
* @param {string} [action_name='index'] The action/method name (defaults to 'index')
|
||||
* @returns {Rsx_Route_Proxy} Route proxy instance for URL generation
|
||||
* @throws {Error} If route not found
|
||||
*/
|
||||
static Route(class_name, action_name = 'index') {
|
||||
// Check if route exists
|
||||
if (!Rsx._routes[class_name]) {
|
||||
throw new Error(`Class ${class_name} not found in routes`);
|
||||
// Check if route exists in definitions
|
||||
if (Rsx._routes[class_name] && Rsx._routes[class_name][action_name]) {
|
||||
const pattern = Rsx._routes[class_name][action_name];
|
||||
return new Rsx_Route_Proxy(class_name, action_name, pattern);
|
||||
}
|
||||
|
||||
if (!Rsx._routes[class_name][action_name]) {
|
||||
throw new Error(`Method ${action_name} not found in class ${class_name}`);
|
||||
}
|
||||
|
||||
const pattern = Rsx._routes[class_name][action_name];
|
||||
return new Rsx_Route_Proxy(class_name, action_name, pattern);
|
||||
// Route not found - use default pattern /_/{controller}/{action}
|
||||
const default_pattern = `/_/${class_name}/${action_name}`;
|
||||
return new Rsx_Route_Proxy(class_name, action_name, default_pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user