From 0f353c14110c1dc2383b231503cf3c933b846d55 Mon Sep 17 00:00:00 2001 From: "Jonathan H. Wage" Date: Tue, 22 Feb 2011 20:54:40 -0600 Subject: [PATCH] A command to generate a migration from the sql queries executed when you load some data fixtures. --- ...rationsGenerateFromDataFixturesCommand.php | 117 ++++++++++++++++++ .../FixturesToMigrationSQLLogger.php | 22 ++++ 2 files changed, 139 insertions(+) create mode 100644 src/Symfony/Bundle/DoctrineMigrationsBundle/Command/MigrationsGenerateFromDataFixturesCommand.php create mode 100644 src/Symfony/Bundle/DoctrineMigrationsBundle/SQLLogger/FixturesToMigrationSQLLogger.php diff --git a/src/Symfony/Bundle/DoctrineMigrationsBundle/Command/MigrationsGenerateFromDataFixturesCommand.php b/src/Symfony/Bundle/DoctrineMigrationsBundle/Command/MigrationsGenerateFromDataFixturesCommand.php new file mode 100644 index 0000000000..5e9e31e267 --- /dev/null +++ b/src/Symfony/Bundle/DoctrineMigrationsBundle/Command/MigrationsGenerateFromDataFixturesCommand.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\DoctrineMigrationsBundle\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Input\InputOption; +use Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand; +use Symfony\Bundle\FrameworkBundle\Command\Command; +use Doctrine\Common\DataFixtures\Executor\ORMExecutor; +use Doctrine\Common\DataFixtures\Purger\ORMPurger; +use Symfony\Bundle\DoctrineAbstractBundle\Common\DataFixtures\Loader as DataFixturesLoader; +use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; +use Doctrine\DBAL\Migrations\Configuration\Configuration; +use Symfony\Bundle\DoctrineMigrationsBundle\SQLLogger\FixturesToMigrationSQLLogger; + +/** + * Command for generating a Doctrine database migration class from a set of fixtures. + * + * @author Jonathan H. Wage + */ +class MigrationsGenerateFromDataFixturesCommand extends GenerateCommand +{ + protected function configure() + { + parent::configure(); + + $this + ->setName('doctrine:migrations:generate:from-data-fixtures') + ->addOption('fixtures', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The directory or file to load data fixtures from.') + ->addOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command.') + ; + } + + public function execute(InputInterface $input, OutputInterface $output) + { + if ( ! class_exists('Doctrine\Common\DataFixtures\Loader')) { + throw new \Exception('You must have the Doctrine data fixtures extension installed in order to use this command.'); + } + + $sqlLogger = new FixturesToMigrationSQLLogger(); + + $container = $this->application->getKernel()->getContainer(); + + $emName = $input->getOption('em'); + $emName = $emName ? $emName : 'default'; + + DoctrineCommand::setApplicationEntityManager($this->application, $emName); + + $emServiceName = sprintf('doctrine.orm.%s_entity_manager', $emName); + $em = $container->get($emServiceName); + + $em->getConnection()->getConfiguration()->setSQLLogger($sqlLogger); + + $configuration = $this->getMigrationConfiguration($input, $output); + + $dirOrFile = $input->getOption('fixtures'); + if ($dirOrFile) { + $paths = is_array($dirOrFile) ? $dirOrFile : array($dirOrFile); + } else { + $paths = array(); + foreach ($this->application->getKernel()->getBundles() as $bundle) { + $paths[] = $bundle->getPath().'/DataFixtures/ORM'; + } + } + + $loader = new DataFixturesLoader($container); + foreach ($paths as $path) { + if (is_dir($path)) { + $loader->loadFromDirectory($path); + } + } + $fixtures = $loader->getFixtures(); + $purger = new ORMPurger($em); + $executor = new ORMExecutor($em, $purger); + $executor->setLogger(function($message) use ($output) { + $output->writeln(sprintf(' > %s', $message)); + }); + $executor->execute($fixtures); + + $queries = $sqlLogger->getQueries(); + + $output->writeln(sprintf(' > %s queries logged', count($queries))); + foreach ($queries as $query) { + $output->writeln(sprintf(' - %s (%s)', $query[0], implode(',', $query[1]))); + } + + $version = date('YmdHis'); + + $up = $this->buildCodeFromSql($configuration, $queries); + $down = 'throw new \Doctrine\DBAL\Migrations\IrreversibleMigrationException();'; + $path = $this->generateMigration($configuration, $input, $version, $up, $down); + + $output->writeln(sprintf(' > Generated new migration class to %s', $path)); + } + + private function buildCodeFromSql(Configuration $configuration, array $queries) + { + $code = array(); + foreach ($queries as $query) { + if (strpos($query[0], $configuration->getMigrationsTableName()) !== false) { + continue; + } + $code[] = sprintf("\$this->_addSql(\"%s\", %s);", $query[0], var_export($query[1], true)); + } + return implode("\n", $code); + } +} \ No newline at end of file diff --git a/src/Symfony/Bundle/DoctrineMigrationsBundle/SQLLogger/FixturesToMigrationSQLLogger.php b/src/Symfony/Bundle/DoctrineMigrationsBundle/SQLLogger/FixturesToMigrationSQLLogger.php new file mode 100644 index 0000000000..01909ed25e --- /dev/null +++ b/src/Symfony/Bundle/DoctrineMigrationsBundle/SQLLogger/FixturesToMigrationSQLLogger.php @@ -0,0 +1,22 @@ +queries[] = array($sql, $params, $types); + } + + public function getQueries() + { + return $this->queries; + } + + public function stopQuery() + { + } +} \ No newline at end of file