/**
  * 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 testTableRenaming()
    {
        $schema1 = '
<database name="test">
    <table name="foo">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar1" type="INTEGER" />
        <column name="bar2" type="INTEGER" />
    </table>
    <table name="foo2">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar1" type="INTEGER" />
        <column name="bar2" type="INTEGER" />
    </table>
</database>
';
        $schema2 = '
<database name="test">
    <table name="foo_bla">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar1" type="INTEGER" />
        <column name="bar2" type="INTEGER" />
    </table>
    <table name="foo_bla2">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar1" type="INTEGER" />
        <column name="bar2" type="INTEGER" />
    </table>
</database>
';
        $d1 = $this->getDatabaseFromSchema($schema1);
        $d2 = $this->getDatabaseFromSchema($schema2);
        $diff = DatabaseComparator::computeDiff($d1, $d2, false, true);
        $renamedTables = $diff->getRenamedTables();
        $firstPair = [key($renamedTables), current($renamedTables)];
        next($renamedTables);
        $secondPair = [key($renamedTables), current($renamedTables)];
        $this->assertEquals('foo', $firstPair[0]);
        $this->assertEquals('foo_bla', $firstPair[1]);
        $this->assertEquals('foo2', $secondPair[0]);
        $this->assertEquals('foo_bla2', $secondPair[1], 'Table `Foo2` should not renamed to `foo_bla` since we have already renamed a table to this name.');
    }
    public function providerForTestGetModifyTableForeignKeysSkipSql4DDL()
    {
        $schema1 = <<<EOF
<database name="test" identifierQuoting="true">
    <table name="test">
        <column name="test" type="INTEGER" primaryKey="true" autoIncrement="true" required="true" />
        <column name="ref_test" type="INTEGER"/>
        <foreign-key foreignTable="test2" onDelete="CASCADE" onUpdate="CASCADE" skipSql="true">
            <reference local="ref_test" foreign="test" />
        </foreign-key>
    </table>
    <table name="test2">
        <column name="test" type="integer" primaryKey="true" />
    </table>
</database>
EOF;
        $schema2 = <<<EOF
<database name="test" identifierQuoting="true">
  <table name="test">
    <column name="test" type="INTEGER" primaryKey="true" autoIncrement="true" required="true" />
    <column name="ref_test" type="INTEGER"/>
  </table>
  <table name="test2">
    <column name="test" type="integer" primaryKey="true" />
  </table>
</database>
EOF;
        $d1 = $this->getDatabaseFromSchema($schema1);
        $d2 = $this->getDatabaseFromSchema($schema2);
        $diff = DatabaseComparator::computeDiff($d2, $d1);
        return [[$diff]];
    }
 /**
  * Compares the current database with $database.
  *
  * @param Database $database
  */
 public function compareCurrentDatabase(Database $database)
 {
     $this->readDatabase();
     $diff = DatabaseComparator::computeDiff($this->database, $database);
     if (false !== $diff) {
         $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff);
         $this->fail(sprintf("There are unexpected diffs: \n%s\n`%s`\nCurrent Database: \n%s\nTo XML Database: \n%s\n", $diff, $sql, $this->database, $database));
     }
     $this->assertFalse($diff, 'no changes.');
 }
