The Five Controllers
All five are generic over the resource type:
@template TResource of AbstractResource. Declare the concrete type via the @extends annotation so static analysis and IDE autocompletion work.
What You Write
Every resource controller implements three things:getResourceClass(): string— return your resource class name.- A route declaration method — see the table below.
__invoke(ApivalkRequestInterface $request): AbstractApivalkResponse— your business logic.
getRequestClass(), getResponseClasses(), and getEmptyResource(). Create and Update also expose a getResource() helper — see below.
Route declaration: buildRoute()
All five resource controllers use buildRoute() — never implement getRoute() directly. The base class provides a final getRoute() that calls your buildRoute() and auto-injects extras:
You only declare the URL, path parameters, authorization, pagination, and rate limit in
buildRoute().
Examples
Create
View
Update
Delete
List
ImplementbuildRoute() instead of getRoute(). Tags, filters, and sortings from the resource are injected automatically — declare only the URL, authorization, pagination, and rate limit.
Nested Resources
BecausebuildRoute() is fully explicit, nested URLs are straightforward — add more path segments and declare each path parameter:
->pathProperty() call documents the parameter in OpenAPI and registers it for validation.
getResource() Helper
AbstractCreateResourceController and AbstractUpdateResourceController expose a typed $this->getResource($request) method that returns a fully populated TResource.
Create — body only. Path parameters are intentionally excluded because the identifier doesn’t exist yet (the server generates it after persisting).
Update — body fields first, then any path parameter whose name matches a resource property is automatically set. If your route has {animal_uuid} and AnimalResource declares an animal_uuid property, $resource->animal_uuid is already populated after calling getResource(). For nested resources with multiple path params (e.g. {user_uuid}/{authenticator_uuid}), only the ones whose names appear as resource properties are set — parent-scope params are ignored.
If you need the raw path value directly without the helper, $request->path()->key always works.
What the Base Class Provides
getRequestClass()— returnsResourceRequest::classby default (a shared, empty request class).getResponseClasses()— the mode-appropriate success response +BadRequestApivalkResponse+ForbiddenApivalkResponse.getEmptyResource()— instantiates the resource class returned bygetResourceClass(), useful insidebuildRoute().
IDE Autocomplete via the DocBlock Generator
After running the docblock generator, a typed request class is generated for each controller that has path parameters, sorting, filtering, or pagination (e.g.AnimalViewRequest, AnimalUpdateRequest, AnimalListRequest). To get full IDE autocomplete in __invoke, add a @param annotation with the generated class:
Update, the same annotation gives you both typed $request->path() and typed $this->getResource($request):
List, annotate with AnimalListRequest to get typed sorting(), filtering(), and paginator().