Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
272 lines
9.9 KiB
Plaintext
Executable File
272 lines
9.9 KiB
Plaintext
Executable File
NAME
|
|
routing - RSX type-safe URL generation and route patterns
|
|
|
|
SYNOPSIS
|
|
Type-safe URL generation in PHP and JavaScript with automatic route discovery
|
|
|
|
DESCRIPTION
|
|
The RSX framework provides type-safe URL generation that ensures routes
|
|
are valid at build time and prevents broken links. Unlike Laravel's
|
|
route() helper which uses string names, RSX uses controller class names
|
|
and actions, providing IDE autocompletion and refactoring safety.
|
|
|
|
Key differences from Laravel:
|
|
- Laravel: route('user.profile', $user) using named routes
|
|
- RSX: Rsx::Route('User_Controller', 'profile')->url(['id' => $user->id])
|
|
|
|
Benefits:
|
|
- No route name management required
|
|
- Automatic route discovery from controller attributes
|
|
- Same syntax works in both PHP and JavaScript
|
|
- IDE autocompletion for controller names
|
|
- Refactoring-safe (renaming controllers updates routes)
|
|
|
|
BASIC USAGE
|
|
PHP Syntax:
|
|
use App\RSpade\Core\Rsx;
|
|
|
|
// Create route proxy (action defaults to 'index')
|
|
$route = Rsx::Route('Demo_Index_Controller');
|
|
$route = Rsx::Route('Demo_Index_Controller', 'show');
|
|
|
|
// Generate URLs
|
|
$url = $route->url(); // /demo
|
|
$url = $route->url(['id' => 123]); // /demo/123 or /demo?id=123
|
|
$absolute = $route->absolute_url(); // https://site.com/demo
|
|
|
|
// Navigate (redirect)
|
|
$route->navigate(); // Sends Location header and exits
|
|
|
|
JavaScript Syntax:
|
|
// Create route proxy (action defaults to 'index')
|
|
const route = Rsx.Route('Demo_Index_Controller');
|
|
const route = Rsx.Route('Demo_Index_Controller', 'show');
|
|
|
|
// Generate URLs
|
|
const url = route.url(); // /demo
|
|
const url = route.url({id: 123}); // /demo/123 or /demo?id=123
|
|
const absolute = route.absolute_url(); // https://site.com/demo
|
|
|
|
// Navigate
|
|
route.navigate(); // Sets window.location.href
|
|
|
|
ROUTE PATTERNS
|
|
Route Definition:
|
|
Routes are defined using #[Route] attributes on controller methods:
|
|
|
|
#[Auth('Permission::authenticated()')]
|
|
#[Route('/users/:division/:id')]
|
|
public static function show_user(Request $request, array $params = [])
|
|
{
|
|
// $params['division'] and $params['id'] contain URL values
|
|
$division = $params['division'];
|
|
$user_id = $params['id'];
|
|
}
|
|
|
|
Parameter Syntax:
|
|
- :param - Required parameter in URL path
|
|
- Routes without parameters use controller/action mapping
|
|
- URL generation validates required parameters are provided
|
|
|
|
URL Parameter Handling:
|
|
- Required parameters (in pattern) must be provided or exception thrown
|
|
- Extra parameters become query string (?key=value)
|
|
- All values automatically URL encoded
|
|
- Supports complex parameter patterns
|
|
|
|
ROUTE ACCESS CONTROL
|
|
All routes MUST have #[Auth] attribute for access control:
|
|
|
|
#[Auth('Permission::anybody()')]
|
|
#[Route('/')]
|
|
public static function index(Request $request, array $params = [])
|
|
{
|
|
return rsx_view('Landing');
|
|
}
|
|
|
|
Access Control Placement:
|
|
1. On route method - Applies to specific route
|
|
2. On pre_dispatch() - Applies to all routes in controller
|
|
3. Both - pre_dispatch checked first, then route
|
|
|
|
Common Patterns:
|
|
// Public route
|
|
#[Auth('Permission::anybody()')]
|
|
|
|
// Authenticated only
|
|
#[Auth('Permission::authenticated()',
|
|
message: 'Please log in',
|
|
redirect: '/login')]
|
|
|
|
// Custom permission with argument
|
|
#[Auth('Permission::has_role("admin")')]
|
|
|
|
// Multiple requirements (all must pass)
|
|
#[Auth('Permission::authenticated()')]
|
|
#[Auth('Permission::has_permission("edit")')]
|
|
|
|
See controller(3) for complete #[Auth] documentation.
|
|
|
|
ROUTE DISCOVERY
|
|
Automatic Discovery:
|
|
The manifest system automatically discovers routes by scanning
|
|
for #[Route] attributes on controller static methods.
|
|
|
|
Discovery Process:
|
|
1. Manifest scanner finds Route attributes during build
|
|
2. Routes extracted and cached in manifest
|
|
3. Bundle compilation injects routes into JavaScript
|
|
4. Both PHP and JS use same routing logic
|
|
|
|
Controller Mapping:
|
|
- Demo_Index_Controller maps to /demo route by default
|
|
- User_Profile_Controller maps to /user/profile
|
|
- Action methods create sub-routes: show -> /demo/show
|
|
|
|
BUNDLE INTEGRATION
|
|
Automatic Route Inclusion:
|
|
Routes are automatically included in JavaScript bundles when
|
|
controllers are in the bundle's include paths.
|
|
|
|
Bundle Configuration:
|
|
class My_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => ['rsx/app/myapp'],
|
|
'include_routes' => ['rsx/app/admin'], // Additional route scanning
|
|
];
|
|
}
|
|
}
|
|
|
|
Route Availability:
|
|
- Routes available in JavaScript when bundle renders
|
|
- Same URL generation logic in both PHP and JavaScript
|
|
- No manual route registration required
|
|
|
|
ADVANCED PATTERNS
|
|
Complex Parameter Examples:
|
|
// Multiple parameters
|
|
#[Route('/api/v1/users/:company/:division/:id')]
|
|
$route->url(['company' => 'acme', 'division' => 'sales', 'id' => 123]);
|
|
// Result: /api/v1/users/acme/sales/123
|
|
|
|
// Query parameters for extra values
|
|
$route->url(['id' => 123, 'format' => 'json', 'include' => 'profile']);
|
|
// Result: /demo/123?format=json&include=profile
|
|
|
|
// Complex objects as parameters
|
|
$route->url(['filter' => ['status' => 'active', 'type' => 'user']]);
|
|
// Result: /demo?filter[status]=active&filter[type]=user
|
|
|
|
Route Groups and Prefixes:
|
|
Routes inherit prefixes from controller structure:
|
|
- Backend_User_Controller -> /backend/user
|
|
- Api_V1_User_Controller -> /api/v1/user
|
|
- Admin_Reports_Controller -> /admin/reports
|
|
|
|
Custom Route Patterns:
|
|
#[Route('/custom/path/:id')] // Custom path
|
|
#[Route('/api/:version/users/:id')] // Multiple segments
|
|
#[Route('/files/:path*')] // Wildcard parameters
|
|
|
|
JAVASCRIPT BUNDLE ROUTES
|
|
Route Availability in JavaScript:
|
|
Routes are injected into JavaScript bundles as part of the Rsx
|
|
framework initialization. No manual configuration required.
|
|
|
|
Bundle Route Extraction:
|
|
// Routes automatically extracted from included controllers
|
|
class Frontend_Bundle extends Rsx_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'include' => [
|
|
'rsx/app/frontend', // Controllers here get routes extracted
|
|
'rsx/app/shared', // Additional controller directories
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
Runtime Route Access:
|
|
// Routes available after bundle loads
|
|
if (typeof Rsx !== 'undefined') {
|
|
const route = Rsx.Route('Demo_Index_Controller');
|
|
const url = route.url();
|
|
}
|
|
|
|
ERROR HANDLING
|
|
Missing Route Errors:
|
|
- PHP: RouteNotFoundException when controller/action not found
|
|
- JavaScript: Error thrown when route not available in bundle
|
|
- Development: Clear error messages with suggestions
|
|
|
|
Parameter Validation:
|
|
- Required parameters must be provided
|
|
- Invalid parameter types rejected
|
|
- URL encoding applied automatically
|
|
|
|
Bundle Configuration Errors:
|
|
- Routes not available if controllers not in bundle includes
|
|
- Clear error messages when routes missing from JavaScript
|
|
|
|
DEBUGGING ROUTES
|
|
View All Routes:
|
|
php artisan rsx:routes # List all discovered routes
|
|
|
|
Test Route Generation:
|
|
php artisan rsx:debug /demo --eval="Rsx.Route('Demo_Index_Controller').url()"
|
|
|
|
Route Information:
|
|
php artisan rsx:manifest:show # View route cache in manifest
|
|
|
|
COMMON PATTERNS
|
|
Controller Navigation:
|
|
// Redirect to another controller
|
|
public static function handle_form(Request $request, array $params = [])
|
|
{
|
|
// Process form...
|
|
Rsx::Route('Dashboard_Index_Controller')->navigate();
|
|
}
|
|
|
|
AJAX URL Generation:
|
|
// Generate URLs for AJAX calls
|
|
const apiUrl = Rsx.Route('Api_User_Controller', 'update').url({id: userId});
|
|
fetch(apiUrl, {method: 'POST', body: formData});
|
|
|
|
Form Action URLs:
|
|
// Generate form action URLs
|
|
<form action="<?= Rsx::Route('User_Profile_Controller', 'update')->url() ?>" method="POST">
|
|
|
|
Link Generation:
|
|
// Generate navigation links
|
|
<a href="<?= Rsx::Route('Dashboard_Index_Controller')->url() ?>">Dashboard</a>
|
|
|
|
TROUBLESHOOTING
|
|
Route Not Found:
|
|
- Verify controller exists and has #[Route] attribute
|
|
- Check controller is in manifest-scanned directories
|
|
- Ensure manifest rebuilt after adding new routes
|
|
|
|
JavaScript Route Unavailable:
|
|
- Verify controller included in bundle configuration
|
|
- Check bundle compiles without errors
|
|
- Ensure bundle renders in HTML output
|
|
|
|
Parameter Errors:
|
|
- Required parameters must match route pattern exactly
|
|
- Parameter names are case-sensitive
|
|
- Use array syntax for multiple parameters
|
|
|
|
URL Generation Issues:
|
|
- Check for typos in controller names
|
|
- Verify action method exists on controller
|
|
- Ensure route pattern matches expected parameters
|
|
|
|
SEE ALSO
|
|
controller - Controller patterns and route attributes
|
|
bundle_api - Bundle system and JavaScript integration
|
|
manifest_api - Route discovery and caching system |