Request & Response
Canvas uses Symfony HttpFoundation for all HTTP handling. Controllers receive a
Request object and return a Response object. Both are injected and resolved
automatically — no manual instantiation required.
Injecting the Request
Type-hint Symfony\Component\HttpFoundation\Request in any controller method and Canvas injects the
current request automatically:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class SearchController extends BaseController {
/**
* @Route("/search", methods={"GET", "POST"})
*/
public function search(Request $request): Response {
$q = $request->query->get('q'); // from URL query string
// ...
}
}
Route parameters and the Request object can be combined freely in the same method signature:
/**
* @Route("/users/{id:int}", methods={"POST"})
*/
public function update(int $id, Request $request): Response {
$name = $request->request->get('name');
// ...
}
Reading Request Data
| Source | Access | Example |
|---|---|---|
| Query string | $request->query->get('key') |
/search?q=canvas → 'canvas' |
| POST body | $request->request->get('key') |
Form field name=Alice |
| All POST data | $request->request->all() |
Returns associative array |
| JSON body | json_decode($request->getContent(), true) |
Raw request body as string via getContent() |
| Headers | $request->headers->get('X-Api-Key') |
Header names are case-insensitive |
| Cookies | $request->cookies->get('key') |
Read-only; cookies are set on the Response |
| Uploaded files | $request->files->get('field') |
Returns UploadedFile instance; see Secure File Upload |
| HTTP method | $request->getMethod() |
Returns 'GET', 'POST', etc. |
| Method check | $request->isMethod('POST') |
Returns bool |
| Client IP | $request->getClientIp() |
Respects trusted proxy configuration |
Returning Responses
Return any Symfony Response subclass from a controller method. BaseController provides helpers for
the most common cases:
// HTML response via template engine
return $this->render('users/index.tpl', ['users' => $users]);
// JSON response
return $this->json(['id' => 1, 'name' => 'Alice']);
// Plain text
return $this->text('OK');
// Redirect
return $this->redirect('/users');
// 404
return $this->notFound('User not found');
// 403
return $this->forbidden('Access denied');
All helpers accept an optional HTTP status code as the last argument. For responses not covered by a helper, instantiate Symfony's classes directly:
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
return new Response('Created', 201);
return new JsonResponse(['error' => 'Not found'], 404);
return new RedirectResponse('/login', 302);
Session
Canvas does not wrap Symfony's session layer. Access the session directly through the request or inject
SessionInterface via the DI container:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
// Via Request (available anywhere you have the request)
$request->getSession()->set('user_id', $user->getId());
$userId = $request->getSession()->get('user_id');
$request->getSession()->remove('user_id');
$request->getSession()->clear(); // Destroy all session data
// Via constructor injection (Canvas resolves the application-wide instance)
class MyService {
public function __construct(private SessionInterface $session) {}
public function doSomething(): void {
$this->session->set('key', 'value');
}
}
Cookies
Read cookies from the request and set them on the response:
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
public function action(Request $request): Response {
// Read
$token = $request->cookies->get('remember_token');
// Write — attach to the response
$response = $this->render('dashboard.tpl');
$response->headers->setCookie(
Cookie::create('remember_token', $token, strtotime('+30 days'))
);
// Delete — expire immediately
$response->headers->clearCookie('remember_token');
return $response;
}
Request Access in Aspects
Aspects receive the request through MethodContextInterface. The request can also be replaced,
which is how aspects like ValidateAspect and
SanitizeAspect pass results downstream via request attributes:
use Quellabs\Canvas\AOP\Contracts\BeforeAspect;
use Quellabs\Canvas\Routing\Contracts\MethodContextInterface;
use Symfony\Component\HttpFoundation\Response;
class StampAspect implements BeforeAspect {
public function before(MethodContextInterface $context): ?Response {
$request = $context->getRequest();
$request->attributes->set('processed_at', microtime(true));
// No need to call setRequest() — attributes are set by reference
return null;
}
}
MethodContextInterface API, see Aspect-Oriented Programming.