Journal — Field report
Illustration : Biblioteca Rector Machado y Nuñez — PDM 1.0 · source
Three Symfony versions, two PHP versions, one codebase. I tried it on my own modules — here is where the line falls between one branch and two.
One module, one repository, one version, installing on anything from PrestaShop 1.7 to PrestaShop 9. On paper it is elegant. In practice you are asking a single codebase to run on three major Symfony versions — 3.4, 4.4 and 6.4 — and on two PHP branches that do not speak the same language.
I tried it on my own modules. Here is what I found.
PrestaShop 1.7.8 still runs on PHP 7.4 at many hosts. Four pieces of syntax are enough to break everything:
bool|array — introduced in PHP 8.0;str_contains(), which does not exist before PHP 8.0;#[…], even purely informational ones;…\Class. That is a reserved word,
rejected by PHP 7.4. My local PHP 8.4 accepted it without complaint, which hid the problem right
up to deployment.None of those four fixes is hard. Together, they strip the module of everything PHP 8 made comfortable — and a developer picking up the code in two years will not understand why it is written as if it were 2019.
In the other direction, the difficulty lies elsewhere. PrestaShop 9 deprecates
FrameworkBundleAdminController, the base class of every admin controller, in favour of
PrestaShopAdminController. The two do not coexist gracefully: the controller becomes a
service, its dependencies come through the constructor, and the way services are reached changes.
Writing a controller that satisfies both means writing two controllers and wiring up the right one based on the detected version. At that point you no longer have a compatible module: you have two modules in one folder, with the complexity thrown in.
It is a clear line, and it does not depend on the PrestaShop version but on the architecture of the module:
Two branches. One for 1.7.8 → 8.x, one for 9.x, each tagged and released separately. That is what serious module vendors do, and it is not laziness: a compatibility layer trying to cover the whole range ends up breaking on both sides, and nobody can tell which path the code took any more.
The only case where a single module holds up is precisely the one where there is nothing to reconcile: no controller, no service, no Symfony form. If your module is in that situation, keep it that way as long as you can. That is its best quality.
Migration Symfony jumps from 4.4 to 6.4 and FrameworkBundleAdminController disappears. An inventory of what breaks, module by module, and of what doesn't move.
Security Three patterns come back in almost every audit of a made-to-order module. None of them is exotic, all of them are avoidable, and reading the code is enough to spot them.
Takeover No access, no repository, no documentation. The audit method I apply before saying whether to repair or rebuild.