Upgrade Guides
This section contains upgrade guides between major versions.v2 to v3
Breaking Changes
-
PHP 7.4 required, was 7.2. Docker image, CI jobs and the composer platform config move with it.
firebase/php-jwtwidens to^6.10 || ^7.0, so PHP 8 consumers pull the patched v7. -
Resource controllers enforce their HTTP method.
AbstractUpdateResourceControllerrequires aPATCHroute andAbstractDeleteResourceControlleraDELETEroute, checked when the route is built. An update controller returning aPUTroute now throws. Partial-update semantics were always what these controllers documented; the check makes a mismatching route fail instead of publishing a contract the controller does not implement. -
Filters declare operators instead of being one. A field is one filter with the operators it accepts, rather than one filter per operator:
The named constructors (
::equals(),::in(),::like(),::contains(),::greaterThan(),::lessThan()) are gone. Declaring the same field twice now throws, where v2 silently kept the last one, which means a v2 route that declared two filters for one field was only ever applying one of them. -
Reading filters changed.
getType(), theisType*()family,getValue()andgetRawValue()are replaced by typed properties plushas()andraw():Property names areequal,notEqual,in,greaterThan,greaterThanOrEqual,lessThan,lessThanOrEqual,like,containsandisNull. -
The
filter[...]query wrapper is gone. Clients send?status[eq]=active, one bracket level, with the operator inside.?filter[status]=activeno longer resolves. Flat notation is unchanged:?status=activestill works and maps to the first operator a field declares, so v2 clients that never used the wrapper need no change. Filter field names may no longer collide withorder_by,offset,cursor,pageorlimit, since filters and framework parameters now share one namespace. A colliding declaration throws when the route is built. -
Filters are validated per operator. An operator a field does not declare, and combinations that can never match (
value[gte]=100&value[lte]=10,eqequal toneq, an emptyinlist), answer422instead of being ignored. -
OpenAPI output targets 3.2.0, was 3.1.1. A filter field with several operators becomes one
deepObjectparameter whose properties are its allowed operators. A field with a single operator is documented flat, with the operator named in the description. Toolchains pinned to 3.1 will reject the document. -
AbstractApivalkController::__invoke()is no longer abstract. Existing controllers keep working,ApivalkRequestInterfaceis still a valid parameter type. What changes is that you can now name your own request class, and should, since the generated shapes forpath(),body()andfiltering()only resolve against the concrete class:A controller without__invoke()is no longer a compile-time error. It is rejected at runtime byRouteCacheFactoryandApivalkControllerFactoryinstead. See Typing$request. -
getRequestClass()andgetResponseClasses()are removed.__invoke()is the single source of truth for both. Its parameter names the request class, and the response classes are read from what its body returns:Delete both methods, and the@extends AbstractApivalkController<GetPetRequest>annotation with them, the template is gone. The same applies to the five resource controller bases, which no longer declare either. Check every migrated controller against this, it is where the migration silently loses documentation: the scan is syntactic, so a response only stays documented if it is constructed with a literalnewinside__invoke()itself.return $this->buildResponse($pet);and$response = $this->service->list(); return $response;both documented fine whilegetResponseClasses()listed them by hand, and both document nothing now. Neither fails, the endpoint simply loses that response from its spec, and a success response built in a helper leaves the operation with no2xxat all. Only two mistakes are loud, both aLogicExceptionnaming the controller: returning an anonymous class, and an__invoke()that yields no response class whatsoever. A controller that builds some of its responses in helpers passes and ships an incomplete document. Worth doing once across the codebase before you publish the new spec: runControllerResponseScanner::scan()over every controller and compare the result against thegetResponseClasses()list you are deleting. The diff is exactly the set of responses you are about to lose, minus the framework error responses that now come from the route instead. See Documented Responses. -
Framework error responses follow the route.
401,404,422and429were appended to every operation; each is now documented only where the route can produce it, and403is documented wherever an authorization declares scopes or permissions. Generated specs change accordingly: authorized routes gain403, and routes without a rate limit, path parameter or anything to validate lose429,404and422. See Automated Error Responses.
New Features
- QUERY transport (RFC 10008).
$route->enableQuery()makes a filtered route additionally reachable as aQUERYrequest whose JSON body carries the filters. Opt-in per route. See Filtering. - New operators:
neq,gte,lteandnull(?end_date[null]=truematches rows without a value). - Per-field IDE shapes.
DocBlockGeneratoremits one interface per filter field listing only the operators that field declares. excludeFromDocumentation()keeps a route out of the generated OpenAPI document, for internal endpoints that should not reach public docs or generated SDKs.
v1 to v2
This section lists major changes and steps required to upgrade from Apivalk v1 to v2.Breaking Changes
- Renamed
MODE_EDITtoMODE_UPDATE: All occurrences ofMODE_EDITinAbstractPropertyCollectionand related security permissions (e.g.,asset:edittoasset:update) have been renamed. - Renamed “Ordering” to “Sorting”: The terminology and related classes/methods have been updated from “Ordering” to “Sorting” (e.g.,
Orderis nowSort). - Property System Refactor:
NumberPropertyhas been split intoIntegerPropertyandFloatProperty.StringPropertynow has specialized variants likeEnumProperty,DateProperty,DateTimeProperty,ByteProperty, andBinaryProperty.
New Features
- Resource System: Introduced
AbstractResourceand a CRUD controller hierarchy (Create,View,List,Update,Delete) to streamline resource management. - Modular Pagination: Added support for multiple pagination strategies (Cursor, Offset, Page) with a new
PaginatorFactory. - Comprehensive Filtering & Sorting: A new robust system for defining filters and sorts on routes, with automatic population from query parameters.
- Property Serializer: Introduced
PropertySerializerfor full round-trip serialization of properties, including validators. - Improved OpenAPI & DocBlock Generation: Enhanced generators to support the new resource system, pagination, filters, and sorts.
- Request Population Strategies: Refactored request population into a modular strategy collection.