foundation/documentation/attribute-routing.md
2025-06-13 18:29:55 +02:00

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