Use EntityManager in Migrations file
Asked Answered
W

3

30

I have this code but does not work:

<?php

namespace Application\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration,
    Doctrine\DBAL\Schema\Schema;

/**
 * Auto-generated Migration: Please modify to your need!
 */
class Version20131021150555 extends AbstractMigration
{

    public function up(Schema $schema)
    {
        // this up() 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("ALTER TABLE person ADD tellphone LONGTEXT DEFAULT NULL");

        $em = $em = $this->getDoctrine()->getEntityManager();
        $persons = $em->getRepository('AutogestionBundle:Person')->fetchAll();

        foreach($persons as $person){
            $person->setTellPhone($person->getCellPhone());
            $em->persist($person);                                                                            
        }
        $em->flush(); 
    }

    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("ALTER TABLE person DROP tellphone");
    }
}

I have add info in cellphone in a new field tellphone.

Thanks

Windjammer answered 21/10, 2013 at 19:4 Comment(3)
What do you mean with 'is not working'. How are these methods called? What is the expected and current outcome?Gurge
This line get errors $em = $em = $this->getDoctrine()->getEntityManager(); I need use EntityManager in this file. ThanksWindjammer
It's not working because you call $this->getDoctrine(), AbstractMigration class doesn't has this method.Sirajuddaula
M
74

This may be an older post, but meanwhile the problem is solved and actually part of the current documentation.

See http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html#container-aware-migrations

// ...
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;

class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{
    use ContainerAwareTrait;

    public function up(Schema $schema)
    {
        // ... migration content
    }

    public function postUp(Schema $schema)
    {
        $em = $this->container->get('doctrine.orm.entity_manager');
        // ... update the entities
    }
}
Michelsen answered 21/9, 2014 at 14:47 Comment(1)
I don't think this works in Symfony 4.4 LTSStorms
E
16

I do realize this is kind of old but learn on my mistake and:

don't even think about using entity manager in migrations

especially in a way you want to use it - to get the entity repository.

Here's why.

Imagine a situation where You have a DogEntity with field $name. You now generate a migration file (lets say its Version1) based on that entity. So far so good.

Next, you want to use entity manager to get the repository of that DogEntity, update the records, do whatever you need to do with that entities. And that works and it's okay (and let's say this migration file has name Version2).

Now, you add a $color field to your DogEntity, again you generate migration (it's a file named Version3). And its okay...

... up until you try to run all migrations from the beggining. In that moment, the error will throw during migration of Version2 file. Why? Because the entity manager looks for the color field in the database. But that field is created later, in Version3 file.

TLDR: Entity Manager looks for columns that you CURRENTLY have in your entity and that can cause problems while running migrations from the start.

Eoin answered 3/2, 2020 at 15:52 Comment(5)
You did a mistake here. It happens because you probably use doctrine:schema:update that's why you got your column color before executing version 2. If you use migration, you shouldn't use schema update or you will always have this kind of behaviour. If you didn't use migration since the begining of your project, just generate a new migration with the current state of your db, don't use schema update, and use doctrine migration appy.Strobila
No, actually what @Eoin is pointing out is right. I encountered this very often. Only workaround I found was manipulating table directly using SQL. Otherwise when executing all migrations from beginning, EntityManager would scream that it can't find a specific column which was added in a later migration. I wish there would be a way to manipulate entites in migrations and tell EntityManager to ignore non existing fields, that would be so much easier........Cougar
But what if you add the the entity manager code in a migration file that gets called after the migration files that create the corresponding columns? Lets say you add the color column to the dog table in migration30 and in migration31 you fill it with values via the help of entity manager. Would that still be a problem?Freedafreedman
This is actually wrong. If you are using the migration in the right way, this should never happen. What @Strobila said in his comment is right. Don't use doctrine:schema:update if you want to run the migration from scratch, and if you need to make changes to the schema, create a new migration! NEVER change existing migrations.Windowlight
Just don't use the addSql to execute your INSERTS/UPDATES, do it using $this->connection->insert. Don't mix schema+data in the same migration, there's nothing wrong with that.Windowlight
C
8

You must call your modifications in the postUp() method - the addSql()- Statements will be executed after up() method is completed, so your new rows (i.e. tellphone) are not available during the up() method!

Chloric answered 21/10, 2013 at 22:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.