ezsystems/ezmigrationbundle
Kaliop eZ-Migration Bundle makes it easy to programmatically deploy changes to eZPlatform/eZPublish 5 database structure and contents using migrations, inspired by DoctrineMigrationsBundle. Requires PHP 5.6+ and eZPlatform/eZPublish 5.4+. Note: this is an unsupported internal fork.
First, the honest framing: this is not a Laravel package. ezsystems/ezmigrationbundle is an internal fork of kaliop/ezmigrationbundle, a Symfony bundle for eZ Platform / eZ Publish 5.x. There is no service provider, no Artisan command, no Eloquent, and no database/migrations. It only makes sense if you have inherited an eZ 5.x/1.x application (Symfony 2.8/3.x, app/console, app/config/config.yml). If your app is actually Laravel, stop here — you cannot use this bundle; write an Artisan migration/seeder instead.
Mental model translation for a Laravel dev:
| Laravel | This bundle |
|---|---|
artisan |
php app/console |
| Service provider | appKernel::registerBundles() |
database/migrations/*.php with up()/down() |
ez_migrations/*.yml, steps only |
migrations table |
bundle-owned Doctrine version table |
| Eloquent models | eZ Repository API (content, content types, locations) |
Minimal steps to get a first migration running:
composer require --dev ezsystems/ezmigrationbundle — but verify the package actually published under that name matches the namespace you get. If you also have kaliop/ezmigrationbundle installed, remove it: both ship Kaliop\eZMigrationBundle\eZMigrationBundle, so you get a duplicate-class fatal error.registerBundles():
new \Kaliop\eZMigrationBundle\eZMigrationBundle(),
ez_migrations/ at project root; configurable via the bundle config — check the upstream README for the exact key, it has moved between versions).php app/console list ez:migration to see the real command names for your version. Historically you get status, migrate, generate, execute.php app/console ez:migration:status — should report an empty/pending state.php app/console ez:migration:generate against an existing content type to produce a real YAML file. Editing a generated file is the fastest way to learn the schema.php app/console ez:migration:migrate and re-check status.First real use case: stand up a demo site — one migration creates the content type(s), a second seeds a small content tree and a demo editor user with a role. That is exactly what eZ built this fork for.
Where to look first (in order): the upstream kaliop/ezmigrationbundle README (authoritative docs; this fork's README is a truncated copy), then the bundle's Command/ directory to confirm command names and options, then the step-handler classes under Core/ to see exactly which YAML keys each type accepts.
Anatomy of a migration. A file is a YAML list of steps; each step has a type and a mode (create / update / delete), plus type-specific keys:
- type: content_type
mode: create
content_type: article
# ...
- type: content
mode: create
content_type: article
parent_location: 2
attributes:
title: "Hello from a migration"
- type: role
mode: create
name: Editor
policies: [...]
- type: user
mode: create
login: demo_editor
email: [email protected]
password: "..."
groups: [...]
Types you will actually use day to day: content, content_type, role, user, user_group, language, url_alias/url_wildcard, and sql as the escape hatch for anything the content API cannot express.
Generate, then edit — don't hand-write from scratch. ez:migration:generate dumps the current repository state (content types, roles, etc.) into a migration. Treat the output as a scaffold: rename steps, strip fields you don't want, and immediately re-read it before committing. Generated migrations capture a whole object graph and are easy to over-commit.
One migration per logical change, ordered by filename. The bundle sorts files and runs pending ones in order. Use zero-padded sortable names (20240301_001_add_article_type.yml) rather than Version1.yml, so you never get a lexicographic surprise. Put unrelated changes in separate files: since there is no rollback, a small blast radius is your only recovery tool.
Cross-step references instead of hard-coded IDs. Creating a content item and then parenting a child to it should not go through guessed location IDs. The bundle lets a step publish its id under a name and later steps consume it — check the upstream README's reference/lookup section for the exact syntax for your version. Hard-coded parent_location: 2 is fine for the root; anything else should be resolved by remote_id/identifier matching.
Write for re-runs. Failures are not transactional (see Gotchas), so assume any step may execute twice: prefer mode: update with an explicit match, or guard creates with SQL/sql-based existence checks. Where a step cannot be made idempotent, write a compensating migration that cleans up the half-applied state and document the manual recovery procedure in the PR.
Deploy workflow. Migrations live in the repo; on release, run ez:migration:status (must show nothing pending that you didn't intend), then ez:migration:migrate --no-interaction -v. Run as the same OS user as PHP-FPM so var/ and storage permissions stay consistent. For larger sites, run content migrations outside the web request cycle and expect slow runs — every created content item fires domain events and search indexing.
Bulk data: generate the YAML, don't loop in YAML. YAML has no loops or includes here. For seeding hundreds of items, script the YAML from a CSV/JSON source in PHP and commit the generated file, or drop to a type: sql step for raw inserts. Keep the generator script next to the migration for auditability.
Custom step handlers are the extension point. If a recurring operation isn't covered by a type, the bundle supports registering custom step handlers as services (see the upstream "custom migration steps" docs). That is cleaner than a 300-line sql step, and much cleaner than a bespoke Symfony command your team will forget exists.
If you genuinely straddle Laravel and eZ: do not try to invoke this from Laravel. Keep eZ migrations in the eZ repo and trigger them as a discrete deploy step (or a queued job that shells out on the eZ host). Cross-stack coupling here buys nothing and fails in confusing ways.
ezsystems/ezmigrationbundle; the code namespace is Kaliop\eZMigrationBundle. Installing it alongside the upstream kaliop/ezmigrationbundle is a fatal duplicate class, not a subtle bug.down() / rollback. There is no rollback command. Recovery = write a new forward migration. Plan every destructive step with an inverse in the same PR.-vvv on migrate for the failing step and file; ez:migration:status to confirm what the bundle thinks is done; ez:migration:execute <file> to run a single migration in isolation while iterating; check the version table when status and reality disagree. git log -p on a generated migration usually explains "why is this field here".How can I help you explore Laravel packages today?