API Platform 3.3: headers, link security, and OpenAPI webhooks

API Platform 3.3 shipped in April 2024 with a set of targeted additions. None of them reshape the architecture — 3.2 already closed that chapter. What 3.3 adds is control over things that were previously either hardcoded or required a workaround: response headers, link visibility on sub-resources, and webhooks in the generated spec. Declarative header configuration Before 3.3, setting custom response headers required either a custom processor that modified the response object or a Symfony event listener on kernel.response. Both approaches worked but lived outside the resource definition. ...

April 29, 2024 · 3 min · Guillaume Delré

Symfony 7.0: PHP 8.2 minimum and annotations finally gone

Symfony 7.0 landed November 29, 2023, same day as 6.4. The pattern holds: the X.0 release cuts deprecated code and raises the PHP floor. 7.0 requires PHP 8.2 and removes everything that 6.4 flagged as deprecated. The most visible removal: Doctrine annotations. @Route, @ORM\Column, @Assert - gone. Native PHP attributes have been the recommended approach since Symfony 5.2. 7.0 just makes it official. Attributes everywhere The migration from annotations to attributes is mostly mechanical: syntax changes from @ to #[], and the class references move from Doctrine annotation classes to PHP attribute classes: ...

January 12, 2024 · 5 min · Guillaume Delré

Symfony 6.4 LTS: AssetMapper, Scheduler, Webhook, and the long-term release

Symfony 6.4 landed November 29, 2023. It’s an LTS with a story: four components that shipped as experimental in earlier releases are now stable. The biggest deal is AssetMapper. AssetMapper Modern frontend tooling in Symfony meant Webpack Encore. Encore works: it handles transpilation, bundling, versioning, hot reload. It also requires Node.js, a separate build step, and a non-trivial amount of configuration for what is often a pretty modest frontend. AssetMapper takes a different position. Modern browsers support ES modules natively. Instead of bundling, ship the files as-is, let the browser resolve imports through an importmap, and manage vendor dependencies through downloaded files rather than npm packages. ...

January 10, 2024 · 6 min · Guillaume Delré

PHP 8.3: typed constants and the small wins that stick

PHP 8.3 landed November 23rd. Quiet release by PHP standards: no enum-sized shift, no JIT. What it does have is a focused set of improvements that close long-standing gaps in the type system and add functions that should have existed years ago. Typed class constants Class constants have been untyped since their introduction. PHP 8.3 fixes that: interface HasVersion { const string VERSION; } class App implements HasVersion { const string VERSION = '1.0.0'; } Without typed constants, an interface constant could be overridden with a completely different type in an implementing class and nothing would complain. Typed constants close that gap, and on interface-driven codebases the impact is immediate. ...

January 7, 2024 · 6 min · Guillaume Delré

API Platform 3.2: errors as resources and sub-resources come back

API Platform 3.2 arrived in October 2023 with three changes that pushed the state model further: errors became resources, sub-resources came back in a form that actually fits the architecture, and the last legacy extension point — event listeners — was formally replaced. Errors as resources Before 3.2, error handling was outside the resource model. Exceptions were caught by a Symfony event listener and converted to a response, with limited control over the shape of the output. ...

October 12, 2023 · 3 min · Guillaume Delré

API Platform 3.1: your resource doesn't have to be your entity

Four months after 3.0, API Platform 3.1 arrived with the first batch of features built on the new state model. Not every change is dramatic, but one of them solves a problem that drove a lot of convoluted workarounds in 2.x: your API resource no longer needs to be your Doctrine entity. The resource/entity split In 2.x, API Platform worked best when your API resource and your persistence model were the same class. Using a DTO as the API surface was possible through the Input/Output DTO system, but that system was removed in 3.0 — it complicated the state model without enough benefit. ...

January 23, 2023 · 4 min · Guillaume Delré

PHP 8.2: readonly classes and the deprecation that matters

PHP 8.2 dropped December 8th. Readonly classes are the headline. The deprecation of dynamic properties is the one that actually requires your attention. Dynamic properties deprecated PHP has always allowed adding properties to objects that weren’t declared in the class: class User {} $user = new User(); $user->name = 'Alice'; // no declaration, no error... until now In 8.2, this triggers a deprecation notice. In PHP 9.0 it becomes a fatal error. The grace period exists, but the migration clock is running. ...

January 22, 2023 · 5 min · Guillaume Delré

API Platform 3.0: a new state model and the end of DataProviders

API Platform 3.0 arrived in September 2022 with Symfony 6.1 as a hard minimum and a core architecture that looked nothing like 2.x. The migration guide is long. The reason it’s long is interesting. The old model had a conceptual leak. DataProviderInterface and DataPersisterInterface were called for every HTTP request, but the provider received the operation context as a hint — not as a contract. A collection provider and an item provider were separate interfaces, but both lived in the same mental bucket: “things that return data.” The HTTP layer knew what was being requested; the provider had to reconstruct that knowledge from context clues passed in the $context array. ...

November 18, 2022 · 4 min · Guillaume Delré

From Vagrant to Docker Compose: a retrospective

I ran Vagrant for years. A Vagrantfile per project, a shared base box, a provision script that worked on Tuesday but not on Thursday. The promise was simple: reproducible environments for everyone on the team. The reality was more complicated. The Vagrant years The setup made sense at the time. One VM per project, provisioned with shell scripts or Ansible, shared via a versioned Vagrantfile. Onboarding was theoretically vagrant up and you’re done. ...

April 18, 2022 · 4 min · Guillaume Delré

Swarrot vs Symfony Messenger: a real-world comparison

We migrated a media microservices platform to Symfony 6 at the start of 2022. Twelve services, most of them consuming messages from RabbitMQ via Swarrot. Symfony 6 made Messenger more central than ever, and during the migration planning a developer asked the obvious question: why not switch at the same time? It ships with the framework. It has retry logic, native AMQP support, first-party documentation. Our setup looked artisanal by comparison. ...

January 26, 2022 · 5 min · Guillaume Delré