示例#5
0
 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;
 }
    public function testGetModifyDatabaseWithBlockStorageDDL()
    {
        $schema1 = <<<EOF
<database name="test">
    <table name="foo1">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="blooopoo" type="INTEGER" />
    </table>
    <table name="foo2">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar" type="INTEGER" />
        <column name="baz" type="VARCHAR" size="12" required="true" />
    </table>
    <table name="foo3">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="yipee" type="INTEGER" />
    </table>
</database>
EOF;
        $schema2 = <<<EOF
<database name="test">
    <table name="foo2">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar1" type="INTEGER" />
        <column name="baz" type="VARCHAR" size="12" required="false" />
        <column name="baz3" type="CLOB" />
        <vendor type="oracle">
            <parameter name="PCTFree" value="20"/>
            <parameter name="InitTrans" value="4"/>
            <parameter name="MinExtents" value="1"/>
            <parameter name="MaxExtents" value="99"/>
            <parameter name="PCTIncrease" value="0"/>
            <parameter name="Tablespace" value="L_128K"/>
            <parameter name="PKPCTFree" value="20"/>
            <parameter name="PKInitTrans" value="4"/>
            <parameter name="PKMinExtents" value="1"/>
            <parameter name="PKMaxExtents" value="99"/>
            <parameter name="PKPCTIncrease" value="0"/>
            <parameter name="PKTablespace" value="IL_128K"/>
        </vendor>
    </table>
    <table name="foo4">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="yipee" type="INTEGER" />
        <vendor type="oracle">
            <parameter name="PCTFree" value="20"/>
            <parameter name="InitTrans" value="4"/>
            <parameter name="MinExtents" value="1"/>
            <parameter name="MaxExtents" value="99"/>
            <parameter name="PCTIncrease" value="0"/>
            <parameter name="Tablespace" value="L_128K"/>
            <parameter name="PKPCTFree" value="20"/>
            <parameter name="PKInitTrans" value="4"/>
            <parameter name="PKMinExtents" value="1"/>
            <parameter name="PKMaxExtents" value="99"/>
            <parameter name="PKPCTIncrease" value="0"/>
            <parameter name="PKTablespace" value="IL_128K"/>
        </vendor>
    </table>
    <table name="foo5">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="lkdjfsh" type="INTEGER" />
        <column name="dfgdsgf" type="CLOB" />
        <index name="lkdjfsh_IDX">
            <index-column name="lkdjfsh"/>
            <vendor type="oracle">
                <parameter name="PCTFree" value="20"/>
                <parameter name="InitTrans" value="4"/>
                <parameter name="MinExtents" value="1"/>
                <parameter name="MaxExtents" value="99"/>
                <parameter name="PCTIncrease" value="0"/>
                <parameter name="Tablespace" value="L_128K"/>
            </vendor>
        </index>
        <vendor type="oracle">
            <parameter name="PCTFree" value="20"/>
            <parameter name="InitTrans" value="4"/>
            <parameter name="MinExtents" value="1"/>
            <parameter name="MaxExtents" value="99"/>
            <parameter name="PCTIncrease" value="0"/>
            <parameter name="Tablespace" value="L_128K"/>
            <parameter name="PKPCTFree" value="20"/>
            <parameter name="PKInitTrans" value="4"/>
            <parameter name="PKMinExtents" value="1"/>
            <parameter name="PKMaxExtents" value="99"/>
            <parameter name="PKPCTIncrease" value="0"/>
            <parameter name="PKTablespace" value="IL_128K"/>
        </vendor>
    </table>
</database>
EOF;
        $d1 = $this->getDatabaseFromSchema($schema1);
        $d2 = $this->getDatabaseFromSchema($schema2);
        $databaseDiff = DatabaseComparator::computeDiff($d1, $d2);
        $expected = "\nALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD';\nALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS';\n\nDROP TABLE foo1 CASCADE CONSTRAINTS;\n\nDROP SEQUENCE foo1_SEQ;\n\nDROP TABLE foo3 CASCADE CONSTRAINTS;\n\nDROP SEQUENCE foo3_SEQ;\n\nCREATE TABLE foo4\n(\n    id NUMBER NOT NULL,\n    yipee NUMBER\n)\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n    MINEXTENTS 1\n    MAXEXTENTS 99\n    PCTINCREASE 0\n)\nTABLESPACE L_128K;\n\nALTER TABLE foo4 ADD CONSTRAINT foo4_pk PRIMARY KEY (id)\nUSING INDEX\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n    MINEXTENTS 1\n    MAXEXTENTS 99\n    PCTINCREASE 0\n)\nTABLESPACE IL_128K;\n\nCREATE SEQUENCE foo4_SEQ\n    INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE ORDER;\n\nCREATE TABLE foo5\n(\n    id NUMBER NOT NULL,\n    lkdjfsh NUMBER,\n    dfgdsgf CLOB\n)\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n    MINEXTENTS 1\n    MAXEXTENTS 99\n    PCTINCREASE 0\n)\nTABLESPACE L_128K;\n\nALTER TABLE foo5 ADD CONSTRAINT foo5_pk PRIMARY KEY (id)\nUSING INDEX\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n    MINEXTENTS 1\n    MAXEXTENTS 99\n    PCTINCREASE 0\n)\nTABLESPACE IL_128K;\n\nCREATE SEQUENCE foo5_SEQ\n    INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE ORDER;\n\nCREATE INDEX lkdjfsh_IDX ON foo5 (lkdjfsh)\nPCTFREE 20\nINITRANS 4\nSTORAGE\n(\n    MINEXTENTS 1\n    MAXEXTENTS 99\n    PCTINCREASE 0\n)\nTABLESPACE L_128K;\n\nALTER TABLE foo2 RENAME COLUMN bar TO bar1;\n\nALTER TABLE foo2\n\n  MODIFY\n(\n    baz NVARCHAR2(12)\n),\n\n  ADD\n(\n    baz3 CLOB\n);\n";
        $this->assertEquals($expected, $this->getPlatform()->getModifyDatabaseDDL($databaseDiff));
    }
 public function testCompareSeveralTableDifferences()
 {
     $d1 = new Database();
     $t1 = new Table('Foo_Table');
     $c1 = new Column('Foo');
     $c1->getDomain()->copy($this->platform->getDomainForType('DOUBLE'));
     $c1->getDomain()->replaceScale(2);
     $c1->getDomain()->replaceSize(3);
     $c1->setNotNull(true);
     $c1->getDomain()->setDefaultValue(new ColumnDefaultValue(123, ColumnDefaultValue::TYPE_VALUE));
     $t1->addColumn($c1);
     $d1->addTable($t1);
     $t2 = new Table('Bar');
     $c2 = new Column('Bar_Column');
     $c2->getDomain()->copy($this->platform->getDomainForType('DOUBLE'));
     $t2->addColumn($c2);
     $d1->addTable($t2);
     $t11 = new Table('Baz');
     $d1->addTable($t11);
     $d2 = new Database();
     $t3 = new Table('Foo_Table');
     $c3 = new Column('Foo1');
     $c3->getDomain()->copy($this->platform->getDomainForType('DOUBLE'));
     $c3->getDomain()->replaceScale(2);
     $c3->getDomain()->replaceSize(3);
     $c3->setNotNull(true);
     $c3->getDomain()->setDefaultValue(new ColumnDefaultValue(123, ColumnDefaultValue::TYPE_VALUE));
     $t3->addColumn($c3);
     $d2->addTable($t3);
     $t4 = new Table('Bar2');
     $c4 = new Column('Bar_Column');
     $c4->getDomain()->copy($this->platform->getDomainForType('DOUBLE'));
     $t4->addColumn($c4);
     $d2->addTable($t4);
     $t5 = new Table('Biz');
     $c5 = new Column('Biz_Column');
     $c5->getDomain()->copy($this->platform->getDomainForType('INTEGER'));
     $t5->addColumn($c5);
     $d2->addTable($t5);
     // Foo_Table was modified, Bar was renamed, Baz was removed, Biz was added
     $dc = new DatabaseComparator();
     $dc->setFromDatabase($d1);
     $dc->setToDatabase($d2);
     $nbDiffs = $dc->compareTables();
     $databaseDiff = $dc->getDatabaseDiff();
     $this->assertEquals(4, $nbDiffs);
     $this->assertEquals(array('Bar' => 'Bar2'), $databaseDiff->getRenamedTables());
     $this->assertEquals(array('Biz' => $t5), $databaseDiff->getAddedTables());
     $this->assertEquals(array('Baz' => $t11), $databaseDiff->getRemovedTables());
     $tableDiff = TableComparator::computeDiff($t1, $t3);
     $this->assertEquals(array('Foo_Table' => $tableDiff), $databaseDiff->getModifiedTables());
 }
