8

I have a Symfony project that is using the DoctrineMigrations bundle, and I have a really simple question: When I run a migration (e.g., when I'm pushing an update to production), how can I insert data to the database?

For example: I have an Entity which is the type of an add. The entity is:

private $addType; // String
private $type1;   // Boolean
private $type2;   // Boolean
private $type3;   // Boolean

I add another field ($type4), and I want to add a new record to the database, with this values:

$addType = 'Type number 4';
$type1 = false;
$type2 = false;
$type3 = false;
$type4 = true;

How can this be done with DoctrineMigrations? Is it possible?

mHouses
  • 875
  • 1
  • 16
  • 36
  • Hi. I am not familiar with DoctrineMigrations, but I am just trying to understand your question. Can I clarify that I understand what you mean: when you are running a migration, you have added a new property (`$type4`) to your entity, and you want to insert a default value (`true`) into the database for this property and its underlying db column. Is this accurate? – Darragh Enright Aug 07 '15 at 13:26
  • @Darragh: Not exactly. The first part is right: add a new property to the entity. But I don't want to define a default value, what I want is to add a new record to the database. I know that this example is so silly, but this is what I need... – mHouses Aug 07 '15 at 14:12
  • Oh right, sorry I didn't understand you. I'll remove my answer. I guess you could still use `$this->connection->executeQuery('INSERT INTO add (foo, bar) VALUES ('a', 'b')` in your migrations. I have no idea if it is possible to use the ORM layer in migrations, assuming this is what you want to do. – Darragh Enright Aug 07 '15 at 14:22
  • Use the doctrinefixturebundle – Matteo Aug 07 '15 at 18:24
  • @Matteo: AFAIK, this isn't an option, because when you run the `fixtures:load` command (I don't remember if it's exactly this command), the database is purged... And I don't want to purge the production database each time I install an update... **EDIT**: There is a flag (`--append`) to not purge the database, but this way you charge ALL the fixtures, not only the new ones... – mHouses Aug 07 '15 at 20:21
  • Yes you can append and load selectively by direcory selector check the option of the cli task. – Matteo Aug 08 '15 at 06:31

7 Answers7

16

Using the Entity Manager as suggested in another answer is not a good idea, as it leads to troubles later.

In the first migration, I created a table with users and populated some users via $em->persist($user); which seemed fine at the beginning.

But after a month, I added a phone column to my User model. And Doctrine generates INSERT statements with this column within the first migration, which fails due to the non-existing column phone. Of course it doesn't exist yet in the first migration. So it is better to go with pure SQL INSERTs.

Cave Johnson
  • 6,499
  • 5
  • 38
  • 57
Josef Svoboda
  • 176
  • 1
  • 4
  • 5
    To avoid that, every change should be made by the migration, even the first `schema:update`... – smarber Jul 18 '17 at 12:21
  • Just to clarify once a migration version is migrated, it will never run again in the future for the same database. It's only once per server. – Sumeet Dec 05 '18 at 13:11
  • @smarber I think there is still a bigger issue which is that using the ORM depends on your current codebase (entity classes), not your database schema. So let's say in one of you migrations you drop a column. If you have to go back to an earlier migration which references the dropped column, an error will be thrown because the current entity class doesn't have that property. So you are right that it needs to have the schema:update but also the migrations should use raw sql instead of the current entity class. – Cave Johnson Apr 17 '21 at 17:25
10

I just asked a related related question.

It is possible to use the migrations bundle to add data to the database. If you add a new property and use the doctrine mapping then the

php app/console doctrine:migrations:diff

command will generate a new migration file. You can just put your insert statements inside this file using the syntax:

$this->addSql('INSERT INTO your_table (name) VALUES ("foo")');

Make sure you put it after the auto-generated schema changes though. If you want to separate your schema changes and your data changes then you can use

php app/console doctrine:migrations:generate

to create an empty migrations file to put your insert statements in.

Like I said in my related question, this is one way to do it, but it requires manually creating these if you want to change this data in the database.

Edit:

Since this answer seems to get a few views I think it's worth adding that to more clearly separate the data changes from the schema changes there is a postUp method that can be overridden and that will be called after the up method.

https://www.doctrine-project.org/projects/doctrine-migrations/en/3.0/reference/migration-classes.html#postup

mickadoo
  • 3,337
  • 1
  • 25
  • 38
3

I've "found" the correct way to solve my problem (insert data after running migrations, using my entity classes).

Here is: https://stackoverflow.com/a/25960400

The idea is to declare the migration as ContainerAware, and then, from the postUp function, call the DI to get the EntityManager. It's really easy, and you can use all your entities and repositories.

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

class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{

    private $container;

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

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

    public function postUp(Schema $schema)
    {
        $em = $this->container->get('doctrine.orm.entity_manager');
        // ... update the entities
    }
}
Community
  • 1
  • 1
mHouses
  • 875
  • 1
  • 16
  • 36
  • 6
    This is bad practice and is not recommended because if you then change your entity then all migrations using it will fail ([as mentioned here](https://github.com/doctrine/migrations/issues/124)) – OKE Dec 01 '16 at 14:27
3

when you make the new field you need to enter this annotation "options={"default":1}" and it should work.

/**
 * @var boolean
 * @ORM\Column(name="type4", type="boolean", options={"default":1})
 */
private $type4 = true;

Took me some time to figure this out :)

Favian Ioel P
  • 312
  • 3
  • 13
3

It does, if you know how to format the array;

$this->connection->insert('user', ['id' => 1, 'gender' => 'Male']);
0

this is good solution for me. Just use bin/console make:migration and when migration is generated just edit if and add "DEFAULT TRUE": $this->addSql('ALTER TABLE event ADD active TINYINT(1) NOT NULL DEFAULT TRUE');

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 04 '21 at 17:50
-1

It doesn't sound a good idea to fill date in migration, not its responsibility, symfony has a way of doing that. https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html

Yang.D
  • 17
  • 3
  • Fixtures are not intended for production data, so this answer is definitely incorrect. If you're adding something like a status or role to a table, fixtures are not an option as they don't keep track of what has been run, and by default clear the entire database. – Brettins Nov 30 '21 at 18:05