252 lines
No EOL
6.3 KiB
Markdown
252 lines
No EOL
6.3 KiB
Markdown
# Attribute-Based Routing
|
|
|
|
The Foundation framework provides a modern attribute-based routing system that automatically discovers and registers
|
|
routes when controllers are registered in the dependency injection container.
|
|
|
|
## Overview
|
|
|
|
Instead of manually registering routes in service providers, controllers can use PHP 8+ attributes to define their
|
|
routes directly on controller methods. Routes are automatically processed when controllers are registered in the
|
|
container.
|
|
|
|
## Key Components
|
|
|
|
### ControllerInterface
|
|
|
|
Controllers must implement `Foundation\Core\Infrastructure\ControllerInterface` to have their route attributes
|
|
processed:
|
|
|
|
```php
|
|
use Foundation\Core\Infrastructure\ControllerInterface;
|
|
|
|
class MyController implements ControllerInterface
|
|
{
|
|
// Route attributes will be processed for this controller
|
|
}
|
|
```
|
|
|
|
### Route Attributes
|
|
|
|
#### Basic Route Attributes
|
|
|
|
- `#[Get('/path')]` - GET requests
|
|
- `#[Post('/path')]` - POST requests
|
|
- `#[Put('/path')]` - PUT requests
|
|
- `#[Delete('/path')]` - DELETE requests
|
|
- `#[Route('/path', ['GET', 'POST'])]` - Custom HTTP methods
|
|
|
|
#### Group Attribute
|
|
|
|
Use `#[Group('/prefix')]` on controller classes to add a common prefix to all routes:
|
|
|
|
```php
|
|
#[Group('/api/users')]
|
|
class UserController implements ControllerInterface
|
|
{
|
|
#[Get('')] // Route: GET /api/users
|
|
#[Get('/{id}')] // Route: GET /api/users/{id}
|
|
#[Post('')] // Route: POST /api/users
|
|
}
|
|
```
|
|
|
|
#### Route Options
|
|
|
|
All route attributes support additional options:
|
|
|
|
```php
|
|
#[Get('/path', name: 'route.name', middleware: [AuthMiddleware::class])]
|
|
#[Group('/api', middleware: [RateLimitMiddleware::class])]
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Basic Controller
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Infrastructure\Web;
|
|
|
|
use Foundation\Core\Infrastructure\ControllerInterface;
|
|
use Foundation\Core\Routing\Attributes\Get;
|
|
use Foundation\Core\Routing\Attributes\Post;
|
|
|
|
class ProductController implements ControllerInterface
|
|
{
|
|
#[Get('/products')]
|
|
public function index(): ResponseInterface
|
|
{
|
|
// Handle GET /products
|
|
}
|
|
|
|
#[Get('/products/{id}')]
|
|
public function show(string $id): ResponseInterface
|
|
{
|
|
// Handle GET /products/{id}
|
|
}
|
|
|
|
#[Post('/products')]
|
|
public function create(): ResponseInterface
|
|
{
|
|
// Handle POST /products
|
|
}
|
|
}
|
|
```
|
|
|
|
### API Controller with Groups
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Infrastructure\Api;
|
|
|
|
use Foundation\Core\Infrastructure\ControllerInterface;
|
|
use Foundation\Core\Routing\Attributes\Get;
|
|
use Foundation\Core\Routing\Attributes\Post;
|
|
use Foundation\Core\Routing\Attributes\Group;
|
|
|
|
#[Group('/api/v1/products')]
|
|
class ProductApiController implements ControllerInterface
|
|
{
|
|
#[Get('')]
|
|
public function index(): ResponseInterface
|
|
{
|
|
// Handle GET /api/v1/products
|
|
}
|
|
|
|
#[Get('/{id}')]
|
|
public function show(string $id): ResponseInterface
|
|
{
|
|
// Handle GET /api/v1/products/{id}
|
|
}
|
|
|
|
#[Post('')]
|
|
public function create(): ResponseInterface
|
|
{
|
|
// Handle POST /api/v1/products
|
|
}
|
|
}
|
|
```
|
|
|
|
### Routes with Middleware
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace App\Infrastructure\Api;
|
|
|
|
use Foundation\Core\Infrastructure\ControllerInterface;
|
|
use Foundation\Core\Routing\Attributes\Get;
|
|
use Foundation\Core\Routing\Attributes\Post;
|
|
use Foundation\Core\Routing\Attributes\Group;
|
|
use App\Middleware\AuthMiddleware;
|
|
use App\Middleware\AdminMiddleware;
|
|
|
|
#[Group('/admin', middleware: [AuthMiddleware::class, AdminMiddleware::class])]
|
|
class AdminController implements ControllerInterface
|
|
{
|
|
#[Get('/dashboard')]
|
|
public function dashboard(): ResponseInterface
|
|
{
|
|
// Handle GET /admin/dashboard
|
|
// AuthMiddleware and AdminMiddleware applied
|
|
}
|
|
|
|
#[Post('/users', middleware: [ValidateUserMiddleware::class])]
|
|
public function createUser(): ResponseInterface
|
|
{
|
|
// Handle POST /admin/users
|
|
// AuthMiddleware, AdminMiddleware, and ValidateUserMiddleware applied
|
|
}
|
|
}
|
|
```
|
|
|
|
## How It Works
|
|
|
|
### Automatic Processing
|
|
|
|
1. **Container Registration**: When a controller is registered in the DI container
|
|
using `$container->register(MyController::class)`, the system automatically checks if it
|
|
implements `ControllerInterface`
|
|
|
|
2. **Attribute Discovery**: If the controller implements the interface, the `AttributeRouteProcessor` scans the
|
|
controller for route attributes
|
|
|
|
3. **Route Registration**: Found route attributes are immediately registered with the Slim application
|
|
|
|
4. **No Bootstrap Phase**: Routes are registered during container setup, not during application bootstrap
|
|
|
|
### Processing Flow
|
|
|
|
```
|
|
Controller Registration
|
|
↓
|
|
ControllerInterface Check
|
|
↓
|
|
Route Attribute Discovery
|
|
↓
|
|
Slim Route Registration
|
|
```
|
|
|
|
## Architecture Benefits
|
|
|
|
### Container-Driven Processing
|
|
|
|
- Only processes controllers that are explicitly registered in the container
|
|
- No filesystem scanning or discovery phase
|
|
- Routes registered immediately when controllers are registered
|
|
|
|
### Type Safety
|
|
|
|
- Explicit interface contract (`ControllerInterface`)
|
|
- Clear intent - controllers must opt-in to route processing
|
|
- IDE support and autocompletion
|
|
|
|
### Extensible Design
|
|
|
|
- Built on generic `AttributeProcessorInterface`
|
|
- Framework ready for other attribute types (validation, caching, etc.)
|
|
- Modular and maintainable architecture
|
|
|
|
## Best Practices
|
|
|
|
### Controller Organization
|
|
|
|
- Keep controllers focused and single-purpose
|
|
- Use groups for logical route prefixes
|
|
- Implement `ControllerInterface` only on actual controllers
|
|
|
|
### Route Design
|
|
|
|
- Use descriptive route paths
|
|
- Group related routes using `#[Group]`
|
|
- Apply middleware at the appropriate level (group vs individual routes)
|
|
|
|
### Module Structure
|
|
|
|
```
|
|
src/Modules/{ModuleName}/Infrastructure/
|
|
├── Api/ # API controllers with /api groups
|
|
├── Web/ # Web controllers for HTML responses
|
|
└── Console/ # Console commands (no route attributes)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Routes Not Registered
|
|
|
|
1. Ensure controller implements `ControllerInterface`
|
|
2. Verify controller is registered in a service provider
|
|
3. Check attribute syntax and imports
|
|
|
|
### Route Conflicts
|
|
|
|
- Use unique route paths
|
|
- Check for overlapping group prefixes
|
|
- Verify HTTP method combinations
|
|
|
|
### Middleware Issues
|
|
|
|
- Ensure middleware classes exist and are registered
|
|
- Check middleware order (group middleware runs before route middleware)
|
|
- Verify middleware implements correct interface |