The Project Drivers Book a call

Zend to Laminas upgrade case study

Zend to Laminas upgrade: Breezio, a live community platform, moved from Zend Framework 2 and PHP 5.6 to Laminas and PHP 8.2 with no rewrite and no broken production. The Project Drivers delivered PHP 8.2 migration, Laminas migration, Elasticsearch upgrade, test suite, DevOps.

Zend to Laminas upgrade for Breezio: Zend to Laminas, PHP 5.6 to 8.2, Elasticsearch 9.3, Backbone 1.6, Redis 8.6, Ubuntu 24.04, Node 24

About the project

If your application still runs your business but sits on end-of-life PHP, an unmaintained framework and abandoned dependencies, and a rewrite is too expensive and risky, this is how we handled it for Breezio, a live community and learning platform. The Project Drivers moved it from Zend Framework 2 and PHP 5.6 to Laminas and PHP 8.2, with Elasticsearch, Redis, Ubuntu, Node and Backbone upgraded alongside, without rebuilding the product. The core upgrade took four weeks, followed by stabilisation on real data.

The upgrade in numbers

MeasureResult
WhenJanuary 2026
Core upgradeFour weeks, followed by stabilisation on real data
CodebaseAbout 1,200 PHP files in 20 modules
Namespace migrationAbout 500 files, done by script rather than by hand
Automated tests133 PHPUnit test files covering every non-SSO controller, where there was no usable suite before
Frontend first loadJavaScript bundle reduced from about 6 MB to a 1.3 MB core plus lazy-loaded chunks
EnvironmentReproducible Docker setup that a new developer can start from the README
RewriteNone: same product, same behaviour, new foundation

What changed

LayerBeforeAfter
FrameworkZend Framework 2Laminas MVC 3.7
LanguagePHP 5.6PHP 8.2
SearchElasticsearch 1.4Elasticsearch 9.3
CacheRedis (legacy)Redis 8.6
Operating systemUbuntu (end of life)Ubuntu 24.04
Build toolingOld Node and GruntNode 24
FrontendBackbone 1.1Backbone 1.6

Why this upgrade was risky

Most companies avoid legacy upgrades because they fear breaking production. This platform had every reason for that fear: end-of-life PHP and framework, abandoned dependencies, a search engine from 2014 and about 1,200 PHP files across 20 modules. The goal was the same product on a stack that is safe to run and cheap to keep developing, not a rewrite.

How we upgraded it without breaking production

How we moved from Zend Framework 2 to Laminas, package by package

Zend Framework 2 is no longer maintained, and the platform was built on top of it and on a layer of community packages named after it. We did not upgrade it in place. We mapped every Zend package to its Laminas successor, found the ones with no successor, and decided for each what to replace, adopt or rebuild.

Framework core

Zend Framework 2Laminas
php >=5.5.0php ^8.2
zendframework/zendframework 2.4.*laminas-mvc ^3.7 plus only the components in use: laminas-authentication ^2.12, laminas-permissions-rbac ^3.3, laminas-session ^2.26, laminas-log ^2.17, laminas-mail ^2.25, laminas-mime ^2.10, laminas-captcha ^2.19, laminas-mvc-plugin-identity ^1.7, laminas-cache-storage-adapter-redis ^2.10
(none)laminas-zendframework-bridge ^1.4, so third-party code that still uses the old Zend names keeps working
zendservice-recaptchalaminas-recaptcha ^3.4
zftoollaminas-cli ^1.9
zend-developer-toolslaminas-developer-tools ^2.10
zendservice-twitterremoved, no longer used
phpunit-selenium based testslaminas-test ^4.4 with PHPUnit 9.5

Community modules: Zfc to Lmc

Zend-era moduleLaminas-era successor
zf-commons/zfc-user 1.*lm-commons/lmc-user ^3.9
zf-commons/zfc-user-doctrine-orm 1.*lm-commons/lmc-user-doctrine-orm ^3.0
zf-commons/zfc-rbac 2.*lm-commons/lmc-rbac-mvc ^4.2
zfr/zfr-cors 1.*lm-commons/lmc-cors ^1.6
zf-commons/zfc-admin 0.2.*folded into the platform’s own Admin module

