public function testValidateReturnsFalseWhenTwoTablesHaveSamePhpName() { $table1 = new Table('foo'); $table2 = new Table('bar'); $table2->setPhpName('Foo'); $database = new Database(); $database->addTable($table1); $database->addTable($table2); $appData = new AppData(); $appData->addDatabase($database); $validator = new PropelSchemaValidator($appData); $this->assertFalse($validator->validate()); $this->assertContains('Table "bar" declares a phpName already used in another table', $validator->getErrors()); }
/** * * @param string $module * @param string $action */ public static function update($module, $action = 'create') { $targetDbName = 'centreon'; ini_set('memory_limit', '-1'); $di = Di::getDefault(); $config = $di->get('config'); $targetDb = 'db_centreon'; $db = $di->get($targetDb); // Configuration for Propel $configParams = array('propel.project' => 'centreon', 'propel.database' => 'mysql', 'propel.database.url' => $config->get($targetDb, 'dsn'), 'propel.database.user' => $config->get($targetDb, 'username'), 'propel.database.password' => $config->get($targetDb, 'password')); // Set the Current Platform and DB Connection $platform = new CentreonMysqlPlatform($db); // Initilize Schema Parser $propelDb = new \MysqlSchemaParser($db); $propelDb->setGeneratorConfig(new \GeneratorConfig($configParams)); $propelDb->setPlatform($platform); // get Current Db State $currentDbAppData = new \AppData($platform); $currentDbAppData->setGeneratorConfig(new \GeneratorConfig($configParams)); $currentDb = $currentDbAppData->addDatabase(array('name' => $targetDbName)); $propelDb->parse($currentDb); // Retreive target DB State $updatedAppData = new \AppData($platform); self::getDbFromXml($updatedAppData, 'centreon'); // Get diff between current db state and target db state $diff = \PropelDatabaseComparator::computeDiff($currentDb, $updatedAppData->getDatabase('centreon'), false); if ($diff !== false) { $strDiff = $platform->getModifyDatabaseDDL($diff); $sqlToBeExecuted = \PropelSQLParser::parseString($strDiff); $finalSql = "\nSET FOREIGN_KEY_CHECKS = 0;\n\n"; if ($action == 'create') { $finalSql .= implode(";\n\n", static::keepCreateStatement($sqlToBeExecuted, $module)); } elseif ($action == 'delete') { $finalSql .= implode(";\n\n", static::keepDeleteStatement($sqlToBeExecuted, $module)); } $finalSql .= ";\n\nSET FOREIGN_KEY_CHECKS = 1;\n\n"; \PropelSQLParser::executeString($finalSql, $db); } // Empty Target DB self::deleteTargetDbSchema($targetDbName); }
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); $appData = new AppData(); $appData->addDatabase($database); $validator = new PropelSchemaValidator($appData); $this->assertTrue($validator->validate()); }
/** * Packages the datamodels to one datamodel per package * * This applies only when the the packageObjectModel option is set. We need to * re-package the datamodels to allow the database package attribute to control * which tables go into which SQL file. * * @return array The packaged datamodels */ protected function packageDataModels() { static $packagedDataModels; if (is_null($packagedDataModels)) { $dataModels = $this->getDataModels(); $dataModel = array_shift($dataModels); $packagedDataModels = array(); $platform = $this->getPlatformForTargetDatabase(); foreach ($dataModel->getDatabases() as $db) { foreach ($db->getTables() as $table) { $package = $table->getPackage(); if (!isset($packagedDataModels[$package])) { $dbClone = $this->cloneDatabase($db); $dbClone->setPackage($package); $ad = new AppData($platform); $ad->setName($dataModel->getName()); $ad->addDatabase($dbClone); $packagedDataModels[$package] = $ad; } $packagedDataModels[$package]->getDatabase($db->getName())->addTable($table); } } } return $packagedDataModels; }
/** * 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); $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 imported from database "%s"', $nbTables, $name), Project::MSG_VERBOSE); } if ($totalNbTables) { $this->log(sprintf('%d tables imported from databases.', $totalNbTables)); } else { $this->log('Database is empty'); } // loading model from XML $this->packageObjectModel = true; $appDatasFromXml = $this->getDataModels(); $appDataFromXml = array_pop($appDatasFromXml); // comparing models $this->log('Comparing models...'); $manager = new PropelMigrationManager(); $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 = PropelDatabaseComparator::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.'); } }
/** * @see sfTask */ protected function execute($arguments = array(), $options = array()) { $databaseManager = new sfDatabaseManager($this->configuration); $connections = $this->getConnections($databaseManager); //$connection = $databaseManager->getDatabase($options['connection'] ? $options['connection'] : null)->getConnection(); $i = new afsDbInfo(); $this->logSection('propel', 'Reading databases structure...'); $ad = new AppData(); $totalNbTables = 0; foreach ($connections as $name => $params) { $pdo = $databaseManager->getDatabase($name)->getConnection(); $database = new Database($name); $platform = $this->getPlatform($databaseManager, $name); $database->setPlatform($platform); $database->setDefaultIdMethod(IDMethod::NATIVE); $parser = $this->getParser($databaseManager, $name, $pdo); //$parser->setMigrationTable($options['migration-table']); $parser->setPlatform($platform); $nbTables = $parser->parse($database); $ad->addDatabase($database); $totalNbTables += $nbTables; $this->logSection('propel', sprintf(' %d tables imported from database "%s"', $nbTables, $name), null, 'COMMENT'); } if ($totalNbTables) { $this->logSection('propel', sprintf('%d tables imported from databases.', $totalNbTables)); } else { $this->logSection('propel', 'Database is empty'); } $this->logSection('propel', 'Loading XML schema files...'); Phing::startup(); // required to locate behavior classes... $this->schemaToXML(self::DO_NOT_CHECK_SCHEMA, 'generated-'); $this->copyXmlSchemaFromPlugins('generated-'); $appData = $this->getModels($databaseManager, true); $this->logSection('propel', sprintf('%d tables defined in the schema files.', $appData->countTables())); $this->cleanup(true); $this->logSection('sql-diff', 'Comparing databases and schemas...'); $manager = new PropelMigrationManager(); $manager->setConnections($connections); foreach ($ad->getDatabases() as $database) { $name = $database->getName(); $filenameDiff = sfConfig::get('sf_data_dir') . "/sql/{$name}." . time() . ".diff.sql"; $this->logSection('sql-diff', sprintf(' Comparing database "%s"', $name), null, 'COMMENT'); if (!$appData->hasDatabase($name)) { // FIXME: tables present in database but not in XML continue; } $databaseDiff = PropelDatabaseComparator::computeDiff($database, $appData->getDatabase($name)); if (!$databaseDiff) { //no diff } $this->logSection('sql-diff', sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription())); $platform = $this->getPlatform($databaseManager, $name); //up sql $upDiff = $platform->getModifyDatabaseDDL($databaseDiff); //down sql $downDiff = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff()); if ($databaseDiff) { $this->logSection('sql-diff', "Writing file {$filenameDiff}"); afStudioUtil::writeFile($filenameDiff, $upDiff); if ($options['insert'] === true || $options['insert'] === 'true') { $this->logSection('sql-diff', "Inserting sql diff"); $i->executeSql($upDiff, Propel::getConnection($name)); } if ($options['build'] === true || $options['build'] === 'true') { $this->logSection('sql-diff', 'Creating models from current schema'); $this->createTask('propel:build-model')->run(); $this->logSection('sql-diff', 'Creating forms from current schema'); $this->createTask('propel:build-forms')->run(); $this->logSection('sql-diff', 'Setting AppFlower project permissions'); $this->createTask('afs:fix-perms')->run(); $this->logSection('sql-diff', 'Creating AppFlower validator cache'); $this->createTask('appflower:validator-cache')->run(array('frontend', 'cache', 'yes')); $this->logSection('sql-diff', 'Clearing Symfony cache'); $this->createTask('cc')->run(); } } } }
/** Sets up the Propel model. */ public function setUp() { $appData = new AppData(new MysqlPlatform()); $this->database = new Database(); $appData->addDatabase($this->database); }
/** * @see sfTask */ protected function execute($arguments = array(), $options = array()) { $databaseManager = new sfDatabaseManager($this->configuration); $connections = $this->getConnections($databaseManager); $this->logSection('propel', 'Reading databases structure...'); $ad = new AppData(); $totalNbTables = 0; foreach ($connections as $name => $params) { if ($options['verbose']) { $this->logSection('propel', sprintf(' Connecting to database "%s" using DSN "%s"', $name, $params['dsn']), null, 'COMMENT'); } $pdo = $databaseManager->getDatabase($name)->getConnection(); $database = new Database($name); $platform = $this->getPlatform($databaseManager, $name); $database->setPlatform($platform); $database->setDefaultIdMethod(IDMethod::NATIVE); $parser = $this->getParser($databaseManager, $name, $pdo); $parser->setMigrationTable($options['migration-table']); $parser->setPlatform($platform); $nbTables = $parser->parse($database); $ad->addDatabase($database); $totalNbTables += $nbTables; if ($options['verbose']) { $this->logSection('propel', sprintf(' %d tables imported from database "%s"', $nbTables, $name), null, 'COMMENT'); } } if ($totalNbTables) { $this->logSection('propel', sprintf('%d tables imported from databases.', $totalNbTables)); } else { $this->logSection('propel', 'Database is empty'); } $this->logSection('propel', 'Loading XML schema files...'); Phing::startup(); // required to locate behavior classes... $this->schemaToXML(self::DO_NOT_CHECK_SCHEMA, 'generated-'); $this->copyXmlSchemaFromPlugins('generated-'); $appData = $this->getModels($databaseManager, $options['verbose']); $this->logSection('propel', sprintf('%d tables defined in the schema files.', $appData->countTables())); $this->cleanup($options['verbose']); $this->logSection('propel', 'Comparing databases and schemas...'); $manager = new PropelMigrationManager(); $manager->setConnections($connections); $migrationsUp = array(); $migrationsDown = array(); foreach ($ad->getDatabases() as $database) { $name = $database->getName(); if ($options['verbose']) { $this->logSection('propel', sprintf(' Comparing database "%s"', $name), null, 'COMMENT'); } if (!$appData->hasDatabase($name)) { // FIXME: tables present in database but not in XML continue; } $databaseDiff = PropelDatabaseComparator::computeDiff($database, $appData->getDatabase($name)); if (!$databaseDiff) { if ($options['verbose']) { $this->logSection('propel', sprintf(' Same XML and database structures for datasource "%s" - no diff to generate', $name), null, 'COMMENT'); } continue; } $this->logSection('propel', sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription())); if ($options['verbose']) { $this->logBlock($databaseDiff, 'COMMENT'); } $platform = $this->getPlatform($databaseManager, $name); $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff); $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff()); } if (!$migrationsUp) { $this->logSection('propel', 'Same XML and database structures for all datasources - no diff to generate'); return; } $timestamp = time(); $migrationDirectory = sfConfig::get('sf_root_dir') . DIRECTORY_SEPARATOR . $options['migration-dir']; $migrationFileName = $manager->getMigrationFileName($timestamp); $migrationFilePath = $migrationDirectory . DIRECTORY_SEPARATOR . $migrationFileName; if ($options['ask-confirmation'] && !$this->askConfirmation(array(sprintf('Migration class will be generated in %s', $migrationFilePath), 'Are you sure you want to proceed? (Y/n)'), 'QUESTION_LARGE', true)) { $this->logSection('propel', 'Task aborted.'); return 1; } $this->getFilesystem()->mkdirs($migrationDirectory); $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp); file_put_contents($migrationFilePath, $migrationClassBody); $this->logSection('propel', sprintf('"%s" file successfully created in %s', $migrationFileName, $migrationDirectory)); if ($editorCmd = $options['editor-cmd']) { $this->logSection('propel', sprintf('Using "%s" as text editor', $editorCmd)); shell_exec($editorCmd . ' ' . escapeshellarg($migrationFilePath)); } else { $this->logSection('propel', ' Please review the generated SQL statements, and add data migration code if necessary.'); $this->logSection('propel', ' Once the migration class is valid, call the "propel:migrate" task to execute it.'); } }
public function testValidateReturnsFalseWhenCrossRefTableHasTwoFksToTheSameTable() { $schema = <<<EOF <database name="bookstore"> <table name="book"> <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" /> <column name="title" type="VARCHAR" size="100" primaryString="true" /> </table> <table name="book_book" isCrossRef="true"> <column name="parent_id" type="INTEGER" primaryKey="true" required="true"/> <column name="child_id" type="INTEGER" primaryKey="true" required="true"/> <foreign-key foreignTable="book"> <reference local="child_id" foreign="id"/> </foreign-key> <foreign-key foreignTable="book"> <reference local="parent_id" foreign="id"/> </foreign-key> </table> </database> EOF; $builder = new PropelQuickBuilder(); $builder->setSchema($schema); $database = $builder->getDatabase(); $appData = new AppData(); $appData->addDatabase($database); $validator = new PropelSchemaValidator($appData); $this->assertFalse($validator->validate()); $this->assertContains('Table "book_book" implements an equal nest relationship for table "book". This feature is not supported', $validator->getErrors()); }
protected static function initializeCurrentSchema($platform) { $configParams = array('propel.project' => 'centreon', 'propel.database' => 'mysql', 'propel.database.driver' => 'mysql', 'propel.database.createUrl' => 'mysql://root@localhost/', 'propel.database.url' => 'mysql:dbname=centreon;host=localhost', 'propel.database.user' => 'root', 'propel.database.password' => '', 'propel.database.encoding' => 'utf-8'); // Initilize Schema Parser $db = Di::getDefault()->get('db_centreon'); $propelDb = new \MysqlSchemaParser($db); $propelDb->setGeneratorConfig(new \GeneratorConfig($configParams)); $propelDb->setPlatform($platform); // get Current Db State $currentDbAppData = new \AppData($platform); $currentDbAppData->setGeneratorConfig(new \GeneratorConfig($configParams)); $currentDb = $currentDbAppData->addDatabase(array('name' => 'centreon')); $propelDb->parse($currentDb); return $currentDb; }