PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/generator/lib/task/PropelSQLDiffTask.php

http://github.com/propelorm/Propel
PHP | 191 lines | 116 code | 22 blank | 53 comment | 10 complexity | 081fff0c2fee2b19f99bffd47e71d5d4 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. require_once dirname(__FILE__) . '/AbstractPropelDataModelTask.php';
  10. require_once dirname(__FILE__) . '/../builder/om/ClassTools.php';
  11. require_once dirname(__FILE__) . '/../builder/om/OMBuilder.php';
  12. require_once dirname(__FILE__) . '/../model/diff/PropelDatabaseComparator.php';
  13. require_once dirname(__FILE__) . '/../util/PropelMigrationManager.php';
  14. /**
  15. * This Task creates the OM classes based on the XML schema file.
  16. *
  17. * @author Hans Lellelid <hans@xmpl.org>
  18. * @package propel.generator.task
  19. */
  20. class PropelSQLDiffTask extends AbstractPropelDataModelTask
  21. {
  22. protected $databaseName;
  23. protected $editorCmd;
  24. protected $isCaseInsensitive = false;
  25. /**
  26. * Sets the datasource name.
  27. *
  28. * This will be used as the <database name=""> value in the generated schema.xml
  29. *
  30. * @param string $v
  31. */
  32. public function setDatabaseName($v)
  33. {
  34. $this->databaseName = $v;
  35. }
  36. /**
  37. * Gets the datasource name.
  38. *
  39. * @return string
  40. */
  41. public function getDatabaseName()
  42. {
  43. return $this->databaseName;
  44. }
  45. /**
  46. * Setter for the editorCmd property
  47. *
  48. * @param string $editorCmd
  49. */
  50. public function setEditorCmd($editorCmd)
  51. {
  52. $this->editorCmd = $editorCmd;
  53. }
  54. /**
  55. * Getter for the editorCmd property
  56. *
  57. * @return string
  58. */
  59. public function getEditorCmd()
  60. {
  61. return $this->editorCmd;
  62. }
  63. /**
  64. * Defines whether the comparison is case insensitive
  65. *
  66. * @param boolean $isCaseInsensitive
  67. */
  68. public function setCaseInsensitive($isCaseInsensitive)
  69. {
  70. $this->isCaseInsensitive = (boolean) $isCaseInsensitive;
  71. }
  72. /**
  73. * Checks whether the comparison is case insensitive
  74. *
  75. * @return boolean
  76. */
  77. public function isCaseInsensitive()
  78. {
  79. return $this->isCaseInsensitive;
  80. }
  81. /**
  82. * Main method builds all the targets for a typical propel project.
  83. */
  84. public function main()
  85. {
  86. // check to make sure task received all correct params
  87. $this->validate();
  88. $generatorConfig = $this->getGeneratorConfig();
  89. // loading model from database
  90. $this->log('Reading databases structure...');
  91. $connections = $generatorConfig->getBuildConnections();
  92. if (!$connections) {
  93. throw new Exception('You must define database connection settings in a buildtime-conf.xml file to use diff');
  94. }
  95. $manager = new PropelMigrationManager();
  96. $manager->setConnections($connections);
  97. $manager->setMigrationDir($this->getOutputDirectory());
  98. $manager->setMigrationTable($this->getGeneratorConfig()->getBuildProperty('migrationTable'));
  99. if ($manager->hasPendingMigrations()) {
  100. throw new Exception('Uncommitted migrations have been found ; you should either execute or delete them before rerunning the \'diff\' task');
  101. }
  102. $totalNbTables = 0;
  103. $ad = new AppData();
  104. foreach ($connections as $name => $params) {
  105. $this->log(sprintf('Connecting to database "%s" using DSN "%s"', $name, $params['dsn']), Project::MSG_VERBOSE);
  106. $pdo = $generatorConfig->getBuildPDO($name);
  107. $database = new Database($name);
  108. $platform = $generatorConfig->getConfiguredPlatform($pdo);
  109. if (!$platform->supportsMigrations()) {
  110. $this->log(sprintf('Skipping database "%s" since vendor "%s" does not support migrations', $name, $platform->getDatabaseType()));
  111. continue;
  112. }
  113. $database->setPlatform($platform);
  114. $database->setDefaultIdMethod(IDMethod::NATIVE);
  115. $parser = $generatorConfig->getConfiguredSchemaParser($pdo);
  116. $nbTables = $parser->parse($database, $this);
  117. $ad->addDatabase($database);
  118. $totalNbTables += $nbTables;
  119. $this->log(sprintf('%d tables found in database "%s"', $nbTables, $name), Project::MSG_VERBOSE);
  120. }
  121. if ($totalNbTables) {
  122. $this->log(sprintf('%d tables found in all databases.', $totalNbTables));
  123. } else {
  124. $this->log('No table found in all databases');
  125. }
  126. // loading model from XML
  127. $this->packageObjectModel = true;
  128. $appDatasFromXml = $this->getDataModels();
  129. $appDataFromXml = array_pop($appDatasFromXml);
  130. // comparing models
  131. $this->log('Comparing models...');
  132. $migrationsUp = array();
  133. $migrationsDown = array();
  134. foreach ($ad->getDatabases() as $database) {
  135. $name = $database->getName();
  136. $this->log(sprintf('Comparing database "%s"', $name), Project::MSG_VERBOSE);
  137. if (!$appDataFromXml->hasDatabase($name)) {
  138. // FIXME: tables present in database but not in XML
  139. continue;
  140. }
  141. $databaseDiff = PropelDatabaseComparator::computeDiff($database, $appDataFromXml->getDatabase($name), $this->isCaseInsensitive());
  142. if (!$databaseDiff) {
  143. $this->log(sprintf('Same XML and database structures for datasource "%s" - no diff to generate', $name), Project::MSG_VERBOSE);
  144. continue;
  145. }
  146. $this->log(sprintf('Structure of database was modified in datasource "%s": %s', $name, $databaseDiff->getDescription()));
  147. $platform = $generatorConfig->getConfiguredPlatform(null, $name);
  148. $migrationsUp[$name] = $platform->getModifyDatabaseDDL($databaseDiff);
  149. $migrationsDown[$name] = $platform->getModifyDatabaseDDL($databaseDiff->getReverseDiff());
  150. }
  151. if (!$migrationsUp) {
  152. $this->log('Same XML and database structures for all datasource - no diff to generate');
  153. return;
  154. }
  155. $timestamp = time();
  156. $migrationFileName = $manager->getMigrationFileName($timestamp);
  157. $migrationClassBody = $manager->getMigrationClassBody($migrationsUp, $migrationsDown, $timestamp);
  158. $_f = new PhingFile($this->getOutputDirectory(), $migrationFileName);
  159. file_put_contents($_f->getAbsolutePath(), $migrationClassBody);
  160. $this->log(sprintf('"%s" file successfully created in %s', $_f->getName(), $_f->getParent()));
  161. if ($editorCmd = $this->getEditorCmd()) {
  162. $this->log(sprintf('Using "%s" as text editor', $editorCmd));
  163. shell_exec($editorCmd . ' ' . escapeshellarg($_f->getAbsolutePath()));
  164. } else {
  165. $this->log(' Please review the generated SQL statements, and add data migration code if necessary.');
  166. $this->log(' Once the migration class is valid, call the "migrate" task to execute it.');
  167. }
  168. }
  169. }