Zend-based packages with no Laminas release

These packages were written for Zend, had no Laminas version and would never get one. We brought each into the codebase as a local module and rewrote it for Laminas, so the platform owns them.

Abandoned packageLocal module
goalio/goalio-rememberme and its Doctrine ORM packageGoalioRememberMe, GoalioRememberMeDoctrineORM
goalio/goalio-forgotpassword and its Doctrine ORM packageGoalioForgotPassword, GoalioForgotPasswordDoctrineORM
goalio/goalio-mailserviceGoalioMailService
socalnick/scn-social-auth and its Doctrine ORM packageScnSocialAuth, ScnSocialAuthDoctrineORM
webino/webino-image-thumbWebinoImageThumb
soflomo/purifierSoflomo/Purifier

Changes inside our own code

Which packages solved the main problem

Four decisions removed the blockers that make a Zend 2 to Laminas migration stall in most projects.

Package or decisionProblem it solved
laminas-zendframework-bridge ^1.4Third-party code still referenced Zend names. The bridge let it run unchanged while we migrated our own code.
laminas-mvc ^3.7 (direct jump)Skipped Zend Framework 2.5 and 3.0 and every intermediate Laminas release, so no throwaway upgrades and no extra deprecation noise.
lmc-user, lmc-rbac-mvc, lmc-corsThe user, role and CORS stack had maintained successors, so authentication and permissions moved over without a rewrite.
Local modules for Goalio, ScnSocialAuth, WebinoImageThumb and SoflomoPackages with no Laminas release could not be installed from Composer any more. Owning them removed the dependency on abandoned authors.

Result

Breezio now runs on a current framework, a modern PHP, an up-to-date search engine and a maintained operating system, builds in a reproducible environment and loads a much smaller frontend, while its users see the same product (see also the Breezio case study). The upgrade also left the team with an automated test suite that did not exist before. The work took place in early 2026, and we chose PHP 8.2 because it was the newest version we could verify against the whole dependency tree, and because the new tests and tooling turn the next PHP upgrade into a routine step instead of another leap.

Sources: the official Laminas migration guide, the laminas-zendframework-bridge project, the PHP 8.2 release notes and the PHP supported versions page.

Frequently asked questions

How long does it take to upgrade PHP 5.6 to PHP 8.2?

It depends on codebase size and dependencies. On Breezio, a platform of about 1,200 PHP files, the core upgrade took four weeks, followed by a stabilisation period on real data. A dependency audit in the first days gives a firm estimate.

Can you upgrade Zend Framework 2 to Laminas without rewriting the application?

Yes. Laminas is the official continuation of Zend Framework. Namespaces are migrated mechanically, a compatibility bridge covers third-party code, and the application keeps its architecture and behaviour. Only changes that PHP 8.2 or Laminas force are made.

Why skip the intermediate Zend Framework and PHP versions?

Each intermediate version adds its own deprecations and its own testing, and is discarded by the next step. When the destination is a direct successor, going straight to it is faster and leaves less throwaway work.

What do you do with abandoned dependencies?

We sort them into four groups: replace with a maintained successor, bring in-house as a local module ported to the new PHP version, patch in the repository when a small fix is enough, or delete if the code never uses it.

How do you avoid breaking a live platform during an upgrade?

We build automated tests first, follow a minimal-change rule, run old and new infrastructure such as Elasticsearch side by side, and verify the result on realistic data before it replaces what users rely on.

Planning a similar upgrade?

If you run a legacy PHP application on Zend Framework, an old Laminas or ZF-era packages, we start by looking at your actual stack, not by selling a rewrite. A first conversation covers:

Write to info@theprojectdrivers.com with your PHP version and a short description of the system, and we will tell you plainly what an upgrade would involve. See also Pricing and System integration & DevOps.

What we delivered

Related

Updated · The Project Drivers