示例#8
0
 private function checkDeletedFk()
 {
     $this->readDatabase();
     $diff = DatabaseComparator::computeDiff($this->database, $this->updatedBuilder->getDatabase());
     $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff);
     $expected = 'issue617_user';
     $this->assertNotContains($expected, $sql);
 }
示例#9
0
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $configOptions = [];
     if ($this->hasInputOption('connection', $input)) {
         foreach ($input->getOption('connection') as $conn) {
             $configOptions += $this->connectionToProperties($conn);
         }
     }
     if ($this->hasInputOption('migration-table', $input)) {
         $configOptions['propel']['migrations']['tableName'] = $input->getOption('migration-table');
     }
     if ($this->hasInputOption('schema-dir', $input)) {
         $configOptions['propel']['paths']['schemaDir'] = $input->getOption('schema-dir');
     }
     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);
     $manager->setSchemas($this->getSchemas($generatorConfig->getSection('paths')['schemaDir'], $input->getOption('recursive')));
     $connections = [];
     $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(['dsn' => $dsn], $infos);
         }
     }
     $manager->setConnections($connections);
     $manager->setMigrationTable($generatorConfig->getConfigProperty('migrations.tableName'));
     $manager->setWorkingDirectory($generatorConfig->getSection('paths')['migrationDir']);
     if ($manager->hasPendingMigrations()) {
         throw new RuntimeException('Uncommitted migrations have been found ; you should either execute or delete them before rerunning the \'diff\' task');
     }
     $totalNbTables = 0;
     $reversedSchema = new Schema();
     foreach ($manager->getDatabases() as $appDatabase) {
         $name = $appDatabase->getName();
         if (!($params = @$connections[$name])) {
             $output->writeln(sprintf('<info>No connection configured for database "%s"</info>', $name));
         }
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $name, $params['dsn']));
         }
         $conn = $manager->getAdapterConnection($name);
         $platform = $generatorConfig->getConfiguredPlatform($conn, $name);
         if (!$platform->supportsMigrations()) {
             $output->writeln(sprintf('Skipping database "%s" since vendor "%s" does not support migrations', $name, $platform->getDatabaseType()));
             continue;
         }
         $additionalTables = [];
         foreach ($appDatabase->getTables() as $table) {
             if ($table->getSchema() && $table->getSchema() != $appDatabase->getSchema()) {
                 $additionalTables[] = $table;
             }
         }
         if ($input->getOption('disable-identifier-quoting')) {
             $platform->setIdentifierQuoting(false);
         }
         $database = new Database($name);
         $database->setPlatform($platform);
         $database->setSchema($appDatabase->getSchema());
         $database->setDefaultIdMethod(IdMethod::NATIVE);
         $parser = $generatorConfig->getConfiguredSchemaParser($conn, $name);
         $nbTables = $parser->parse($database, $additionalTables);
         $reversedSchema->addDatabase($database);
         $totalNbTables += $nbTables;
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('%d tables found in database "%s"', $nbTables, $name), Output::VERBOSITY_VERBOSE);
         }
     }
     if ($totalNbTables) {
         $output->writeln(sprintf('%d tables found in all databases.', $totalNbTables));
     } else {
         $output->writeln('No table found in all databases');
     }
     // comparing models
     $output->writeln('Comparing models...');
     $tableRenaming = $input->getOption('table-renaming');
     $migrationsUp = [];
     $migrationsDown = [];
     $removeTable = !$input->getOption('skip-removed-table');
     $excludedTables = $input->getOption('skip-tables');
     foreach ($reversedSchema->getDatabases() as $database) {
         $name = $database->getName();
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('Comparing database "%s"', $name));
         }
         if (!($appDataDatabase = $manager->getDatabase($name))) {
             $output->writeln(sprintf('<error>Database "%s" does not exist in schema.xml. Skipped.</error>', $name));
             continue;
         }
         $configManager = new ConfigurationManager();
         $excludedTables = array_merge((array) $excludedTables, (array) $configManager->getSection('exclude_tables'));
         $databaseDiff = DatabaseComparator::computeDiff($database, $appDataDatabase, false, $tableRenaming, $removeTable, $excludedTables);
         if (!$databaseDiff) {
             if ($input->getOption('verbose')) {
                 $output->writeln(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name));
             }
             continue;
         }
         $output->writeln(sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription()));
         foreach ($databaseDiff->getPossibleRenamedTables() as $fromTableName => $toTableName) {
             $output->writeln(sprintf('<info>Possible table renaming detected: "%s" to "%s". It will be deleted and recreated. Use --table-renaming to only rename it.</info>', $fromTableName, $toTableName));
         }
         $conn = $manager->getAdapterConnection($name);
         $platform = $generatorConfig->getConfiguredPlatform($conn, $name);
         if ($input->getOption('disable-identifier-quoting')) {
             $platform->setIdentifierQuoting(false);
         }
         $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff);
         $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff());
     }
     if (!$migrationsUp) {
         $output->writeln('Same XML and database structures for all datasource - no diff to generate');
         return;
     }
     $timestamp = time();
     $migrationFileName = $manager->getMigrationFileName($timestamp);
     $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp, $input->getOption('comment'));
     $file = $generatorConfig->getSection('paths')['migrationDir'] . DIRECTORY_SEPARATOR . $migrationFileName;
     file_put_contents($file, $migrationClassBody);
     $output->writeln(sprintf('"%s" file successfully created.', $file));
     if (null !== ($editorCmd = $input->getOption('editor'))) {
         $output->writeln(sprintf('Using "%s" as text editor', $editorCmd));
         shell_exec($editorCmd . ' ' . escapeshellarg($file));
     } else {
         $output->writeln('Please review the generated SQL statements, and add data migration code if necessary.');
         $output->writeln('Once the migration class is valid, call the "migrate" task to execute it.');
     }
 }
