2
0

AbstractPlatform.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. namespace PhpDevCommunity\PaperORM\Platform;
  3. use LogicException;
  4. use PhpDevCommunity\PaperORM\Collection\ObjectStorage;
  5. use PhpDevCommunity\PaperORM\Mapping\Column\Column;
  6. use PhpDevCommunity\PaperORM\Mapping\Column\JoinColumn;
  7. use PhpDevCommunity\PaperORM\Mapping\Index;
  8. use PhpDevCommunity\PaperORM\Metadata\DatabaseSchemaDiffMetadata;
  9. use PhpDevCommunity\PaperORM\Metadata\ColumnMetadata;
  10. use PhpDevCommunity\PaperORM\Metadata\IndexMetadata;
  11. use PhpDevCommunity\PaperORM\Schema\SchemaInterface;
  12. abstract class AbstractPlatform implements PlatformInterface
  13. {
  14. final public function mapColumnsToMetadata(array $columns): array
  15. {
  16. $columnsMetadata = [];
  17. foreach ($columns as $column) {
  18. if (!$column instanceof Column) {
  19. throw new LogicException(sprintf("The column '%s' is not supported.", is_object($column) ? get_class($column) : gettype($column)));
  20. }
  21. $columnsMetadata[] = $this->mapColumnToMetadata($column);
  22. }
  23. return $columnsMetadata;
  24. }
  25. final public function mapColumnToMetadata(Column $column): ColumnMetadata
  26. {
  27. $mappings = $this->getColumnTypeMappings();
  28. $className = get_class($column);
  29. if (!array_key_exists($className, $mappings)) {
  30. throw new LogicException(sprintf("The column type '%s' is not supported.", $column->getType()));
  31. }
  32. $sqlType = $mappings[$className];
  33. return ColumnMetadata::fromColumn($column, $sqlType);
  34. }
  35. /**
  36. * @param string $tableName
  37. * @param array<Column> $columns
  38. * @param array<Index> $indexes
  39. * @return void
  40. */
  41. final public function diff(string $tableName, array $columns, array $indexes): DatabaseSchemaDiffMetadata
  42. {
  43. list($columnsToAdd, $columnsToUpdate, $columnsToDrop, $originalColumns) = $this->diffColumns($tableName, $columns);
  44. list($indexesToAdd, $indexesToUpdate, $indexesToDrop, $originalIndexes) = $this->diffIndexes($tableName, $indexes);
  45. return new DatabaseSchemaDiffMetadata(
  46. $columnsToAdd,
  47. $columnsToUpdate,
  48. $columnsToDrop,
  49. $originalColumns,
  50. $indexesToAdd,
  51. $indexesToUpdate,
  52. $indexesToDrop,
  53. $originalIndexes
  54. );
  55. }
  56. private function diffColumns(string $tableName, array $columns): array
  57. {
  58. $columnsFromTable = $this->listTableColumns($tableName);
  59. $columnsFromTableByName = [];
  60. foreach ($columnsFromTable as $columnMetadata) {
  61. $columnsFromTableByName[$columnMetadata->getName()] = $columnMetadata;
  62. }
  63. $columnsToAdd = [];
  64. $columnsToUpdate = [];
  65. $columnsToDrop = [];
  66. $columnsExisting = [];
  67. foreach ($columns as $column) {
  68. $columnMetadata = $this->mapColumnToMetadata($column);
  69. if (isset($columnsFromTableByName[$columnMetadata->getName()])) {
  70. $columnFromTable = $columnsFromTableByName[$columnMetadata->getName()];
  71. if ($columnFromTable->toArray() != $columnMetadata->toArray()) {
  72. $columnsToUpdate[] = $columnMetadata;
  73. }
  74. } else {
  75. $columnsToAdd[] = $columnMetadata;
  76. }
  77. $columnsExisting[] = $columnMetadata->getName();
  78. }
  79. foreach ($columnsFromTableByName as $columnMetadata) {
  80. if (!in_array($columnMetadata->getName(), $columnsExisting)) {
  81. $columnsToDrop[] = $columnMetadata;
  82. }
  83. }
  84. return [$columnsToAdd, $columnsToUpdate, $columnsToDrop, $columnsFromTable];
  85. }
  86. /**
  87. * @param string $tableName
  88. * @param array<Index> $indexes
  89. * @return array
  90. */
  91. private function diffIndexes(string $tableName, array $indexes): array
  92. {
  93. $indexesFromTable = new ObjectStorage($this->listTableIndexes($tableName));
  94. $indexesToAdd = [];
  95. $indexesToUpdate = [];
  96. $indexesToDrop = [];
  97. $indexesExisting = [];
  98. foreach ($indexes as $index) {
  99. $indexMetadata = new IndexMetadata($tableName, $index->getName() ?: $this->generateIndexName($index->getColumns()), $index->getColumns(), $index->isUnique());
  100. $indexFound = $indexesFromTable->findOneBy('getName', $indexMetadata->getName());
  101. if ($indexFound) {
  102. if ($indexMetadata->toArray() != $indexFound->toArray()) {
  103. $indexesToUpdate[] = $indexMetadata;
  104. }
  105. }else {
  106. $indexesToAdd[] = $indexMetadata;
  107. }
  108. $indexesExisting[] = $indexMetadata->getName();
  109. }
  110. foreach ($indexesFromTable as $index) {
  111. if (!in_array($index->getName(), $indexesExisting)) {
  112. $indexesToDrop[] = $index;
  113. }
  114. }
  115. return [$indexesToAdd, $indexesToUpdate, $indexesToDrop, $indexesFromTable->toArray()];
  116. }
  117. final protected function generateIndexName(array $columnNames): string
  118. {
  119. $hash = implode("", array_map(static function ($column) {
  120. return dechex(crc32($column));
  121. }, $columnNames));
  122. return strtoupper(substr($this->getPrefixIndexName() . $hash, 0, $this->getMaxLength()));
  123. }
  124. }