Eleven Out of Twelve

The composer.json in each service had this in its post-install-cmd section: "post-install-cmd": [ "bin/console cache:clear --env=prod", "bin/console doctrine:migrations:migrate --no-interaction" ] post-install-cmd runs during composer install, which in the production Dockerfile runs during the image build. There is no database available during a Docker build. The migration command either failed silently, or connected to nothing, or was skipped by Doctrine when it couldn’t find a schema to compare against. In any case, it didn’t migrate anything. ...

May 17, 2026 · 5 min · Guillaume Delré

PostgreSQL full-text search through Doctrine, without a line of raw SQL

The search box on the media library returned results in 800 milliseconds on staging. Production had forty times more rows. The query plan showed a sequential scan: no index involved, no way to fix it with a standard B-tree. The product team also wanted multi-word search: type “interview president”, get results containing both words. A LIKE query with wildcards has no clean way to express that without multiple independent conditions, each requiring its own scan. ...

February 10, 2025 · 6 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é

Enforcing UTC in Doctrine without touching your entities

A timestamp coming back from the database one hour off. Not every time. Only when the dev server runs in Europe/Paris and CI runs in UTC. The kind of bug that disappears when you look for it and comes back in production on a Friday evening. The problem isn’t in the business logic. It’s in what Doctrine quietly does with dates. What Doctrine does by default When you declare a datetime field in a Doctrine entity, the conversion between PHP and the database goes through DateTimeType. That class calls format() on your DateTime object to write to the database, and DateTime::createFromFormat() to read it back. No mention of timezone anywhere. ...

February 19, 2017 · 4 min · Guillaume Delré