示例#10
0
 /**
  * Compares the current database with $database.
  *
  * @param Database $database
  * @throws BuildException if a difference has been found between $database and the real database
  */
 public function compareCurrentDatabase(Database $database)
 {
     $this->readDatabase();
     $diff = DatabaseComparator::computeDiff($this->database, $database);
     if (false !== $diff) {
         $sql = $this->database->getPlatform()->getModifyDatabaseDDL($diff);
         throw new BuildException(sprintf("There are unexpected diffs (real to model): \n%s\n-----%s-----\nCurrent Database: \n%s\nTo XML Database: \n%s\n", $diff, $sql, $this->database, $database));
     }
     $this->assertFalse($diff, 'no changes.');
 }
示例#11
0
 /**
  * Main method builds all the targets for a typical propel project.
  */
 public function main()
 {
     // check to make sure task received all correct params
     $this->validate();
     $generatorConfig = $this->getGeneratorConfig();
     // loading model from database
     $this->log('Reading databases structure...');
     $connections = $generatorConfig->getBuildConnections();
     if (!$connections) {
         throw new Exception('You must define database connection settings in a buildtime-conf.xml file to use diff');
     }
     $totalNbTables = 0;
     $ad = new AppData();
     foreach ($connections as $name => $params) {
         $this->log(sprintf('Connecting to database "%s" using DSN "%s"', $name, $params['dsn']), Project::MSG_VERBOSE);
         $pdo = $generatorConfig->getBuildPDO($name);
         $database = new Database($name);
         $platform = $generatorConfig->getConfiguredPlatform($pdo);
         if (!$platform->supportsMigrations()) {
             $this->log(sprintf('Skipping database "%s" since vendor "%s" does not support migrations', $name, $platform->getDatabaseType()));
             continue;
         }
         $database->setPlatform($platform);
         $database->setDefaultIdMethod(IdMethod::NATIVE);
         $parser = $generatorConfig->getConfiguredSchemaParser($pdo);
         $nbTables = $parser->parse($database, $this);
         $ad->addDatabase($database);
         $totalNbTables += $nbTables;
         $this->log(sprintf('%d tables found in database "%s"', $nbTables, $name), Project::MSG_VERBOSE);
     }
     if ($totalNbTables) {
         $this->log(sprintf('%d tables found in all databases.', $totalNbTables));
     } else {
         $this->log('No table found in all databases');
     }
     // loading model from XML
     $this->packageObjectModel = true;
     $appDatasFromXml = $this->getDataModels();
     $appDataFromXml = array_pop($appDatasFromXml);
     // comparing models
     $this->log('Comparing models...');
     $manager = new MigrationManager();
     $manager->setConnections($connections);
     $manager->setMigrationDir($this->getOutputDirectory());
     $migrationsUp = array();
     $migrationsDown = array();
     foreach ($ad->getDatabases() as $database) {
         $name = $database->getName();
         $this->log(sprintf('Comparing database "%s"', $name), Project::MSG_VERBOSE);
         if (!$appDataFromXml->hasDatabase($name)) {
             // FIXME: tables present in database but not in XML
             continue;
         }
         $databaseDiff = DatabaseComparator::computeDiff($database, $appDataFromXml->getDatabase($name), $this->isCaseInsensitive());
         if (!$databaseDiff) {
             $this->log(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name), Project::MSG_VERBOSE);
             continue;
         }
         $this->log(sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription()));
         $platform = $generatorConfig->getConfiguredPlatform(null, $name);
         $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff);
         $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff());
     }
     if (!$migrationsUp) {
         $this->log('Same XML and database structures for all datasource - no diff to generate');
         return;
     }
     $timestamp = time();
     $migrationFileName = $manager->getMigrationFileName($timestamp);
     $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp);
     $_f = new PhingFile($this->getOutputDirectory(), $migrationFileName);
     file_put_contents($_f->getAbsolutePath(), $migrationClassBody);
     $this->log(sprintf('"%s" file successfully created in %s', $_f->getName(), $_f->getParent()));
     if ($editorCmd = $this->getEditorCmd()) {
         $this->log(sprintf('Using "%s" as text editor', $editorCmd));
         shell_exec($editorCmd . ' ' . escapeshellarg($_f->getAbsolutePath()));
     } else {
         $this->log('  Please review the generated SQL statements, and add data migration code if necessary.');
         $this->log('  Once the migration class is valid, call the "migrate" task to execute it.');
     }
 }
 public function testExcludedTablesWithRenaming()
 {
     $dc = new DatabaseComparator();
     $this->assertCount(0, $dc->getExcludedTables());
     $dc->setExcludedTables(array('foo'));
     $this->assertCount(1, $dc->getExcludedTables());
     $d1 = new Database();
     $d2 = new Database();
     $t2 = new Table('Bar');
     $d2->addTable($t2);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Bar'));
     $this->assertFalse($diff);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Baz'));
     $this->assertInstanceOf('Propel\\Generator\\Model\\Diff\\DatabaseDiff', $diff);
     $d1 = new Database();
     $t1 = new Table('Foo');
     $d1->addTable($t1);
     $d2 = new Database();
     $t2 = new Table('Bar');
     $d2->addTable($t2);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Bar', 'Foo'));
     $this->assertFalse($diff);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Foo'));
     $this->assertInstanceOf('Propel\\Generator\\Model\\Diff\\DatabaseDiff', $diff);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Bar'));
     $this->assertInstanceOf('Propel\\Generator\\Model\\Diff\\DatabaseDiff', $diff);
     $d1 = new Database();
     $t1 = new Table('Foo');
     $c1 = new Column('col1');
     $t1->addColumn($c1);
     $d1->addTable($t1);
     $d2 = new Database();
     $t2 = new Table('Foo');
     $d2->addTable($t2);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Bar', 'Foo'));
     $this->assertFalse($diff);
     $diff = DatabaseComparator::computeDiff($d1, $d2, false, true, true, array('Bar'));
     $this->assertInstanceOf('Propel\\Generator\\Model\\Diff\\DatabaseDiff', $diff);
 }
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $generatorConfig = $this->getGeneratorConfig(array('propel.platform.class' => $input->getOption('platform'), 'propel.reverse.parser.class' => $this->getReverseClass($input), 'propel.migration.table' => $input->getOption('migration-table')), $input);
     $this->createDirectory($input->getOption('output-dir'));
     $manager = new MigrationManager();
     $manager->setGeneratorConfig($generatorConfig);
     $manager->setSchemas($this->getSchemas($input->getOption('input-dir')));
     $connections = array();
     $optionConnections = $input->getOption('connection');
     if (!$optionConnections) {
         $connections = $generatorConfig->getBuildConnections($input->getOption('input-dir'));
     } 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($input->getOption('output-dir'));
     if ($manager->hasPendingMigrations()) {
         throw new RuntimeException('Uncommitted migrations have been found ; you should either execute or delete them before rerunning the \'diff\' task');
     }
     $totalNbTables = 0;
     $schema = new Schema();
     foreach ($connections as $name => $params) {
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('Connecting to database "%s" using DSN "%s"', $name, $params['dsn']));
         }
         $conn = $manager->getAdapterConnection($name);
         $platform = $generatorConfig->getConfiguredPlatform($conn, $name);
         if (!$platform->supportsMigrations()) {
             $output->writeln(sprintf('Skipping database "%s" since vendor "%s" does not support migrations', $name, $platform->getDatabaseType()));
             continue;
         }
         $database = new Database($name);
         $database->setPlatform($platform);
         $database->setDefaultIdMethod(IdMethod::NATIVE);
         $parser = $generatorConfig->getConfiguredSchemaParser($conn);
         $nbTables = $parser->parse($database, $this);
         $schema->addDatabase($database);
         $totalNbTables += $nbTables;
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('%d tables found in database "%s"', $nbTables, $name), Output::VERBOSITY_VERBOSE);
         }
     }
     if ($totalNbTables) {
         $output->writeln(sprintf('%d tables found in all databases.', $totalNbTables));
     } else {
         $output->writeln('No table found in all databases');
     }
     $appDatasFromXml = $manager->getDataModels();
     $appDataFromXml = array_pop($appDatasFromXml);
     // comparing models
     $output->writeln('Comparing models...');
     $migrationsUp = array();
     $migrationsDown = array();
     foreach ($schema->getDatabases() as $database) {
         $name = $database->getName();
         if ($input->getOption('verbose')) {
             $output->writeln(sprintf('Comparing database "%s"', $name));
         }
         if (!$appDataFromXml->hasDatabase($name)) {
             // FIXME: tables present in database but not in XML
             continue;
         }
         $databaseDiff = DatabaseComparator::computeDiff($database, $appDataFromXml->getDatabase($name));
         if (!$databaseDiff) {
             if ($input->getOption('verbose')) {
                 $output->writeln(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name));
             }
             continue;
         }
         $output->writeln(sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription()));
         $platform = $generatorConfig->getConfiguredPlatform(null, $name);
         $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff);
         $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff());
     }
     if (!$migrationsUp) {
         $output->writeln('Same XML and database structures for all datasource - no diff to generate');
         return;
     }
     $timestamp = time();
     $migrationFileName = $manager->getMigrationFileName($timestamp);
     $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp);
     $file = $input->getOption('output-dir') . DIRECTORY_SEPARATOR . $migrationFileName;
     file_put_contents($file, $migrationClassBody);
     $output->writeln(sprintf('"%s" file successfully created.', $file));
     if (null !== ($editorCmd = $input->getOption('editor'))) {
         $output->writeln(sprintf('Using "%s" as text editor', $editorCmd));
         shell_exec($editorCmd . ' ' . escapeshellarg($file));
     } else {
         $output->writeln('Please review the generated SQL statements, and add data migration code if necessary.');
         $output->writeln('Once the migration class is valid, call the "migrate" task to execute it.');
     }
 }