ReCreateTable.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Setup\Declaration\Schema\Operations;
  7. use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataBetweenShards;
  8. use Magento\Framework\Setup\Declaration\Schema\Db\Statement;
  9. use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory;
  10. use Magento\Framework\Setup\Declaration\Schema\Dto\Table;
  11. use Magento\Framework\Setup\Declaration\Schema\ElementHistory;
  12. use Magento\Framework\Setup\Declaration\Schema\ElementHistoryFactory;
  13. use Magento\Framework\Setup\Declaration\Schema\OperationInterface;
  14. /**
  15. * Recreate table operation.
  16. * Drops and creates table again.
  17. */
  18. class ReCreateTable implements OperationInterface
  19. {
  20. /**
  21. * Operation name.
  22. */
  23. const OPERATION_NAME = 'recreate_table';
  24. /**
  25. * @var CreateTable
  26. */
  27. private $createTable;
  28. /**
  29. * @var DropTable
  30. */
  31. private $dropTable;
  32. /**
  33. * @var MigrateDataBetweenShards
  34. */
  35. private $migrateDataBetweenShards;
  36. /**
  37. * @var ElementHistoryFactory
  38. */
  39. private $elementHistoryFactory;
  40. /**
  41. * @var ElementFactory
  42. */
  43. private $elementFactory;
  44. /**
  45. * Constructor.
  46. *
  47. * @param CreateTable $createTable
  48. * @param DropTable $dropTable
  49. * @param MigrateDataBetweenShards $migrateDataBetweenShards
  50. * @param ElementHistoryFactory $elementHistoryFactory
  51. * @param ElementFactory $elementFactory
  52. */
  53. public function __construct(
  54. CreateTable $createTable,
  55. DropTable $dropTable,
  56. MigrateDataBetweenShards $migrateDataBetweenShards,
  57. ElementHistoryFactory $elementHistoryFactory,
  58. ElementFactory $elementFactory
  59. ) {
  60. $this->createTable = $createTable;
  61. $this->dropTable = $dropTable;
  62. $this->migrateDataBetweenShards = $migrateDataBetweenShards;
  63. $this->elementHistoryFactory = $elementHistoryFactory;
  64. $this->elementFactory = $elementFactory;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function isOperationDestructive()
  70. {
  71. return true;
  72. }
  73. /**
  74. * {@inheritdoc}
  75. */
  76. public function getOperationName()
  77. {
  78. return self::OPERATION_NAME;
  79. }
  80. /**
  81. * Merge 2 tables: take old data from new table, columns and indexes from old tables:
  82. * we need to take in account, that 3-rd party extensions can add columns and indexes and also
  83. * internal constraints in old way: with UpgradeSchema/InstallSchema scripts
  84. *
  85. * @param ElementHistory $elementHistory
  86. * @return Table
  87. */
  88. private function getRecreatedTable(ElementHistory $elementHistory) : Table
  89. {
  90. /** @var Table $newTable */
  91. $newTable = $elementHistory->getNew();
  92. /** @var Table $oldTable */
  93. $oldTable = $elementHistory->getOld();
  94. /** @var Table $recreationTable */
  95. $recreationTable = $this->elementFactory->create(
  96. 'table',
  97. [
  98. 'name' => $newTable->getName(),
  99. 'type' => 'table',
  100. 'nameWithoutPrefix' => $newTable->getNameWithoutPrefix(),
  101. 'resource' => $newTable->getResource(),
  102. 'engine' => $newTable->getEngine(),
  103. 'charset' => $newTable->getCharset(),
  104. 'collation' => $newTable->getCollation(),
  105. 'onCreate' => $newTable->getOnCreate(),
  106. 'comment' => $newTable->getOnCreate(),
  107. 'columns' => $oldTable->getColumns(),
  108. 'indexes' => $oldTable->getIndexes(),
  109. 'constraints' => array_merge($oldTable->getInternalConstraints(), $newTable->getReferenceConstraints())
  110. ]
  111. );
  112. return $recreationTable;
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function doOperation(ElementHistory $elementHistory)
  118. {
  119. $recreatedTable = $this->getRecreatedTable($elementHistory);
  120. $recreatedElementHistory = $this->elementHistoryFactory->create(
  121. [
  122. 'old' => $elementHistory->getOld(),
  123. 'new' => $recreatedTable
  124. ]
  125. );
  126. $statements = $this->createTable->doOperation($recreatedElementHistory);
  127. /** @var Statement $statement */
  128. foreach ($statements as $statement) {
  129. if ($this->migrateDataBetweenShards->isApplicable((string) $recreatedTable->getOnCreate())) {
  130. $statement->addTrigger($this->migrateDataBetweenShards->getCallback($recreatedElementHistory));
  131. }
  132. }
  133. return array_merge($statements, $this->dropTable->doOperation($recreatedElementHistory));
  134. }
  135. }