/src/Propel/Generator/Model/Diff/PropelTableComparator.php

https://github.com/esimionato/Propel2 · PHP · 312 lines · 183 code · 34 blank · 95 comment · 22 complexity · f9cb9e7e936b10cb91fb33430fc341bc 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. namespace Propel\Generator\Model\Diff;
  10. use Propel\Generator\Model\Table;
  11. /**
  12. * Service class for comparing Table objects
  13. * Heavily inspired by Doctrine2's Migrations
  14. * (see http://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Schema/)
  15. *
  16. * @package propel.generator.model.diff
  17. */
  18. class PropelTableComparator
  19. {
  20. protected $tableDiff;
  21. public function __construct($tableDiff = null)
  22. {
  23. $this->tableDiff = (null === $tableDiff) ? new PropelTableDiff() : $tableDiff;
  24. }
  25. public function getTableDiff()
  26. {
  27. return $this->tableDiff;
  28. }
  29. /**
  30. * Set the table the comparator starts from
  31. *
  32. * @param Table $fromTable
  33. */
  34. public function setFromTable(Table $fromTable)
  35. {
  36. $this->tableDiff->setFromTable($fromTable);
  37. }
  38. /**
  39. * Get the table the comparator starts from
  40. *
  41. * @return Table
  42. */
  43. public function getFromTable()
  44. {
  45. return $this->tableDiff->getFromTable();
  46. }
  47. /**
  48. * Set the table the comparator goes to
  49. *
  50. * @param Table $toTable
  51. */
  52. public function setToTable(Table $toTable)
  53. {
  54. $this->tableDiff->setToTable($toTable);
  55. }
  56. /**
  57. * Get the table the comparator goes to
  58. *
  59. * @return Table
  60. */
  61. public function getToTable()
  62. {
  63. return $this->tableDiff->getToTable();
  64. }
  65. /**
  66. * Compute and return the difference between two table objects
  67. *
  68. * @param Column $fromTable
  69. * @param Column $toTable
  70. * @param boolean $caseInsensitive Whether the comparison is case insensitive.
  71. * False by default.
  72. *
  73. * @return PropelTableDiff|boolean return false if the two tables are similar
  74. */
  75. public static function computeDiff(Table $fromTable, Table $toTable, $caseInsensitive = false)
  76. {
  77. $tc = new self();
  78. $tc->setFromTable($fromTable);
  79. $tc->setToTable($toTable);
  80. $differences = 0;
  81. $differences += $tc->compareColumns($caseInsensitive);
  82. $differences += $tc->comparePrimaryKeys($caseInsensitive);
  83. $differences += $tc->compareIndices($caseInsensitive);
  84. $differences += $tc->compareForeignKeys($caseInsensitive);
  85. return ($differences > 0) ? $tc->getTableDiff() : false;
  86. }
  87. /**
  88. * Compare the columns of the fromTable and the toTable,
  89. * and modifies the inner tableDiff if necessary.
  90. * Returns the number of differences.
  91. *
  92. * @param boolean $caseInsensitive Whether the comparison is case insensitive.
  93. * False by default.
  94. *
  95. * @return integer The number of column differences
  96. */
  97. public function compareColumns($caseInsensitive = false)
  98. {
  99. $fromTableColumns = $this->getFromTable()->getColumns();
  100. $toTableColumns = $this->getToTable()->getColumns();
  101. $columnDifferences = 0;
  102. // check for new columns in $toTable
  103. foreach ($toTableColumns as $column) {
  104. if (!$this->getFromTable()->hasColumn($column->getName(), $caseInsensitive)) {
  105. $this->tableDiff->addAddedColumn($column->getName(), $column);
  106. $columnDifferences++;
  107. }
  108. }
  109. // check for removed columns in $toTable
  110. foreach ($fromTableColumns as $column) {
  111. if (!$this->getToTable()->hasColumn($column->getName(), $caseInsensitive)) {
  112. $this->tableDiff->addRemovedColumn($column->getName(), $column);
  113. $columnDifferences++;
  114. }
  115. }
  116. // check for column differences
  117. foreach ($fromTableColumns as $fromColumn) {
  118. if ($this->getToTable()->hasColumn($fromColumn->getName(), $caseInsensitive)) {
  119. $toColumn = $this->getToTable()->getColumn($fromColumn->getName(), $caseInsensitive);
  120. $columnDiff = PropelColumnComparator::computeDiff($fromColumn, $toColumn, $caseInsensitive);
  121. if ($columnDiff) {
  122. $this->tableDiff->addModifiedColumn($fromColumn->getName(), $columnDiff);
  123. $columnDifferences++;
  124. }
  125. }
  126. }
  127. // check for column renamings
  128. foreach ($this->tableDiff->getAddedColumns() as $addedColumnName => $addedColumn) {
  129. foreach ($this->tableDiff->getRemovedColumns() as $removedColumnName => $removedColumn) {
  130. if (!PropelColumnComparator::computeDiff($addedColumn, $removedColumn, $caseInsensitive)) {
  131. // no difference except the name, that's probably a renaming
  132. $this->tableDiff->addRenamedColumn($removedColumn, $addedColumn);
  133. $this->tableDiff->removeAddedColumn($addedColumnName);
  134. $this->tableDiff->removeRemovedColumn($removedColumnName);
  135. $columnDifferences--;
  136. }
  137. }
  138. }
  139. return $columnDifferences;
  140. }
  141. /**
  142. * Compare the primary keys of the fromTable and the toTable,
  143. * and modifies the inner tableDiff if necessary.
  144. * Returns the number of differences.
  145. *
  146. * @param boolean $caseInsensitive Whether the comparison is case insensitive.
  147. * False by default.
  148. *
  149. * @return integer The number of primary key differences
  150. */
  151. public function comparePrimaryKeys($caseInsensitive = false)
  152. {
  153. $pkDifferences = 0;
  154. $fromTablePk = $this->getFromTable()->getPrimaryKey();
  155. $toTablePk = $this->getToTable()->getPrimaryKey();
  156. // check for new pk columns in $toTable
  157. foreach ($toTablePk as $column) {
  158. if (!$this->getFromTable()->hasColumn($column->getName(), $caseInsensitive) ||
  159. !$this->getFromTable()->getColumn($column->getName(), $caseInsensitive)->isPrimaryKey()) {
  160. $this->tableDiff->addAddedPkColumn($column->getName(), $column);
  161. $pkDifferences++;
  162. }
  163. }
  164. // check for removed pk columns in $toTable
  165. foreach ($fromTablePk as $column) {
  166. if (!$this->getToTable()->hasColumn($column->getName(), $caseInsensitive) ||
  167. !$this->getToTable()->getColumn($column->getName(), $caseInsensitive)->isPrimaryKey()) {
  168. $this->tableDiff->addRemovedPkColumn($column->getName(), $column);
  169. $pkDifferences++;
  170. }
  171. }
  172. // check for column renamings
  173. foreach ($this->tableDiff->getAddedPkColumns() as $addedColumnName => $addedColumn) {
  174. foreach ($this->tableDiff->getRemovedPkColumns() as $removedColumnName => $removedColumn) {
  175. if (!PropelColumnComparator::computeDiff($addedColumn, $removedColumn, $caseInsensitive)) {
  176. // no difference except the name, that's probably a renaming
  177. $this->tableDiff->addRenamedPkColumn($removedColumn, $addedColumn);
  178. $this->tableDiff->removeAddedPkColumn($addedColumnName);
  179. $this->tableDiff->removeRemovedPkColumn($removedColumnName);
  180. $pkDifferences--;
  181. }
  182. }
  183. }
  184. return $pkDifferences;
  185. }
  186. /**
  187. * Compare the indices and unique indices of the fromTable and the toTable,
  188. * and modifies the inner tableDiff if necessary.
  189. * Returns the number of differences.
  190. *
  191. * @param boolean $caseInsensitive Whether the comparison is case insensitive.
  192. * False by default.
  193. *
  194. * @return integer The number of index differences
  195. */
  196. public function compareIndices($caseInsensitive = false)
  197. {
  198. $indexDifferences = 0;
  199. $fromTableIndices = array_merge($this->getFromTable()->getIndices(), $this->getFromTable()->getUnices());
  200. $toTableIndices = array_merge($this->getToTable()->getIndices(), $this->getToTable()->getUnices());
  201. foreach ($toTableIndices as $toTableIndexPos => $toTableIndex) {
  202. foreach ($fromTableIndices as $fromTableIndexPos => $fromTableIndex) {
  203. if (PropelIndexComparator::computeDiff($fromTableIndex, $toTableIndex, $caseInsensitive) === false) {
  204. unset($fromTableIndices[$fromTableIndexPos]);
  205. unset($toTableIndices[$toTableIndexPos]);
  206. } else {
  207. $test = $caseInsensitive ?
  208. strtolower($fromTableIndex->getName()) == strtolower($toTableIndex->getName()) :
  209. $fromTableIndex->getName() == $toTableIndex->getName();
  210. if ($test) {
  211. // same name, but different columns
  212. $this->tableDiff->addModifiedIndex($fromTableIndex->getName(), $fromTableIndex, $toTableIndex);
  213. unset($fromTableIndices[$fromTableIndexPos]);
  214. unset($toTableIndices[$toTableIndexPos]);
  215. $indexDifferences++;
  216. }
  217. }
  218. }
  219. }
  220. foreach ($fromTableIndices as $fromTableIndexPos => $fromTableIndex) {
  221. $this->tableDiff->addRemovedIndex($fromTableIndex->getName(), $fromTableIndex);
  222. $indexDifferences++;
  223. }
  224. foreach ($toTableIndices as $toTableIndexPos => $toTableIndex) {
  225. $this->tableDiff->addAddedIndex($toTableIndex->getName(), $toTableIndex);
  226. $indexDifferences++;
  227. }
  228. return $indexDifferences;
  229. }
  230. /**
  231. * Compare the foreign keys of the fromTable and the toTable,
  232. * and modifies the inner tableDiff if necessary.
  233. * Returns the number of differences.
  234. *
  235. * @param boolean $caseInsensitive Whether the comparison is case insensitive.
  236. * False by default.
  237. *
  238. * @return integer The number of foreign key differences
  239. */
  240. public function compareForeignKeys($caseInsensitive = false)
  241. {
  242. $fkDifferences = 0;
  243. $fromTableFks = $this->getFromTable()->getForeignKeys();
  244. $toTableFks = $this->getToTable()->getForeignKeys();
  245. foreach ($fromTableFks as $fromTableFkPos => $fromTableFk) {
  246. foreach ($toTableFks as $toTableFkPos => $toTableFk) {
  247. if (PropelForeignKeyComparator::computeDiff($fromTableFk, $toTableFk, $caseInsensitive) === false) {
  248. unset($fromTableFks[$fromTableFkPos]);
  249. unset($toTableFks[$toTableFkPos]);
  250. } else {
  251. $test = $caseInsensitive ?
  252. strtolower($fromTableFk->getName()) == strtolower($toTableFk->getName()) :
  253. $fromTableFk->getName() == $toTableFk->getName();
  254. if ($test) {
  255. // same name, but different columns
  256. $this->tableDiff->addModifiedFk($fromTableFk->getName(), $fromTableFk, $toTableFk);
  257. unset($fromTableFks[$fromTableFkPos]);
  258. unset($toTableFks[$toTableFkPos]);
  259. $fkDifferences++;
  260. }
  261. }
  262. }
  263. }
  264. foreach ($fromTableFks as $fromTableFkPos => $fromTableFk) {
  265. if (!$fromTableFk->isSkipSql() && !in_array($fromTableFk, $toTableFks)) {
  266. $this->tableDiff->addRemovedFk($fromTableFk->getName(), $fromTableFk);
  267. $fkDifferences++;
  268. }
  269. }
  270. foreach ($toTableFks as $toTableFkPos => $toTableFk) {
  271. if (!$toTableFk->isSkipSql() && !in_array($toTableFk, $fromTableFks)) {
  272. $this->tableDiff->addAddedFk($toTableFk->getName(), $toTableFk);
  273. $fkDifferences++;
  274. }
  275. }
  276. return $fkDifferences;
  277. }
  278. }