DoctrineMigrationsBundle
DoctrineMigrationsBundle copied to clipboard
Multiple entity managers support
Inside our ERP system we have calls to multiple database storages. To use them with Symfony2, we've defined them as different connections each one attached to a different entity manager.
If we make some change to the database structure there is no way to specify on which entity manager this change is going to be performed.
This can be controlled via the command line, but doing so is not reliable, unless we cherry-pick the doctrine migrations on deployment and specify different "--em" argument depending on the current migration.
+1
+1
+1
Awesome!
+1
+1
Currently this can be achieved by using Container Aware Migrations. If one can have the service container injected, he can obtain an instance of some entity manager and its connection.
Here's a reference.
By the time of posting this issue there was no such functionality. It is, however, considered as a workaround. It does not seem right to have the container on your disposal.
+1
Another workaround would be to implement the --configuration option properly. Currently the $this->configuration (AbstractCommand) gets overwritten with the default and therefore does not do what it was supposed to do: run migrations from a specific folder, using a specific migrations table. Changing the if statement in getMigrationConfiguration (if (! $this->configuration) to always pass (true || ! $this... ) allowed me to use a different folder, a different table and (in combination with --em) a different entity manager.
EDIT: just saw there is a fix... https://github.com/doctrine/DoctrineMigrationsBundle/issues/18
:+1:
But seriously: What happened to this ticket?
Two years later nothing has changed.
I am still going to recommend the Container Aware Migrations as a workaround.
:thumbsup: +1 Hope to see this someday...
For me, ContainerAwareInterface
approach is completely sufficient and working.
I suggest closing, since 2 years passed with no PR.
@dinamic how do you use the new entity manager to execute the migrations? From the container you can get the proper $em but then, the addSql()
calls continue using the other connection.
class Version20141028122535 extends AbstractMigration implements ContainerAwareInterface
{
private $container;
/**
* @var EntityManager
*/
private $em;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function preUp(Schema $schema)
{
$this->em = $this->container->get('doctrine.orm.shared_entity_manager');
}
public function preDown(Schema $schema)
{
$this->em = $this->container->get('doctrine.orm.shared_entity_manager');
}
public function up(Schema $schema)
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->em->getConnection()->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('CREATE TABLE new_table (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
}
public function down(Schema $schema)
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('DROP TABLE new_table');
}
}
Yea, that was a problem I noticed when I tried it later on. I ended up getting the connection from the entity manager and executing the queries towards it. It's not ideal, but it works and we don't really have another way around.
ContainerAwareInterface has nothing to do with this issue. With ContainerAwareInterface you can get any entity manager you want, but you don't know what entity manager was selected in command line.
That's correct. You don't know and you don't actually care what's selected on the command line.
The ContainerAwareInterface
solves a problem here, it's not the cause of it.
We are still waiting for a proper fix to be applied for this problem. Until then, ContainerAwareInterface
is the necessary evil.
+1
+1
+1
A few downsides I found to the proposed container workaround:
- It's ugly as hell.
- You get a console warning for not executing any SQL.
- The queries get executed even if you do a dry-run.
@stof We have a fork where we added support for this. Kinda necessary with 16 EMs on the app.
Couple of things:
- we need to track the em migration was executed against like so http://i.imgur.com/aAhHfuh.png
- changes to doctrine/migrations are necessary
If we clean the code up a bit would you be in a position to merge a PR in on both this repo and doctrine/migrations ?
@spinx does it really need a change in doctrine/migrations itself ? what kind of change ?
@stof Mostly changes to commands. To allow diffing on all EMs, generating migrations for EMs. As I mentioned the only downside is that you need to track which EM the migration is for so you need to append EM name or similar to the migration version.
@spinx or you just use different configuration for different em and your problem is already solved.
@mikeSimonson I'm not sure I understand what you mean by that. Can you elaborate ?
@spinx For each migration command you can pass an entity manager and a migration configuration. In the migration configuration you can set the migration folder and the sql table that will hold the version migrated. Then you create an em configuration for all your different em.
The result will be that the migration on your different em are going to be independent of each other.
Ah, I see. Might be a way to go, not sure.
@stof Is adding em to migration version acceptable ? Or maybe a column of 'manager' that defaults to 'default' instead, to have more backwards compatibility. People are probably relying on versions to be integers, right?
That would be a huge BC break and honestly you shouldn't use the em for migrations in the first place. It's only going to bring you performance issues and troubles.
Wouldn't use the EM but you somehow need to know against which EM you want to execute. Also if you are diffing to generate migrations files, the way it works now, having unix time as version, you can't really generate migrations for multiple EMs. Well you can do sleep(1) which is a bas solution as well.