Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load Symfony2 fixtures from migration class?

We've built up a set of data fixtures to seed the database with all our reference values. We are also using the DoctrineMigrationsBundle to manage schema updates. We would like to trigger the fixture load within our initial schema migration class so the system gets populated before running any additional schema updates.

I found in the docs that you can make migration classes container aware, but I can't figure out how to jump from that to calling/running the data fixtures. I haven't found any good answers on Stackoverflow or via google. Has anyone done this and can point me in the right direction? (or have suggestions on a better way to manage seed data in conjunction with schema migrations). Thanks.

This is using Symfony Version: 2.4

like image 541
Cameron M Avatar asked Jan 10 '23 04:01

Cameron M


2 Answers

This is interesting question. I've found the "dirty" solution, but it works well.


namespace Application\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;

class Version20140811164659 extends AbstractMigration implements ContainerAwareInterface
{
    private $container;

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

    public function up(Schema $schema)
    {
        // ... your code here
    }

    public function postUp(Schema $schema)
    {
        // here you have to define fixtures dir
        $this->loadFixtures('src/Acme/BlogBundle/DataFixtures/ORM');
    }

    public function down(Schema $schema)
    {
        // ... your code here
    }

    public function loadFixtures($dir, $append = true)
    {
        $kernel = $this->container->get('kernel');
        $application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
        $application->setAutoExit(false);

        //Loading Fixtures
        $options = array('command' => 'doctrine:fixtures:load', "--fixtures" => $dir, "--append" => (boolean) $append);
        $application->run(new \Symfony\Component\Console\Input\ArrayInput($options));
    }
}

This solution simply running console command php app/console doctrine:fixtures:load --fixtures=src/Acme/BlogBundle/DataFixtures/ORM --append after "up" migration. Sorry for poore English. If you'll find clear solution, share it ;)

like image 70
Serge Kvashnin Avatar answered Jan 14 '23 19:01

Serge Kvashnin


I've made a migration class to address this very problem. The code is essentially inspired from the doctrine:fixtures:load command.

<?php

namespace AppBundle\Migrations;

use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class AbstractFixturesAwareMigration extends AbstractMigration implements ContainerAwareInterface
{
    private $container;
    private $fixtures;

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

    protected function getContainer()
    {
        return $this->container;
    }

    protected function addFixture(FixtureInterface $fixture)
    {
        if(null === $this->fixtures) {
            $this->fixtures = new ContainerAwareLoader($this->getContainer());
        }

        $this->fixtures->addFixture($fixture);

        return $this;
    }

    protected function executeFixtures($em = null, $append = true, $purgeMode = ORMPurger::PURGE_MODE_DELETE)
    {
        $em = $this->getContainer()->get('doctrine')->getManager($em);
        $purger = new ORMPurger($em);
        $purger->setPurgeMode($purgeMode);
        $executor = new ORMExecutor($em, $purger);
        $executor->execute($this->fixtures->getFixtures(), $append);
        $this->fixtures = null;

        return $this;
    }
}

Usage is pretty straightforward:

<?php

namespace Application\Migrations;

use AppBundle\Migrations\AbstractFixturesAwareMigration
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20170726102103 extends AbstractFixturesAwareMigration
{        
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs
        // [...]
    }

    public function postUp(Schema $schema)
    {
        // LoadMyData can be any fixture class
        $this->addFixture(new LoadMyData());
        $this->executeFixtures();
    }        

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs
        // [...]
    }
}
like image 28
Lulhum Avatar answered Jan 14 '23 18:01

Lulhum