webignition/container-aware-migration
Container-aware migration support for Laravel packages, letting migrations resolve services and dependencies from the application container instead of relying on hard-coded class instantiation. Useful for packages that need flexible, testable migrations across differing application setups.
This is a very small utility package, not a bundle. It gives you an abstract Doctrine migration class that is aware of the Symfony service container, so a migration can call application services instead of doing everything through raw SQL.
Install it and inspect what you actually got:
composer require webignition/container-aware-migration
Open vendor/webignition/container-aware-migration/src/ first. Confirm the base class name/namespace, and check composer.json for its doctrine/migrations, symfony/dependency-injection, and PHP constraints. This package has very low adoption, so verify compatibility before relying on it.
Generate a migration normally, then change it to extend the package’s base class instead of Doctrine\Migrations\AbstractMigration:
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Webignition\ContainerAwareMigration\ContainerAwareMigration;
final class Version20240101000000 extends ContainerAwareMigration
{
public function up(Schema $schema): void
{
$service = $this->container->get(MyDataBackfillService::class);
$service->run();
}
public function down(Schema $schema): void
{
// reverse or no-op
}
}
Adjust the namespace/class name to match the package source.
First real use case: a data migration that needs an application service — a repository, slug generator, importer, or API client — that is awkward to reproduce in raw SQL. Use the container only for that service; keep schema changes on $this->connection / DBAL.
If your Symfony/DoctrineMigrationsBundle version does not inject the container into migrations, this package alone will not make it work. In that case use constructor injection through Doctrine migration services or a custom migration factory instead.
Use it selectively. Keep ordinary schema migrations extending AbstractMigration. Extend the container-aware class only when the migration genuinely needs a Symfony service.
Create an app-level base class. Extend the package class once, add helpers, and make all container-aware migrations extend that:
abstract class AppMigration extends ContainerAwareMigration
{
protected function service(string $id): object
{
if ($this->container === null) {
throw new \LogicException('Container was not injected into migration.');
}
return $this->container->get($id);
}
}
Fetch services inside up() / down(). Do not store request state or long-lived service references on the migration object. Migrations are instantiated and executed in CLI context.
Combine service calls with DBAL. Use the service for business logic, but use $this->connection for direct SQL, schema checks, and bulk operations. This keeps the migration easier to reason about.
Make data migrations idempotent. Check whether rows already exist, use deterministic updates, and batch large operations. A migration that calls a service can be re-run accidentally in development.
Use it for backfills, not for new application behavior. A good pattern is: read IDs with DBAL, call a service per batch, write results with DBAL. A bad pattern is: call a service that itself performs unpredictable side effects across the whole dataset.
Test migrations with a manually injected container. In a kernel test, boot the kernel and call setContainer($container) on the migration before executing it. This catches missing/private service wiring before deployment.
Handle generated migrations. doctrine:migrations:diff normally generates a class extending AbstractMigration. Either edit the generated file or add a post-generation step/custom template so it extends your base class.
Extension point: override setContainer() in your app base class to add guards or normalize the container type, then expose narrow helper methods such as getRepository() or getService().
$this->container is null, this package is not wired into your current stack. Check your DoctrineMigrationsBundle version and migration factory configuration.$this->container->get(SomeService::class) will throw unless that service is public or exposed through a service locator. Prefer injecting a small public facade/service locator over making many services public.request_stack, security tokens, sessions, and similar services are unreliable or unavailable in CLI migrations. Use only stable, stateless services.doctrine.orm.entity_manager from the container is tempting, but after a failed flush the EM can be closed. Use DBAL for schema changes and isolate ORM work into small batches with clear().ContainerAwareInterface / ContainerAwareTrait have been deprecated or removed across Symfony versions, and this package is tiny and low-activity. Check constraints and pin versions; if it is incompatible, inline the equivalent base class yourself.bin/console doctrine:migrations:status, inspect the migration with bin/console debug:container <service>, execute a single migration in dev, and add an explicit null-container assertion. Do not leave var_dump() debugging in production migrations.AbstractMigration + ContainerAwareInterface wrapper. If it is unmaintained, create your own three-line base class in your application and remove the dependency.How can I help you explore Laravel packages today?