/** * Dumps a single Schema model into an XML formatted version. * * @param Schema $schema The schema object * @param boolean $doFinalInitialization Whether or not to validate the schema * @return string */ public function dumpSchema(Schema $schema, $doFinalInitialization = true) { $rootNode = $this->document->createElement('app-data'); $this->document->appendChild($rootNode); foreach ($schema->getDatabases($doFinalInitialization) as $database) { $this->appendDatabaseNode($database, $rootNode); } return trim($this->document->saveXML()); }
/** * {@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.'); } }
/** Sets up the Propel model. */ public function setUp() { $schema = new Schema(new MysqlPlatform()); $this->database = new Database(); $schema->addDatabase($this->database); }
/** * Returns the GeneratorConfigInterface object. * * @return GeneratorConfigInterface */ public function getGeneratorConfig() { if ($this->parentSchema) { return $this->parentSchema->getGeneratorConfig(); } }
public function testSetGeneratorConfig() { $config = $this->getMock('Propel\\Generator\\Config\\GeneratorConfig'); $schema = new Schema(); $schema->setGeneratorConfig($config); $this->assertSame($config, $schema->getGeneratorConfig()); }
public function startElement($parser, $name, $attributes) { $parentTag = $this->peekCurrentSchemaTag(); if (false === $parentTag) { switch ($name) { case 'database': if ($this->isExternalSchema()) { $this->currentPackage = isset($attributes['package']) ? $attributes['package'] : null; if (null === $this->currentPackage) { $this->currentPackage = $this->defaultPackage; } } else { $this->currDB = $this->schema->addDatabase($attributes); } break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('database' === $parentTag) { switch ($name) { case 'external-schema': $xmlFile = isset($attributes['filename']) ? $attributes['filename'] : null; // 'referenceOnly' attribute is valid in the main schema XML file only, // and it's ignored in the nested external-schemas if (!$this->isExternalSchema()) { $isForRefOnly = isset($attributes['referenceOnly']) ? $attributes['referenceOnly'] : null; $this->isForReferenceOnly = null !== $isForRefOnly ? 'true' === strtolower($isForRefOnly) : true; // defaults to TRUE } if ('/' !== $xmlFile[0]) { $xmlFile = realpath(dirname($this->currentXmlFile) . DIRECTORY_SEPARATOR . $xmlFile); if (!file_exists($xmlFile)) { throw new SchemaException(sprintf('Unknown include external "%s"', $xmlFile)); } } $this->parseFile($xmlFile); break; case 'domain': $this->currDB->addDomain($attributes); break; case 'table': if (!isset($attributes['schema']) && $this->currDB->getSchema() && $this->currDB->getPlatform()->supportsSchemas() && false === strpos($attributes['name'], $this->currDB->getPlatform()->getSchemaDelimiter())) { $attributes['schema'] = $this->currDB->getSchema(); } $this->currTable = $this->currDB->addTable($attributes); if ($this->isExternalSchema()) { $this->currTable->setForReferenceOnly($this->isForReferenceOnly); $this->currTable->setPackage($this->currentPackage); } break; case 'vendor': $this->currVendorObject = $this->currDB->addVendorInfo($attributes); break; case 'behavior': $this->currBehavior = $this->currDB->addBehavior($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('table' === $parentTag) { switch ($name) { case 'column': $this->currColumn = $this->currTable->addColumn($attributes); break; case 'foreign-key': $this->currFK = $this->currTable->addForeignKey($attributes); break; case 'index': $this->currIndex = new Index(); $this->currIndex->setTable($this->currTable); $this->currIndex->loadMapping($attributes); break; case 'unique': $this->currUnique = new Unique(); $this->currUnique->setTable($this->currTable); $this->currUnique->loadMapping($attributes); break; case 'vendor': $this->currVendorObject = $this->currTable->addVendorInfo($attributes); break; case 'id-method-parameter': $this->currTable->addIdMethodParameter($attributes); break; case 'behavior': $this->currBehavior = $this->currTable->addBehavior($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('column' === $parentTag) { switch ($name) { case 'inheritance': $this->currColumn->addInheritance($attributes); break; case 'vendor': $this->currVendorObject = $this->currColumn->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('foreign-key' === $parentTag) { switch ($name) { case 'reference': $this->currFK->addReference($attributes); break; case 'vendor': $this->currVendorObject = $this->currUnique->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('index' === $parentTag) { switch ($name) { case 'index-column': $this->currIndex->addColumn($attributes); break; case 'vendor': $this->currVendorObject = $this->currIndex->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('unique' === $parentTag) { switch ($name) { case 'unique-column': $this->currUnique->addColumn($attributes); break; case 'vendor': $this->currVendorObject = $this->currUnique->addVendorInfo($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ($parentTag == 'behavior') { switch ($name) { case 'parameter': $this->currBehavior->addParameter($attributes); break; default: $this->_throwInvalidTagException($parser, $name); } } elseif ('vendor' === $parentTag) { switch ($name) { case 'parameter': $this->currVendorObject->setParameter($attributes['name'], $attributes['value']); break; default: $this->_throwInvalidTagException($parser, $name); } } else { // it must be an invalid tag $this->_throwInvalidTagException($parser, $name); } $this->pushCurrentSchemaTag($name); }
public function testSetGeneratorConfig() { $config = $this->getMockBuilder('Propel\\Generator\\Config\\GeneratorConfig')->disableOriginalConstructor()->getMock(); $schema = new Schema(); $schema->setGeneratorConfig($config); $this->assertSame($config, $schema->getGeneratorConfig()); }
/** * {@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.'); } }
<?php use Propel\Generator\Model\Schema; use Propel\Generator\Platform\MysqlPlatform; $database = (include __DIR__ . DIRECTORY_SEPARATOR . 'blog-database.php'); $schema = new Schema(new MysqlPlatform()); $schema->setName('acme'); $schema->addDatabase($database); return $schema;
public function testAutoNamespaceToDatabaseSchemaName() { $yamlConf = <<<EOF propel: database: connections: mysource: adapter: mysql classname: Propel\\Runtime\\Connection\\DebugPDO dsn: mysql:host=localhost;dbname=mydb user: root password: generator: schema: autoNamespace: true EOF; $configFilename = sys_get_temp_dir() . '/propel.yml'; $filesystem = new Filesystem(); $filesystem->dumpFile($configFilename, $yamlConf); $schema = 'TestSchema'; $config = new GeneratorConfig($configFilename); $platform = new MysqlPlatform(); $parentSchema = new Schema($platform); $parentSchema->setGeneratorConfig($config); $db = new Database(); $db->setPlatform($platform); $db->setParentSchema($parentSchema); $db->setSchema($schema); $this->assertEquals($schema, $db->getNamespace()); }
public function testValidateReturnsTrueWhenTwoTablesHaveSamePhpNameInDifferentNamespaces() { $column1 = new Column('id'); $column1->setPrimaryKey(true); $table1 = new Table('foo'); $table1->addColumn($column1); $table1->setNamespace('Foo'); $column2 = new Column('id'); $column2->setPrimaryKey(true); $table2 = new Table('bar'); $table2->addColumn($column2); $table2->setPhpName('Foo'); $table2->setNamespace('Bar'); $database = new Database(); $database->addTable($table1); $database->addTable($table2); $schema = new Schema(); $schema->addDatabase($database); $validator = new SchemaValidator($schema); $this->assertTrue($validator->validate()); }