IndexerTableSwapper.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\CatalogRule\Model\Indexer;
  8. use Magento\Framework\App\ResourceConnection;
  9. /**
  10. * @inheritDoc
  11. */
  12. class IndexerTableSwapper implements IndexerTableSwapperInterface
  13. {
  14. /**
  15. * Keys are original tables' names, values - created temporary tables.
  16. *
  17. * @var string[]
  18. */
  19. private $temporaryTables = [];
  20. /**
  21. * @var ResourceConnection
  22. */
  23. private $resourceConnection;
  24. /**
  25. * @param ResourceConnection $resource
  26. */
  27. public function __construct(ResourceConnection $resource)
  28. {
  29. $this->resourceConnection = $resource;
  30. }
  31. /**
  32. * Create temporary table based on given table to use instead of original.
  33. *
  34. * @param string $originalTableName
  35. *
  36. * @return string Created table name.
  37. */
  38. private function createTemporaryTable(string $originalTableName): string
  39. {
  40. $temporaryTableName = $this->resourceConnection->getTableName(
  41. $originalTableName . '__temp' . $this->generateRandomSuffix()
  42. );
  43. $this->resourceConnection->getConnection()->query(
  44. sprintf(
  45. 'create table %s like %s',
  46. $temporaryTableName,
  47. $this->resourceConnection->getTableName($originalTableName)
  48. )
  49. );
  50. return $temporaryTableName;
  51. }
  52. /**
  53. * Random suffix for temporary tables not to conflict with each other.
  54. *
  55. * @return string
  56. */
  57. private function generateRandomSuffix(): string
  58. {
  59. return bin2hex(random_bytes(4));
  60. }
  61. /**
  62. * @inheritDoc
  63. */
  64. public function getWorkingTableName(string $originalTable): string
  65. {
  66. $originalTable = $this->resourceConnection->getTableName($originalTable);
  67. if (!array_key_exists($originalTable, $this->temporaryTables)) {
  68. $this->temporaryTables[$originalTable] = $this->createTemporaryTable($originalTable);
  69. }
  70. return $this->temporaryTables[$originalTable];
  71. }
  72. /**
  73. * @inheritDoc
  74. */
  75. public function swapIndexTables(array $originalTablesNames)
  76. {
  77. $toRename = [];
  78. /** @var string[] $toDrop */
  79. $toDrop = [];
  80. /** @var string[] $temporaryTablesRenamed */
  81. $temporaryTablesRenamed = [];
  82. //Renaming temporary tables to original tables' names, dropping old
  83. //tables.
  84. foreach ($originalTablesNames as $tableName) {
  85. $tableName = $this->resourceConnection->getTableName($tableName);
  86. $temporaryOriginalName = $this->resourceConnection->getTableName(
  87. $tableName . $this->generateRandomSuffix()
  88. );
  89. $temporaryTableName = $this->getWorkingTableName($tableName);
  90. $toRename[] = [
  91. 'oldName' => $tableName,
  92. 'newName' => $temporaryOriginalName,
  93. ];
  94. $toRename[] = [
  95. 'oldName' => $temporaryTableName,
  96. 'newName' => $tableName,
  97. ];
  98. $toDrop[] = $temporaryOriginalName;
  99. $temporaryTablesRenamed[] = $tableName;
  100. }
  101. //Swapping tables.
  102. $this->resourceConnection->getConnection()->renameTablesBatch($toRename);
  103. //Cleaning up.
  104. foreach ($temporaryTablesRenamed as $tableName) {
  105. unset($this->temporaryTables[$tableName]);
  106. }
  107. //Removing old ones.
  108. foreach ($toDrop as $tableName) {
  109. $this->resourceConnection->getConnection()->dropTable($tableName);
  110. }
  111. }
  112. }