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é

Symfony 6.0: PHP 8.1 only, and the security system rebuilt

Symfony 6.0 released November 29, 2021. The defining characteristic: PHP 8.1 is the minimum. Not supported, required. The releases team waited for PHP 8.1 to ship, then cut Symfony 6.0 the next day. This isn’t just a version bump. It’s a commitment to build against the current language instead of the historical floor. The security system, finally rebuilt The Symfony security component has two systems. The old one (AnonymousToken, GuardAuthenticatorInterface, a tangle of interfaces that made you implement methods you didn’t need) had been deprecated. 6.0 removes it entirely. ...

January 12, 2022 · 5 min · Guillaume Delré

Symfony 5.4 LTS: enum support, route aliases, and the PHP 8.1 bridge

Symfony 5.4 landed November 29, 2021, same day as Symfony 6.0 and one day after PHP 8.1 was released. Not a coincidence. 5.4 is the LTS, and its job is to carry as much of 6.0’s feature set as possible while keeping 5.x compatibility intact. It’s also the first Symfony release that actually understands PHP 8.1 features. Enum support PHP 8.1 introduced native enums. Symfony 5.4 embraces them immediately: enum Status: string { case Active = 'active'; case Inactive = 'inactive'; } The EnumType form type renders enums as select fields, no custom transformers needed. The validator understands backed enums. The serializer maps enum values to their backing type and back. Three components updated in one shot, which meant migrating codebases from pseudo-enum constants to real PHP 8.1 enums was actually pretty smooth. ...

January 10, 2022 · 7 min · Guillaume Delré

PHP 8.1: enums, fibers, and the type system growing up

PHP 8.1 released November 25th. It follows 8.0’s sweeping overhaul with something different: fewer features, but each one thought through rather than bolted on. Enums This is the one that changes codebases the moment you upgrade. Before 8.1, PHP enumerations were either class constants, strings, or integers with nothing enforcing them: // before: nothing stops Status::INVALID from being passed const ACTIVE = 'active'; const INACTIVE = 'inactive'; // after enum Status: string { case Active = 'active'; case Inactive = 'inactive'; } function activate(Status $status): void { ... } PHP enums are objects, not scalars. They support methods, interfaces, and constants. Backed enums (with a string or int value) serialize cleanly and map to database columns naturally. Pure enums (no backing type) enforce domain concepts without worrying about serialization. ...

January 9, 2022 · 5 min · Guillaume Delré

PHP 8.0: match, named arguments, attributes, and JIT

PHP 8.0 shipped November 26th. I’ve been running it for six weeks on a side project and a greenfield service at work. It’s the most significant PHP release since 7.0, and in some ways more impactful, because the changes pile on top of each other in useful ways. JIT The Just-In-Time compiler was the headline announcement. The reality in production is more nuanced: for typical web apps (database queries, HTTP calls, template rendering) the gains are modest, because those workloads are I/O bound, not compute bound. Where JIT actually shines is CPU-intensive code: image manipulation, data transformation, mathematical computation. ...

January 10, 2021 · 8 min · Guillaume Delré

Revision pruning with window functions and logarithms, when DQL wasn't enough

Every content update on the platform creates a revision. That’s by design: editors need a history they can roll back to, and the platform needs an audit trail. What nobody anticipated was the rate. Some articles go through forty saves in a single afternoon. A high-traffic piece accumulates hundreds of revisions over its lifetime. After a few months, the revision table had several million rows. Deleting them naively wasn’t an option. “Keep the last 50” loses all historical context for articles that haven’t been touched in a year. “Keep one per day” loses all the detail for content that’s actively being edited. What we needed was a distribution that matched how revisions are actually used: dense coverage for recent history, sparse coverage for old history. ...

September 27, 2020 · 8 min · Guillaume Delré

PHP 7.4: typed properties and the arrow function you actually want

PHP 7.4 landed November 28th. It’s the last 7.x release before PHP 8.0, and it feels like it. The features are substantial enough to stand on their own, but they also read as groundwork for what’s coming. Typed properties This is the one. Since PHP 7.0, you could type function parameters and return values. But class properties? Still untyped: class User { public int $id; public string $name; public ?DateTimeInterface $deletedAt; } 7.4 changes that. Typed properties enforce types at assignment, not just at call sites. Classes become self-documenting in a way that docblocks never quite managed, and the engine catches type errors before they propagate through half your stack. ...

January 12, 2020 · 6 min · Guillaume Delré

Symfony 5.0: String, Notifier, and the secrets vault

Symfony 5.0 released November 21, 2019, same day as 4.4. Where 4.4 is about stability and a long support window, 5.0 is the next chapter: no deprecated code, PHP 7.2.5 minimum, and a handful of new components that finally address gaps that had piled up for years. The String component PHP’s string handling is famously scattered: prefix-style functions here (str_), suffix-style there (strpos), inconsistent encoding support, and nothing object-oriented in sight. The String component wraps all of this into a fluent, unicode-aware object API: ...

January 6, 2020 · 5 min · Guillaume Delré