ezsystems/ezpublish-legacy-installer
Composer installer for eZ Publish Legacy that automatically places legacy extensions and packages into the correct eZ Publish directory structure, simplifying dependency management and deployment for older eZ Publish projects.
This package is a Composer installer plugin for eZ Publish Legacy — it is not something you use in your Laravel application code. It hooks into Composer so that legacy eZ extensions (the old ezpublish-legacy-extension / ezpublish-legacy-* package types) get installed into the correct extension/ directories with the correct structure, instead of the default vendor/ layout.
Where to look first
composer.json — confirm the package type you're installing (ezpublish-legacy-extension, ezpublish-legacy-design, or ezpublish-legacy-lib) and that the plugin is required as ezsystems/ezpublish-legacy-installer.composer.json extra block — this is where ezpublish-legacy-extension-name (and equivalents) is declared and where the installer decides the target folder.vendor/ezsystems/ezpublish-legacy-installer/ — read the installer source to see how it resolves paths relative to your legacy root.First use case
Add the installer to your legacy project, then require a single legacy extension and verify it lands in extension/<name>/ rather than vendor/:
composer require ezsystems/ezpublish-legacy-installer
composer require <vendor>/<legacy-extension>
ls extension/
v2.1.0 note: this release adds Composer 2 support. If your project is still on Composer 1, pin to the 2.0.x line until you've validated the upgrade path; if you're on Composer 2, this is the release that makes the plugin usable at all.
Keep the installer a root-level dev/tooling dependency. The plugin must be installed in the root project for Composer to activate it. Requiring it only as a transitive dependency of an extension will not register the installer reliably across Composer versions.
Pin the installer in composer.json explicitly rather than relying on transitive resolution, so Composer 1/Composer 2 behaviour is deterministic across your team and CI:
{
"require": {
"ezsystems/ezpublish-legacy-installer": "^2.1"
},
"config": {
"allow-plugins": {
"ezsystems/ezpublish-legacy-installer": true
}
}
}
Allow the plugin explicitly (Composer 2.2+). Composer 2 requires interactive approval or an allow-plugins entry for every plugin. Bake this into the repo and into CI so interactive prompts never block a build.
Treat legacy extensions as Composer packages, not vendored copies. Declare them in composer.json with the right type and let the installer place them. This gives you lockfile-level reproducibility for extension versions — a real upgrade over the old extension/ + git submodule habit.
Use a dedicated legacy application skeleton. The typical layout is an eZ Publish Legacy root (ezpublish_legacy/) alongside a Symfony/Laravel app, with the installer configured (via extra in the root composer.json) to point at that root. Keep the legacy root path in config, not hardcoded in scripts.
CI pattern:
composer install --no-interaction --prefer-dist
composer check-platform-reqs
php bin/php/ezpgenerateautoloads.php # regenerate legacy autoloads after install
Run the legacy autoload regeneration after every composer install, otherwise newly installed extensions exist on disk but are invisible to the legacy kernel.
Composer 2 migration checkpoint. Since v2.1.0 is the Composer 2 line, do the upgrade deliberately: run composer update on a branch, diff the lockfile, and confirm each legacy package still resolves to its expected install path before merging. Don't let a routine composer update silently drag the installer across a major Composer version boundary.
Silent plugin non-activation. If the installer isn't allowed, Composer 2 installs the package but never runs it — extensions then land in vendor/ and you get confusing "extension not found" errors from the legacy kernel rather than a clear Composer error. Check composer diagnose and confirm the plugin appears as active.
Composer 1 vs 2 divergence in path resolution. The v2.1.0 changes are specifically about Composer 2 API compatibility, so behaviour around install paths and package-type handling can differ from 2.0.x. If two machines behave differently while running the same lockfile, compare composer --version first — this is the most likely culprit post-upgrade.
extra key naming is the usual failure point. The extension name in extra determines the target directory. A mismatch (or a missing ezpublish-legacy-extension-name) results in a package installed under an unexpected folder name, which the legacy config then can't find. Always verify extension/<expected-name>/ after install.
Legacy autoloads are not Composer autoloads. The legacy kernel uses its own autoload generator. composer dump-autoload is not sufficient — you need the eZ autoload regeneration step. Wire it into a post-install-cmd/post-update-cmd script so it can't be forgotten.
Permissions and ownership. The installer writes directly into extension/ (and similar) with the running user's ownership. In containerised or CI setups where composer install runs as a different user than the web server, you get unreadable extension directories that only fail at runtime. Normalise permissions after install.
Don't mix vendored and Composer-managed extensions. If an extension exists in extension/ from a previous manual install and you then add it via Composer, you get a half-overwritten directory. Remove manual copies first.
Extension points are thin. There is no meaningful hook surface for customising install behaviour; the practical customisation is the root composer.json extra/config. If you need non-standard layout, you're better off restructuring the legacy root than patching the installer.
Version constraint hygiene. Because this package is tightly coupled to Composer's plugin API, constrain it (^2.1) and re-validate on every Composer major release. This release is a good reminder that the installer's version is effectively a function of your Composer version, not just your eZ version.
Debugging checklist when installs go wrong: (1) plugin allowed? (2) Composer major version? (3) correct package type and extra key? (4) legacy autoloads regenerated? (5) target directory writable and correctly owned?
How can I help you explore Laravel packages today?