/** * @param string $xml * * @return Database */ public function applyXml($xml) { $this->readDatabase(); $builder = new QuickBuilder(); $builder->setPlatform($this->database->getPlatform()); $builder->setSchema($xml); $database = $builder->getDatabase(); $database->setSchema('migration'); $database->setPlatform($this->database->getPlatform()); $diff = DatabaseComparator::computeDiff($this->database, $database); if (false === $diff) { return null; } $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $this->con->beginTransaction(); $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { $stmt = $this->con->prepare($statement); $stmt->execute(); } catch (\Exception $e) { $this->con->rollBack(); throw new BuildException(sprintf("Can not execute SQL: \n%s\nFrom database: \n%s\n\nTo database: \n%s\n", $statement, $this->database, $database), null, $e); } } $this->con->commit(); return $database; }
/** * @param string $xml * * @return Database|boolean */ public function applyXml($xml, $changeRequired = false) { $this->readDatabase(); $builder = new QuickBuilder(); $builder->setIdentifierQuoting(true); $builder->setPlatform($this->database->getPlatform()); $builder->setSchema($xml); $database = $builder->getDatabase(); $database->setSchema('migration'); $database->setPlatform($this->database->getPlatform()); $diff = DatabaseComparator::computeDiff($this->database, $database); if (false === $diff) { if ($changeRequired) { throw new BuildException(sprintf("No changes in schema to current database: \nSchema database:\n%s\n\nCurrent Database:\n%s", $database, $this->database)); } return false; } $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $this->con->beginTransaction(); if (!$sql) { throw new BuildException(sprintf('Ooops. There is a diff between current database and schema xml but no SQL has been generated. Change: %s', $diff)); } $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { $stmt = $this->con->prepare($statement); $stmt->execute(); } catch (\Exception $e) { throw new BuildException(sprintf("Can not execute SQL: \n%s\nFrom database: \n%s\n\nTo database: \n%s\n", $statement, $this->database, $database), null, $e); } } $this->con->commit(); return $database; }
/** * Main method builds all the targets for a typical propel project. */ public function main() { $manager = new MigrationManager(); $manager->setConnections($this->getGeneratorConfig()->getBuildConnections()); $manager->setMigrationTable($this->getMigrationTable()); $manager->setMigrationDir($this->getOutputDirectory()); $previousTimestamps = $manager->getAlreadyExecutedMigrationTimestamps(); if (!($nextMigrationTimestamp = array_pop($previousTimestamps))) { $this->log('No migration were ever executed on this database - nothing to reverse.'); return false; } $this->log(sprintf('Executing migration %s down', $manager->getMigrationClassName($nextMigrationTimestamp))); if ($nbPreviousTimestamps = count($previousTimestamps)) { $previousTimestamp = array_pop($previousTimestamps); } else { $previousTimestamp = 0; } $migration = $manager->getMigrationObject($nextMigrationTimestamp); if (false === $migration->preDown($manager)) { $this->log('preDown() returned false. Aborting migration.', Project::MSG_ERR); return false; } foreach ($migration->getDownSQL() as $datasource => $sql) { $connection = $manager->getConnection($datasource); $this->log(sprintf('Connecting to database "%s" using DSN "%s"', $datasource, $connection['dsn']), Project::MSG_VERBOSE); $pdo = $manager->getPdoConnection($datasource); $res = 0; $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { $this->log(sprintf('Executing statement "%s"', $statement), Project::MSG_VERBOSE); $stmt = $pdo->prepare($statement); $stmt->execute(); $res++; } catch (PDOException $e) { $this->log(sprintf('Failed to execute SQL "%s"', $statement), Project::MSG_ERR); // continue } } if (!$res) { $this->log('No statement was executed. The version was not updated.'); $this->log(sprintf('Please review the code in "%s"', $manager->getMigrationDir() . DIRECTORY_SEPARATOR . $manager->getMigrationClassName($nextMigrationTimestamp))); $this->log('Migration aborted', Project::MSG_ERR); return false; } $this->log(sprintf('%d of %d SQL statements executed successfully on datasource "%s"', $res, count($statements), $datasource)); $manager->updateLatestMigrationTimestamp($datasource, $previousTimestamp); $this->log(sprintf('Downgraded migration date to %d for datasource "%s"', $previousTimestamp, $datasource), Project::MSG_VERBOSE); } $migration->postDown($manager); if ($nbPreviousTimestamps) { $this->log(sprintf('Reverse migration complete. %d more migrations available for reverse.', $nbPreviousTimestamps)); } else { $this->log('Reverse migration complete. No more migration available for reverse'); } }
/** * Detects the differences between current connected database and $pDatabase * and updates the schema. This does not DROP tables. * * @param Database $pDatabase */ public function updateSchema($pDatabase) { $diff = DatabaseComparator::computeDiff($this->database, $pDatabase); $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { if (strpos($statement, 'DROP') === 0) { // drop statements cause errors since the table doesn't exist continue; } $stmt = $this->con->prepare($statement); $stmt->execute(); } }
public function updateDB(ConnectionInterface $con) { $database = $this->readConnectedDatabase(); $diff = DatabaseComparator::computeDiff($database, $this->database); if (false === $diff) { return null; } $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff); $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { $stmt = $con->prepare($statement); $stmt->execute(); } catch (\Exception $e) { //echo $sql; //uncomment for better debugging throw new BuildException(sprintf("Can not execute SQL: \n%s\nFrom database: \n%s\n\nTo database: \n%s\n\nDiff:\n%s", $statement, $this->database, $database, $diff), null, $e); } } return $database; }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $configOptions = array(); if ($this->hasInputOption('output-dir', $input)) { $configOptions['propel']['paths']['migrationDir'] = $input->getOption('output-dir'); } if ($this->hasInputOption('migration-table', $input)) { $configOptions['propel']['migrations']['tableName'] = $input->getOption('migration-table'); } $generatorConfig = $this->getGeneratorConfig($configOptions, $input); $this->createDirectory($generatorConfig->getSection('paths')['migrationDir']); $manager = new MigrationManager(); $manager->setGeneratorConfig($generatorConfig); $connections = array(); $optionConnections = $input->getOption('connection'); if (!$optionConnections) { $connections = $generatorConfig->getBuildConnections(); } else { foreach ($optionConnections as $connection) { list($name, $dsn, $infos) = $this->parseConnection($connection); $connections[$name] = array_merge(array('dsn' => $dsn), $infos); } } $manager->setConnections($connections); $manager->setMigrationTable($generatorConfig->getSection('migrations')['tableName']); $manager->setWorkingDirectory($generatorConfig->getSection('paths')['migrationDir']); if (!($nextMigrationTimestamp = $manager->getFirstUpMigrationTimestamp())) { $output->writeln('All migrations were already executed - nothing to migrate.'); return false; } if ($input->getOption('fake')) { $output->writeln(sprintf('Faking migration %s up', $manager->getMigrationClassName($nextMigrationTimestamp))); } else { $output->writeln(sprintf('Executing migration %s up', $manager->getMigrationClassName($nextMigrationTimestamp))); } $migration = $manager->getMigrationObject($nextMigrationTimestamp); if (!$input->getOption('fake')) { if (false === $migration->preUp($manager)) { if ($input->getOption('force')) { $output->writeln('<error>preUp() returned false. Continue migration.</error>'); } else { $output->writeln('<error>preUp() returned false. Aborting migration.</error>'); return false; } } } foreach ($migration->getUpSQL() as $datasource => $sql) { $connection = $manager->getConnection($datasource); if ($input->getOption('verbose')) { $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $datasource, $connection['dsn'])); } $conn = $manager->getAdapterConnection($datasource); $res = 0; $statements = SqlParser::parseString($sql); if (!$input->getOption('fake')) { foreach ($statements as $statement) { try { if ($input->getOption('verbose')) { $output->writeln(sprintf('Executing statement "%s"', $statement)); } $conn->exec($statement); $res++; } catch (\Exception $e) { if ($input->getOption('force')) { //continue, but print error message $output->writeln(sprintf('<error>Failed to execute SQL "%s". Continue migration.</error>', $statement)); } else { throw new RuntimeException(sprintf('<error>Failed to execute SQL "%s". Aborting migration.</error>', $statement), 0, $e); } } } //make sure foreign_keys are activated again in mysql $output->writeln(sprintf('%d of %d SQL statements executed successfully on datasource "%s"', $res, count($statements), $datasource)); } $manager->updateLatestMigrationTimestamp($datasource, $nextMigrationTimestamp); if ($input->getOption('verbose')) { $output->writeln(sprintf('Updated latest migration date to %d for datasource "%s"', $nextMigrationTimestamp, $datasource)); } } if (!$input->getOption('fake')) { $migration->postUp($manager); } if ($timestamps = $manager->getValidMigrationTimestamps()) { $output->writeln(sprintf('Migration complete. %d migrations left to execute.', count($timestamps))); } else { $output->writeln('Migration complete. No further migration to execute.'); } }
public function buildSQL(ConnectionInterface $con) { $statements = SqlParser::parseString($this->getSQL()); foreach ($statements as $statement) { if (strpos($statement, 'DROP') === 0) { // drop statements cause errors since the table doesn't exist continue; } $stmt = $con->prepare($statement); if ($stmt instanceof StatementInterface) { // only execute if has no error $stmt->execute(); } } return count($statements); }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $configOptions = array(); if ($this->hasInputOption('output-dir', $input)) { $configOptions['propel']['paths']['migrationDir'] = $input->getOption('output-dir'); } if ($this->hasInputOption('migration-table', $input)) { $configOptions['propel']['migrations']['tableName'] = $input->getOption('migration-table'); } $generatorConfig = $this->getGeneratorConfig($configOptions, $input); $this->createDirectory($generatorConfig->getSection('paths')['migrationDir']); $manager = new MigrationManager(); $manager->setGeneratorConfig($generatorConfig); $connections = array(); $optionConnections = $input->getOption('connection'); if (!$optionConnections) { $connections = $generatorConfig->getBuildConnections(); } else { foreach ($optionConnections as $connection) { list($name, $dsn, $infos) = $this->parseConnection($connection); $connections[$name] = array_merge(array('dsn' => $dsn), $infos); } } $manager->setConnections($connections); $manager->setMigrationTable($generatorConfig->getSection('migrations')['tableName']); $manager->setWorkingDirectory($generatorConfig->getSection('paths')['migrationDir']); $previousTimestamps = $manager->getAlreadyExecutedMigrationTimestamps(); if (!($nextMigrationTimestamp = array_pop($previousTimestamps))) { $output->writeln('No migration were ever executed on this database - nothing to reverse.'); return false; } $output->writeln(sprintf('Executing migration %s down', $manager->getMigrationClassName($nextMigrationTimestamp))); if ($nbPreviousTimestamps = count($previousTimestamps)) { $previousTimestamp = array_pop($previousTimestamps); } else { $previousTimestamp = 0; } $migration = $manager->getMigrationObject($nextMigrationTimestamp); if (!$input->getOption('fake')) { if (false === $migration->preDown($manager)) { if ($input->getOption('force')) { $output->writeln('<error>preDown() returned false. Continue migration.</error>'); } else { $output->writeln('<error>preDown() returned false. Aborting migration.</error>'); return false; } } } foreach ($migration->getDownSQL() as $datasource => $sql) { $connection = $manager->getConnection($datasource); if ($input->getOption('verbose')) { $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $datasource, $connection['dsn'])); } $conn = $manager->getAdapterConnection($datasource); $res = 0; $statements = SqlParser::parseString($sql); if (!$input->getOption('fake')) { foreach ($statements as $statement) { try { if ($input->getOption('verbose')) { $output->writeln(sprintf('Executing statement "%s"', $statement)); } $conn->exec($statement); $res++; } catch (\Exception $e) { if ($input->getOption('force')) { //continue, but print error message $output->writeln(sprintf('<error>Failed to execute SQL "%s". Continue migration.</error>', $statement)); } else { throw new RuntimeException(sprintf('<error>Failed to execute SQL "%s". Aborting migration.</error>', $statement), 0, $e); } } } $output->writeln(sprintf('%d of %d SQL statements executed successfully on datasource "%s"', $res, count($statements), $datasource)); } $manager->removeMigrationTimestamp($datasource, $nextMigrationTimestamp); if ($input->getOption('verbose')) { $output->writeln(sprintf('Downgraded migration date to %d for datasource "%s"', $previousTimestamp, $datasource)); } } if (!$input->getOption('fake')) { $migration->postDown($manager); } if ($nbPreviousTimestamps) { $output->writeln(sprintf('Reverse migration complete. %d more migrations available for reverse.', $nbPreviousTimestamps)); } else { $output->writeln('Reverse migration complete. No more migration available for reverse'); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $generatorConfig = $this->getGeneratorConfig(array('propel.platform.class' => $input->getOption('platform')), $input); $this->createDirectory($input->getOption('output-dir')); $manager = new MigrationManager(); $manager->setGeneratorConfig($generatorConfig); $connections = array(); foreach ($input->getOption('connection') as $connection) { list($name, $dsn, $infos) = $this->parseConnection($connection); $connections[$name] = array_merge(array('dsn' => $dsn), $infos); } $manager->setConnections($connections); $manager->setMigrationTable($input->getOption('migration-table')); $manager->setWorkingDirectory($input->getOption('output-dir')); $previousTimestamps = $manager->getAlreadyExecutedMigrationTimestamps(); if (!($nextMigrationTimestamp = array_pop($previousTimestamps))) { $output->writeln('No migration were ever executed on this database - nothing to reverse.'); return false; } $output->writeln(sprintf('Executing migration %s down', $manager->getMigrationClassName($nextMigrationTimestamp))); if ($nbPreviousTimestamps = count($previousTimestamps)) { $previousTimestamp = array_pop($previousTimestamps); } else { $previousTimestamp = 0; } $migration = $manager->getMigrationObject($nextMigrationTimestamp); if (false === $migration->preDown($manager)) { $output->writeln('<error>preDown() returned false. Aborting migration.</error>'); return false; } foreach ($migration->getDownSQL() as $datasource => $sql) { $connection = $manager->getConnection($datasource); if ($input->getOption('verbose')) { $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $datasource, $connection['dsn'])); } $conn = $manager->getAdapterConnection($datasource); $res = 0; $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { if ($input->getOption('verbose')) { $output->writeln(sprintf('Executing statement "%s"', $statement)); } $stmt = $conn->prepare($statement); $stmt->execute(); $res++; } catch (PDOException $e) { $output->writeln(sprintf('<error>Failed to execute SQL "%s"</error>', $statement)); } } if (!$res) { $output->writeln('No statement was executed. The version was not updated.'); $output->writeln(sprintf('Please review the code in "%s"', $manager->getMigrationDir() . DIRECTORY_SEPARATOR . $manager->getMigrationClassName($nextMigrationTimestamp))); $output->writeln('<error>Migration aborted</error>'); return false; } $output->writeln(sprintf('%d of %d SQL statements executed successfully on datasource "%s"', $res, count($statements), $datasource)); $manager->updateLatestMigrationTimestamp($datasource, $previousTimestamp); if ($input->getOption('verbose')) { $output->writeln(sprintf('Downgraded migration date to %d for datasource "%s"', $previousTimestamp, $datasource)); } } $migration->postDown($manager); if ($nbPreviousTimestamps) { $output->writeln(sprintf('Reverse migration complete. %d more migrations available for reverse.', $nbPreviousTimestamps)); } else { $output->writeln('Reverse migration complete. No more migration available for reverse'); } }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $configOptions = array(); if ($this->hasInputOption('output-dir', $input)) { $configOptions['propel']['paths']['migrationDir'] = $input->getOption('output-dir'); } $generatorConfig = $this->getGeneratorConfig($configOptions, $input); $this->createDirectory($generatorConfig->getSection('paths')['migrationDir']); $manager = new MigrationManager(); $manager->setGeneratorConfig($generatorConfig); $connections = array(); $optionConnections = $input->getOption('connection'); if (!$optionConnections) { $connections = $generatorConfig->getBuildConnections(); } else { foreach ($optionConnections as $connection) { list($name, $dsn, $infos) = $this->parseConnection($connection); $connections[$name] = array_merge(array('dsn' => $dsn), $infos); } } $manager->setConnections($connections); $manager->setMigrationTable($input->getOption('migration-table')); $manager->setWorkingDirectory($generatorConfig->getSection('paths')['migrationDir']); if (!$manager->getFirstUpMigrationTimestamp()) { $output->writeln('All migrations were already executed - nothing to migrate.'); return false; } $timestamps = $manager->getValidMigrationTimestamps(); if (count($timestamps) > 1) { $output->writeln(sprintf('%d migrations to execute', count($timestamps))); } foreach ($timestamps as $timestamp) { $output->writeln(sprintf('Executing migration %s up', $manager->getMigrationClassName($timestamp))); $migration = $manager->getMigrationObject($timestamp); if (property_exists($migration, 'comment') && $migration->comment) { $output->writeln(sprintf('<info>%s</info>', $migration->comment)); } if (false === $migration->preUp($manager)) { $output->writeln('<error>preUp() returned false. Aborting migration.</error>'); return false; } foreach ($migration->getUpSQL() as $datasource => $sql) { $connection = $manager->getConnection($datasource); if ($input->getOption('verbose')) { $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $datasource, $connection['dsn'])); } $conn = $manager->getAdapterConnection($datasource); $res = 0; $statements = SqlParser::parseString($sql); foreach ($statements as $statement) { try { if ($input->getOption('verbose')) { $output->writeln(sprintf('Executing statement "%s"', $statement)); } $stmt = $conn->prepare($statement); $stmt->execute(); $res++; } catch (\PDOException $e) { $output->writeln(sprintf('<error>Failed to execute SQL "%s": %s</error>', $statement, $e->getMessage())); // continue } } if (!$res) { $output->writeln('No statement was executed. The version was not updated.'); $output->writeln(sprintf('Please review the code in "%s"', $manager->getWorkingDirectory() . DIRECTORY_SEPARATOR . $manager->getMigrationClassName($timestamp))); $output->writeln('<error>Migration aborted</error>'); return false; } $output->writeln(sprintf('%d of %d SQL statements executed successfully on datasource "%s"', $res, count($statements), $datasource)); } // migrations for datasources have passed - update the timestamp // for all datasources foreach ($manager->getConnections() as $datasource => $connection) { $manager->updateLatestMigrationTimestamp($datasource, $timestamp); if ($input->getOption('verbose')) { $output->writeln(sprintf('Updated latest migration date to %d for datasource "%s"', $timestamp, $datasource)); } } $migration->postUp($manager); } $output->writeln('Migration complete. No further migration to execute.'); }