Routing
Canvas uses annotation-based routing. Routes are defined directly in controller methods using the @Route
annotation, eliminating the need for separate route configuration files.
Request Lifecycle
When a request arrives, Canvas checks its own routes first. If a match is found,
any @InterceptWith aspects run before and around the controller method.
The controller executes and returns a response, after which After aspects run.
If no Canvas route matches, the request falls through to the Legacy Bridge.
If an exception is thrown at any point, the error handling system takes over.
Route Discovery
Canvas automatically discovers routes by scanning your src/Controllers directory for classes with
@Route annotations. The discovered routes are compiled and cached for performance.
Controller Structure
Routes must be defined in controller classes:
<?php
namespace App\Controllers;
use Quellabs\Canvas\Annotations\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UserController {
/**
* @Route("/api/users")
*/
public function index(): Response {
return new Response('User list');
}
}
HTTP Methods
Routes default to GET requests when no methods parameter is specified. Use the methods
parameter to support additional HTTP methods:
/**
* @Route("/api/users")
*/
public function index(): Response {
// Only accepts GET requests (default)
}
/**
* @Route("/api/users", methods={"POST"})
*/
public function create(): Response {
// Only accepts POST requests
}
/**
* @Route("/api/users", methods={"GET", "POST"})
*/
public function manage(): Response {
// Accepts both GET and POST
}
Route Parameters
Capture URL segments as method parameters. Parameters are injected by name - the parameter name in your method must match the placeholder name in the route:
/**
* @Route("/users/{id}/posts/{postId}")
*/
public function userPost(string $id, string $postId): Response {
// URL: /users/123/posts/456
// $id = "123", $postId = "456"
// Parameter names must match route placeholders
}
Route Parameter Validation
Validate route parameters with type constraints. Routes with parameters that fail validation will not match, allowing the router to continue searching for other matching routes:
/**
* @Route("/users/{id:int}")
*/
public function show(int $id): Response {
// Matches: /users/123
// Doesn't match: /users/abc (fails int validation, router continues)
}
Available Validation Patterns
{x:int}- Integer values only (digits){x:alpha}- Alphabetic characters only (a-z, A-Z){x:alnum}- Alphanumeric characters only (a-z, A-Z, 0-9){x:slug}- URL-friendly slugs (lowercase letters, digits, hyphens){x:uuid}- UUID format (8-4-4-4-12 hex digits){x:email}- Valid email address format
Accessing Request Data
Inject Symfony's Request as a controller method parameter to read query strings, POST body, headers,
cookies, and session data. See Request & Response for the full
reference.