Installation
Add the bundle to your composer.json:
composer require datafactory/ezmigrationbundle
Enable it in config/bundles.php:
return [
// ...
Datafactory\EzMigrationBundle\DatafactoryEzMigrationBundle::class => ['all' => true],
];
First Migration
Create a migration class in src/Datafactory/EzMigrationBundle/Migration/:
php bin/console generate:ezmigration
This generates a skeleton class (e.g., MyFirstMigration.php) extending AbstractMigration.
Run the Migration Execute via CLI:
php bin/console ez:migrate --migration=MyFirstMigration
Key Files to Review
src/Datafactory/EzMigrationBundle/Resources/config/services.xml (service definitions)src/Datafactory/EzMigrationBundle/Migration/AbstractMigration.php (base class for migrations)config/packages/ez_migration.yaml (default configuration)Migration Class Structure
Extend AbstractMigration and implement:
public function up()
{
// Logic to upgrade content (e.g., update fields, move nodes, etc.)
$this->updateContentType('article', ['field_definitions' => [...]]);
}
public function down()
{
// Revert logic (if needed)
}
Common Use Cases
$this->updateContentType('book', [
'field_definitions' => [
'author' => ['identifier' => 'author', 'data_type_string' => 'ezstring']
]
]);
$content = $this->getContentService()->loadContent($contentId);
$this->updateContentField($content, 'title', 'New Title');
$this->moveContent($contentId, $newParentLocationId);
Dependency Injection Inject services in your migration:
public function __construct(
private ContentService $contentService,
private LocationService $locationService
) {}
Batch Processing For large datasets, use chunking:
$contents = $this->getContentService()->loadContents(['filter' => [...]]);
foreach ($contents as $content) {
$this->processContent($content);
if ($i % 100 === 0) {
$this->getLogger()->info('Processed ' . $i . ' items');
}
}
Integration with Symfony Commands
Extend EzMigrationCommand for custom CLI commands:
class CustomMigrationCommand extends EzMigrationCommand
{
protected function configure()
{
$this->setName('app:custom-migrate');
}
}
eZ Platform Version Compatibility
ContentService or LocationService APIs.Transaction Handling
$this->getConnection()->beginTransaction();
try {
$this->updateContent($content);
$this->getConnection()->commit();
} catch (\Exception $e) {
$this->getConnection()->rollBack();
throw $e;
}
Performance Issues
$search = new ContentSearchCriteria();
$search->query = new Criteria\Query();
$search->query->filter = new Criteria\LogicalAnd([
new Criteria\MatchFieldValue('content_type_identifier', 'article'),
]);
$search->limit = 100;
$search->offset = 0;
Logger Misuse
ErrorHandler for exceptions:
try {
$this->riskyOperation();
} catch (\Exception $e) {
$this->getLogger()->error($e->getMessage());
throw $e; // Re-throw to fail the migration
}
Down Migration Limitations
down() methods are not automatically executed on rollback. Manually trigger them:
php bin/console ez:migrate --migration=MyFirstMigration --down
Enable Debug Mode
Set ez_migration.debug: true in config/packages/ez_migration.yaml to log SQL queries and migration steps.
Dry Runs
Add a dryRun flag to your migration to log changes without executing them:
private $dryRun = true;
public function updateContent($content) {
if (!$this->dryRun) {
$this->getContentService()->saveContent($content);
} else {
$this->getLogger()->info('Would update: ' . $content->getId());
}
}
Checkpointing
Use EzMigrationBundle's checkpoint system to resume interrupted migrations:
public function up() {
$this->checkpoint('step_1');
// ... operations ...
$this->checkpoint('step_2');
}
Then resume from a specific checkpoint:
php bin/console ez:migrate --migration=MyFirstMigration --resume-from=step_2
Custom Migration Steps
Create reusable migration steps by extending AbstractMigrationStep:
class UpdateAuthorFieldStep extends AbstractMigrationStep
{
public function execute($content) {
$content->setFieldValue('author', 'New Author');
return $content;
}
}
Use it in your migration:
$step = new UpdateAuthorFieldStep();
$this->processContent($content, $step);
Event Listeners
Subscribe to migration events (e.g., ez_migration.pre_migrate, ez_migration.post_migrate) in services.yaml:
services:
App\EventListener\MigrationListener:
tags:
- { name: kernel.event_listener, event: ez_migration.pre_migrate, method: onPreMigrate }
Custom Validators Validate content before migration:
public function validateContent($content) {
if (!$content->hasField('required_field')) {
throw new \RuntimeException('Content missing required field');
}
}
How can I help you explore Laravel packages today?