public function getMigrationConfig(InputInterface $input, OutputWriter $outputWriter) { /** * If a configuration option is passed to the command line, use that configuration * instead of any other one. */ if ($input->getOption('configuration')) { $outputWriter->write("Loading configuration from command option: " . $input->getOption('configuration')); return $this->loadConfig($input->getOption('configuration'), $outputWriter); } /** * If a configuration has already been set using DI or a Setter use it. */ if ($this->configuration) { $outputWriter->write("Loading configuration from the integration code of your framework (setter)."); return $this->configuration; } /** * If no any other config has been found, look for default config file in the path. */ $defaultConfig = array('migrations.xml', 'migrations.yml', 'migrations.yaml'); foreach ($defaultConfig as $config) { if ($this->configExists($config)) { $outputWriter->write("Loading configuration from file: {$config}"); return $this->loadConfig($config, $outputWriter); } } return new Configuration($this->connection, $outputWriter); }
/** * @param array $queriesByVersion array Keys are versions and values are arrays of SQL queries (they must be castable to string) * @param string $direction * @return int|bool */ public function write(array $queriesByVersion, $direction) { $path = $this->buildMigrationFilePath(); $string = $this->buildMigrationFile($queriesByVersion, $direction); if ($this->outputWriter) { $this->outputWriter->write("\n" . sprintf('Writing migration file to "<info>%s</info>"', $path)); } return file_put_contents($path, $string); }
private function executeRegisteredSql($dryRun = false, $timeAllQueries = false) { if (!$dryRun) { if (!empty($this->sql)) { foreach ($this->sql as $key => $query) { $queryStart = microtime(true); if (!isset($this->params[$key])) { $this->outputWriter->write(' <comment>-></comment> ' . $query); $this->connection->exec($query); } else { $this->outputWriter->write(sprintf(' <comment>-</comment> %s (with parameters)', $query)); $this->connection->executeQuery($query, $this->params[$key], $this->types[$key]); } $this->outputQueryTime($queryStart, $timeAllQueries); } } else { $this->outputWriter->write(sprintf('<error>Migration %s was executed but did not result in any SQL statements.</error>', $this->version)); } } else { foreach ($this->sql as $query) { $this->outputWriter->write(' <comment>-></comment> ' . $query); } } $this->resetRegisteredSql(); }
/** * Print a warning message if the condition evalutes to TRUE. * * @param bool $condition * @param string $message */ public function warnIf($condition, $message = '') { $message = strlen($message) ? $message : 'Unknown Reason'; if ($condition === true) { $this->outputWriter->write(' <warning>Warning during ' . $this->version->getExecutionState() . ': ' . $message . '</warning>'); } }
private function outputQueryTime($queryStart, $timeAllQueries = false) { if ($timeAllQueries !== false) { $queryEnd = microtime(true); $queryTime = round($queryEnd - $queryStart, 4); $this->outputWriter->write(sprintf(" <info>%ss</info>", $queryTime)); } }
public function write($message) { if ($this->outputInterface) { $this->outputInterface->writeln($message); } else { parent::write($message); } }
/** * Run a migration to the current version or the given target version. * * @param string $to The version to migrate to. * @param boolean $dryRun Whether or not to make this a dry run and not execute anything. * @param boolean $timeAllQueries Measuring or not the execution time of each SQL query. * * @return array $sql The array of migration sql statements * * @throws MigrationException */ public function migrate($to = null, $dryRun = false, $timeAllQueries = false) { /** * If no version to migrate to is given we default to the last available one. */ if ($to === null) { $to = $this->configuration->getLatestVersion(); } $from = (string) $this->configuration->getCurrentVersion(); $to = (string) $to; /** * Throw an error if we can't find the migration to migrate to in the registered * migrations. */ $migrations = $this->configuration->getMigrations(); if (!isset($migrations[$to]) && $to > 0) { throw MigrationException::unknownMigrationVersion($to); } $direction = $from > $to ? 'down' : 'up'; $migrationsToExecute = $this->configuration->getMigrationsToExecute($direction, $to); /** * If * there are no migrations to execute * and there are migrations, * and the migration from and to are the same * means we are already at the destination return an empty array() * to signify that there is nothing left to do. */ if ($from === $to && empty($migrationsToExecute) && !empty($migrations)) { return array(); } $output = $dryRun ? 'Executing dry run of migration' : 'Migrating'; $output .= ' <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>'; $this->outputWriter->write(sprintf($output, $direction, $to, $from)); /** * If there are no migrations to execute throw an exception. */ if (empty($migrationsToExecute)) { throw MigrationException::noMigrationsToExecute(); } $sql = array(); $time = 0; foreach ($migrationsToExecute as $version) { $versionSql = $version->execute($direction, $dryRun, $timeAllQueries); $sql[$version->getVersion()] = $versionSql; $time += $version->getTime(); } $this->outputWriter->write("\n <comment>------------------------</comment>\n"); $this->outputWriter->write(sprintf(" <info>++</info> finished in %s", $time)); $this->outputWriter->write(sprintf(" <info>++</info> %s migrations executed", count($migrationsToExecute))); $this->outputWriter->write(sprintf(" <info>++</info> %s sql queries", count($sql, true) - count($sql))); return $sql; }
/** * Run a migration to the current version or the given target version. * * @param string $to The version to migrate to. * @param string $dryRun Whether or not to make this a dry run and not execute anything. * @return array $sql The array of migration sql statements * @throws MigrationException */ public function migrate($to = null, $dryRun = false) { if ($to === null) { $to = $this->configuration->getLatestVersion(); } $from = $this->configuration->getCurrentVersion(); $from = (string) $from; $to = (string) $to; $migrations = $this->configuration->getMigrations(); if ( ! isset($migrations[$to]) && $to > 0) { throw MigrationException::unknownMigrationVersion($to); } if ($from === $to) { throw MigrationException::alreadyAtVersion($to); } $direction = $from > $to ? 'down' : 'up'; $migrations = $this->configuration->getMigrationsToExecute($direction, $to); if ($dryRun === false) { $this->outputWriter->write(sprintf('Migrating <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from)); } else { $this->outputWriter->write(sprintf('Executing dry run of migration <info>%s</info> to <comment>%s</comment> from <comment>%s</comment>', $direction, $to, $from)); } if (empty($migrations)) { throw MigrationException::noMigrationsToExecute(); } $sql = array(); $time = 0; foreach ($migrations as $version) { $versionSql = $version->execute($direction, $dryRun); $sql[$version->getVersion()] = $versionSql; $time += $version->getTime(); } $this->outputWriter->write("\n <comment>------------------------</comment>\n"); $this->outputWriter->write(sprintf(" <info>++</info> finished in %s", $time)); $this->outputWriter->write(sprintf(" <info>++</info> %s migrations executed", count($migrations))); $this->outputWriter->write(sprintf(" <info>++</info> %s sql queries", count($sql, true) - count($sql))); return $sql; }
protected function write($message) { $this->outputWriter->write($message); }
/** * Execute this migration version up or down and and return the SQL. * * @param string $direction The direction to execute the migration. * @param boolean $dryRun Whether to not actually execute the migration SQL and just do a dry run. * * @return array $sql * * @throws \Exception when migration fails */ public function execute($direction, $dryRun = false, $timeAllQueries = false) { $this->sql = array(); $transaction = $this->migration->isTransactional(); if ($transaction) { //only start transaction if in transactional mode $this->connection->beginTransaction(); } try { $migrationStart = microtime(true); $this->state = self::STATE_PRE; $fromSchema = $this->sm->createSchema(); $this->migration->{'pre' . ucfirst($direction)}($fromSchema); if ($direction === 'up') { $this->outputWriter->write("\n" . sprintf(' <info>++</info> migrating <comment>%s</comment>', $this->version) . "\n"); } else { $this->outputWriter->write("\n" . sprintf(' <info>--</info> reverting <comment>%s</comment>', $this->version) . "\n"); } $this->state = self::STATE_EXEC; $toSchema = clone $fromSchema; $this->migration->{$direction}($toSchema); $this->addSql($fromSchema->getMigrateToSql($toSchema, $this->platform)); if (!$dryRun) { if ($this->sql) { foreach ($this->sql as $key => $query) { $queryStart = microtime(true); if (!isset($this->params[$key])) { $this->outputWriter->write(' <comment>-></comment> ' . $query); $this->connection->executeQuery($query); } else { $this->outputWriter->write(sprintf(' <comment>-</comment> %s (with parameters)', $query)); $this->connection->executeQuery($query, $this->params[$key], $this->types[$key]); } $queryEnd = microtime(true); $queryTime = round($queryEnd - $queryStart, 4); if ($timeAllQueries !== false) { $this->outputWriter->write(sprintf(" <info>%ss</info>", $queryTime)); } } } else { $this->outputWriter->write(sprintf('<error>Migration %s was executed but did not result in any SQL statements.</error>', $this->version)); } if ($direction === 'up') { $this->markMigrated(); } else { $this->markNotMigrated(); } } else { foreach ($this->sql as $query) { $this->outputWriter->write(' <comment>-></comment> ' . $query); } } $this->state = self::STATE_POST; $this->migration->{'post' . ucfirst($direction)}($toSchema); $migrationEnd = microtime(true); $this->time = round($migrationEnd - $migrationStart, 2); if ($direction === 'up') { $this->outputWriter->write(sprintf("\n <info>++</info> migrated (%ss)", $this->time)); } else { $this->outputWriter->write(sprintf("\n <info>--</info> reverted (%ss)", $this->time)); } if ($transaction) { //commit only if running in transactional mode $this->connection->commit(); } $this->state = self::STATE_NONE; return $this->sql; } catch (SkipMigrationException $e) { if ($transaction) { //only rollback transaction if in transactional mode $this->connection->rollback(); } if ($dryRun == false) { // now mark it as migrated if ($direction === 'up') { $this->markMigrated(); } else { $this->markNotMigrated(); } } $this->outputWriter->write(sprintf("\n <info>SS</info> skipped (Reason: %s)", $e->getMessage())); $this->state = self::STATE_NONE; return array(); } catch (\Exception $e) { $this->outputWriter->write(sprintf('<error>Migration %s failed during %s. Error %s</error>', $this->version, $this->getExecutionState(), $e->getMessage())); if ($transaction) { //only rollback transaction if in transactional mode $this->connection->rollback(); } $this->state = self::STATE_NONE; throw $e; } }
/** * Execute this migration version up or down and and return the SQL. * * @param string $direction The direction to execute the migration. * @param string $dryRun Whether to not actually execute the migration SQL and just do a dry run. * @return array $sql * @throws Exception when migration fails */ public function execute($direction, $dryRun = false) { $this->_sql = array(); $this->_connection->beginTransaction(); try { $start = microtime(true); $this->_state = self::STATE_PRE; $fromSchema = $this->_sm->createSchema(); $this->_migration->{'pre' . ucfirst($direction)}($fromSchema); if ($direction === 'up') { $this->_outputWriter->write("\n" . sprintf(' <info>++</info> migrating <comment>%s</comment>', $this->_version) . "\n"); } else { $this->_outputWriter->write("\n" . sprintf(' <info>--</info> reverting <comment>%s</comment>', $this->_version) . "\n"); } $this->_state = self::STATE_EXEC; $toSchema = clone $fromSchema; $this->_migration->{$direction}($toSchema); $this->addSql($fromSchema->getMigrateToSql($toSchema, $this->_platform)); if ($dryRun === false) { if ($this->_sql) { $count = count($this->_sql); foreach ($this->_sql as $query) { $this->_outputWriter->write(' <comment>-></comment> ' . $query); $this->_connection->executeQuery($query); } } else { $this->_outputWriter->write(sprintf('<error>Migration %s was executed but did not result in any SQL statements.</error>', $this->_version)); } if ($direction === 'up') { $this->markMigrated(); } else { $this->markNotMigrated(); } } else { foreach ($this->_sql as $query) { $this->_outputWriter->write(' <comment>-></comment> ' . $query); } } $this->_state = self::STATE_POST; $this->_migration->{'post' . ucfirst($direction)}($toSchema); $end = microtime(true); $this->_time = round($end - $start, 2); if ($direction === 'up') { $this->_outputWriter->write(sprintf("\n <info>++</info> migrated (%ss)", $this->_time)); } else { $this->_outputWriter->write(sprintf("\n <info>--</info> reverted (%ss)", $this->_time)); } $this->_connection->commit(); return $this->_sql; } catch (SkipMigrationException $e) { $this->_connection->rollback(); // now mark it as migrated if ($direction === 'up') { $this->markMigrated(); } else { $this->markNotMigrated(); } $this->_outputWriter->write(sprintf("\n <info>SS</info> skipped (Reason: %s)", $e->getMessage())); } catch (\Exception $e) { $this->_outputWriter->write(sprintf('<error>Migration %s failed during %s. Error %s</error>', $this->_version, $this->getExecutionState(), $e->getMessage())); $this->_connection->rollback(); $this->_state = self::STATE_NONE; throw $e; } $this->_state = self::STATE_NONE; }
/** * Outputs a SQL query via the `OutputWriter`. * * @param int $idx The SQL query index. Used to look up params. * @param string $query the query to output * @return void */ private function outputSqlQuery($idx, $query) { $params = $this->formatParamsForOutput(isset($this->params[$idx]) ? $this->params[$idx] : [], isset($this->types[$idx]) ? $this->types[$idx] : []); $this->outputWriter->write(rtrim(sprintf(' <comment>-></comment> %s %s', $query, $params))); }
/** * Do not accept any parameter */ public function __construct() { parent::__construct(null); }
private function noMigrations() { $this->outputWriter->write('<comment>No migrations to execute.</comment>'); return []; }