huynguyen_isobar

Untitled

Feb 26th, 2018
668
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 264.28 KB | None | 0 0
  1. diff --git a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php
  2. index 4cf4e15b6c0..64636c8469e 100644
  3. --- a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php
  4. +++ b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php
  5. @@ -19,20 +19,11 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D
  6. *
  7. * @return $this
  8. * @throws \Exception
  9. + * @deprecated
  10. */
  11. public function reindexAll()
  12. {
  13. - $this->tableStrategy->setUseIdxTable(true);
  14. -
  15. - $this->beginTransaction();
  16. - try {
  17. - $this->_prepareBundlePrice();
  18. - $this->commit();
  19. - } catch (\Exception $e) {
  20. - $this->rollBack();
  21. - throw $e;
  22. - }
  23. -
  24. + parent::reindexAll();
  25. return $this;
  26. }
  27.  
  28. @@ -41,13 +32,20 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D
  29. *
  30. * @param int|array $entityIds
  31. * @return $this
  32. + * @deprecated
  33. */
  34. public function reindexEntity($entityIds)
  35. {
  36. - $this->_prepareBundlePrice($entityIds);
  37. -
  38. + parent::reindexEntity($entityIds);
  39. return $this;
  40. }
  41. + /**
  42. + * @inheritdoc
  43. + */
  44. + protected function reindex($entityIds = null)
  45. + {
  46. + $this->_prepareBundlePrice($entityIds);
  47. + }
  48.  
  49. /**
  50. * Retrieve temporary price index table name for fixed bundle products
  51. diff --git a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Stock.php b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Stock.php
  52. index c05c1dc8b7f..c84e2963e13 100644
  53. --- a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Stock.php
  54. +++ b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Stock.php
  55. @@ -6,6 +6,8 @@
  56. namespace Magento\Bundle\Model\ResourceModel\Indexer;
  57.  
  58. use Magento\Catalog\Api\Data\ProductInterface;
  59. +use Magento\CatalogInventory\Model\Indexer\Stock\Action\Full;
  60. +use Magento\Framework\App\ObjectManager;
  61.  
  62. /**
  63. * Bundle Stock Status Indexer Resource Model
  64. @@ -14,16 +16,44 @@ use Magento\Catalog\Api\Data\ProductInterface;
  65. */
  66. class Stock extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\DefaultStock
  67. {
  68. + /**
  69. + * @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
  70. + */
  71. + private $activeTableSwitcher;
  72. +
  73. + /**
  74. + * Stock constructor.
  75. + * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  76. + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
  77. + * @param \Magento\Eav\Model\Config $eavConfig
  78. + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  79. + * @param null $connectionName
  80. + * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
  81. + */
  82. + public function __construct(
  83. + \Magento\Framework\Model\ResourceModel\Db\Context $context,
  84. + \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
  85. + \Magento\Eav\Model\Config $eavConfig,
  86. + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  87. + $connectionName = null,
  88. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
  89. + ) {
  90. + parent::__construct($context, $tableStrategy, $eavConfig, $scopeConfig, $connectionName);
  91. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
  92. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
  93. + );
  94. + }
  95. +
  96. /**
  97. * Reindex temporary (price result data) for defined product(s)
  98. *
  99. * @param int|array $entityIds
  100. * @return $this
  101. + * @deprecated
  102. */
  103. public function reindexEntity($entityIds)
  104. {
  105. - $this->_updateIndex($entityIds);
  106. -
  107. + parent::reindexEntity($entityIds);
  108. return $this;
  109. }
  110.  
  111. @@ -48,7 +78,10 @@ class Stock extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\
  112. {
  113. $this->_cleanBundleOptionStockData();
  114. $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
  115. - $idxTable = $usePrimaryTable ? $this->getMainTable() : $this->getIdxTable();
  116. + $table = $this->getActionType() === Full::ACTION_TYPE
  117. + ? $this->activeTableSwitcher->getAdditionalTableName($this->getMainTable())
  118. + : $this->getMainTable();
  119. + $idxTable = $usePrimaryTable ? $table : $this->getIdxTable();
  120. $connection = $this->getConnection();
  121. $select = $connection->select()->from(
  122. ['product' => $this->getTable('catalog_product_entity')],
  123. diff --git a/vendor/magento/module-bundle/etc/di.xml b/vendor/magento/module-bundle/etc/di.xml
  124. index 2899ce28d04..64ed00121e6 100644
  125. --- a/vendor/magento/module-bundle/etc/di.xml
  126. +++ b/vendor/magento/module-bundle/etc/di.xml
  127. @@ -129,4 +129,24 @@
  128. </argument>
  129. </arguments>
  130. </type>
  131. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator">
  132. + <arguments>
  133. + <argument name="estimators" xsi:type="array">
  134. + <item name="bundle" xsi:type="object">Magento\Catalog\Model\Indexer\Price\CompositeProductBatchSizeManagement</item>
  135. + </argument>
  136. + </arguments>
  137. + </type>
  138. + <type name="Magento\Bundle\Model\ResourceModel\Indexer\Price">
  139. + <arguments>
  140. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  141. + <argument name="connectionName" xsi:type="string">indexer</argument>
  142. + </arguments>
  143. + </type>
  144. + <type name="Magento\CatalogInventory\Model\Indexer\Stock\Action\Full">
  145. + <arguments>
  146. + <argument name="batchRowsCount" xsi:type="array">
  147. + <item name="bundle" xsi:type="number">136</item>
  148. + </argument>
  149. + </arguments>
  150. + </type>
  151. </config>
  152. diff --git a/vendor/magento/module-catalog/Model/Indexer/Category/Product/AbstractAction.php b/vendor/magento/module-catalog/Model/Indexer/Category/Product/AbstractAction.php
  153. index 250ea1d477a..013a6e4016f 100644
  154. --- a/vendor/magento/module-catalog/Model/Indexer/Category/Product/AbstractAction.php
  155. +++ b/vendor/magento/module-catalog/Model/Indexer/Category/Product/AbstractAction.php
  156. @@ -165,6 +165,9 @@ abstract class AbstractAction
  157. /**
  158. * Return main index table name
  159. *
  160. + * This table should be used on frontend(clients)
  161. + * The name is switched between 'catalog_category_product_index' and 'catalog_category_product_index_replica'
  162. + *
  163. * @return string
  164. */
  165. protected function getMainTable()
  166. diff --git a/vendor/magento/module-catalog/Model/Indexer/Category/Product/Action/Full.php b/vendor/magento/module-catalog/Model/Indexer/Category/Product/Action/Full.php
  167. index 5a5dced86f9..d4ee1d66757 100644
  168. --- a/vendor/magento/module-catalog/Model/Indexer/Category/Product/Action/Full.php
  169. +++ b/vendor/magento/module-catalog/Model/Indexer/Category/Product/Action/Full.php
  170. @@ -5,6 +5,22 @@
  171. */
  172. namespace Magento\Catalog\Model\Indexer\Category\Product\Action;
  173.  
  174. +use Magento\Framework\App\ObjectManager;
  175. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  176. +use Magento\Framework\DB\Query\Generator as QueryGenerator;
  177. +use Magento\Framework\App\ResourceConnection;
  178. +use Magento\Store\Model\StoreManagerInterface;
  179. +use Magento\Catalog\Model\Config;
  180. +use Magento\Framework\Indexer\BatchProviderInterface;
  181. +use Magento\Framework\Indexer\BatchSizeManagementInterface;
  182. +use Magento\Framework\EntityManager\MetadataPool;
  183. +
  184. +/**
  185. + * Class Full reindex action
  186. + *
  187. + * @package Magento\Catalog\Model\Indexer\Category\Product\Action
  188. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  189. + */
  190. class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction
  191. {
  192. /**
  193. @@ -14,6 +30,68 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
  194. */
  195. protected $useTempTable = false;
  196.  
  197. + /**
  198. + * @var \Magento\Framework\Indexer\BatchSizeManagementInterface
  199. + */
  200. + private $batchSizeManagement;
  201. +
  202. + /**
  203. + * @var \Magento\Framework\Indexer\BatchProviderInterface
  204. + */
  205. + private $batchProvider;
  206. +
  207. + /**
  208. + * @var \Magento\Framework\EntityManager\MetadataPool
  209. + */
  210. + protected $metadataPool;
  211. +
  212. + /**
  213. + * Row count to process in a batch
  214. + *
  215. + * @var int
  216. + */
  217. + private $batchRowsCount;
  218. +
  219. + /**
  220. + * @var ActiveTableSwitcher
  221. + */
  222. + private $activeTableSwitcher;
  223. +
  224. + /**
  225. + * @param ResourceConnection $resource
  226. + * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  227. + * @param \Magento\Catalog\Model\Config $config
  228. + * @param QueryGenerator|null $queryGenerator
  229. + * @param \Magento\Framework\Indexer\BatchSizeManagementInterface|null $batchSizeManagement
  230. + * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
  231. + * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool
  232. + * @param int|null $batchRowsCount
  233. + * @param ActiveTableSwitcher|null $activeTableSwitcher
  234. + */
  235. + public function __construct(
  236. + ResourceConnection $resource,
  237. + StoreManagerInterface $storeManager,
  238. + Config $config,
  239. + QueryGenerator $queryGenerator = null,
  240. + BatchSizeManagementInterface $batchSizeManagement = null,
  241. + BatchProviderInterface $batchProvider = null,
  242. + MetadataPool $metadataPool = null,
  243. + $batchRowsCount = null,
  244. + ActiveTableSwitcher $activeTableSwitcher = null
  245. + ) {
  246. + parent::__construct(
  247. + $resource,
  248. + $storeManager,
  249. + $config
  250. + );
  251. + $objectManager = ObjectManager::getInstance();
  252. + $this->batchSizeManagement = $batchSizeManagement ?: $objectManager->get(BatchSizeManagementInterface::class);
  253. + $this->batchProvider = $batchProvider ?: $objectManager->get(BatchProviderInterface::class);
  254. + $this->metadataPool = $metadataPool ?: $objectManager->get(MetadataPool::class);
  255. + $this->batchRowsCount = $batchRowsCount;
  256. + $this->activeTableSwitcher = $activeTableSwitcher ?: $objectManager->get(ActiveTableSwitcher::class);
  257. + }
  258. +
  259. /**
  260. * Refresh entities index
  261. *
  262. @@ -21,13 +99,8 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
  263. */
  264. public function execute()
  265. {
  266. - $this->clearTmpData();
  267. -
  268. $this->reindex();
  269. -
  270. - $this->publishData();
  271. - $this->removeUnnecessaryData();
  272. -
  273. + $this->activeTableSwitcher->switchTable($this->connection, [$this->getMainTable()]);
  274. return $this;
  275. }
  276.  
  277. @@ -42,7 +115,7 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
  278. $this->getMainTable(),
  279. []
  280. )->joinLeft(
  281. - ['t' => $this->getMainTmpTable()],
  282. + ['t' => $this->getMainTable()],
  283. $this->getMainTable() .
  284. '.category_id = t.category_id AND ' .
  285. $this->getMainTable() .
  286. @@ -75,19 +148,17 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
  287. protected function publishData()
  288. {
  289. $select = $this->connection->select()->from($this->getMainTmpTable());
  290. + $columns = array_keys($this->connection->describeTable($this->getMainTable()));
  291. + $tableName = $this->activeTableSwitcher->getAdditionalTableName($this->getMainTable());
  292.  
  293. - $queries = $this->prepareSelectsByRange($select, 'category_id');
  294. -
  295. - foreach ($queries as $query) {
  296. - $this->connection->query(
  297. - $this->connection->insertFromSelect(
  298. - $query,
  299. - $this->getMainTable(),
  300. - ['category_id', 'product_id', 'position', 'is_parent', 'store_id', 'visibility'],
  301. - \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
  302. - )
  303. - );
  304. - }
  305. + $this->connection->query(
  306. + $this->connection->insertFromSelect(
  307. + $select,
  308. + $tableName,
  309. + $columns,
  310. + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
  311. + )
  312. + );
  313. }
  314.  
  315. /**
  316. @@ -99,4 +170,75 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
  317. {
  318. $this->connection->delete($this->getMainTmpTable());
  319. }
  320. +
  321. + /**
  322. + * {@inheritdoc}
  323. + */
  324. + protected function reindexRootCategory(\Magento\Store\Model\Store $store)
  325. + {
  326. + if ($this->isIndexRootCategoryNeeded()) {
  327. + $this->reindexCategoriesBySelect($this->getAllProducts($store), 'cp.entity_id IN (?)');
  328. + }
  329. + }
  330. +
  331. + /**
  332. + * Reindex products of anchor categories
  333. + *
  334. + * @param \Magento\Store\Model\Store $store
  335. + * @return void
  336. + */
  337. + protected function reindexAnchorCategories(\Magento\Store\Model\Store $store)
  338. + {
  339. + $this->reindexCategoriesBySelect($this->getAnchorCategoriesSelect($store), 'ccp.product_id IN (?)');
  340. + }
  341. +
  342. + /**
  343. + * Reindex products of non anchor categories
  344. + *
  345. + * @param \Magento\Store\Model\Store $store
  346. + * @return void
  347. + */
  348. + protected function reindexNonAnchorCategories(\Magento\Store\Model\Store $store)
  349. + {
  350. + $this->reindexCategoriesBySelect($this->getNonAnchorCategoriesSelect($store), 'ccp.product_id IN (?)');
  351. + }
  352. +
  353. + /**
  354. + * Reindex categories using given SQL select and condition.
  355. + *
  356. + * @param \Magento\Framework\DB\Select $basicSelect
  357. + * @param string $whereCondition
  358. + * @return void
  359. + */
  360. + private function reindexCategoriesBySelect(\Magento\Framework\DB\Select $basicSelect, $whereCondition)
  361. + {
  362. + $entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
  363. + $columns = array_keys($this->connection->describeTable($this->getMainTmpTable()));
  364. + $this->batchSizeManagement->ensureBatchSize($this->connection, $this->batchRowsCount);
  365. + $batches = $this->batchProvider->getBatches(
  366. + $this->connection,
  367. + $entityMetadata->getEntityTable(),
  368. + $entityMetadata->getIdentifierField(),
  369. + $this->batchRowsCount
  370. + );
  371. + foreach ($batches as $batch) {
  372. + $this->clearTmpData();
  373. + $resultSelect = clone $basicSelect;
  374. + $select = $this->connection->select();
  375. + $select->distinct(true);
  376. + $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
  377. + $entityIds = $this->batchProvider->getBatchIds($this->connection, $select, $batch);
  378. + $resultSelect->where($whereCondition, $entityIds);
  379. + $this->connection->query(
  380. + $this->connection->insertFromSelect(
  381. + $resultSelect,
  382. + $this->getMainTmpTable(),
  383. + $columns,
  384. + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
  385. + )
  386. + );
  387. + $this->publishData();
  388. + $this->removeUnnecessaryData();
  389. + }
  390. + }
  391. }
  392. diff --git a/vendor/magento/module-catalog/Model/Indexer/Category/Product/RowSizeEstimator.php b/vendor/magento/module-catalog/Model/Indexer/Category/Product/RowSizeEstimator.php
  393. new file mode 100644
  394. index 00000000000..7057d1c0667
  395. --- /dev/null
  396. +++ b/vendor/magento/module-catalog/Model/Indexer/Category/Product/RowSizeEstimator.php
  397. @@ -0,0 +1,77 @@
  398. +<?php
  399. +/**
  400. + * Copyright © Magento, Inc. All rights reserved.
  401. + * See COPYING.txt for license details.
  402. + */
  403. +
  404. +namespace Magento\Catalog\Model\Indexer\Category\Product;
  405. +
  406. +use Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface;
  407. +
  408. +/**
  409. + * Class RowSizeEstimator
  410. + * Intended to estimate amount of memory necessary for saving the biggest category in the DB
  411. + * @package Magento\Catalog\Model\Indexer\Category\Product
  412. + */
  413. +class RowSizeEstimator implements IndexTableRowSizeEstimatorInterface
  414. +{
  415. + /**
  416. + * Amount of memory for index data row.
  417. + */
  418. + const ROW_MEMORY_SIZE = 100;
  419. +
  420. + /**
  421. + * @var \Magento\Framework\App\ResourceConnection
  422. + */
  423. + private $resourceConnection;
  424. +
  425. + /**
  426. + * @param \Magento\Framework\App\ResourceConnection $resourceConnection
  427. + */
  428. + public function __construct(
  429. + \Magento\Framework\App\ResourceConnection $resourceConnection
  430. + ) {
  431. + $this->resourceConnection = $resourceConnection;
  432. + }
  433. +
  434. + /**
  435. + * Calculate memory size for largest possible category in database.
  436. + *
  437. + * Result value is a multiplication of
  438. + * a) maximum amount of products in one category
  439. + * b) amount of store groups
  440. + * c) memory amount per each index row in DB table
  441. + *
  442. + * {@inheritdoc}
  443. + */
  444. + public function estimateRowSize()
  445. + {
  446. + $connection = $this->resourceConnection->getConnection();
  447. +
  448. + // get store groups count except the default
  449. + $storeGroupSelect = $connection->select()
  450. + ->from(
  451. + $this->resourceConnection->getTableName('store_group'),
  452. + ['count' => new \Zend_Db_Expr('count(*)')]
  453. + )->where('group_id > 0');
  454. + $storeGroupCount = $connection->fetchOne($storeGroupSelect);
  455. +
  456. + // get max possible categories per product
  457. + // subselect with categories count per product
  458. + $categoryCounterSubSelect = $connection->select()
  459. + ->from(
  460. + $this->resourceConnection->getTableName('catalog_category_product'),
  461. + ['counter' => new \Zend_Db_Expr('count(category_id)')]
  462. + )->group('product_id');
  463. +
  464. + // select maximum value from subselect
  465. + $productCountSelect = $connection->select()
  466. + ->from(
  467. + ['counters' => $categoryCounterSubSelect],
  468. + [new \Zend_Db_Expr('max(counter)')]
  469. + );
  470. + $maxProducts = $connection->fetchOne($productCountSelect);
  471. +
  472. + return ceil($storeGroupCount * $maxProducts * self::ROW_MEMORY_SIZE);
  473. + }
  474. +}
  475. diff --git a/vendor/magento/module-catalog/Model/Indexer/Product/Eav/AbstractAction.php b/vendor/magento/module-catalog/Model/Indexer/Product/Eav/AbstractAction.php
  476. index bd3586eff92..ce31c4f2182 100644
  477. --- a/vendor/magento/module-catalog/Model/Indexer/Product/Eav/AbstractAction.php
  478. +++ b/vendor/magento/module-catalog/Model/Indexer/Product/Eav/AbstractAction.php
  479. @@ -28,6 +28,7 @@ abstract class AbstractAction
  480. protected $_eavDecimalFactory;
  481.  
  482. /**
  483. + * AbstractAction constructor.
  484. * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
  485. * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
  486. */
  487. @@ -84,6 +85,7 @@ abstract class AbstractAction
  488. * Reindex entities
  489. *
  490. * @param null|array|int $ids
  491. + * @throws \Exception
  492. * @return void
  493. */
  494. public function reindex($ids = null)
  495. @@ -92,8 +94,55 @@ abstract class AbstractAction
  496. if ($ids === null) {
  497. $indexer->reindexAll();
  498. } else {
  499. + if (!is_array($ids)) {
  500. + $ids = [$ids];
  501. + }
  502. + $ids = $this->processRelations($indexer, $ids);
  503. $indexer->reindexEntities($ids);
  504. + $destinationTable = $indexer->getMainTable();
  505. + $this->syncData($indexer, $destinationTable, $ids);
  506. }
  507. }
  508. }
  509. +
  510. + /**
  511. + * Synchronize data between index storage and original storage
  512. + *
  513. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer
  514. + * @param string $destinationTable
  515. + * @param array $ids
  516. + * @throws \Exception
  517. + * @return void
  518. + */
  519. + protected function syncData($indexer, $destinationTable, $ids)
  520. + {
  521. + $connection = $indexer->getConnection();
  522. + $connection->beginTransaction();
  523. + try {
  524. + // remove old index
  525. + $where = $connection->quoteInto('entity_id IN(?)', $ids);
  526. + $connection->delete($destinationTable, $where);
  527. + // insert new index
  528. + $indexer->insertFromTable($indexer->getIdxTable(), $destinationTable);
  529. + $connection->commit();
  530. + } catch (\Exception $e) {
  531. + $connection->rollBack();
  532. + throw $e;
  533. + }
  534. + }
  535. +
  536. + /**
  537. + * Retrieve product relations by children and parent
  538. + *
  539. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav $indexer
  540. + * @param array $ids
  541. + *
  542. + * @return $ids
  543. + */
  544. + protected function processRelations($indexer, $ids)
  545. + {
  546. + $parentIds = $indexer->getRelationsByChild($ids);
  547. + $childIds = $indexer->getRelationsByParent($ids);
  548. + return array_unique(array_merge($ids, $childIds, $parentIds));
  549. + }
  550. }
  551. diff --git a/vendor/magento/module-catalog/Model/Indexer/Product/Eav/Action/Full.php b/vendor/magento/module-catalog/Model/Indexer/Product/Eav/Action/Full.php
  552. index 7c2b2c137da..0c41c3e6eb0 100644
  553. --- a/vendor/magento/module-catalog/Model/Indexer/Product/Eav/Action/Full.php
  554. +++ b/vendor/magento/module-catalog/Model/Indexer/Product/Eav/Action/Full.php
  555. @@ -5,11 +5,66 @@
  556. */
  557. namespace Magento\Catalog\Model\Indexer\Product\Eav\Action;
  558.  
  559. +use Magento\Framework\App\ObjectManager;
  560. +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory;
  561. +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory;
  562. +use Magento\Framework\EntityManager\MetadataPool;
  563. +use Magento\Framework\Indexer\BatchProviderInterface;
  564. +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator;
  565. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  566. +use Magento\Catalog\Api\Data\ProductInterface;
  567. +use Magento\Framework\Exception\LocalizedException;
  568. +use Magento\Framework\DB\Adapter\AdapterInterface;
  569. +
  570. /**
  571. * Class Full reindex action
  572. */
  573. class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
  574. {
  575. + /**
  576. + * @var \Magento\Framework\EntityManager\MetadataPool
  577. + */
  578. + private $metadataPool;
  579. +
  580. + /**
  581. + * @var \Magento\Framework\Indexer\BatchProviderInterface
  582. + */
  583. + private $batchProvider;
  584. +
  585. + /**
  586. + * @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator
  587. + */
  588. + private $batchSizeCalculator;
  589. +
  590. + /**
  591. + * @var ActiveTableSwitcher
  592. + */
  593. + private $activeTableSwitcher;
  594. +
  595. + /**
  596. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
  597. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
  598. + * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool
  599. + * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
  600. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator
  601. + * @param ActiveTableSwitcher|null $activeTableSwitcher
  602. + */
  603. + public function __construct(
  604. + DecimalFactory $eavDecimalFactory,
  605. + SourceFactory $eavSourceFactory,
  606. + MetadataPool $metadataPool = null,
  607. + BatchProviderInterface $batchProvider = null,
  608. + BatchSizeCalculator $batchSizeCalculator = null,
  609. + ActiveTableSwitcher $activeTableSwitcher = null
  610. + ) {
  611. + parent::__construct($eavDecimalFactory, $eavSourceFactory);
  612. + $objectManager = ObjectManager::getInstance();
  613. + $this->metadataPool = $metadataPool ?: $objectManager->get(MetadataPool::class);
  614. + $this->batchProvider = $batchProvider ?: $objectManager->get(BatchProviderInterface::class);
  615. + $this->batchSizeCalculator = $batchSizeCalculator ?: $objectManager->get(BatchSizeCalculator::class);
  616. + $this->activeTableSwitcher = $activeTableSwitcher ?: $objectManager->get(ActiveTableSwitcher::class);
  617. + }
  618. +
  619. /**
  620. * Execute Full reindex
  621. *
  622. @@ -21,9 +76,59 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
  623. public function execute($ids = null)
  624. {
  625. try {
  626. - $this->reindex();
  627. + foreach ($this->getIndexers() as $indexerName => $indexer) {
  628. + $connection = $indexer->getConnection();
  629. + $mainTable = $this->activeTableSwitcher->getAdditionalTableName($indexer->getMainTable());
  630. + $connection->truncateTable($mainTable);
  631. + $entityMetadata = $this->metadataPool->getMetadata(ProductInterface::class);
  632. + $batches = $this->batchProvider->getBatches(
  633. + $connection,
  634. + $entityMetadata->getEntityTable(),
  635. + $entityMetadata->getIdentifierField(),
  636. + $this->batchSizeCalculator->estimateBatchSize($connection, $indexerName)
  637. + );
  638. +
  639. + foreach ($batches as $batch) {
  640. + /** @var \Magento\Framework\DB\Select $select */
  641. + $select = $connection->select();
  642. + $select->distinct(true);
  643. + $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
  644. + $entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch);
  645. + if (!empty($entityIds)) {
  646. + $indexer->reindexEntities($this->processRelations($indexer, $entityIds));
  647. + $this->syncData($indexer, $mainTable);
  648. + }
  649. + }
  650. + $this->activeTableSwitcher->switchTable($indexer->getConnection(), [$indexer->getMainTable()]);
  651. + }
  652. + } catch (\Exception $e) {
  653. + throw new LocalizedException(__($e->getMessage()), $e);
  654. + }
  655. + }
  656. +
  657. + /**
  658. + * @inheritdoc
  659. + */
  660. + protected function syncData($indexer, $destinationTable, $ids = null)
  661. + {
  662. + $connection = $indexer->getConnection();
  663. + $connection->beginTransaction();
  664. + try {
  665. + $sourceTable = $indexer->getIdxTable();
  666. + $sourceColumns = array_keys($connection->describeTable($sourceTable));
  667. + $targetColumns = array_keys($connection->describeTable($destinationTable));
  668. + $select = $connection->select()->from($sourceTable, $sourceColumns);
  669. + $query = $connection->insertFromSelect(
  670. + $select,
  671. + $destinationTable,
  672. + $targetColumns,
  673. + AdapterInterface::INSERT_ON_DUPLICATE
  674. + );
  675. + $connection->query($query);
  676. + $connection->commit();
  677. } catch (\Exception $e) {
  678. - throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
  679. + $connection->rollBack();
  680. + throw $e;
  681. }
  682. }
  683. }
  684. diff --git a/vendor/magento/module-catalog/Model/Indexer/Product/Price/AbstractAction.php b/vendor/magento/module-catalog/Model/Indexer/Product/Price/AbstractAction.php
  685. index 3b3804220db..b41de15063e 100644
  686. --- a/vendor/magento/module-catalog/Model/Indexer/Product/Price/AbstractAction.php
  687. +++ b/vendor/magento/module-catalog/Model/Indexer/Product/Price/AbstractAction.php
  688. @@ -70,6 +70,11 @@ abstract class AbstractAction
  689. */
  690. protected $_indexers;
  691.  
  692. + /**
  693. + * @var \Magento\Catalog\Model\ResourceModel\Product
  694. + */
  695. + private $productResource;
  696. +
  697. /**
  698. * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
  699. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  700. @@ -213,46 +218,80 @@ abstract class AbstractAction
  701. $table = $this->_defaultIndexerResource->getTable('catalog_product_index_tier_price');
  702. $this->_emptyTable($table);
  703.  
  704. - $websiteExpression = $this->_connection->getCheckSql(
  705. - 'tp.website_id = 0',
  706. - 'ROUND(tp.value * cwd.rate, 4)',
  707. - 'tp.value'
  708. - );
  709. $linkField = $this->getProductIdFieldName();
  710. - $select = $this->_connection->select()->from(
  711. + $priceAttribute = $this->getProductResource()->getAttribute('price');
  712. + $baseColumns = [
  713. + 'cpe.entity_id',
  714. + 'tp.customer_group_id',
  715. + 'tp.website_id'
  716. + ];
  717. + if ($linkField !== 'entity_id') {
  718. + $baseColumns[] = 'cpe.' . $linkField;
  719. + };
  720. + $subSelect = $this->_connection->select()->from(
  721. ['cpe' => $this->_defaultIndexerResource->getTable('catalog_product_entity')],
  722. - ['cpe.entity_id']
  723. - )->join(
  724. + array_merge_recursive(
  725. + $baseColumns,
  726. + ['value' => 'min(tp.value)']
  727. + )
  728. + )->joinInner(
  729. ['tp' => $this->_defaultIndexerResource->getTable(['catalog_product_entity', 'tier_price'])],
  730. 'tp.' . $linkField . ' = cpe.' . $linkField,
  731. []
  732. - )->join(
  733. - ['cg' => $this->_defaultIndexerResource->getTable('customer_group')],
  734. - 'tp.all_groups = 1 OR (tp.all_groups = 0 AND tp.customer_group_id = cg.customer_group_id)',
  735. - ['customer_group_id']
  736. - )->join(
  737. - ['cw' => $this->_defaultIndexerResource->getTable('store_website')],
  738. - 'tp.website_id = 0 OR tp.website_id = cw.website_id',
  739. - ['website_id']
  740. - )->join(
  741. - ['cwd' => $this->_defaultIndexerResource->getTable('catalog_product_index_website')],
  742. - 'cw.website_id = cwd.website_id',
  743. - []
  744. - )->where(
  745. - 'cw.website_id != 0'
  746. - )->columns(
  747. - new \Zend_Db_Expr("MIN({$websiteExpression})")
  748. - )->group(
  749. - ['cpe.entity_id', 'cg.customer_group_id', 'cw.website_id']
  750. - );
  751. + )->where("cpe.entity_id IN(?)", $entityIds)
  752. + ->where("tp.website_id != 0")
  753. + ->group(['cpe.entity_id', 'tp.customer_group_id', 'tp.website_id']);
  754. +
  755. + $subSelect2 = $this->_connection->select()
  756. + ->from(
  757. + ['cpe' => $this->_defaultIndexerResource->getTable('catalog_product_entity')],
  758. + array_merge_recursive(
  759. + $baseColumns,
  760. + ['MIN(ROUND(tp.value * cwd.rate, 4)) AS value']
  761. + )
  762. + )
  763. + ->joinInner(
  764. + ['tp' => $this->_defaultIndexerResource->getTable(['catalog_product_entity', 'tier_price'])],
  765. + 'tp.' . $linkField . ' = cpe.' . $linkField,
  766. + []
  767. + )->join(
  768. + ['cw' => $this->_defaultIndexerResource->getTable('store_website')],
  769. + true,
  770. + []
  771. + )
  772. + ->joinInner(
  773. + ['cwd' => $this->_defaultIndexerResource->getTable('catalog_product_index_website')],
  774. + 'cw.website_id = cwd.website_id',
  775. + []
  776. + )
  777. + ->where("cpe.entity_id IN(?)", $entityIds)
  778. + ->where("tp.website_id = 0")
  779. + ->group(
  780. + ['cpe.entity_id', 'tp.customer_group_id', 'tp.website_id']
  781. + );
  782.  
  783. - if (!empty($entityIds)) {
  784. - $select->where("cpe.entity_id IN(?)", $entityIds);
  785. - }
  786. + $unionSelect = $this->_connection->select()
  787. + ->union([$subSelect, $subSelect2], \Magento\Framework\DB\Select::SQL_UNION_ALL);
  788. + $select = $this->_connection->select()
  789. + ->from(
  790. + ['b' => new \Zend_Db_Expr(sprintf('(%s)', $unionSelect->assemble()))],
  791. + [
  792. + 'b.entity_id',
  793. + 'b.customer_group_id',
  794. + 'b.website_id',
  795. + 'b.value'
  796. + ]
  797. + )
  798. + ->joinInner(
  799. + ['product_price' => $priceAttribute->getBackend()->getTable()],
  800. + 'b.' . $linkField . ' = product_price.' . $linkField,
  801. + []
  802. + )
  803. + ->group(['b.entity_id', 'b.customer_group_id', 'b.website_id']);
  804. +
  805. + $query = $select->insertFromSelect($table, [], false);
  806.  
  807. - $query = $select->insertFromSelect($table);
  808. $this->_connection->query($query);
  809. -
  810. return $this;
  811. }
  812.  
  813. @@ -441,7 +480,7 @@ abstract class AbstractAction
  814.  
  815. if ($children) {
  816. $select = $this->_connection->select()->from(
  817. - $this->_defaultIndexerResource->getTable('catalog_product_index_price')
  818. + $this->getIndexTargetTable()
  819. )->where(
  820. 'entity_id IN(?)',
  821. $children
  822. @@ -453,6 +492,18 @@ abstract class AbstractAction
  823. return $this;
  824. }
  825.  
  826. + /**
  827. + * Retrieve index table that will be used for write operations.
  828. + *
  829. + * This method is used during both partial and full reindex to identify the table.
  830. + *
  831. + * @return string
  832. + */
  833. + protected function getIndexTargetTable()
  834. + {
  835. + return $this->_defaultIndexerResource->getTable('catalog_product_index_price');
  836. + }
  837. +
  838. /**
  839. * @return string
  840. */
  841. @@ -462,4 +513,17 @@ abstract class AbstractAction
  842. $indexList = $this->_connection->getIndexList($table);
  843. return $indexList[$this->_connection->getPrimaryKeyName($table)]['COLUMNS_LIST'][0];
  844. }
  845. +
  846. + /**
  847. + * @return \Magento\Catalog\Model\ResourceModel\Product
  848. + * @deprecated
  849. + */
  850. + private function getProductResource()
  851. + {
  852. + if (null === $this->productResource) {
  853. + $this->productResource = \Magento\Framework\App\ObjectManager::getInstance()
  854. + ->get(\Magento\Catalog\Model\ResourceModel\Product::class);
  855. + }
  856. + return $this->productResource;
  857. + }
  858. }
  859. diff --git a/vendor/magento/module-catalog/Model/Indexer/Product/Price/Action/Full.php b/vendor/magento/module-catalog/Model/Indexer/Product/Price/Action/Full.php
  860. index 8148703b177..ed43c243f35 100644
  861. --- a/vendor/magento/module-catalog/Model/Indexer/Product/Price/Action/Full.php
  862. +++ b/vendor/magento/module-catalog/Model/Indexer/Product/Price/Action/Full.php
  863. @@ -5,33 +5,163 @@
  864. */
  865. namespace Magento\Catalog\Model\Indexer\Product\Price\Action;
  866.  
  867. +use Magento\Framework\App\ObjectManager;
  868. +
  869. /**
  870. * Class Full reindex action
  871. - *
  872. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  873. */
  874. class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
  875. {
  876. + /**
  877. + * @var \Magento\Framework\EntityManager\MetadataPool
  878. + */
  879. + private $metadataPool;
  880. +
  881. + /**
  882. + * @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator
  883. + */
  884. + private $batchSizeCalculator;
  885. +
  886. + /**
  887. + * @var \Magento\Framework\Indexer\BatchProviderInterface
  888. + */
  889. + private $batchProvider;
  890. +
  891. + /**
  892. + * @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
  893. + */
  894. + private $activeTableSwitcher;
  895. +
  896. + /**
  897. + * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
  898. + * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  899. + * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
  900. + * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
  901. + * @param \Magento\Framework\Stdlib\DateTime $dateTime
  902. + * @param \Magento\Catalog\Model\Product\Type $catalogProductType
  903. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory
  904. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource
  905. + * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool
  906. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator|null $batchSizeCalculator
  907. + * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
  908. + * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
  909. + *
  910. + * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  911. + */
  912. + public function __construct(
  913. + \Magento\Framework\App\Config\ScopeConfigInterface $config,
  914. + \Magento\Store\Model\StoreManagerInterface $storeManager,
  915. + \Magento\Directory\Model\CurrencyFactory $currencyFactory,
  916. + \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
  917. + \Magento\Framework\Stdlib\DateTime $dateTime,
  918. + \Magento\Catalog\Model\Product\Type $catalogProductType,
  919. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory,
  920. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource,
  921. + \Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
  922. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator $batchSizeCalculator = null,
  923. + \Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
  924. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
  925. + ) {
  926. + parent::__construct(
  927. + $config,
  928. + $storeManager,
  929. + $currencyFactory,
  930. + $localeDate,
  931. + $dateTime,
  932. + $catalogProductType,
  933. + $indexerPriceFactory,
  934. + $defaultIndexerResource
  935. + );
  936. + $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(
  937. + \Magento\Framework\EntityManager\MetadataPool::class
  938. + );
  939. + $this->batchSizeCalculator = $batchSizeCalculator ?: ObjectManager::getInstance()->get(
  940. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator::class
  941. + );
  942. + $this->batchProvider = $batchProvider ?: ObjectManager::getInstance()->get(
  943. + \Magento\Framework\Indexer\BatchProviderInterface::class
  944. + );
  945. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
  946. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
  947. + );
  948. + }
  949. +
  950. /**
  951. * Execute Full reindex
  952. *
  953. * @param array|int|null $ids
  954. * @return void
  955. * @throws \Magento\Framework\Exception\LocalizedException
  956. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  957. */
  958. public function execute($ids = null)
  959. {
  960. try {
  961. - $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(true);
  962. - $this->_emptyTable($this->_defaultIndexerResource->getIdxTable());
  963. + $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false);
  964. $this->_prepareWebsiteDateTable();
  965. - $this->_prepareTierPriceIndex();
  966.  
  967. + $entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
  968. + $replicaTable = $this->activeTableSwitcher->getAdditionalTableName(
  969. + $this->_defaultIndexerResource->getMainTable()
  970. + );
  971. +
  972. + /** @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer $indexer */
  973. foreach ($this->getTypeIndexers() as $indexer) {
  974. - $indexer->reindexAll();
  975. + $indexer->getTableStrategy()->setUseIdxTable(false);
  976. + $connection = $indexer->getConnection();
  977. +
  978. + $batches = $this->batchProvider->getBatches(
  979. + $connection,
  980. + $entityMetadata->getEntityTable(),
  981. + $entityMetadata->getIdentifierField(),
  982. + $this->batchSizeCalculator->estimateBatchSize($connection, $indexer->getTypeId())
  983. + );
  984. +
  985. + foreach ($batches as $batch) {
  986. + // Get entity ids from batch
  987. + $select = $connection->select();
  988. + $select->distinct(true);
  989. + $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
  990. + $select->where('type_id = ?', $indexer->getTypeId());
  991. +
  992. + $entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch);
  993. +
  994. + if (!empty($entityIds)) {
  995. + // Temporary table will created if not exists
  996. + $idxTableName = $this->_defaultIndexerResource->getIdxTable();
  997. + $this->_emptyTable($idxTableName);
  998. +
  999. + if ($indexer->getIsComposite()) {
  1000. + $this->_copyRelationIndexData($entityIds);
  1001. + }
  1002. + $this->_prepareTierPriceIndex($entityIds);
  1003. +
  1004. + // Reindex entities by id
  1005. + $indexer->reindexEntity($entityIds);
  1006. +
  1007. + // Sync data from temp table to index table
  1008. + $this->_insertFromTable($idxTableName, $replicaTable);
  1009. +
  1010. + // Drop temporary index table
  1011. + $connection->dropTable($idxTableName);
  1012. + }
  1013. + }
  1014. }
  1015. - $this->_syncData();
  1016. + $this->activeTableSwitcher->switchTable(
  1017. + $this->_defaultIndexerResource->getConnection(),
  1018. + [$this->_defaultIndexerResource->getMainTable()]
  1019. + );
  1020. } catch (\Exception $e) {
  1021. throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
  1022. }
  1023. }
  1024. +
  1025. + /**
  1026. + * @inheritdoc
  1027. + */
  1028. + protected function getIndexTargetTable()
  1029. + {
  1030. + return $this->activeTableSwitcher->getAdditionalTableName($this->_defaultIndexerResource->getMainTable());
  1031. + }
  1032. }
  1033. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Indexer/ActiveTableSwitcher.php b/vendor/magento/module-catalog/Model/ResourceModel/Indexer/ActiveTableSwitcher.php
  1034. new file mode 100644
  1035. index 00000000000..6d3451f2d90
  1036. --- /dev/null
  1037. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Indexer/ActiveTableSwitcher.php
  1038. @@ -0,0 +1,63 @@
  1039. +<?php
  1040. +/**
  1041. + * Copyright © Magento, Inc. All rights reserved.
  1042. + * See COPYING.txt for license details.
  1043. + */
  1044. +namespace Magento\Catalog\Model\ResourceModel\Indexer;
  1045. +
  1046. +/**
  1047. + * Logic for switching active and replica index tables.
  1048. + */
  1049. +class ActiveTableSwitcher
  1050. +{
  1051. + /** Suffix for replica index table. */
  1052. + private $additionalTableSuffix = '_replica';
  1053. +
  1054. + /** Suffix for outdated index table. */
  1055. + private $outdatedTableSuffix = '_outdated';
  1056. +
  1057. + /**
  1058. + * Switch index tables from replica to active.
  1059. + *
  1060. + * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
  1061. + * @param array $tableNames
  1062. + * @return void
  1063. + */
  1064. + public function switchTable(\Magento\Framework\DB\Adapter\AdapterInterface $connection, array $tableNames)
  1065. + {
  1066. + $toRename = [];
  1067. + foreach ($tableNames as $tableName) {
  1068. + $outdatedTableName = $tableName . $this->outdatedTableSuffix;
  1069. + $replicaTableName = $tableName . $this->additionalTableSuffix;
  1070. +
  1071. + $renameBatch = [
  1072. + [
  1073. + 'oldName' => $tableName,
  1074. + 'newName' => $outdatedTableName
  1075. + ],
  1076. + [
  1077. + 'oldName' => $replicaTableName,
  1078. + 'newName' => $tableName
  1079. + ],
  1080. + [
  1081. + 'oldName' => $outdatedTableName,
  1082. + 'newName' => $replicaTableName
  1083. + ]
  1084. + ];
  1085. + $toRename = array_merge($toRename, $renameBatch);
  1086. + }
  1087. +
  1088. + if (!empty($toRename)) {
  1089. + $connection->renameTablesBatch($toRename);
  1090. + }
  1091. + }
  1092. +
  1093. + /**
  1094. + * @param string $tableName
  1095. + * @return string
  1096. + */
  1097. + public function getAdditionalTableName($tableName)
  1098. + {
  1099. + return $tableName . $this->additionalTableSuffix;
  1100. + }
  1101. +}
  1102. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Layer/Filter/Price.php b/vendor/magento/module-catalog/Model/ResourceModel/Layer/Filter/Price.php
  1103. index a8b7bf29601..a99d88aa914 100644
  1104. --- a/vendor/magento/module-catalog/Model/ResourceModel/Layer/Filter/Price.php
  1105. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Layer/Filter/Price.php
  1106. @@ -7,6 +7,7 @@ namespace Magento\Catalog\Model\ResourceModel\Layer\Filter;
  1107.  
  1108. /**
  1109. * Catalog Layer Price Filter resource model
  1110. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  1111. */
  1112. class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
  1113. {
  1114. @@ -43,7 +44,7 @@ class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
  1115. * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
  1116. * @param \Magento\Customer\Model\Session $session
  1117. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  1118. - * @param string $connectionName
  1119. + * @param null $connectionName
  1120. */
  1121. public function __construct(
  1122. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  1123. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
  1124. index 7cd1c8c09fc..ca7b8e9badf 100644
  1125. --- a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
  1126. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/AbstractEav.php
  1127. @@ -11,6 +11,7 @@ use Magento\Catalog\Api\Data\ProductInterface;
  1128. * Catalog Product Eav Attributes abstract indexer resource model
  1129. *
  1130. * @author Magento Core Team <core@magentocommerce.com>
  1131. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  1132. */
  1133. abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer
  1134. {
  1135. @@ -22,13 +23,12 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
  1136. protected $_eventManager = null;
  1137.  
  1138. /**
  1139. - * Construct
  1140. - *
  1141. + * AbstractEav constructor.
  1142. * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  1143. * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
  1144. * @param \Magento\Eav\Model\Config $eavConfig
  1145. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  1146. - * @param string $connectionName
  1147. + * @param null $connectionName
  1148. */
  1149. public function __construct(
  1150. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  1151. @@ -75,40 +75,11 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
  1152. */
  1153. public function reindexEntities($processIds)
  1154. {
  1155. - $connection = $this->getConnection();
  1156. -
  1157. $this->clearTemporaryIndexTable();
  1158.  
  1159. - if (!is_array($processIds)) {
  1160. - $processIds = [$processIds];
  1161. - }
  1162. -
  1163. - $parentIds = $this->getRelationsByChild($processIds);
  1164. - if ($parentIds) {
  1165. - $processIds = array_unique(array_merge($processIds, $parentIds));
  1166. - }
  1167. - $childIds = $this->getRelationsByParent($processIds);
  1168. - if ($childIds) {
  1169. - $processIds = array_unique(array_merge($processIds, $childIds));
  1170. - }
  1171. -
  1172. $this->_prepareIndex($processIds);
  1173. $this->_prepareRelationIndex($processIds);
  1174. $this->_removeNotVisibleEntityFromIndex();
  1175. -
  1176. - $connection->beginTransaction();
  1177. - try {
  1178. - // remove old index
  1179. - $where = $connection->quoteInto('entity_id IN(?)', $processIds);
  1180. - $connection->delete($this->getMainTable(), $where);
  1181. -
  1182. - // insert new index
  1183. - $this->insertFromTable($this->getIdxTable(), $this->getMainTable());
  1184. - $connection->commit();
  1185. - } catch (\Exception $e) {
  1186. - $connection->rollBack();
  1187. - throw $e;
  1188. - }
  1189. return $this;
  1190. }
  1191.  
  1192. @@ -218,7 +189,8 @@ abstract class AbstractEav extends \Magento\Catalog\Model\ResourceModel\Product\
  1193. ]
  1194. );
  1195. if ($parentIds !== null) {
  1196. - $select->where('e.entity_id IN(?)', $parentIds);
  1197. + $ids = implode(',', array_map('intval', $parentIds));
  1198. + $select->where("e.entity_id IN({$ids})");
  1199. }
  1200.  
  1201. /**
  1202. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/BatchSizeCalculator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/BatchSizeCalculator.php
  1203. new file mode 100644
  1204. index 00000000000..479dcf70f4a
  1205. --- /dev/null
  1206. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/BatchSizeCalculator.php
  1207. @@ -0,0 +1,60 @@
  1208. +<?php
  1209. +/**
  1210. + * Copyright © Magento, Inc. All rights reserved.
  1211. + * See COPYING.txt for license details.
  1212. + */
  1213. +
  1214. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav;
  1215. +
  1216. +use Magento\Framework\DB\Adapter\AdapterInterface;
  1217. +use Magento\Framework\Exception\NoSuchEntityException;
  1218. +
  1219. +/**
  1220. + * Composite batch size calculator for EAV related indexers.
  1221. + *
  1222. + * Can be configured to provide batch sizes for different indexer types.
  1223. + */
  1224. +class BatchSizeCalculator
  1225. +{
  1226. + /**
  1227. + * @var array
  1228. + */
  1229. + private $batchSizes;
  1230. +
  1231. + /**
  1232. + * @var \Magento\Framework\Indexer\BatchSizeManagement[]
  1233. + */
  1234. + private $batchSizeManagers;
  1235. +
  1236. + /**
  1237. + * @param array $batchSizes preferable sizes (number of rows in batch) of batches per index type
  1238. + * @param array $batchSizeManagers batch managers per index type
  1239. + */
  1240. + public function __construct(
  1241. + array $batchSizes,
  1242. + array $batchSizeManagers
  1243. + ) {
  1244. + $this->batchSizes = $batchSizes;
  1245. + $this->batchSizeManagers = $batchSizeManagers;
  1246. + }
  1247. +
  1248. + /**
  1249. + * Estimate batch size and ensure that database will be able to handle it properly.
  1250. + *
  1251. + * @param AdapterInterface $connection
  1252. + * @param string $indexerTypeId unique identifier of the indexer
  1253. + * @return int estimated batch size
  1254. + * @throws NoSuchEntityException thrown if indexer identifier is not recognized
  1255. + */
  1256. + public function estimateBatchSize(
  1257. + AdapterInterface $connection,
  1258. + $indexerTypeId
  1259. + ) {
  1260. + if (!isset($this->batchSizes[$indexerTypeId])) {
  1261. + throw NoSuchEntityException::singleField('indexTypeId', $indexerTypeId);
  1262. + }
  1263. + $this->batchSizeManagers[$indexerTypeId]->ensureBatchSize($connection, $this->batchSizes[$indexerTypeId]);
  1264. +
  1265. + return $this->batchSizes[$indexerTypeId];
  1266. + }
  1267. +}
  1268. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/DecimalRowSizeEstimator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/DecimalRowSizeEstimator.php
  1269. new file mode 100644
  1270. index 00000000000..0c8c3a9c0b1
  1271. --- /dev/null
  1272. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/DecimalRowSizeEstimator.php
  1273. @@ -0,0 +1,79 @@
  1274. +<?php
  1275. +/**
  1276. + * Copyright © Magento, Inc. All rights reserved.
  1277. + * See COPYING.txt for license details.
  1278. + */
  1279. +
  1280. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav;
  1281. +
  1282. +use Magento\Store\Api\StoreManagementInterface;
  1283. +use Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface;
  1284. +use Magento\Framework\EntityManager\MetadataPool;
  1285. +use Magento\Catalog\Api\Data\ProductInterface;
  1286. +
  1287. +/**
  1288. + * Estimator of the EAV decimal index table row size.
  1289. + *
  1290. + * Estimates the amount of memory required to store the index data of the product
  1291. + * with the highest number of attributes/values.
  1292. + *
  1293. + * Can be used with batch size manager to ensure that the batch will be handled correctly by the database.
  1294. + * @see \Magento\Framework\Indexer\BatchSizeManagement
  1295. + */
  1296. +class DecimalRowSizeEstimator implements IndexTableRowSizeEstimatorInterface
  1297. +{
  1298. + /**
  1299. + * @var Decimal
  1300. + */
  1301. + private $indexerResource;
  1302. +
  1303. + /**
  1304. + * @var StoreManagementInterface
  1305. + */
  1306. + private $storeManagement;
  1307. +
  1308. + /**
  1309. + * @var MetadataPool
  1310. + */
  1311. + private $metadataPool;
  1312. +
  1313. + /**
  1314. + * @param StoreManagementInterface $storeManagement
  1315. + * @param Decimal $indexerResource
  1316. + * @param MetadataPool $metadataPool
  1317. + */
  1318. + public function __construct(
  1319. + StoreManagementInterface $storeManagement,
  1320. + Decimal $indexerResource,
  1321. + MetadataPool $metadataPool
  1322. + ) {
  1323. + $this->storeManagement = $storeManagement;
  1324. + $this->indexerResource = $indexerResource;
  1325. + $this->metadataPool = $metadataPool;
  1326. + }
  1327. +
  1328. + /**
  1329. + * @inheritdoc
  1330. + */
  1331. + public function estimateRowSize()
  1332. + {
  1333. + $connection = $this->indexerResource->getConnection();
  1334. + $entityIdField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
  1335. +
  1336. + $valueSelect = $connection->select();
  1337. + $valueSelect->from(
  1338. + ['value_table' => $this->indexerResource->getTable('catalog_product_entity_decimal')],
  1339. + ['count' => new \Zend_Db_Expr('count(value_table.value_id)')]
  1340. + );
  1341. + $valueSelect->group([$entityIdField, 'store_id']);
  1342. +
  1343. + $maxSelect = $connection->select();
  1344. + $maxSelect->from(
  1345. + ['max_value' => $valueSelect],
  1346. + ['count' => new \Zend_Db_Expr('MAX(count)')]
  1347. + );
  1348. + $maxRowsPerStore = $connection->fetchOne($maxSelect);
  1349. +
  1350. + return ceil($maxRowsPerStore * $this->storeManagement->getCount() * 500);
  1351. + }
  1352. +}
  1353. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  1354. index e7cf48c378c..364f7dad61d 100644
  1355. --- a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  1356. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  1357. @@ -11,10 +11,12 @@ use Magento\Catalog\Api\Data\ProductInterface;
  1358. /**
  1359. * Catalog Product Eav Select and Multiply Select Attributes Indexer resource model
  1360. *
  1361. - * @author Magento Core Team <core@magentocommerce.com>
  1362. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  1363. */
  1364. class Source extends AbstractEav
  1365. {
  1366. + const TRANSIT_PREFIX = 'transit_';
  1367. +
  1368. /**
  1369. * Catalog resource helper
  1370. *
  1371. @@ -30,7 +32,7 @@ class Source extends AbstractEav
  1372. * @param \Magento\Eav\Model\Config $eavConfig
  1373. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  1374. * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
  1375. - * @param string $connectionName
  1376. + * @param null|string $connectionName
  1377. */
  1378. public function __construct(
  1379. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  1380. @@ -40,8 +42,14 @@ class Source extends AbstractEav
  1381. \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper,
  1382. $connectionName = null
  1383. ) {
  1384. + parent::__construct(
  1385. + $context,
  1386. + $tableStrategy,
  1387. + $eavConfig,
  1388. + $eventManager,
  1389. + $connectionName
  1390. + );
  1391. $this->_resourceHelper = $resourceHelper;
  1392. - parent::__construct($context, $tableStrategy, $eavConfig, $eventManager, $connectionName);
  1393. }
  1394.  
  1395. /**
  1396. @@ -110,30 +118,27 @@ class Source extends AbstractEav
  1397. $connection = $this->getConnection();
  1398. $idxTable = $this->getIdxTable();
  1399. // prepare select attributes
  1400. - if ($attributeId === null) {
  1401. - $attrIds = $this->_getIndexableAttributes(false);
  1402. - } else {
  1403. - $attrIds = [$attributeId];
  1404. - }
  1405. -
  1406. + $attrIds = $attributeId === null ? $this->_getIndexableAttributes(false) : [$attributeId];
  1407. if (!$attrIds) {
  1408. return $this;
  1409. }
  1410. $productIdField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
  1411. + $attrIdsFlat = implode(',', array_map('intval', $attrIds));
  1412. + $ifNullSql = $connection->getIfNullSql('pis.value', 'COALESCE(ds.value, dd.value)');
  1413.  
  1414. - /**@var $subSelect \Magento\Framework\DB\Select*/
  1415. - $subSelect = $connection->select()->from(
  1416. + /**@var $select \Magento\Framework\DB\Select*/
  1417. + $select = $connection->select()->distinct(true)->from(
  1418. ['s' => $this->getTable('store')],
  1419. - ['store_id', 'website_id']
  1420. + []
  1421. )->joinLeft(
  1422. ['dd' => $this->getTable('catalog_product_entity_int')],
  1423. 'dd.store_id = 0',
  1424. - ['attribute_id']
  1425. + []
  1426. )->joinLeft(
  1427. ['ds' => $this->getTable('catalog_product_entity_int')],
  1428. "ds.store_id = s.store_id AND ds.attribute_id = dd.attribute_id AND " .
  1429. "ds.{$productIdField} = dd.{$productIdField}",
  1430. - ['value' => new \Zend_Db_Expr('COALESCE(ds.value, dd.value)')]
  1431. + []
  1432. )->joinLeft(
  1433. ['d2d' => $this->getTable('catalog_product_entity_int')],
  1434. sprintf(
  1435. @@ -149,48 +154,38 @@ class Source extends AbstractEav
  1436. )->joinLeft(
  1437. ['cpe' => $this->getTable('catalog_product_entity')],
  1438. "cpe.{$productIdField} = dd.{$productIdField}",
  1439. - array_unique([$productIdField, 'entity_id'])
  1440. + []
  1441. + )->joinLeft(
  1442. + ['pis' => $this->getTable('catalog_product_entity_int')],
  1443. + "pis.{$productIdField} = cpe.{$productIdField} " .
  1444. + "AND pis.attribute_id = dd.attribute_id AND pis.store_id = s.store_id",
  1445. + []
  1446. )->where(
  1447. 's.store_id != 0'
  1448. )->where(
  1449. '(ds.value IS NOT NULL OR dd.value IS NOT NULL)'
  1450. )->where(
  1451. (new \Zend_Db_Expr('COALESCE(d2s.value, d2d.value)')) . ' = ' . ProductStatus::STATUS_ENABLED
  1452. - )->distinct(true);
  1453. -
  1454. - if ($entityIds !== null) {
  1455. - $subSelect->where('cpe.entity_id IN(?)', $entityIds);
  1456. - }
  1457. -
  1458. - $ifNullSql = $connection->getIfNullSql('pis.value', 'pid.value');
  1459. - /**@var $select \Magento\Framework\DB\Select*/
  1460. - $select = $connection->select()->distinct(true)->from(
  1461. - ['pid' => new \Zend_Db_Expr(sprintf('(%s)', $subSelect->assemble()))],
  1462. - []
  1463. - )->joinLeft(
  1464. - ['pis' => $this->getTable('catalog_product_entity_int')],
  1465. - "pis.{$productIdField} = pid.{$productIdField}"
  1466. - .' AND pis.attribute_id = pid.attribute_id AND pis.store_id = pid.store_id',
  1467. - []
  1468. + )->where(
  1469. + "dd.attribute_id IN({$attrIdsFlat})"
  1470. + )->where(
  1471. + 'NOT(pis.value IS NULL AND pis.value_id IS NOT NULL)'
  1472. + )->where(
  1473. + $ifNullSql . ' IS NOT NULL'
  1474. )->columns(
  1475. [
  1476. - 'pid.entity_id',
  1477. - 'pid.attribute_id',
  1478. - 'pid.store_id',
  1479. - 'value' => $ifNullSql,
  1480. - 'pid.entity_id',
  1481. + 'cpe.entity_id',
  1482. + 'dd.attribute_id',
  1483. + 's.store_id',
  1484. + 'value' => new \Zend_Db_Expr('COALESCE(ds.value, dd.value)'),
  1485. + 'cpe.entity_id',
  1486. ]
  1487. - )->where(
  1488. - 'pid.attribute_id IN(?)',
  1489. - $attrIds
  1490. );
  1491.  
  1492. - $select->where($ifNullSql . ' IS NOT NULL');
  1493. -
  1494. - /**
  1495. - * Exclude attribute values that contains NULL
  1496. - */
  1497. - $select->where('NOT(pis.value IS NULL AND pis.value_id IS NOT NULL)');
  1498. + if ($entityIds !== null) {
  1499. + $ids = implode(',', array_map('intval', $entityIds));
  1500. + $select->where("cpe.entity_id IN({$ids})");
  1501. + }
  1502.  
  1503. /**
  1504. * Add additional external limitation
  1505. @@ -199,14 +194,13 @@ class Source extends AbstractEav
  1506. 'prepare_catalog_product_index_select',
  1507. [
  1508. 'select' => $select,
  1509. - 'entity_field' => new \Zend_Db_Expr('pid.entity_id'),
  1510. - 'website_field' => new \Zend_Db_Expr('pid.website_id'),
  1511. - 'store_field' => new \Zend_Db_Expr('pid.store_id'),
  1512. + 'entity_field' => new \Zend_Db_Expr('cpe.entity_id'),
  1513. + 'website_field' => new \Zend_Db_Expr('s.website_id'),
  1514. + 'store_field' => new \Zend_Db_Expr('s.store_id'),
  1515. ]
  1516. );
  1517. $query = $select->insertFromSelect($idxTable);
  1518. $connection->query($query);
  1519. -
  1520. return $this;
  1521. }
  1522.  
  1523. @@ -325,11 +319,8 @@ class Source extends AbstractEav
  1524. }
  1525.  
  1526. /**
  1527. - * Prepares data from select to save.
  1528. - *
  1529. * @param \Magento\Framework\DB\Select $select
  1530. * @param array $options
  1531. - *
  1532. * @return void
  1533. */
  1534. private function saveDataFromSelect(\Magento\Framework\DB\Select $select, array $options)
  1535. @@ -365,4 +356,48 @@ class Source extends AbstractEav
  1536. {
  1537. return $this->tableStrategy->getTableName('catalog_product_index_eav');
  1538. }
  1539. +
  1540. + /**
  1541. + * Prepare data index for product relations
  1542. + *
  1543. + * @param array $parentIds the parent entity ids limitation
  1544. + * @return $this
  1545. + */
  1546. + protected function _prepareRelationIndex($parentIds = null)
  1547. + {
  1548. + $connection = $this->getConnection();
  1549. + $idxTable = $this->getIdxTable();
  1550. +
  1551. + if (!$this->tableStrategy->getUseIdxTable()) {
  1552. + $additionalIdxTable = $connection->getTableName(self::TRANSIT_PREFIX . $this->getIdxTable());
  1553. + $connection->createTemporaryTableLike($additionalIdxTable, $idxTable);
  1554. +
  1555. + $query = $connection->insertFromSelect(
  1556. + $this->_prepareRelationIndexSelect($parentIds),
  1557. + $additionalIdxTable,
  1558. + []
  1559. + );
  1560. + $connection->query($query);
  1561. +
  1562. + $select = $connection->select()->from($additionalIdxTable);
  1563. + $query = $connection->insertFromSelect(
  1564. + $select,
  1565. + $idxTable,
  1566. + [],
  1567. + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
  1568. + );
  1569. + $connection->query($query);
  1570. +
  1571. + $connection->dropTemporaryTable($additionalIdxTable);
  1572. + } else {
  1573. + $query = $connection->insertFromSelect(
  1574. + $this->_prepareRelationIndexSelect($parentIds),
  1575. + $idxTable,
  1576. + [],
  1577. + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
  1578. + );
  1579. + $connection->query($query);
  1580. + }
  1581. + return $this;
  1582. + }
  1583. }
  1584. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/SourceRowSizeEstimator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/SourceRowSizeEstimator.php
  1585. new file mode 100644
  1586. index 00000000000..d212337ae7c
  1587. --- /dev/null
  1588. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/SourceRowSizeEstimator.php
  1589. @@ -0,0 +1,107 @@
  1590. +<?php
  1591. +/**
  1592. + * Copyright © Magento, Inc. All rights reserved.
  1593. + * See COPYING.txt for license details.
  1594. + */
  1595. +
  1596. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav;
  1597. +
  1598. +use Magento\Store\Api\StoreManagementInterface;
  1599. +use Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface;
  1600. +use Magento\Framework\EntityManager\MetadataPool;
  1601. +use Magento\Catalog\Api\Data\ProductInterface;
  1602. +use Magento\Framework\DB\Adapter\AdapterInterface;
  1603. +
  1604. +/**
  1605. + * Estimator of the EAV index table row size.
  1606. + *
  1607. + * Estimates the amount of memory required to store the index data of the product
  1608. + * with the highest number of attributes/values.
  1609. + *
  1610. + * Can be used with batch size manager to ensure that the batch will be handled correctly by the database.
  1611. + * @see \Magento\Framework\Indexer\BatchSizeManagement
  1612. + */
  1613. +class SourceRowSizeEstimator implements IndexTableRowSizeEstimatorInterface
  1614. +{
  1615. + /**
  1616. + * @var StoreManagementInterface
  1617. + */
  1618. + private $storeManagement;
  1619. +
  1620. + /**
  1621. + * @var Source
  1622. + */
  1623. + private $indexerResource;
  1624. +
  1625. + /**
  1626. + * @var MetadataPool
  1627. + */
  1628. + private $metadataPool;
  1629. +
  1630. + /**
  1631. + * @param StoreManagementInterface $storeManagement
  1632. + * @param Source $indexerResource
  1633. + * @param MetadataPool $metadataPool
  1634. + */
  1635. + public function __construct(
  1636. + StoreManagementInterface $storeManagement,
  1637. + Source $indexerResource,
  1638. + MetadataPool $metadataPool
  1639. + ) {
  1640. + $this->storeManagement = $storeManagement;
  1641. + $this->indexerResource = $indexerResource;
  1642. + $this->metadataPool = $metadataPool;
  1643. + }
  1644. +
  1645. + /**
  1646. + * @inheritdoc
  1647. + */
  1648. + public function estimateRowSize()
  1649. + {
  1650. + $connection = $this->indexerResource->getConnection();
  1651. + $entityIdField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
  1652. +
  1653. + $maxRowsPerStore = max(
  1654. + $this->getMaxRowsPerStore(
  1655. + $connection,
  1656. + $this->indexerResource->getTable('catalog_product_entity_int'),
  1657. + $entityIdField
  1658. + ),
  1659. + $this->getMaxRowsPerStore(
  1660. + $connection,
  1661. + $this->indexerResource->getTable('catalog_product_entity_varchar'),
  1662. + $entityIdField
  1663. + )
  1664. + );
  1665. +
  1666. + return ceil($maxRowsPerStore * $this->storeManagement->getCount() * 500);
  1667. + }
  1668. +
  1669. + /**
  1670. + * Calculate maximum rows per store and product stored in the target table.
  1671. + *
  1672. + * @param AdapterInterface $connection
  1673. + * @param string $valueTable name of the target table
  1674. + * @param string $entityIdField entity ID field name
  1675. + * @return string maximum rows per store and product stored in the table
  1676. + */
  1677. + private function getMaxRowsPerStore(
  1678. + AdapterInterface $connection,
  1679. + $valueTable,
  1680. + $entityIdField
  1681. + ) {
  1682. + $valueSelect = $connection->select();
  1683. + $valueSelect->from(
  1684. + ['value_table' => $valueTable],
  1685. + ['count' => new \Zend_Db_Expr('count(value_table.value_id)')]
  1686. + );
  1687. + $valueSelect->group([$entityIdField, 'store_id']);
  1688. +
  1689. + $maxSelect = $connection->select();
  1690. + $maxSelect->from(
  1691. + ['max_value' => $valueSelect],
  1692. + ['count' => new \Zend_Db_Expr('MAX(count)')]
  1693. + );
  1694. + return $connection->fetchOne($maxSelect);
  1695. + }
  1696. +}
  1697. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
  1698. index ffaf8a5d100..d81b38e9ac7 100644
  1699. --- a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
  1700. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
  1701. @@ -39,11 +39,12 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild
  1702. private $baseSelectProcessor;
  1703.  
  1704. /**
  1705. + * LinkedProductSelectBuilderByIndexPrice constructor.
  1706. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  1707. * @param \Magento\Framework\App\ResourceConnection $resourceConnection
  1708. * @param \Magento\Customer\Model\Session $customerSession
  1709. * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
  1710. - * @param BaseSelectProcessorInterface $baseSelectProcessor
  1711. + * @param BaseSelectProcessorInterface|null $baseSelectProcessor
  1712. */
  1713. public function __construct(
  1714. \Magento\Store\Model\StoreManagerInterface $storeManager,
  1715. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/BatchSizeCalculator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/BatchSizeCalculator.php
  1716. new file mode 100644
  1717. index 00000000000..b31147af234
  1718. --- /dev/null
  1719. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/BatchSizeCalculator.php
  1720. @@ -0,0 +1,59 @@
  1721. +<?php
  1722. +/**
  1723. + * Copyright © Magento, Inc. All rights reserved.
  1724. + * See COPYING.txt for license details.
  1725. + */
  1726. +
  1727. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price;
  1728. +
  1729. +/**
  1730. + * Ensure that size of index MEMORY table is enough for configured rows count in batch.
  1731. + */
  1732. +class BatchSizeCalculator
  1733. +{
  1734. + /**
  1735. + * @var array
  1736. + */
  1737. + private $batchRowsCount;
  1738. +
  1739. + /**
  1740. + * @var \Magento\Framework\Indexer\BatchSizeManagementInterface[]
  1741. + */
  1742. + private $estimators;
  1743. +
  1744. + /**
  1745. + * BatchSizeCalculator constructor.
  1746. + * @param array $batchRowsCount
  1747. + * @param array $estimators
  1748. + */
  1749. + public function __construct(array $batchRowsCount, array $estimators)
  1750. + {
  1751. + $this->batchRowsCount = $batchRowsCount;
  1752. + $this->estimators = $estimators;
  1753. + }
  1754. +
  1755. + /**
  1756. + * Retrieve batch size for the given indexer.
  1757. + *
  1758. + * Ensure that the database will be able to handle provided batch size correctly.
  1759. + *
  1760. + * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
  1761. + * @param string $indexerTypeId
  1762. + * @return int
  1763. + */
  1764. + public function estimateBatchSize(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $indexerTypeId)
  1765. + {
  1766. + $batchRowsCount = isset($this->batchRowsCount[$indexerTypeId])
  1767. + ? $this->batchRowsCount[$indexerTypeId]
  1768. + : $this->batchRowsCount['default'];
  1769. +
  1770. + /** @var \Magento\Framework\Indexer\BatchSizeManagementInterface $calculator */
  1771. + $calculator = isset($this->estimators[$indexerTypeId])
  1772. + ? $this->estimators[$indexerTypeId]
  1773. + : $this->estimators['default'];
  1774. +
  1775. + $calculator->ensureBatchSize($connection, $batchRowsCount);
  1776. +
  1777. + return $batchRowsCount;
  1778. + }
  1779. +}
  1780. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php
  1781. new file mode 100644
  1782. index 00000000000..a3425bfc9d7
  1783. --- /dev/null
  1784. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php
  1785. @@ -0,0 +1,88 @@
  1786. +<?php
  1787. +/**
  1788. + * Copyright © Magento, Inc. All rights reserved.
  1789. + * See COPYING.txt for license details.
  1790. + */
  1791. +
  1792. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price;
  1793. +
  1794. +use Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface;
  1795. +use Magento\Store\Api\WebsiteManagementInterface;
  1796. +use Magento\Customer\Model\ResourceModel\Group\CollectionFactory;
  1797. +
  1798. +/**
  1799. + * Estimate index memory size for largest composite product in catalog.
  1800. + */
  1801. +class CompositeProductRowSizeEstimator implements IndexTableRowSizeEstimatorInterface
  1802. +{
  1803. + /**
  1804. + * Calculated memory size for one record in catalog_product_index_price table
  1805. + */
  1806. + const MEMORY_SIZE_FOR_ONE_ROW = 200;
  1807. +
  1808. + /**
  1809. + * @var DefaultPrice
  1810. + */
  1811. + private $indexerResource;
  1812. +
  1813. + /**
  1814. + * @var WebsiteManagementInterface
  1815. + */
  1816. + private $websiteManagement;
  1817. +
  1818. + /**
  1819. + * @var CollectionFactory
  1820. + */
  1821. + private $collectionFactory;
  1822. +
  1823. + /**
  1824. + * @param DefaultPrice $indexerResource
  1825. + * @param WebsiteManagementInterface $websiteManagement
  1826. + * @param CollectionFactory $collectionFactory
  1827. + */
  1828. + public function __construct(
  1829. + DefaultPrice $indexerResource,
  1830. + WebsiteManagementInterface $websiteManagement,
  1831. + CollectionFactory $collectionFactory
  1832. + ) {
  1833. + $this->indexerResource = $indexerResource;
  1834. + $this->websiteManagement = $websiteManagement;
  1835. + $this->collectionFactory = $collectionFactory;
  1836. + }
  1837. +
  1838. + /**
  1839. + * Calculate memory size for largest composite product in database.
  1840. + *
  1841. + * {@inheritdoc}
  1842. + */
  1843. + public function estimateRowSize()
  1844. + {
  1845. + $websitesCount = $this->websiteManagement->getCount();
  1846. + $customerGroupCount = $this->collectionFactory->create()->getSize();
  1847. +
  1848. + $connection = $this->indexerResource->getConnection();
  1849. + $relationSelect = $connection->select();
  1850. + $relationSelect->from(
  1851. + ['relation' => $this->indexerResource->getTable('catalog_product_relation')],
  1852. + ['count' => new \Zend_Db_Expr('count(relation.child_id)')]
  1853. + );
  1854. + $relationSelect->group('parent_id');
  1855. +
  1856. + $maxSelect = $connection->select();
  1857. + $maxSelect->from(
  1858. + ['max_value' => $relationSelect],
  1859. + ['count' => new \Zend_Db_Expr('MAX(count)')]
  1860. + );
  1861. + $maxRelatedProductCount = $connection->fetchOne($maxSelect);
  1862. +
  1863. + /**
  1864. + * Calculate memory size for largest composite product in database.
  1865. + *
  1866. + * $maxRelatedProductCount - maximum number of related products
  1867. + * $websitesCount - active websites
  1868. + * $customerGroupCount - active customer groups
  1869. + * MEMORY_SIZE_FOR_ONE_ROW - calculated memory size for one record in catalog_product_index_price table
  1870. + */
  1871. + return ceil($maxRelatedProductCount * $websitesCount * $customerGroupCount * self::MEMORY_SIZE_FOR_ONE_ROW);
  1872. + }
  1873. +}
  1874. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
  1875. index 8a97d43a18d..5d1353ccd57 100644
  1876. --- a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
  1877. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
  1878. @@ -12,6 +12,7 @@ use Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer;
  1879. * For correctly work need define product type id
  1880. *
  1881. * @author Magento Core Team <core@magentocommerce.com>
  1882. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  1883. */
  1884. class DefaultPrice extends AbstractIndexer implements PriceInterface
  1885. {
  1886. @@ -44,14 +45,19 @@ class DefaultPrice extends AbstractIndexer implements PriceInterface
  1887. protected $_eventManager = null;
  1888.  
  1889. /**
  1890. - * Class constructor
  1891. + * @var bool|null
  1892. + */
  1893. + private $hasEntity = null;
  1894. +
  1895. + /**
  1896. + * DefaultPrice constructor.
  1897. *
  1898. * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  1899. * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
  1900. * @param \Magento\Eav\Model\Config $eavConfig
  1901. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  1902. * @param \Magento\Framework\Module\Manager $moduleManager
  1903. - * @param string $connectionName
  1904. + * @param string|null $connectionName
  1905. */
  1906. public function __construct(
  1907. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  1908. @@ -677,16 +683,19 @@ class DefaultPrice extends AbstractIndexer implements PriceInterface
  1909. */
  1910. protected function hasEntity()
  1911. {
  1912. - $reader = $this->getConnection();
  1913. -
  1914. - $select = $reader->select()->from(
  1915. - [$this->getTable('catalog_product_entity')],
  1916. - ['count(entity_id)']
  1917. - )->where(
  1918. - 'type_id=?',
  1919. - $this->getTypeId()
  1920. - );
  1921. + if ($this->hasEntity === null) {
  1922. + $reader = $this->getConnection();
  1923. +
  1924. + $select = $reader->select()->from(
  1925. + [$this->getTable('catalog_product_entity')],
  1926. + ['count(entity_id)']
  1927. + )->where(
  1928. + 'type_id=?',
  1929. + $this->getTypeId()
  1930. + );
  1931. + $this->hasEntity = (int)$reader->fetchOne($select) > 0;
  1932. + }
  1933.  
  1934. - return (int)$reader->fetchOne($select) > 0;
  1935. + return $this->hasEntity;
  1936. }
  1937. }
  1938. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/IndexTableRowSizeEstimator.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/IndexTableRowSizeEstimator.php
  1939. new file mode 100644
  1940. index 00000000000..89df6677f24
  1941. --- /dev/null
  1942. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Price/IndexTableRowSizeEstimator.php
  1943. @@ -0,0 +1,63 @@
  1944. +<?php
  1945. +/**
  1946. + * Copyright © Magento, Inc. All rights reserved.
  1947. + * See COPYING.txt for license details.
  1948. + */
  1949. +
  1950. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price;
  1951. +
  1952. +/**
  1953. + * Estimate index memory size for simple product.
  1954. + * Size depends on websites and customer groups count.
  1955. + */
  1956. +class IndexTableRowSizeEstimator implements \Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface
  1957. +{
  1958. + /**
  1959. + * Calculated memory size for one record in catalog_product_index_price table
  1960. + */
  1961. + const MEMORY_SIZE_FOR_ONE_ROW = 120;
  1962. +
  1963. + /**
  1964. + * @var \Magento\Store\Api\WebsiteManagementInterface
  1965. + */
  1966. + private $websiteManagement;
  1967. +
  1968. + /**
  1969. + * @var \Magento\Customer\Model\ResourceModel\Group\CollectionFactory
  1970. + */
  1971. + private $collectionFactory;
  1972. +
  1973. + /**
  1974. + * CompositeProductBatchSizeCalculator constructor.
  1975. + * @param \Magento\Store\Api\WebsiteManagementInterface $websiteManagement
  1976. + * @param \Magento\Customer\Model\ResourceModel\Group\CollectionFactory $collectionFactory
  1977. + */
  1978. + public function __construct(
  1979. + \Magento\Store\Api\WebsiteManagementInterface $websiteManagement,
  1980. + \Magento\Customer\Model\ResourceModel\Group\CollectionFactory $collectionFactory
  1981. + ) {
  1982. + $this->websiteManagement = $websiteManagement;
  1983. + $this->collectionFactory = $collectionFactory;
  1984. + }
  1985. +
  1986. + /**
  1987. + * @inheritdoc
  1988. + */
  1989. + public function estimateRowSize()
  1990. + {
  1991. + $websitesCount = $this->websiteManagement->getCount();
  1992. +
  1993. + /** @var \Magento\Customer\Model\ResourceModel\Group\Collection $collection */
  1994. + $collection = $this->collectionFactory->create();
  1995. + $customerGroupCount = $collection->getSize();
  1996. +
  1997. + /**
  1998. + * Calculate memory size for product in database.
  1999. + *
  2000. + * $websitesCount - active websites
  2001. + * $customerGroupCount - active customer groups
  2002. + * MEMORY_SIZE_FOR_ONE_ROW - calculated memory size for one record in catalog_product_index_price table
  2003. + */
  2004. + return ceil($websitesCount * $customerGroupCount * self::MEMORY_SIZE_FOR_ONE_ROW);
  2005. + }
  2006. +}
  2007. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/TemporaryTableStrategy.php b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/TemporaryTableStrategy.php
  2008. new file mode 100644
  2009. index 00000000000..54673cb01bb
  2010. --- /dev/null
  2011. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/TemporaryTableStrategy.php
  2012. @@ -0,0 +1,87 @@
  2013. +<?php
  2014. +/**
  2015. + * Copyright © Magento, Inc. All rights reserved.
  2016. + * See COPYING.txt for license details.
  2017. + */
  2018. +
  2019. +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer;
  2020. +
  2021. +/**
  2022. + * Provided logic will create temporary table based on memory table and will return new index table name.
  2023. + */
  2024. +class TemporaryTableStrategy implements \Magento\Framework\Indexer\Table\StrategyInterface
  2025. +{
  2026. + /**
  2027. + * Suffix for new temporary table
  2028. + */
  2029. + const TEMP_SUFFIX = '_temp';
  2030. +
  2031. + /**
  2032. + * @var \Magento\Framework\Indexer\Table\Strategy
  2033. + */
  2034. + private $strategy;
  2035. +
  2036. + /**
  2037. + * Application resource
  2038. + *
  2039. + * @var \Magento\Framework\App\ResourceConnection
  2040. + */
  2041. + private $resource;
  2042. +
  2043. + /**
  2044. + * TemporaryTableStrategy constructor.
  2045. + * @param \Magento\Framework\Indexer\Table\Strategy $strategy
  2046. + * @param \Magento\Framework\App\ResourceConnection $resource
  2047. + */
  2048. + public function __construct(
  2049. + \Magento\Framework\Indexer\Table\StrategyInterface $strategy,
  2050. + \Magento\Framework\App\ResourceConnection $resource
  2051. + ) {
  2052. + $this->strategy = $strategy;
  2053. + $this->resource = $resource;
  2054. + }
  2055. +
  2056. + /**
  2057. + * @inheritdoc
  2058. + */
  2059. + public function getUseIdxTable()
  2060. + {
  2061. + return $this->strategy->getUseIdxTable();
  2062. + }
  2063. +
  2064. + /**
  2065. + * @inheritdoc
  2066. + */
  2067. + public function setUseIdxTable($value = false)
  2068. + {
  2069. + return $this->strategy->setUseIdxTable($value);
  2070. + }
  2071. +
  2072. + /**
  2073. + * @inheritdoc
  2074. + */
  2075. + public function getTableName($tablePrefix)
  2076. + {
  2077. + return $this->resource->getTableName($this->prepareTableName($tablePrefix));
  2078. + }
  2079. +
  2080. + /**
  2081. + * Create temporary index table based on memory table
  2082. + *
  2083. + * {@inheritdoc}
  2084. + */
  2085. + public function prepareTableName($tablePrefix)
  2086. + {
  2087. + if ($this->getUseIdxTable()) {
  2088. + return $tablePrefix . self::IDX_SUFFIX;
  2089. + }
  2090. +
  2091. + // Create temporary table
  2092. + $this->resource->getConnection('indexer')->createTemporaryTableLike(
  2093. + $this->resource->getTableName($tablePrefix . self::TEMP_SUFFIX),
  2094. + $this->resource->getTableName($tablePrefix . self::TMP_SUFFIX),
  2095. + true
  2096. + );
  2097. + return $tablePrefix . self::TEMP_SUFFIX;
  2098. + }
  2099. +}
  2100. diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Url.php b/vendor/magento/module-catalog/Model/ResourceModel/Url.php
  2101. index cb4c3143fc3..c4bab809c2f 100644
  2102. --- a/vendor/magento/module-catalog/Model/ResourceModel/Url.php
  2103. +++ b/vendor/magento/module-catalog/Model/ResourceModel/Url.php
  2104. @@ -13,6 +13,7 @@ namespace Magento\Catalog\Model\ResourceModel;
  2105. use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
  2106. use Magento\Catalog\Api\Data\CategoryInterface;
  2107. use Magento\Framework\EntityManager\MetadataPool;
  2108. +use Magento\Framework\App\ObjectManager;
  2109.  
  2110. /**
  2111. * Class Url
  2112. diff --git a/vendor/magento/module-catalog/Setup/UpgradeSchema.php b/vendor/magento/module-catalog/Setup/UpgradeSchema.php
  2113. index 213cbe8b0cf..b46c8cfd91e 100644
  2114. --- a/vendor/magento/module-catalog/Setup/UpgradeSchema.php
  2115. +++ b/vendor/magento/module-catalog/Setup/UpgradeSchema.php
  2116. @@ -37,6 +37,56 @@ class UpgradeSchema implements UpgradeSchemaInterface
  2117. $this->addSourceEntityIdToProductEavIndex($setup);
  2118. }
  2119.  
  2120. + if (version_compare($context->getVersion(), '2.1.4.1.2', '<')) {
  2121. + //remove fk from price index table
  2122. + $setup->getConnection()->dropForeignKey(
  2123. + $setup->getTable('catalog_product_index_price'),
  2124. + $setup->getFkName(
  2125. + 'catalog_product_index_price',
  2126. + 'entity_id',
  2127. + 'catalog_product_entity',
  2128. + 'entity_id'
  2129. + )
  2130. + );
  2131. + $setup->getConnection()->dropForeignKey(
  2132. + $setup->getTable('catalog_product_index_price'),
  2133. + $setup->getFkName(
  2134. + 'catalog_product_index_price',
  2135. + 'website_id',
  2136. + 'store_website',
  2137. + 'website_id'
  2138. + )
  2139. + );
  2140. + $setup->getConnection()->dropForeignKey(
  2141. + $setup->getTable('catalog_product_index_price'),
  2142. + $setup->getFkName(
  2143. + 'catalog_product_index_price',
  2144. + 'customer_group_id',
  2145. + 'customer_group',
  2146. + 'customer_group_id'
  2147. + )
  2148. + );
  2149. +
  2150. + $this->addReplicaTable($setup, 'catalog_product_index_eav', 'catalog_product_index_eav_replica');
  2151. + $this->addReplicaTable(
  2152. + $setup,
  2153. + 'catalog_product_index_eav_decimal',
  2154. + 'catalog_product_index_eav_decimal_replica'
  2155. + );
  2156. + // By adding 'catalog_product_index_price_replica' we provide separation of tables
  2157. + // used for indexation write and read operations and affected models.
  2158. + $this->addReplicaTable(
  2159. + $setup,
  2160. + 'catalog_product_index_price',
  2161. + 'catalog_product_index_price_replica'
  2162. + );
  2163. + // the same for 'catalog_category_product_index'
  2164. + $this->addReplicaTable(
  2165. + $setup,
  2166. + 'catalog_category_product_index',
  2167. + 'catalog_category_product_index_replica'
  2168. + );
  2169. + }
  2170. $setup->endSetup();
  2171. }
  2172.  
  2173. @@ -46,7 +96,6 @@ class UpgradeSchema implements UpgradeSchemaInterface
  2174. * It is useful to identify original entity in a composite products.
  2175. *
  2176. * @param SchemaSetupInterface $setup
  2177. - *
  2178. * @return void
  2179. */
  2180. private function addSourceEntityIdToProductEavIndex(SchemaSetupInterface $setup)
  2181. @@ -60,7 +109,6 @@ class UpgradeSchema implements UpgradeSchemaInterface
  2182. 'catalog_product_index_eav_decimal_tmp',
  2183. ];
  2184. $connection = $setup->getConnection();
  2185. -
  2186. foreach ($tables as $tableName) {
  2187. $tableName = $setup->getTable($tableName);
  2188. $connection->addColumn(
  2189. @@ -328,4 +376,22 @@ class UpgradeSchema implements UpgradeSchemaInterface
  2190. $connection->dropColumn($setup->getTable($filedInfo['table']), $filedInfo['column']);
  2191. }
  2192. }
  2193. +
  2194. + /**
  2195. + * Add the replica table for existing one.
  2196. + *
  2197. + * @param SchemaSetupInterface $setup
  2198. + * @param string $existingTable
  2199. + * @param string $replicaTable
  2200. + * @return void
  2201. + */
  2202. + private function addReplicaTable(SchemaSetupInterface $setup, $existingTable, $replicaTable)
  2203. + {
  2204. + $sql = sprintf(
  2205. + 'CREATE TABLE IF NOT EXISTS %s LIKE %s',
  2206. + $setup->getConnection()->quoteIdentifier($setup->getTable($replicaTable)),
  2207. + $setup->getConnection()->quoteIdentifier($setup->getTable($existingTable))
  2208. + );
  2209. + $setup->getConnection()->query($sql);
  2210. + }
  2211. }
  2212. diff --git a/vendor/magento/module-catalog/etc/di.xml b/vendor/magento/module-catalog/etc/di.xml
  2213. index 793c6351ffe..469e4d7cc17 100644
  2214. --- a/vendor/magento/module-catalog/etc/di.xml
  2215. +++ b/vendor/magento/module-catalog/etc/di.xml
  2216. @@ -46,6 +46,7 @@
  2217. <preference for="Magento\Catalog\Api\ProductManagementInterface" type="Magento\Catalog\Model\ProductManagement" />
  2218. <preference for="Magento\Catalog\Api\AttributeSetFinderInterface" type="Magento\Catalog\Model\Product\Attribute\AttributeSetFinder" />
  2219. <preference for="Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolverInterface" type="Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver"/>
  2220. + <preference for="Magento\Framework\Indexer\BatchProviderInterface" type="Magento\Framework\Indexer\BatchProvider" />
  2221. <type name="Magento\Customer\Model\ResourceModel\Visitor">
  2222. <plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
  2223. </type>
  2224. @@ -806,4 +807,78 @@
  2225. <plugin name="copy_quote_files_to_order" type="Magento\Catalog\Model\Plugin\QuoteItemProductOption"/>
  2226. </type>
  2227. <preference for="Magento\Catalog\Pricing\Price\MinimalPriceCalculatorInterface" type="Magento\Catalog\Pricing\Price\MinimalTierPriceCalculator" />
  2228. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator">
  2229. + <arguments>
  2230. + <argument name="batchRowsCount" xsi:type="array">
  2231. + <item name="default" xsi:type="number">5000</item></argument>
  2232. + <argument name="estimators" xsi:type="array">
  2233. + <item name="default" xsi:type="object">Magento\Catalog\Model\Indexer\Price\BatchSizeManagement</item>
  2234. + </argument>
  2235. + </arguments>
  2236. + </type>
  2237. + <virtualType name="Magento\Catalog\Model\Indexer\Price\CompositeProductBatchSizeManagement" type="Magento\Framework\Indexer\BatchSizeManagement">
  2238. + <arguments>
  2239. + <argument name="rowSizeEstimator" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\CompositeProductRowSizeEstimator</argument>
  2240. + </arguments>
  2241. + </virtualType>
  2242. + <virtualType name="Magento\Catalog\Model\Indexer\Price\BatchSizeManagement" type="Magento\Framework\Indexer\BatchSizeManagement">
  2243. + <arguments>
  2244. + <argument name="rowSizeEstimator" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableRowSizeEstimator</argument>
  2245. + </arguments>
  2246. + </virtualType>
  2247. + <type name="Magento\Catalog\Model\Indexer\Category\Product\Action\Full">
  2248. + <arguments>
  2249. + <argument name="batchRowsCount" xsi:type="number">100000</argument>
  2250. + <argument name="batchSizeManagement" xsi:type="object">Magento\Catalog\Model\Indexer\CategoryProductBatchSize</argument>
  2251. + </arguments>
  2252. + </type>
  2253. + <virtualType name="Magento\Catalog\Model\Indexer\CategoryProductBatchSize" type="Magento\Framework\Indexer\BatchSizeManagement">
  2254. + <arguments>
  2255. + <argument name="rowSizeEstimator" xsi:type="object">Magento\Catalog\Model\Indexer\Category\Product\RowSizeEstimator</argument>
  2256. + </arguments>
  2257. + </virtualType>
  2258. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy" shared="false">
  2259. + <arguments>
  2260. + <argument name="strategy" xsi:type="object">Magento\Framework\Indexer\Table\Strategy</argument>
  2261. + </arguments>
  2262. + </type>
  2263. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice">
  2264. + <arguments>
  2265. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  2266. + <argument name="connectionName" xsi:type="string">indexer</argument>
  2267. + </arguments>
  2268. + </type>
  2269. + <type name="Magento\Catalog\Model\Indexer\Product\Eav\Action\Full">
  2270. + <arguments>
  2271. + <argument name="batchSizeCalculator" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator</argument>
  2272. + </arguments>
  2273. + </type>
  2274. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source">
  2275. + <arguments>
  2276. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  2277. + <argument name="connectionName" xsi:type="string">indexer</argument>
  2278. + </arguments>
  2279. + </type>
  2280. + <virtualType name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalBatchSizeManagement" type="Magento\Framework\Indexer\BatchSizeManagement">
  2281. + <arguments>
  2282. + <argument name="rowSizeEstimator" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalRowSizeEstimator</argument>
  2283. + </arguments>
  2284. + </virtualType>
  2285. + <virtualType name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceBatchSizeManagement" type="Magento\Framework\Indexer\BatchSizeManagement">
  2286. + <arguments>
  2287. + <argument name="rowSizeEstimator" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceRowSizeEstimator</argument>
  2288. + </arguments>
  2289. + </virtualType>
  2290. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator">
  2291. + <arguments>
  2292. + <argument name="batchSizes" xsi:type="array">
  2293. + <item name="decimal" xsi:type="number">1000</item>
  2294. + <item name="source" xsi:type="number">1000</item>
  2295. + </argument>
  2296. + <argument name="batchSizeManagers" xsi:type="array">
  2297. + <item name="decimal" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalBatchSizeManagement</item>
  2298. + <item name="source" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceBatchSizeManagement</item>
  2299. + </argument>
  2300. + </arguments>
  2301. + </type>
  2302. </config>
  2303. diff --git a/vendor/magento/module-catalog/etc/module.xml b/vendor/magento/module-catalog/etc/module.xml
  2304. index 57117669454..d3dd9716abe 100644
  2305. --- a/vendor/magento/module-catalog/etc/module.xml
  2306. +++ b/vendor/magento/module-catalog/etc/module.xml
  2307. @@ -6,7 +6,7 @@
  2308. */
  2309. -->
  2310. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  2311. - <module name="Magento_Catalog" setup_version="2.1.4">
  2312. + <module name="Magento_Catalog" setup_version="2.1.4.1.2">
  2313. <sequence>
  2314. <module name="Magento_Eav"/>
  2315. <module name="Magento_Cms"/>
  2316. diff --git a/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/AbstractAction.php b/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/AbstractAction.php
  2317. index cd4a3b440ab..6bbcc9dde1a 100644
  2318. --- a/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/AbstractAction.php
  2319. +++ b/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/AbstractAction.php
  2320. @@ -186,10 +186,10 @@ abstract class AbstractAction
  2321.  
  2322. $this->_deleteOldRelations($tableName);
  2323.  
  2324. - $columns = array_keys($this->_connection->describeTable($idxTableName));
  2325. - $select = $this->_connection->select()->from($idxTableName, $columns);
  2326. + $columns = array_keys($this->_getConnection()->describeTable($idxTableName));
  2327. + $select = $this->_getConnection()->select()->from($idxTableName, $columns);
  2328. $query = $select->insertFromSelect($tableName, $columns);
  2329. - $this->_connection->query($query);
  2330. + $this->_getConnection()->query($query);
  2331. return $this;
  2332. }
  2333.  
  2334. @@ -202,7 +202,7 @@ abstract class AbstractAction
  2335. */
  2336. protected function _deleteOldRelations($tableName)
  2337. {
  2338. - $select = $this->_connection->select()
  2339. + $select = $this->_getConnection()->select()
  2340. ->from(['s' => $tableName])
  2341. ->joinLeft(
  2342. ['w' => $this->_getTable('catalog_product_website')],
  2343. @@ -212,7 +212,7 @@ abstract class AbstractAction
  2344. ->where('w.product_id IS NULL');
  2345.  
  2346. $sql = $select->deleteFromSelect('s');
  2347. - $this->_connection->query($sql);
  2348. + $this->_getConnection()->query($sql);
  2349. }
  2350.  
  2351. /**
  2352. diff --git a/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/Action/Full.php b/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/Action/Full.php
  2353. index 2f545417a07..baa770c25bc 100644
  2354. --- a/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/Action/Full.php
  2355. +++ b/vendor/magento/module-catalog-inventory/Model/Indexer/Stock/Action/Full.php
  2356. @@ -8,18 +8,106 @@
  2357.  
  2358. namespace Magento\CatalogInventory\Model\Indexer\Stock\Action;
  2359.  
  2360. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  2361. +use Magento\Framework\App\ResourceConnection;
  2362. +use Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory;
  2363. +use Magento\Catalog\Model\Product\Type as ProductType;
  2364. +use Magento\Framework\Indexer\CacheContext;
  2365. +use Magento\Framework\Event\ManagerInterface as EventManager;
  2366. +use Magento\Framework\EntityManager\MetadataPool;
  2367. +use Magento\Framework\Indexer\BatchSizeManagementInterface;
  2368. +use Magento\Framework\Indexer\BatchProviderInterface;
  2369. +use Magento\Framework\App\ObjectManager;
  2370. +use Magento\Framework\Exception\LocalizedException;
  2371. +use Magento\CatalogInventory\Model\Indexer\Stock\AbstractAction;
  2372. +
  2373. /**
  2374. * Class Full reindex action
  2375. *
  2376. * @package Magento\CatalogInventory\Model\Indexer\Stock\Action
  2377. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  2378. */
  2379. -class Full extends \Magento\CatalogInventory\Model\Indexer\Stock\AbstractAction
  2380. +class Full extends AbstractAction
  2381. {
  2382. + /**
  2383. + * Action type representation
  2384. + */
  2385. + const ACTION_TYPE = 'full';
  2386. +
  2387. + /**
  2388. + * @var MetadataPool
  2389. + */
  2390. + private $metadataPool;
  2391. +
  2392. + /**
  2393. + * @var BatchSizeManagementInterface
  2394. + */
  2395. + private $batchSizeManagement;
  2396. +
  2397. + /**
  2398. + * @var BatchProviderInterface
  2399. + */
  2400. + private $batchProvider;
  2401. +
  2402. + /**
  2403. + * @var array
  2404. + */
  2405. + private $batchRowsCount;
  2406. +
  2407. + /**
  2408. + * @var ActiveTableSwitcher
  2409. + */
  2410. + private $activeTableSwitcher;
  2411. +
  2412. + /**
  2413. + * @param ResourceConnection $resource
  2414. + * @param StockFactory $indexerFactory
  2415. + * @param ProductType $catalogProductType
  2416. + * @param CacheContext $cacheContext
  2417. + * @param EventManager $eventManager
  2418. + * @param MetadataPool|null $metadataPool
  2419. + * @param BatchSizeManagementInterface|null $batchSizeManagement
  2420. + * @param BatchProviderInterface|null $batchProvider
  2421. + * @param array $batchRowsCount
  2422. + * @param ActiveTableSwitcher|null $activeTableSwitcher
  2423. + *
  2424. + * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  2425. + */
  2426. + public function __construct(
  2427. + ResourceConnection $resource,
  2428. + StockFactory $indexerFactory,
  2429. + ProductType $catalogProductType,
  2430. + CacheContext $cacheContext,
  2431. + EventManager $eventManager,
  2432. + MetadataPool $metadataPool = null,
  2433. + BatchSizeManagementInterface $batchSizeManagement = null,
  2434. + BatchProviderInterface $batchProvider = null,
  2435. + array $batchRowsCount = [],
  2436. + ActiveTableSwitcher $activeTableSwitcher = null
  2437. + ) {
  2438. + parent::__construct(
  2439. + $resource,
  2440. + $indexerFactory,
  2441. + $catalogProductType,
  2442. + $cacheContext,
  2443. + $eventManager
  2444. + );
  2445. +
  2446. + $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class);
  2447. + $this->batchProvider = $batchProvider ?: ObjectManager::getInstance()->get(BatchProviderInterface::class);
  2448. + $this->batchSizeManagement = $batchSizeManagement ?: ObjectManager::getInstance()->get(
  2449. + \Magento\CatalogInventory\Model\Indexer\Stock\BatchSizeManagement::class
  2450. + );
  2451. + $this->batchRowsCount = $batchRowsCount;
  2452. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()
  2453. + ->get(ActiveTableSwitcher::class);
  2454. + }
  2455. +
  2456. /**
  2457. * Execute Full reindex
  2458. *
  2459. * @param null|array $ids
  2460. - * @throws \Magento\Framework\Exception\LocalizedException
  2461. + * @throws LocalizedException
  2462. *
  2463. * @return void
  2464. *
  2465. @@ -28,9 +116,49 @@ class Full extends \Magento\CatalogInventory\Model\Indexer\Stock\AbstractAction
  2466. public function execute($ids = null)
  2467. {
  2468. try {
  2469. - $this->reindexAll();
  2470. + $this->useIdxTable(false);
  2471. + $entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
  2472. +
  2473. + $columns = array_keys($this->_getConnection()->describeTable($this->_getIdxTable()));
  2474. +
  2475. + /** @var \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\DefaultStock $indexer */
  2476. + foreach ($this->_getTypeIndexers() as $indexer) {
  2477. + $indexer->setActionType(self::ACTION_TYPE);
  2478. + $connection = $indexer->getConnection();
  2479. + $tableName = $this->activeTableSwitcher->getAdditionalTableName($indexer->getMainTable());
  2480. +
  2481. + $batchRowCount = isset($this->batchRowsCount[$indexer->getTypeId()])
  2482. + ? $this->batchRowsCount[$indexer->getTypeId()]
  2483. + : $this->batchRowsCount['default'];
  2484. +
  2485. + $this->batchSizeManagement->ensureBatchSize($connection, $batchRowCount);
  2486. + $batches = $this->batchProvider->getBatches(
  2487. + $connection,
  2488. + $entityMetadata->getEntityTable(),
  2489. + $entityMetadata->getIdentifierField(),
  2490. + $batchRowCount
  2491. + );
  2492. +
  2493. + foreach ($batches as $batch) {
  2494. + $this->clearTemporaryIndexTable();
  2495. + // Get entity ids from batch
  2496. + $select = $connection->select();
  2497. + $select->distinct(true);
  2498. + $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
  2499. + $select->where('type_id = ?', $indexer->getTypeId());
  2500. +
  2501. + $entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch);
  2502. + if (!empty($entityIds)) {
  2503. + $indexer->reindexEntity($entityIds);
  2504. + $select = $connection->select()->from($this->_getIdxTable(), $columns);
  2505. + $query = $select->insertFromSelect($tableName, $columns);
  2506. + $connection->query($query);
  2507. + }
  2508. + }
  2509. + }
  2510. + $this->activeTableSwitcher->switchTable($indexer->getConnection(), [$indexer->getMainTable()]);
  2511. } catch (\Exception $e) {
  2512. - throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
  2513. + throw new LocalizedException(__($e->getMessage()), $e);
  2514. }
  2515. }
  2516. }
  2517. diff --git a/vendor/magento/module-catalog-inventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php b/vendor/magento/module-catalog-inventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
  2518. index fcac88be425..ba9960a6b9c 100644
  2519. --- a/vendor/magento/module-catalog-inventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
  2520. +++ b/vendor/magento/module-catalog-inventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php
  2521. @@ -10,6 +10,7 @@ use Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer;
  2522. use Magento\CatalogInventory\Model\Stock;
  2523. use Magento\Framework\DB\Adapter\AdapterInterface;
  2524. use Magento\CatalogInventory\Api\StockConfigurationInterface;
  2525. +use Magento\CatalogInventory\Model\Indexer\Stock\Action\Full;
  2526.  
  2527. /**
  2528. * CatalogInventory Default Stock Status Indexer Resource Model
  2529. @@ -48,6 +49,13 @@ class DefaultStock extends AbstractIndexer implements StockInterface
  2530. */
  2531. protected $stockConfiguration;
  2532.  
  2533. + /**
  2534. + * Param for switching logic which depends on action type (full reindex or partial)
  2535. + *
  2536. + * @var string
  2537. + */
  2538. + private $actionType;
  2539. +
  2540. /**
  2541. * Class constructor
  2542. *
  2543. @@ -106,10 +114,38 @@ class DefaultStock extends AbstractIndexer implements StockInterface
  2544. */
  2545. public function reindexEntity($entityIds)
  2546. {
  2547. + if ($this->getActionType() === Full::ACTION_TYPE) {
  2548. + $this->tableStrategy->setUseIdxTable(false);
  2549. + $this->_prepareIndexTable($entityIds);
  2550. + return $this;
  2551. + }
  2552. +
  2553. $this->_updateIndex($entityIds);
  2554. return $this;
  2555. }
  2556.  
  2557. + /**
  2558. + * Returns action run type
  2559. + *
  2560. + * @return string
  2561. + */
  2562. + public function getActionType()
  2563. + {
  2564. + return $this->actionType;
  2565. + }
  2566. +
  2567. + /**
  2568. + * Set action run type
  2569. + *
  2570. + * @param string $type
  2571. + * @return $this
  2572. + */
  2573. + public function setActionType($type)
  2574. + {
  2575. + $this->actionType = $type;
  2576. + return $this;
  2577. + }
  2578. +
  2579. /**
  2580. * Set active Product Type Id
  2581. *
  2582. @@ -221,7 +257,7 @@ class DefaultStock extends AbstractIndexer implements StockInterface
  2583. protected function _prepareIndexTable($entityIds = null)
  2584. {
  2585. $connection = $this->getConnection();
  2586. - $select = $this->_getStockStatusSelect($entityIds);
  2587. + $select = $this->_getStockStatusSelect($entityIds, true);
  2588. $select = $this->getQueryProcessorComposite()->processQuery($select, $entityIds);
  2589. $query = $select->insertFromSelect($this->getIdxTable());
  2590. $connection->query($query);
  2591. diff --git a/vendor/magento/module-catalog-inventory/Setup/UpgradeSchema.php b/vendor/magento/module-catalog-inventory/Setup/UpgradeSchema.php
  2592. new file mode 100644
  2593. index 00000000000..f1975841f1d
  2594. --- /dev/null
  2595. +++ b/vendor/magento/module-catalog-inventory/Setup/UpgradeSchema.php
  2596. @@ -0,0 +1,46 @@
  2597. +<?php
  2598. +/**
  2599. + * Copyright © 2013-2017 Magento, Inc. All rights reserved.
  2600. + * See COPYING.txt for license details.
  2601. + */
  2602. +
  2603. +namespace Magento\CatalogInventory\Setup;
  2604. +
  2605. +use Magento\Framework\Setup\UpgradeSchemaInterface;
  2606. +use Magento\Framework\Setup\ModuleContextInterface;
  2607. +use Magento\Framework\Setup\SchemaSetupInterface;
  2608. +
  2609. +class UpgradeSchema implements UpgradeSchemaInterface
  2610. +{
  2611. + /**
  2612. + * {@inheritdoc}
  2613. + */
  2614. + public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
  2615. + {
  2616. + $setup->startSetup();
  2617. +
  2618. + if (version_compare($context->getVersion(), '2.0.1.1.2', '<')) {
  2619. + $this->addReplicaTable($setup, 'cataloginventory_stock_status', 'cataloginventory_stock_status_replica');
  2620. + }
  2621. +
  2622. + $setup->endSetup();
  2623. + }
  2624. +
  2625. + /**
  2626. + * Add replica table for existing one.
  2627. + *
  2628. + * @param SchemaSetupInterface $setup
  2629. + * @param string $existingTable
  2630. + * @param string $replicaTable
  2631. + * @return void
  2632. + */
  2633. + private function addReplicaTable(SchemaSetupInterface $setup, $existingTable, $replicaTable)
  2634. + {
  2635. + $sql = sprintf(
  2636. + 'CREATE TABLE IF NOT EXISTS %s LIKE %s',
  2637. + $setup->getConnection()->quoteIdentifier($setup->getTable($replicaTable)),
  2638. + $setup->getConnection()->quoteIdentifier($setup->getTable($existingTable))
  2639. + );
  2640. + $setup->getConnection()->query($sql);
  2641. + }
  2642. +}
  2643. diff --git a/vendor/magento/module-catalog-inventory/etc/di.xml b/vendor/magento/module-catalog-inventory/etc/di.xml
  2644. index 9e970cef7d0..10a72edb0db 100644
  2645. --- a/vendor/magento/module-catalog-inventory/etc/di.xml
  2646. +++ b/vendor/magento/module-catalog-inventory/etc/di.xml
  2647. @@ -86,4 +86,22 @@
  2648. <argument name="indexerProcessor" xsi:type="object">Magento\CatalogInventory\Model\Indexer\Stock\Processor</argument>
  2649. </arguments>
  2650. </type>
  2651. + <virtualType name="Magento\CatalogInventory\Model\Indexer\Stock\BatchSizeManagement" type="Magento\Framework\Indexer\BatchSizeManagement">
  2652. + <arguments>
  2653. + <argument name="rowSizeEstimator" xsi:type="object">Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\IndexTableRowSizeEstimator</argument>
  2654. + </arguments>
  2655. + </virtualType>
  2656. + <virtualType name="Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\IndexTableRowSizeEstimator" type="Magento\Framework\Indexer\IndexTableRowSizeEstimator">
  2657. + <arguments>
  2658. + <argument name="rowMemorySize" xsi:type="number">100</argument>
  2659. + </arguments>
  2660. + </virtualType>
  2661. + <type name="Magento\CatalogInventory\Model\Indexer\Stock\Action\Full">
  2662. + <arguments>
  2663. + <argument name="batchRowsCount" xsi:type="array">
  2664. + <item name="default" xsi:type="number">200</item>
  2665. + </argument>
  2666. + <argument name="batchSizeManagement" xsi:type="object">Magento\CatalogInventory\Model\Indexer\Stock\BatchSizeManagement</argument>
  2667. + </arguments>
  2668. + </type>
  2669. </config>
  2670. diff --git a/vendor/magento/module-catalog-inventory/etc/module.xml b/vendor/magento/module-catalog-inventory/etc/module.xml
  2671. index 6d86fa55984..676d3e8ef82 100644
  2672. --- a/vendor/magento/module-catalog-inventory/etc/module.xml
  2673. +++ b/vendor/magento/module-catalog-inventory/etc/module.xml
  2674. @@ -6,7 +6,7 @@
  2675. */
  2676. -->
  2677. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  2678. - <module name="Magento_CatalogInventory" setup_version="2.0.1">
  2679. + <module name="Magento_CatalogInventory" setup_version="2.0.1.1.2">
  2680. <sequence>
  2681. <module name="Magento_Catalog"/>
  2682. </sequence>
  2683. diff --git a/vendor/magento/module-catalog-rule/Api/IndexerTableSwapperInterface.php b/vendor/magento/module-catalog-rule/Api/IndexerTableSwapperInterface.php
  2684. new file mode 100644
  2685. index 00000000000..664505c48ba
  2686. --- /dev/null
  2687. +++ b/vendor/magento/module-catalog-rule/Api/IndexerTableSwapperInterface.php
  2688. @@ -0,0 +1,32 @@
  2689. +<?php
  2690. +/**
  2691. + * Copyright © Magento, Inc. All rights reserved.
  2692. + * See COPYING.txt for license details.
  2693. + */
  2694. +
  2695. +namespace Magento\CatalogRule\Api;
  2696. +
  2697. +/**
  2698. + * Manage additional tables used while building new index to preserve
  2699. + * index tables until the process finishes.
  2700. + */
  2701. +interface IndexerTableSwapperInterface
  2702. +{
  2703. + /**
  2704. + * Get working table name used to build index.
  2705. + *
  2706. + * @param string $originalTable
  2707. + *
  2708. + * @return string
  2709. + */
  2710. + public function getWorkingTableName(string $originalTable): string;
  2711. +
  2712. + /**
  2713. + * Swap working tables with actual tables to save new indexes.
  2714. + *
  2715. + * @param string[] $originalTablesNames
  2716. + *
  2717. + * @return void
  2718. + */
  2719. + public function swapIndexTables(array $originalTablesNames);
  2720. +}
  2721. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/IndexBuilder.php b/vendor/magento/module-catalog-rule/Model/Indexer/IndexBuilder.php
  2722. index 423aaa6986e..af17aa7efbc 100644
  2723. --- a/vendor/magento/module-catalog-rule/Model/Indexer/IndexBuilder.php
  2724. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/IndexBuilder.php
  2725. @@ -6,16 +6,17 @@
  2726.  
  2727. namespace Magento\CatalogRule\Model\Indexer;
  2728.  
  2729. -use Magento\Catalog\Api\Data\ProductInterface;
  2730. use Magento\Catalog\Model\Product;
  2731. use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory as RuleCollectionFactory;
  2732. use Magento\CatalogRule\Model\Rule;
  2733. -use Magento\Framework\App\ResourceConnection;
  2734. -use Magento\Framework\EntityManager\MetadataPool;
  2735. +use Magento\Framework\App\ObjectManager;
  2736. use Magento\Framework\Pricing\PriceCurrencyInterface;
  2737. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface as TableSwapper;
  2738.  
  2739. /**
  2740. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  2741. + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  2742. + * @SuppressWarnings(PHPMD.TooManyFields)
  2743. */
  2744. class IndexBuilder
  2745. {
  2746. @@ -23,6 +24,7 @@ class IndexBuilder
  2747.  
  2748. /**
  2749. * @var \Magento\Framework\EntityManager\MetadataPool
  2750. + * @deprecated
  2751. */
  2752. protected $metadataPool;
  2753.  
  2754. @@ -32,6 +34,7 @@ class IndexBuilder
  2755. * This array contain list of CatalogRuleGroupWebsite table columns
  2756. *
  2757. * @var array
  2758. + * @deprecated
  2759. */
  2760. protected $_catalogRuleGroupWebsiteColumnsList = ['rule_id', 'customer_group_id', 'website_id'];
  2761.  
  2762. @@ -95,6 +98,46 @@ class IndexBuilder
  2763. */
  2764. protected $connection;
  2765.  
  2766. + /**
  2767. + * @var \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator
  2768. + */
  2769. + private $productPriceCalculator;
  2770. +
  2771. + /**
  2772. + * @var \Magento\CatalogRule\Model\Indexer\ReindexRuleProduct
  2773. + */
  2774. + private $reindexRuleProduct;
  2775. +
  2776. + /**
  2777. + * @var \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite
  2778. + */
  2779. + private $reindexRuleGroupWebsite;
  2780. +
  2781. + /**
  2782. + * @var \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder
  2783. + */
  2784. + private $ruleProductsSelectBuilder;
  2785. +
  2786. + /**
  2787. + * @var \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice
  2788. + */
  2789. + private $reindexRuleProductPrice;
  2790. +
  2791. + /**
  2792. + * @var \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor
  2793. + */
  2794. + private $pricesPersistor;
  2795. +
  2796. + /**
  2797. + * @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
  2798. + */
  2799. + private $activeTableSwitcher;
  2800. +
  2801. + /**
  2802. + * @var TableSwapper
  2803. + */
  2804. + private $tableSwapper;
  2805. +
  2806. /**
  2807. * @param RuleCollectionFactory $ruleCollectionFactory
  2808. * @param PriceCurrencyInterface $priceCurrency
  2809. @@ -106,7 +149,16 @@ class IndexBuilder
  2810. * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
  2811. * @param \Magento\Catalog\Model\ProductFactory $productFactory
  2812. * @param int $batchCount
  2813. + * @param \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator|null $productPriceCalculator
  2814. + * @param \Magento\CatalogRule\Model\Indexer\ReindexRuleProduct|null $reindexRuleProduct
  2815. + * @param \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite|null $reindexRuleGroupWebsite
  2816. + * @param \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder|null $ruleProductsSelectBuilder
  2817. + * @param \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice|null $reindexRuleProductPrice
  2818. + * @param \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor|null $pricesPersistor
  2819. + * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
  2820. + * @param TableSwapper|null $tableSwapper
  2821. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  2822. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  2823. */
  2824. public function __construct(
  2825. RuleCollectionFactory $ruleCollectionFactory,
  2826. @@ -118,7 +170,15 @@ class IndexBuilder
  2827. \Magento\Framework\Stdlib\DateTime $dateFormat,
  2828. \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
  2829. \Magento\Catalog\Model\ProductFactory $productFactory,
  2830. - $batchCount = 1000
  2831. + $batchCount = 1000,
  2832. + \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator $productPriceCalculator = null,
  2833. + \Magento\CatalogRule\Model\Indexer\ReindexRuleProduct $reindexRuleProduct = null,
  2834. + \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite $reindexRuleGroupWebsite = null,
  2835. + \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder $ruleProductsSelectBuilder = null,
  2836. + \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice $reindexRuleProductPrice = null,
  2837. + \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor $pricesPersistor = null,
  2838. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null,
  2839. + TableSwapper $tableSwapper = null
  2840. ) {
  2841. $this->resource = $resource;
  2842. $this->connection = $resource->getConnection();
  2843. @@ -131,6 +191,30 @@ class IndexBuilder
  2844. $this->dateTime = $dateTime;
  2845. $this->productFactory = $productFactory;
  2846. $this->batchCount = $batchCount;
  2847. +
  2848. + $this->productPriceCalculator = $productPriceCalculator ?: ObjectManager::getInstance()->get(
  2849. + \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator::class
  2850. + );
  2851. + $this->reindexRuleProduct = $reindexRuleProduct ?: ObjectManager::getInstance()->get(
  2852. + \Magento\CatalogRule\Model\Indexer\ReindexRuleProduct::class
  2853. + );
  2854. + $this->reindexRuleGroupWebsite = $reindexRuleGroupWebsite ?: ObjectManager::getInstance()->get(
  2855. + \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite::class
  2856. + );
  2857. + $this->ruleProductsSelectBuilder = $ruleProductsSelectBuilder ?: ObjectManager::getInstance()->get(
  2858. + \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder::class
  2859. + );
  2860. + $this->reindexRuleProductPrice = $reindexRuleProductPrice ?: ObjectManager::getInstance()->get(
  2861. + \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice::class
  2862. + );
  2863. + $this->pricesPersistor = $pricesPersistor ?: ObjectManager::getInstance()->get(
  2864. + \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor::class
  2865. + );
  2866. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
  2867. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
  2868. + );
  2869. +
  2870. + $this->tableSwapper = $tableSwapper ?: ObjectManager::getInstance()->get(TableSwapper::class);
  2871. }
  2872.  
  2873. /**
  2874. @@ -207,9 +291,19 @@ class IndexBuilder
  2875. protected function doReindexFull()
  2876. {
  2877. foreach ($this->getAllRules() as $rule) {
  2878. - $this->updateRuleProductData($rule);
  2879. + $this->reindexRuleProduct->execute($rule, $this->batchCount, true);
  2880. }
  2881. - $this->deleteOldData()->applyAllRules();
  2882. +
  2883. + $this->reindexRuleProductPrice->execute($this->batchCount, null, true);
  2884. + $this->reindexRuleGroupWebsite->execute(true);
  2885. +
  2886. + $this->tableSwapper->swapIndexTables(
  2887. + [
  2888. + $this->getTable('catalogrule_product'),
  2889. + $this->getTable('catalogrule_product_price'),
  2890. + $this->getTable('catalogrule_group_website')
  2891. + ]
  2892. + );
  2893. }
  2894.  
  2895. /**
  2896. @@ -305,7 +399,8 @@ class IndexBuilder
  2897. throw $e;
  2898. }
  2899.  
  2900. - $this->applyAllRules($product);
  2901. + $this->reindexRuleProductPrice->execute($this->batchCount, $product);
  2902. + $this->reindexRuleGroupWebsite->execute();
  2903.  
  2904. return $this;
  2905. }
  2906. @@ -322,8 +417,8 @@ class IndexBuilder
  2907. /**
  2908. * @param Rule $rule
  2909. * @return $this
  2910. - * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  2911. - * @SuppressWarnings(PHPMD.NPathComplexity)
  2912. + * @deprecated
  2913. + * @see \Magento\CatalogRule\Model\Indexer\ReindexRuleProduct::execute
  2914. */
  2915. protected function updateRuleProductData(Rule $rule)
  2916. {
  2917. @@ -340,63 +435,7 @@ class IndexBuilder
  2918. );
  2919. }
  2920.  
  2921. - if (!$rule->getIsActive()) {
  2922. - return $this;
  2923. - }
  2924. -
  2925. - $websiteIds = $rule->getWebsiteIds();
  2926. - if (!is_array($websiteIds)) {
  2927. - $websiteIds = explode(',', $websiteIds);
  2928. - }
  2929. - if (empty($websiteIds)) {
  2930. - return $this;
  2931. - }
  2932. -
  2933. - \Magento\Framework\Profiler::start('__MATCH_PRODUCTS__');
  2934. - $productIds = $rule->getMatchingProductIds();
  2935. - \Magento\Framework\Profiler::stop('__MATCH_PRODUCTS__');
  2936. -
  2937. - $customerGroupIds = $rule->getCustomerGroupIds();
  2938. - $fromTime = strtotime($rule->getFromDate());
  2939. - $toTime = strtotime($rule->getToDate());
  2940. - $toTime = $toTime ? $toTime + self::SECONDS_IN_DAY - 1 : 0;
  2941. - $sortOrder = (int)$rule->getSortOrder();
  2942. - $actionOperator = $rule->getSimpleAction();
  2943. - $actionAmount = $rule->getDiscountAmount();
  2944. - $actionStop = $rule->getStopRulesProcessing();
  2945. -
  2946. - $rows = [];
  2947. -
  2948. - foreach ($productIds as $productId => $validationByWebsite) {
  2949. - foreach ($websiteIds as $websiteId) {
  2950. - if (empty($validationByWebsite[$websiteId])) {
  2951. - continue;
  2952. - }
  2953. - foreach ($customerGroupIds as $customerGroupId) {
  2954. - $rows[] = [
  2955. - 'rule_id' => $ruleId,
  2956. - 'from_time' => $fromTime,
  2957. - 'to_time' => $toTime,
  2958. - 'website_id' => $websiteId,
  2959. - 'customer_group_id' => $customerGroupId,
  2960. - 'product_id' => $productId,
  2961. - 'action_operator' => $actionOperator,
  2962. - 'action_amount' => $actionAmount,
  2963. - 'action_stop' => $actionStop,
  2964. - 'sort_order' => $sortOrder,
  2965. - ];
  2966. -
  2967. - if (count($rows) == $this->batchCount) {
  2968. - $this->connection->insertMultiple($this->getTable('catalogrule_product'), $rows);
  2969. - $rows = [];
  2970. - }
  2971. - }
  2972. - }
  2973. - }
  2974. - if (!empty($rows)) {
  2975. - $this->connection->insertMultiple($this->getTable('catalogrule_product'), $rows);
  2976. - }
  2977. -
  2978. + $this->reindexRuleProduct->execute($rule, $this->batchCount);
  2979. return $this;
  2980. }
  2981.  
  2982. @@ -404,123 +443,27 @@ class IndexBuilder
  2983. * @param Product|null $product
  2984. * @throws \Exception
  2985. * @return $this
  2986. - * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  2987. - * @SuppressWarnings(PHPMD.NPathComplexity)
  2988. - * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  2989. + * @deprecated
  2990. + * @see \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice::execute
  2991. + * @see \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite::execute
  2992. */
  2993. protected function applyAllRules(Product $product = null)
  2994. {
  2995. - $fromDate = mktime(0, 0, 0, date('m'), date('d') - 1);
  2996. - $toDate = mktime(0, 0, 0, date('m'), date('d') + 1);
  2997. -
  2998. - /**
  2999. - * Update products rules prices per each website separately
  3000. - * because of max join limit in mysql
  3001. - */
  3002. - foreach ($this->storeManager->getWebsites() as $website) {
  3003. - $productsStmt = $this->getRuleProductsStmt($website->getId(), $product);
  3004. -
  3005. - $dayPrices = [];
  3006. - $stopFlags = [];
  3007. - $prevKey = null;
  3008. -
  3009. - while ($ruleData = $productsStmt->fetch()) {
  3010. - $ruleProductId = $ruleData['product_id'];
  3011. - $productKey = $ruleProductId .
  3012. - '_' .
  3013. - $ruleData['website_id'] .
  3014. - '_' .
  3015. - $ruleData['customer_group_id'];
  3016. -
  3017. - if ($prevKey && $prevKey != $productKey) {
  3018. - $stopFlags = [];
  3019. - if (count($dayPrices) > $this->batchCount) {
  3020. - $this->saveRuleProductPrices($dayPrices);
  3021. - $dayPrices = [];
  3022. - }
  3023. - }
  3024. -
  3025. - $ruleData['from_time'] = $this->roundTime($ruleData['from_time']);
  3026. - $ruleData['to_time'] = $this->roundTime($ruleData['to_time']);
  3027. - /**
  3028. - * Build prices for each day
  3029. - */
  3030. - for ($time = $fromDate; $time <= $toDate; $time += self::SECONDS_IN_DAY) {
  3031. - if (($ruleData['from_time'] == 0 ||
  3032. - $time >= $ruleData['from_time']) && ($ruleData['to_time'] == 0 ||
  3033. - $time <= $ruleData['to_time'])
  3034. - ) {
  3035. - $priceKey = $time . '_' . $productKey;
  3036. -
  3037. - if (isset($stopFlags[$priceKey])) {
  3038. - continue;
  3039. - }
  3040. -
  3041. - if (!isset($dayPrices[$priceKey])) {
  3042. - $dayPrices[$priceKey] = [
  3043. - 'rule_date' => $time,
  3044. - 'website_id' => $ruleData['website_id'],
  3045. - 'customer_group_id' => $ruleData['customer_group_id'],
  3046. - 'product_id' => $ruleProductId,
  3047. - 'rule_price' => $this->calcRuleProductPrice($ruleData),
  3048. - 'latest_start_date' => $ruleData['from_time'],
  3049. - 'earliest_end_date' => $ruleData['to_time'],
  3050. - ];
  3051. - } else {
  3052. - $dayPrices[$priceKey]['rule_price'] = $this->calcRuleProductPrice(
  3053. - $ruleData,
  3054. - $dayPrices[$priceKey]
  3055. - );
  3056. - $dayPrices[$priceKey]['latest_start_date'] = max(
  3057. - $dayPrices[$priceKey]['latest_start_date'],
  3058. - $ruleData['from_time']
  3059. - );
  3060. - $dayPrices[$priceKey]['earliest_end_date'] = min(
  3061. - $dayPrices[$priceKey]['earliest_end_date'],
  3062. - $ruleData['to_time']
  3063. - );
  3064. - }
  3065. -
  3066. - if ($ruleData['action_stop']) {
  3067. - $stopFlags[$priceKey] = true;
  3068. - }
  3069. - }
  3070. - }
  3071. -
  3072. - $prevKey = $productKey;
  3073. - }
  3074. - $this->saveRuleProductPrices($dayPrices);
  3075. - }
  3076. -
  3077. - return $this->updateCatalogRuleGroupWebsiteData();
  3078. + $this->reindexRuleProductPrice->execute($this->batchCount, $product);
  3079. + $this->reindexRuleGroupWebsite->execute();
  3080. + return $this;
  3081. }
  3082.  
  3083. /**
  3084. * Update CatalogRuleGroupWebsite data
  3085. *
  3086. * @return $this
  3087. + * @deprecated
  3088. + * @see \Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite::execute
  3089. */
  3090. protected function updateCatalogRuleGroupWebsiteData()
  3091. {
  3092. - $this->connection->delete($this->getTable('catalogrule_group_website'), []);
  3093. -
  3094. - $timestamp = $this->dateTime->gmtTimestamp();
  3095. -
  3096. - $select = $this->connection->select()->distinct(
  3097. - true
  3098. - )->from(
  3099. - $this->getTable('catalogrule_product'),
  3100. - $this->_catalogRuleGroupWebsiteColumnsList
  3101. - )->where(
  3102. - "{$timestamp} >= from_time AND (({$timestamp} <= to_time AND to_time > 0) OR to_time = 0)"
  3103. - );
  3104. - $query = $select->insertFromSelect(
  3105. - $this->getTable('catalogrule_group_website'),
  3106. - $this->_catalogRuleGroupWebsiteColumnsList
  3107. - );
  3108. -
  3109. - $this->connection->query($query);
  3110. -
  3111. + $this->reindexRuleGroupWebsite->execute();
  3112. return $this;
  3113. }
  3114.  
  3115. @@ -539,33 +482,12 @@ class IndexBuilder
  3116. * @param array $ruleData
  3117. * @param null $productData
  3118. * @return float
  3119. + * @deprecated
  3120. + * @see \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator::calculate
  3121. */
  3122. protected function calcRuleProductPrice($ruleData, $productData = null)
  3123. {
  3124. - if ($productData !== null && isset($productData['rule_price'])) {
  3125. - $productPrice = $productData['rule_price'];
  3126. - } else {
  3127. - $productPrice = $ruleData['default_price'];
  3128. - }
  3129. -
  3130. - switch ($ruleData['action_operator']) {
  3131. - case 'to_fixed':
  3132. - $productPrice = min($ruleData['action_amount'], $productPrice);
  3133. - break;
  3134. - case 'to_percent':
  3135. - $productPrice = $productPrice * $ruleData['action_amount'] / 100;
  3136. - break;
  3137. - case 'by_fixed':
  3138. - $productPrice = max(0, $productPrice - $ruleData['action_amount']);
  3139. - break;
  3140. - case 'by_percent':
  3141. - $productPrice = $productPrice * (1 - $ruleData['action_amount'] / 100);
  3142. - break;
  3143. - default:
  3144. - $productPrice = 0;
  3145. - }
  3146. -
  3147. - return $this->priceCurrency->round($productPrice);
  3148. + return $this->productPriceCalculator->calculate($ruleData, $productData);
  3149. }
  3150.  
  3151. /**
  3152. @@ -573,107 +495,24 @@ class IndexBuilder
  3153. * @param Product|null $product
  3154. * @return \Zend_Db_Statement_Interface
  3155. * @throws \Magento\Framework\Exception\LocalizedException
  3156. + * @deprecated
  3157. + * @see \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder::build
  3158. */
  3159. protected function getRuleProductsStmt($websiteId, Product $product = null)
  3160. {
  3161. - /**
  3162. - * Sort order is important
  3163. - * It used for check stop price rule condition.
  3164. - * website_id customer_group_id product_id sort_order
  3165. - * 1 1 1 0
  3166. - * 1 1 1 1
  3167. - * 1 1 1 2
  3168. - * if row with sort order 1 will have stop flag we should exclude
  3169. - * all next rows for same product id from price calculation
  3170. - */
  3171. - $select = $this->connection->select()->from(
  3172. - ['rp' => $this->getTable('catalogrule_product')]
  3173. - )->order(
  3174. - ['rp.website_id', 'rp.customer_group_id', 'rp.product_id', 'rp.sort_order', 'rp.rule_id']
  3175. - );
  3176. -
  3177. - if ($product && $product->getEntityId()) {
  3178. - $select->where('rp.product_id=?', $product->getEntityId());
  3179. - }
  3180. -
  3181. - /**
  3182. - * Join default price and websites prices to result
  3183. - */
  3184. - $priceAttr = $this->eavConfig->getAttribute(Product::ENTITY, 'price');
  3185. - $priceTable = $priceAttr->getBackend()->getTable();
  3186. - $attributeId = $priceAttr->getId();
  3187. -
  3188. - $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
  3189. - $select->join(
  3190. - ['e' => $this->getTable('catalog_product_entity')],
  3191. - sprintf('e.entity_id = rp.product_id'),
  3192. - []
  3193. - );
  3194. - $joinCondition = '%1$s.' . $linkField . '=e.' . $linkField . ' AND (%1$s.attribute_id='
  3195. - . $attributeId
  3196. - . ') and %1$s.store_id=%2$s';
  3197. -
  3198. - $select->join(
  3199. - ['pp_default' => $priceTable],
  3200. - sprintf($joinCondition, 'pp_default', \Magento\Store\Model\Store::DEFAULT_STORE_ID),
  3201. - []
  3202. - );
  3203. -
  3204. - $website = $this->storeManager->getWebsite($websiteId);
  3205. - $defaultGroup = $website->getDefaultGroup();
  3206. - if ($defaultGroup instanceof \Magento\Store\Model\Group) {
  3207. - $storeId = $defaultGroup->getDefaultStoreId();
  3208. - } else {
  3209. - $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID;
  3210. - }
  3211. -
  3212. - $select->joinInner(
  3213. - ['product_website' => $this->getTable('catalog_product_website')],
  3214. - 'product_website.product_id=rp.product_id '
  3215. - . 'AND product_website.website_id = rp.website_id '
  3216. - . 'AND product_website.website_id='
  3217. - . $websiteId,
  3218. - []
  3219. - );
  3220. -
  3221. - $tableAlias = 'pp' . $websiteId;
  3222. - $select->joinLeft(
  3223. - [$tableAlias => $priceTable],
  3224. - sprintf($joinCondition, $tableAlias, $storeId),
  3225. - []
  3226. - );
  3227. - $select->columns([
  3228. - 'default_price' =>$this->connection->getIfNullSql($tableAlias . '.value', 'pp_default.value'),
  3229. - ]);
  3230. -
  3231. - return $this->connection->query($select);
  3232. + return $this->ruleProductsSelectBuilder->build($websiteId, $product);
  3233. }
  3234.  
  3235. /**
  3236. * @param array $arrData
  3237. * @return $this
  3238. * @throws \Exception
  3239. + * @deprecated
  3240. + * @see \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor::execute
  3241. */
  3242. protected function saveRuleProductPrices($arrData)
  3243. {
  3244. - if (empty($arrData)) {
  3245. - return $this;
  3246. - }
  3247. -
  3248. - $productIds = [];
  3249. -
  3250. - try {
  3251. - foreach ($arrData as $key => $data) {
  3252. - $productIds['product_id'] = $data['product_id'];
  3253. - $arrData[$key]['rule_date'] = $this->dateFormat->formatDate($data['rule_date'], false);
  3254. - $arrData[$key]['latest_start_date'] = $this->dateFormat->formatDate($data['latest_start_date'], false);
  3255. - $arrData[$key]['earliest_end_date'] = $this->dateFormat->formatDate($data['earliest_end_date'], false);
  3256. - }
  3257. - $this->connection->insertOnDuplicate($this->getTable('catalogrule_product_price'), $arrData);
  3258. - } catch (\Exception $e) {
  3259. - throw $e;
  3260. - }
  3261. -
  3262. + $this->pricesPersistor->execute($arrData);
  3263. return $this;
  3264. }
  3265.  
  3266. @@ -684,8 +523,7 @@ class IndexBuilder
  3267. */
  3268. protected function getActiveRules()
  3269. {
  3270. - return $this->ruleCollectionFactory->create()
  3271. - ->addFieldToFilter('is_active', 1);
  3272. + return $this->ruleCollectionFactory->create()->addFieldToFilter('is_active', 1);
  3273. }
  3274.  
  3275. /**
  3276. @@ -722,6 +560,7 @@ class IndexBuilder
  3277. /**
  3278. * @param int $timeStamp
  3279. * @return int
  3280. + * @deprecated
  3281. */
  3282. private function roundTime($timeStamp)
  3283. {
  3284. @@ -734,6 +573,7 @@ class IndexBuilder
  3285.  
  3286. /**
  3287. * @return MetadataPool
  3288. + * @deprecated
  3289. */
  3290. private function getMetadataPool()
  3291. {
  3292. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/IndexerTableSwapper.php b/vendor/magento/module-catalog-rule/Model/Indexer/IndexerTableSwapper.php
  3293. new file mode 100644
  3294. index 00000000000..e2e53f724a7
  3295. --- /dev/null
  3296. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/IndexerTableSwapper.php
  3297. @@ -0,0 +1,127 @@
  3298. +<?php
  3299. +/**
  3300. + * Copyright © Magento, Inc. All rights reserved.
  3301. + * See COPYING.txt for license details.
  3302. + */
  3303. +
  3304. +namespace Magento\CatalogRule\Model\Indexer;
  3305. +
  3306. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface;
  3307. +use Magento\Framework\App\ResourceConnection;
  3308. +
  3309. +/**
  3310. + * @inheritDoc
  3311. + */
  3312. +class IndexerTableSwapper implements IndexerTableSwapperInterface
  3313. +{
  3314. + /**
  3315. + * Keys are original tables' names, values - created temporary tables.
  3316. + *
  3317. + * @var string[]
  3318. + */
  3319. + private $temporaryTables = [];
  3320. +
  3321. + /**
  3322. + * @var ResourceConnection
  3323. + */
  3324. + private $resourceConnection;
  3325. +
  3326. + /**
  3327. + * @param ResourceConnection $resource
  3328. + */
  3329. + public function __construct(ResourceConnection $resource)
  3330. + {
  3331. + $this->resourceConnection = $resource;
  3332. + }
  3333. +
  3334. + /**
  3335. + * Create temporary table based on given table to use instead of original.
  3336. + *
  3337. + * @param string $originalTableName
  3338. + *
  3339. + * @return string Created table name.
  3340. + * @throws \Throwable
  3341. + */
  3342. + private function createTemporaryTable(string $originalTableName): string
  3343. + {
  3344. + $temporaryTableName = $this->resourceConnection->getTableName(
  3345. + $originalTableName . '__temp' . $this->generateRandomSuffix()
  3346. + );
  3347. +
  3348. + $this->resourceConnection->getConnection()->query(
  3349. + sprintf(
  3350. + 'create table %s like %s',
  3351. + $temporaryTableName,
  3352. + $this->resourceConnection->getTableName($originalTableName)
  3353. + )
  3354. + );
  3355. +
  3356. + return $temporaryTableName;
  3357. + }
  3358. +
  3359. + /**
  3360. + * Random suffix for temporary tables not to conflict with each other.
  3361. + *
  3362. + * @return string
  3363. + */
  3364. + private function generateRandomSuffix(): string
  3365. + {
  3366. + return bin2hex(random_bytes(4));
  3367. + }
  3368. +
  3369. + /**
  3370. + * @inheritDoc
  3371. + */
  3372. + public function getWorkingTableName(string $originalTable): string
  3373. + {
  3374. + $originalTable = $this->resourceConnection->getTableName($originalTable);
  3375. + if (!array_key_exists($originalTable, $this->temporaryTables)) {
  3376. + $this->temporaryTables[$originalTable]
  3377. + = $this->createTemporaryTable($originalTable);
  3378. + }
  3379. +
  3380. + return $this->temporaryTables[$originalTable];
  3381. + }
  3382. +
  3383. + /**
  3384. + * @inheritDoc
  3385. + */
  3386. + public function swapIndexTables(array $originalTablesNames)
  3387. + {
  3388. + $toRename = [];
  3389. + /** @var string[] $toDrop */
  3390. + $toDrop = [];
  3391. + /** @var string[] $temporaryTablesRenamed */
  3392. + $temporaryTablesRenamed = [];
  3393. + //Renaming temporary tables to original tables' names, dropping old
  3394. + //tables.
  3395. + foreach ($originalTablesNames as $tableName) {
  3396. + $tableName = $this->resourceConnection->getTableName($tableName);
  3397. + $temporaryOriginalName = $this->resourceConnection->getTableName(
  3398. + $tableName . $this->generateRandomSuffix()
  3399. + );
  3400. + $temporaryTableName = $this->getWorkingTableName($tableName);
  3401. + $toRename[] = [
  3402. + 'oldName' => $tableName,
  3403. + 'newName' => $temporaryOriginalName
  3404. + ];
  3405. + $toRename[] = [
  3406. + 'oldName' => $temporaryTableName,
  3407. + 'newName' => $tableName
  3408. + ];
  3409. + $toDrop[] = $temporaryOriginalName;
  3410. + $temporaryTablesRenamed[] = $tableName;
  3411. + }
  3412. +
  3413. + //Swapping tables.
  3414. + $this->resourceConnection->getConnection()->renameTablesBatch($toRename);
  3415. + //Cleaning up.
  3416. + foreach ($temporaryTablesRenamed as $tableName) {
  3417. + unset($this->temporaryTables[$tableName]);
  3418. + }
  3419. + //Removing old ones.
  3420. + foreach ($toDrop as $tableName) {
  3421. + $this->resourceConnection->getConnection()->dropTable($tableName);
  3422. + }
  3423. + }
  3424. +}
  3425. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/ProductPriceCalculator.php b/vendor/magento/module-catalog-rule/Model/Indexer/ProductPriceCalculator.php
  3426. new file mode 100644
  3427. index 00000000000..02b499c75b7
  3428. --- /dev/null
  3429. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/ProductPriceCalculator.php
  3430. @@ -0,0 +1,61 @@
  3431. +<?php
  3432. +/**
  3433. + * Copyright © Magento, Inc. All rights reserved.
  3434. + * See COPYING.txt for license details.
  3435. + */
  3436. +
  3437. +namespace Magento\CatalogRule\Model\Indexer;
  3438. +
  3439. +/**
  3440. + * Product price calculation according rules settings.
  3441. + */
  3442. +class ProductPriceCalculator
  3443. +{
  3444. + /**
  3445. + * @var \Magento\Framework\Pricing\PriceCurrencyInterface
  3446. + */
  3447. + private $priceCurrency;
  3448. +
  3449. + /**
  3450. + * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
  3451. + */
  3452. + public function __construct(\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency)
  3453. + {
  3454. + $this->priceCurrency = $priceCurrency;
  3455. + }
  3456. +
  3457. + /**
  3458. + * Calculates product price.
  3459. + *
  3460. + * @param array $ruleData
  3461. + * @param null $productData
  3462. + * @return float
  3463. + */
  3464. + public function calculate($ruleData, $productData = null)
  3465. + {
  3466. + if ($productData !== null && isset($productData['rule_price'])) {
  3467. + $productPrice = $productData['rule_price'];
  3468. + } else {
  3469. + $productPrice = $ruleData['default_price'];
  3470. + }
  3471. +
  3472. + switch ($ruleData['action_operator']) {
  3473. + case 'to_fixed':
  3474. + $productPrice = min($ruleData['action_amount'], $productPrice);
  3475. + break;
  3476. + case 'to_percent':
  3477. + $productPrice = $productPrice * $ruleData['action_amount'] / 100;
  3478. + break;
  3479. + case 'by_fixed':
  3480. + $productPrice = max(0, $productPrice - $ruleData['action_amount']);
  3481. + break;
  3482. + case 'by_percent':
  3483. + $productPrice = $productPrice * (1 - $ruleData['action_amount'] / 100);
  3484. + break;
  3485. + default:
  3486. + $productPrice = 0;
  3487. + }
  3488. +
  3489. + return $this->priceCurrency->round($productPrice);
  3490. + }
  3491. +}
  3492. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleGroupWebsite.php b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleGroupWebsite.php
  3493. new file mode 100644
  3494. index 00000000000..482aaf4834d
  3495. --- /dev/null
  3496. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleGroupWebsite.php
  3497. @@ -0,0 +1,92 @@
  3498. +<?php
  3499. +/**
  3500. + * Copyright © Magento, Inc. All rights reserved.
  3501. + * See COPYING.txt for license details.
  3502. + */
  3503. +
  3504. +namespace Magento\CatalogRule\Model\Indexer;
  3505. +
  3506. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface as TableSwapper;
  3507. +use Magento\Framework\App\ObjectManager;
  3508. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  3509. +
  3510. +/**
  3511. + * Reindex information about rule relations with customer groups and websites.
  3512. + */
  3513. +class ReindexRuleGroupWebsite
  3514. +{
  3515. + /**
  3516. + * @var \Magento\Framework\Stdlib\DateTime\DateTime
  3517. + */
  3518. + private $dateTime;
  3519. +
  3520. + /**
  3521. + * @var \Magento\Framework\App\ResourceConnection
  3522. + */
  3523. + private $resource;
  3524. +
  3525. + /**
  3526. + * @var array
  3527. + */
  3528. + private $catalogRuleGroupWebsiteColumnsList = ['rule_id', 'customer_group_id', 'website_id'];
  3529. +
  3530. + /**
  3531. + * @var TableSwapper
  3532. + */
  3533. + private $tableSwapper;
  3534. +
  3535. + /**
  3536. + * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
  3537. + * @param \Magento\Framework\App\ResourceConnection $resource
  3538. + * @param ActiveTableSwitcher $activeTableSwitcher
  3539. + * @param TableSwapper|null $tableSwapper
  3540. + *
  3541. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  3542. + */
  3543. + public function __construct(
  3544. + \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
  3545. + \Magento\Framework\App\ResourceConnection $resource,
  3546. + ActiveTableSwitcher $activeTableSwitcher,
  3547. + TableSwapper $tableSwapper = null
  3548. + ) {
  3549. + $this->dateTime = $dateTime;
  3550. + $this->resource = $resource;
  3551. + $this->tableSwapper = $tableSwapper ?: ObjectManager::getInstance()->get(TableSwapper::class);
  3552. + }
  3553. +
  3554. + /**
  3555. + * Prepare and persist information about rule relations with customer groups and websites to index table.
  3556. + *
  3557. + * @param bool $useAdditionalTable
  3558. + * @return bool
  3559. + */
  3560. + public function execute($useAdditionalTable = false)
  3561. + {
  3562. + $connection = $this->resource->getConnection();
  3563. + $timestamp = $this->dateTime->gmtTimestamp();
  3564. +
  3565. + $indexTable = $this->resource->getTableName('catalogrule_group_website');
  3566. + $ruleProductTable = $this->resource->getTableName('catalogrule_product');
  3567. + if ($useAdditionalTable) {
  3568. + $indexTable = $this->resource->getTableName(
  3569. + $this->tableSwapper->getWorkingTableName('catalogrule_group_website')
  3570. + );
  3571. + $ruleProductTable = $this->resource->getTableName(
  3572. + $this->tableSwapper->getWorkingTableName('catalogrule_product')
  3573. + );
  3574. + }
  3575. +
  3576. + $connection->delete($indexTable);
  3577. + $select = $connection->select()->distinct(
  3578. + true
  3579. + )->from(
  3580. + $ruleProductTable,
  3581. + $this->catalogRuleGroupWebsiteColumnsList
  3582. + )->where(
  3583. + "{$timestamp} >= from_time AND (({$timestamp} <= to_time AND to_time > 0) OR to_time = 0)"
  3584. + );
  3585. + $query = $select->insertFromSelect($indexTable, $this->catalogRuleGroupWebsiteColumnsList);
  3586. + $connection->query($query);
  3587. + return true;
  3588. + }
  3589. +}
  3590. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProduct.php b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProduct.php
  3591. new file mode 100644
  3592. index 00000000000..f79f5aad6d6
  3593. --- /dev/null
  3594. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProduct.php
  3595. @@ -0,0 +1,123 @@
  3596. +<?php
  3597. +/**
  3598. + * Copyright © Magento, Inc. All rights reserved.
  3599. + * See COPYING.txt for license details.
  3600. + */
  3601. +
  3602. +namespace Magento\CatalogRule\Model\Indexer;
  3603. +
  3604. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface as TableSwapper;
  3605. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  3606. +use Magento\Framework\App\ObjectManager;
  3607. +
  3608. +/**
  3609. + * Reindex rule relations with products.
  3610. + */
  3611. +class ReindexRuleProduct
  3612. +{
  3613. + /**
  3614. + * @var \Magento\Framework\App\ResourceConnection
  3615. + */
  3616. + private $resource;
  3617. +
  3618. + /**
  3619. + * @var TableSwapper
  3620. + */
  3621. + private $tableSwapper;
  3622. +
  3623. + /**
  3624. + * @param \Magento\Framework\App\ResourceConnection $resource
  3625. + * @param ActiveTableSwitcher $activeTableSwitcher
  3626. + * @param TableSwapper|null $tableSwapper
  3627. + *
  3628. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  3629. + */
  3630. + public function __construct(
  3631. + \Magento\Framework\App\ResourceConnection $resource,
  3632. + ActiveTableSwitcher $activeTableSwitcher,
  3633. + TableSwapper $tableSwapper = null
  3634. + ) {
  3635. + $this->resource = $resource;
  3636. + $this->tableSwapper = $tableSwapper ?: ObjectManager::getInstance()->get(TableSwapper::class);
  3637. + }
  3638. +
  3639. + /**
  3640. + * Reindex information about rule relations with products.
  3641. + *
  3642. + * @param \Magento\CatalogRule\Model\Rule $rule
  3643. + * @param int $batchCount
  3644. + * @param bool $useAdditionalTable
  3645. + * @return bool
  3646. + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  3647. + * @SuppressWarnings(PHPMD.NPathComplexity)
  3648. + */
  3649. + public function execute(
  3650. + \Magento\CatalogRule\Model\Rule $rule,
  3651. + $batchCount,
  3652. + $useAdditionalTable = false
  3653. + ) {
  3654. + if (!$rule->getIsActive() || empty($rule->getWebsiteIds())) {
  3655. + return false;
  3656. + }
  3657. +
  3658. + $connection = $this->resource->getConnection();
  3659. + $websiteIds = $rule->getWebsiteIds();
  3660. + if (!is_array($websiteIds)) {
  3661. + $websiteIds = explode(',', $websiteIds);
  3662. + }
  3663. +
  3664. + \Magento\Framework\Profiler::start('__MATCH_PRODUCTS__');
  3665. + $productIds = $rule->getMatchingProductIds();
  3666. + \Magento\Framework\Profiler::stop('__MATCH_PRODUCTS__');
  3667. +
  3668. + $indexTable = $this->resource->getTableName('catalogrule_product');
  3669. + if ($useAdditionalTable) {
  3670. + $indexTable = $this->resource->getTableName(
  3671. + $this->tableSwapper->getWorkingTableName('catalogrule_product')
  3672. + );
  3673. + }
  3674. +
  3675. + $ruleId = $rule->getId();
  3676. + $customerGroupIds = $rule->getCustomerGroupIds();
  3677. + $fromTime = strtotime($rule->getFromDate());
  3678. + $toTime = strtotime($rule->getToDate());
  3679. + $toTime = $toTime ? $toTime + \Magento\CatalogRule\Model\Indexer\IndexBuilder::SECONDS_IN_DAY - 1 : 0;
  3680. + $sortOrder = (int)$rule->getSortOrder();
  3681. + $actionOperator = $rule->getSimpleAction();
  3682. + $actionAmount = $rule->getDiscountAmount();
  3683. + $actionStop = $rule->getStopRulesProcessing();
  3684. +
  3685. + $rows = [];
  3686. +
  3687. + foreach ($productIds as $productId => $validationByWebsite) {
  3688. + foreach ($websiteIds as $websiteId) {
  3689. + if (empty($validationByWebsite[$websiteId])) {
  3690. + continue;
  3691. + }
  3692. + foreach ($customerGroupIds as $customerGroupId) {
  3693. + $rows[] = [
  3694. + 'rule_id' => $ruleId,
  3695. + 'from_time' => $fromTime,
  3696. + 'to_time' => $toTime,
  3697. + 'website_id' => $websiteId,
  3698. + 'customer_group_id' => $customerGroupId,
  3699. + 'product_id' => $productId,
  3700. + 'action_operator' => $actionOperator,
  3701. + 'action_amount' => $actionAmount,
  3702. + 'action_stop' => $actionStop,
  3703. + 'sort_order' => $sortOrder,
  3704. + ];
  3705. +
  3706. + if (count($rows) == $batchCount) {
  3707. + $connection->insertMultiple($indexTable, $rows);
  3708. + $rows = [];
  3709. + }
  3710. + }
  3711. + }
  3712. + }
  3713. + if (!empty($rows)) {
  3714. + $connection->insertMultiple($indexTable, $rows);
  3715. + }
  3716. + return true;
  3717. + }
  3718. +}
  3719. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProductPrice.php b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProductPrice.php
  3720. new file mode 100644
  3721. index 00000000000..6a87be3c50a
  3722. --- /dev/null
  3723. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/ReindexRuleProductPrice.php
  3724. @@ -0,0 +1,168 @@
  3725. +<?php
  3726. +/**
  3727. + * Copyright © Magento, Inc. All rights reserved.
  3728. + * See COPYING.txt for license details.
  3729. + */
  3730. +
  3731. +namespace Magento\CatalogRule\Model\Indexer;
  3732. +
  3733. +/**
  3734. + * Reindex product prices according rule settings.
  3735. + */
  3736. +class ReindexRuleProductPrice
  3737. +{
  3738. + /**
  3739. + * @var \Magento\Store\Model\StoreManagerInterface
  3740. + */
  3741. + private $storeManager;
  3742. +
  3743. + /**
  3744. + * @var \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder
  3745. + */
  3746. + private $ruleProductsSelectBuilder;
  3747. +
  3748. + /**
  3749. + * @var \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator
  3750. + */
  3751. + private $productPriceCalculator;
  3752. +
  3753. + /**
  3754. + * @var \Magento\Framework\Stdlib\DateTime\DateTime
  3755. + */
  3756. + private $dateTime;
  3757. +
  3758. + /**
  3759. + * @var \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor
  3760. + */
  3761. + private $pricesPersistor;
  3762. +
  3763. + /**
  3764. + * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  3765. + * @param RuleProductsSelectBuilder $ruleProductsSelectBuilder
  3766. + * @param ProductPriceCalculator $productPriceCalculator
  3767. + * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
  3768. + * @param \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor $pricesPersistor
  3769. + */
  3770. + public function __construct(
  3771. + \Magento\Store\Model\StoreManagerInterface $storeManager,
  3772. + \Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder $ruleProductsSelectBuilder,
  3773. + \Magento\CatalogRule\Model\Indexer\ProductPriceCalculator $productPriceCalculator,
  3774. + \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
  3775. + \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor $pricesPersistor
  3776. + ) {
  3777. + $this->storeManager = $storeManager;
  3778. + $this->ruleProductsSelectBuilder = $ruleProductsSelectBuilder;
  3779. + $this->productPriceCalculator = $productPriceCalculator;
  3780. + $this->dateTime = $dateTime;
  3781. + $this->pricesPersistor = $pricesPersistor;
  3782. + }
  3783. +
  3784. + /**
  3785. + * Reindex product prices.
  3786. + *
  3787. + * @param int $batchCount
  3788. + * @param \Magento\Catalog\Model\Product|null $product
  3789. + * @param bool $useAdditionalTable
  3790. + * @return bool
  3791. + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  3792. + */
  3793. + public function execute(
  3794. + $batchCount,
  3795. + \Magento\Catalog\Model\Product $product = null,
  3796. + $useAdditionalTable = false
  3797. + ) {
  3798. + $fromDate = mktime(0, 0, 0, date('m'), date('d') - 1);
  3799. + $toDate = mktime(0, 0, 0, date('m'), date('d') + 1);
  3800. +
  3801. + /**
  3802. + * Update products rules prices per each website separately
  3803. + * because of max join limit in mysql
  3804. + */
  3805. + foreach ($this->storeManager->getWebsites() as $website) {
  3806. + $productsStmt = $this->ruleProductsSelectBuilder->build($website->getId(), $product, $useAdditionalTable);
  3807. + $dayPrices = [];
  3808. + $stopFlags = [];
  3809. + $prevKey = null;
  3810. +
  3811. + while ($ruleData = $productsStmt->fetch()) {
  3812. + $ruleProductId = $ruleData['product_id'];
  3813. + $productKey = $ruleProductId .
  3814. + '_' .
  3815. + $ruleData['website_id'] .
  3816. + '_' .
  3817. + $ruleData['customer_group_id'];
  3818. +
  3819. + if ($prevKey && $prevKey != $productKey) {
  3820. + $stopFlags = [];
  3821. + if (count($dayPrices) > $batchCount) {
  3822. + $this->pricesPersistor->execute($dayPrices, $useAdditionalTable);
  3823. + $dayPrices = [];
  3824. + }
  3825. + }
  3826. +
  3827. + $ruleData['from_time'] = $this->roundTime($ruleData['from_time']);
  3828. + $ruleData['to_time'] = $this->roundTime($ruleData['to_time']);
  3829. + /**
  3830. + * Build prices for each day
  3831. + */
  3832. + for ($time = $fromDate; $time <= $toDate; $time += IndexBuilder::SECONDS_IN_DAY) {
  3833. + if (($ruleData['from_time'] == 0 ||
  3834. + $time >= $ruleData['from_time']) && ($ruleData['to_time'] == 0 ||
  3835. + $time <= $ruleData['to_time'])
  3836. + ) {
  3837. + $priceKey = $time . '_' . $productKey;
  3838. +
  3839. + if (isset($stopFlags[$priceKey])) {
  3840. + continue;
  3841. + }
  3842. +
  3843. + if (!isset($dayPrices[$priceKey])) {
  3844. + $dayPrices[$priceKey] = [
  3845. + 'rule_date' => $time,
  3846. + 'website_id' => $ruleData['website_id'],
  3847. + 'customer_group_id' => $ruleData['customer_group_id'],
  3848. + 'product_id' => $ruleProductId,
  3849. + 'rule_price' => $this->productPriceCalculator->calculate($ruleData),
  3850. + 'latest_start_date' => $ruleData['from_time'],
  3851. + 'earliest_end_date' => $ruleData['to_time'],
  3852. + ];
  3853. + } else {
  3854. + $dayPrices[$priceKey]['rule_price'] = $this->productPriceCalculator->calculate(
  3855. + $ruleData,
  3856. + $dayPrices[$priceKey]
  3857. + );
  3858. + $dayPrices[$priceKey]['latest_start_date'] = max(
  3859. + $dayPrices[$priceKey]['latest_start_date'],
  3860. + $ruleData['from_time']
  3861. + );
  3862. + $dayPrices[$priceKey]['earliest_end_date'] = min(
  3863. + $dayPrices[$priceKey]['earliest_end_date'],
  3864. + $ruleData['to_time']
  3865. + );
  3866. + }
  3867. +
  3868. + if ($ruleData['action_stop']) {
  3869. + $stopFlags[$priceKey] = true;
  3870. + }
  3871. + }
  3872. + }
  3873. +
  3874. + $prevKey = $productKey;
  3875. + }
  3876. + $this->pricesPersistor->execute($dayPrices, $useAdditionalTable);
  3877. + }
  3878. + return true;
  3879. + }
  3880. +
  3881. + /**
  3882. + * @param int $timeStamp
  3883. + * @return int
  3884. + */
  3885. + private function roundTime($timeStamp)
  3886. + {
  3887. + if (is_numeric($timeStamp) && $timeStamp != 0) {
  3888. + $timeStamp = $this->dateTime->timestamp($this->dateTime->date('Y-m-d 00:00:00', $timeStamp));
  3889. + }
  3890. + return $timeStamp;
  3891. + }
  3892. +}
  3893. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductPricesPersistor.php b/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductPricesPersistor.php
  3894. new file mode 100644
  3895. index 00000000000..ad5a2d25948
  3896. --- /dev/null
  3897. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductPricesPersistor.php
  3898. @@ -0,0 +1,95 @@
  3899. +<?php
  3900. +/**
  3901. + * Copyright © Magento, Inc. All rights reserved.
  3902. + * See COPYING.txt for license details.
  3903. + */
  3904. +
  3905. +namespace Magento\CatalogRule\Model\Indexer;
  3906. +
  3907. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface as TableSwapper;
  3908. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  3909. +use Magento\Framework\App\ObjectManager;
  3910. +
  3911. +/**
  3912. + * Persist product prices to index table.
  3913. + */
  3914. +class RuleProductPricesPersistor
  3915. +{
  3916. + /**
  3917. + * @var \Magento\Framework\App\ResourceConnection
  3918. + */
  3919. + private $resource;
  3920. +
  3921. + /**
  3922. + * @var \Magento\Framework\Stdlib\DateTime
  3923. + */
  3924. + private $dateFormat;
  3925. +
  3926. + /**
  3927. + * @var TableSwapper
  3928. + */
  3929. + private $tableSwapper;
  3930. +
  3931. + /**
  3932. + * @param \Magento\Framework\Stdlib\DateTime $dateFormat
  3933. + * @param \Magento\Framework\App\ResourceConnection $resource
  3934. + * @param ActiveTableSwitcher $activeTableSwitcher
  3935. + * @param TableSwapper|null $tableSwapper
  3936. + *
  3937. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  3938. + */
  3939. + public function __construct(
  3940. + \Magento\Framework\Stdlib\DateTime $dateFormat,
  3941. + \Magento\Framework\App\ResourceConnection $resource,
  3942. + ActiveTableSwitcher $activeTableSwitcher,
  3943. + TableSwapper $tableSwapper = null
  3944. + ) {
  3945. + $this->dateFormat = $dateFormat;
  3946. + $this->resource = $resource;
  3947. + $this->tableSwapper = $tableSwapper ?: ObjectManager::getInstance()->get(TableSwapper::class);
  3948. + }
  3949. +
  3950. + /**
  3951. + * Persist prices data to index table.
  3952. + *
  3953. + * @param array $priceData
  3954. + * @param bool $useAdditionalTable
  3955. + * @return bool
  3956. + * @throws \Exception
  3957. + */
  3958. + public function execute(array $priceData, $useAdditionalTable = false)
  3959. + {
  3960. + if (empty($priceData)) {
  3961. + return false;
  3962. + }
  3963. +
  3964. + $connection = $this->resource->getConnection();
  3965. + $indexTable = $this->resource->getTableName('catalogrule_product_price');
  3966. + if ($useAdditionalTable) {
  3967. + $indexTable = $this->resource->getTableName(
  3968. + $this->tableSwapper->getWorkingTableName('catalogrule_product_price')
  3969. + );
  3970. + }
  3971. +
  3972. + $productIds = [];
  3973. +
  3974. + try {
  3975. + foreach ($priceData as $key => $data) {
  3976. + $productIds['product_id'] = $data['product_id'];
  3977. + $priceData[$key]['rule_date'] = $this->dateFormat->formatDate($data['rule_date'], false);
  3978. + $priceData[$key]['latest_start_date'] = $this->dateFormat->formatDate(
  3979. + $data['latest_start_date'],
  3980. + false
  3981. + );
  3982. + $priceData[$key]['earliest_end_date'] = $this->dateFormat->formatDate(
  3983. + $data['earliest_end_date'],
  3984. + false
  3985. + );
  3986. + }
  3987. + $connection->insertOnDuplicate($indexTable, $priceData);
  3988. + } catch (\Exception $e) {
  3989. + throw $e;
  3990. + }
  3991. + return true;
  3992. + }
  3993. +}
  3994. diff --git a/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductsSelectBuilder.php b/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductsSelectBuilder.php
  3995. new file mode 100644
  3996. index 00000000000..65ca07a524a
  3997. --- /dev/null
  3998. +++ b/vendor/magento/module-catalog-rule/Model/Indexer/RuleProductsSelectBuilder.php
  3999. @@ -0,0 +1,163 @@
  4000. +<?php
  4001. +/**
  4002. + * Copyright © Magento, Inc. All rights reserved.
  4003. + * See COPYING.txt for license details.
  4004. + */
  4005. +
  4006. +namespace Magento\CatalogRule\Model\Indexer;
  4007. +
  4008. +use Magento\CatalogRule\Api\IndexerTableSwapperInterface as TableSwapper;
  4009. +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
  4010. +use Magento\Framework\App\ObjectManager;
  4011. +
  4012. +/**
  4013. + * Build select for rule relation with product.
  4014. + */
  4015. +class RuleProductsSelectBuilder
  4016. +{
  4017. + /**
  4018. + * @var \Magento\Framework\App\ResourceConnection
  4019. + */
  4020. + private $resource;
  4021. +
  4022. + /**
  4023. + * @var \Magento\Eav\Model\Config
  4024. + */
  4025. + private $eavConfig;
  4026. +
  4027. + /**
  4028. + * @var \Magento\Store\Model\StoreManagerInterface
  4029. + */
  4030. + private $storeManager;
  4031. +
  4032. + /**
  4033. + * @var \Magento\Framework\EntityManager\MetadataPool
  4034. + */
  4035. + private $metadataPool;
  4036. +
  4037. + /**
  4038. + * @var TableSwapper
  4039. + */
  4040. + private $tableSwapper;
  4041. +
  4042. + /**
  4043. + * @param \Magento\Framework\App\ResourceConnection $resource
  4044. + * @param \Magento\Eav\Model\Config $eavConfig
  4045. + * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  4046. + * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
  4047. + * @param ActiveTableSwitcher $activeTableSwitcher
  4048. + * @param TableSwapper|null $tableSwapper
  4049. + *
  4050. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  4051. + */
  4052. + public function __construct(
  4053. + \Magento\Framework\App\ResourceConnection $resource,
  4054. + \Magento\Eav\Model\Config $eavConfig,
  4055. + \Magento\Store\Model\StoreManagerInterface $storeManager,
  4056. + \Magento\Framework\EntityManager\MetadataPool $metadataPool,
  4057. + ActiveTableSwitcher $activeTableSwitcher,
  4058. + TableSwapper $tableSwapper = null
  4059. + ) {
  4060. + $this->eavConfig = $eavConfig;
  4061. + $this->storeManager = $storeManager;
  4062. + $this->metadataPool = $metadataPool;
  4063. + $this->resource = $resource;
  4064. + $this->tableSwapper = $tableSwapper ?: ObjectManager::getInstance()->get(TableSwapper::class);
  4065. + }
  4066. +
  4067. + /**
  4068. + * Build select for indexer according passed parameters.
  4069. + *
  4070. + * @param int $websiteId
  4071. + * @param \Magento\Catalog\Model\Product|null $product
  4072. + * @param bool $useAdditionalTable
  4073. + * @return \Zend_Db_Statement_Interface
  4074. + */
  4075. + public function build(
  4076. + $websiteId,
  4077. + \Magento\Catalog\Model\Product $product = null,
  4078. + $useAdditionalTable = false
  4079. + ) {
  4080. + $connection = $this->resource->getConnection();
  4081. + $indexTable = $this->resource->getTableName('catalogrule_product');
  4082. + if ($useAdditionalTable) {
  4083. + $indexTable = $this->resource->getTableName(
  4084. + $this->tableSwapper->getWorkingTableName('catalogrule_product')
  4085. + );
  4086. + }
  4087. +
  4088. + /**
  4089. + * Sort order is important
  4090. + * It used for check stop price rule condition.
  4091. + * website_id customer_group_id product_id sort_order
  4092. + * 1 1 1 0
  4093. + * 1 1 1 1
  4094. + * 1 1 1 2
  4095. + * if row with sort order 1 will have stop flag we should exclude
  4096. + * all next rows for same product id from price calculation
  4097. + */
  4098. + $select = $connection->select()->from(
  4099. + ['rp' => $indexTable]
  4100. + )->order(
  4101. + ['rp.website_id', 'rp.customer_group_id', 'rp.product_id', 'rp.sort_order', 'rp.rule_id']
  4102. + );
  4103. +
  4104. + if ($product && $product->getEntityId()) {
  4105. + $select->where('rp.product_id=?', $product->getEntityId());
  4106. + }
  4107. +
  4108. + /**
  4109. + * Join default price and websites prices to result
  4110. + */
  4111. + $priceAttr = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'price');
  4112. + $priceTable = $priceAttr->getBackend()->getTable();
  4113. + $attributeId = $priceAttr->getId();
  4114. +
  4115. + $linkField = $this->metadataPool
  4116. + ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
  4117. + ->getLinkField();
  4118. + $select->join(
  4119. + ['e' => $this->resource->getTableName('catalog_product_entity')],
  4120. + sprintf('e.entity_id = rp.product_id'),
  4121. + []
  4122. + );
  4123. + $joinCondition = '%1$s.' . $linkField . '=e.' . $linkField . ' AND (%1$s.attribute_id='
  4124. + . $attributeId
  4125. + . ') and %1$s.store_id=%2$s';
  4126. +
  4127. + $select->join(
  4128. + ['pp_default' => $priceTable],
  4129. + sprintf($joinCondition, 'pp_default', \Magento\Store\Model\Store::DEFAULT_STORE_ID),
  4130. + []
  4131. + );
  4132. +
  4133. + $website = $this->storeManager->getWebsite($websiteId);
  4134. + $defaultGroup = $website->getDefaultGroup();
  4135. + if ($defaultGroup instanceof \Magento\Store\Model\Group) {
  4136. + $storeId = $defaultGroup->getDefaultStoreId();
  4137. + } else {
  4138. + $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID;
  4139. + }
  4140. +
  4141. + $select->joinInner(
  4142. + ['product_website' => $this->resource->getTableName('catalog_product_website')],
  4143. + 'product_website.product_id=rp.product_id '
  4144. + . 'AND product_website.website_id = rp.website_id '
  4145. + . 'AND product_website.website_id='
  4146. + . $websiteId,
  4147. + []
  4148. + );
  4149. +
  4150. + $tableAlias = 'pp' . $websiteId;
  4151. + $select->joinLeft(
  4152. + [$tableAlias => $priceTable],
  4153. + sprintf($joinCondition, $tableAlias, $storeId),
  4154. + []
  4155. + );
  4156. + $select->columns([
  4157. + 'default_price' => $connection->getIfNullSql($tableAlias . '.value', 'pp_default.value'),
  4158. + ]);
  4159. +
  4160. + return $connection->query($select);
  4161. + }
  4162. +}
  4163. diff --git a/vendor/magento/module-catalog-rule/Model/Rule.php b/vendor/magento/module-catalog-rule/Model/Rule.php
  4164. index f94bdb5fa80..ef1c286eb9b 100644
  4165. --- a/vendor/magento/module-catalog-rule/Model/Rule.php
  4166. +++ b/vendor/magento/module-catalog-rule/Model/Rule.php
  4167. @@ -505,9 +505,11 @@ class Rule extends \Magento\Rule\Model\AbstractModel implements \Magento\Catalog
  4168. public function afterSave()
  4169. {
  4170. if ($this->isObjectNew()) {
  4171. - $this->getMatchingProductIds();
  4172. - if (!empty($this->_productIds) && is_array($this->_productIds)) {
  4173. - $this->_ruleProductProcessor->reindexList($this->_productIds);
  4174. + if (!$this->_ruleProductProcessor->isIndexerScheduled()) {
  4175. + $this->getMatchingProductIds();
  4176. + if (!empty($this->_productIds) && is_array($this->_productIds)) {
  4177. + $this->_getResource()->addCommitCallback([$this, 'reindex']);
  4178. + }
  4179. }
  4180. } else {
  4181. $this->_ruleProductProcessor->getIndexer()->invalidate();
  4182. @@ -515,6 +517,16 @@ class Rule extends \Magento\Rule\Model\AbstractModel implements \Magento\Catalog
  4183. return parent::afterSave();
  4184. }
  4185.  
  4186. + /**
  4187. + * Init indexing process after rule save
  4188. + *
  4189. + * @return void
  4190. + */
  4191. + public function reindex()
  4192. + {
  4193. + $this->_ruleProductProcessor->reindexList($this->_productIds);
  4194. + }
  4195. +
  4196. /**
  4197. * {@inheritdoc}
  4198. *
  4199. diff --git a/vendor/magento/module-catalog-rule/Setup/UpgradeSchema.php b/vendor/magento/module-catalog-rule/Setup/UpgradeSchema.php
  4200. index ac667186a9a..c86f02c40a5 100644
  4201. --- a/vendor/magento/module-catalog-rule/Setup/UpgradeSchema.php
  4202. +++ b/vendor/magento/module-catalog-rule/Setup/UpgradeSchema.php
  4203. @@ -26,6 +26,31 @@ class UpgradeSchema implements UpgradeSchemaInterface
  4204. $this->removeSubProductDiscounts($setup);
  4205. }
  4206.  
  4207. + if (version_compare($context->getVersion(), '2.0.1.1.2', '<')) {
  4208. + $connection = $setup->getConnection();
  4209. + $connection->dropForeignKey(
  4210. + $setup->getTable('catalogrule_group_website'),
  4211. + $setup->getFkName(
  4212. + 'catalogrule_group_website',
  4213. + 'customer_group_id',
  4214. + 'customer_group',
  4215. + 'customer_group_id'
  4216. + )
  4217. + );
  4218. + $connection->dropForeignKey(
  4219. + $setup->getTable('catalogrule_group_website'),
  4220. + $setup->getFkName('catalogrule_group_website', 'rule_id', 'catalogrule', 'rule_id')
  4221. + );
  4222. + $connection->dropForeignKey(
  4223. + $setup->getTable('catalogrule_group_website'),
  4224. + $setup->getFkName('catalogrule_group_website', 'website_id', 'store_website', 'website_id')
  4225. + );
  4226. +
  4227. + $this->addReplicaTable($setup, 'catalogrule_product', 'catalogrule_product_replica');
  4228. + $this->addReplicaTable($setup, 'catalogrule_product_price', 'catalogrule_product_price_replica');
  4229. + $this->addReplicaTable($setup, 'catalogrule_group_website', 'catalogrule_group_website_replica');
  4230. + }
  4231. +
  4232. $setup->endSetup();
  4233. }
  4234.  
  4235. @@ -55,4 +80,22 @@ class UpgradeSchema implements UpgradeSchemaInterface
  4236. }
  4237. }
  4238. }
  4239. +
  4240. + /**
  4241. + * Add the replica table for existing one.
  4242. + *
  4243. + * @param SchemaSetupInterface $setup
  4244. + * @param string $existingTable
  4245. + * @param string $replicaTable
  4246. + * @return void
  4247. + */
  4248. + private function addReplicaTable(SchemaSetupInterface $setup, $existingTable, $replicaTable)
  4249. + {
  4250. + $sql = sprintf(
  4251. + 'CREATE TABLE IF NOT EXISTS %s LIKE %s',
  4252. + $setup->getTable($replicaTable),
  4253. + $setup->getTable($existingTable)
  4254. + );
  4255. + $setup->getConnection()->query($sql);
  4256. + }
  4257. }
  4258. diff --git a/vendor/magento/module-catalog-rule/etc/di.xml b/vendor/magento/module-catalog-rule/etc/di.xml
  4259. index 6783fd6d69b..1aaed9c3cbd 100644
  4260. --- a/vendor/magento/module-catalog-rule/etc/di.xml
  4261. +++ b/vendor/magento/module-catalog-rule/etc/di.xml
  4262. @@ -126,4 +126,5 @@
  4263. </argument>
  4264. </arguments>
  4265. </type>
  4266. + <preference for="Magento\CatalogRule\Api\IndexerTableSwapperInterface" type="Magento\CatalogRule\Model\Indexer\IndexerTableSwapper" />
  4267. </config>
  4268. diff --git a/vendor/magento/module-catalog-rule/etc/module.xml b/vendor/magento/module-catalog-rule/etc/module.xml
  4269. index 6a864895ffe..d0af39d3f01 100644
  4270. --- a/vendor/magento/module-catalog-rule/etc/module.xml
  4271. +++ b/vendor/magento/module-catalog-rule/etc/module.xml
  4272. @@ -6,7 +6,7 @@
  4273. */
  4274. -->
  4275. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  4276. - <module name="Magento_CatalogRule" setup_version="2.0.1">
  4277. + <module name="Magento_CatalogRule" setup_version="2.0.1.1.2">
  4278. <sequence>
  4279. <module name="Magento_Rule"/>
  4280. <module name="Magento_Catalog"/>
  4281. diff --git a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Aggregation/DataProvider.php b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Aggregation/DataProvider.php
  4282. index 495b22048b4..0c8c26904d1 100644
  4283. --- a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Aggregation/DataProvider.php
  4284. +++ b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Aggregation/DataProvider.php
  4285. @@ -6,6 +6,7 @@
  4286. namespace Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation;
  4287.  
  4288. use Magento\Catalog\Model\Product;
  4289. +use Magento\CatalogInventory\Model\Stock;
  4290. use Magento\Customer\Model\Session;
  4291. use Magento\Eav\Model\Config;
  4292. use Magento\Framework\App\ResourceConnection;
  4293. @@ -15,7 +16,6 @@ use Magento\Framework\DB\Ddl\Table;
  4294. use Magento\Framework\DB\Select;
  4295. use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface;
  4296. use Magento\Framework\Search\Request\BucketInterface;
  4297. -use Magento\CatalogInventory\Model\Stock;
  4298.  
  4299. /**
  4300. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  4301. diff --git a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/AliasResolver.php b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/AliasResolver.php
  4302. index 52a2c6ff40c..8f5a231b1dd 100644
  4303. --- a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/AliasResolver.php
  4304. +++ b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/AliasResolver.php
  4305. @@ -6,24 +6,22 @@
  4306.  
  4307. namespace Magento\CatalogSearch\Model\Adapter\Mysql\Filter;
  4308.  
  4309. +
  4310. use Magento\CatalogSearch\Model\Search\RequestGenerator;
  4311.  
  4312. /**
  4313. - * Purpose of class is to resolve table alias for Search Request filter.
  4314. + * Purpose of class is to resolve table alias for Search Request filter
  4315. */
  4316. class AliasResolver
  4317. {
  4318. /**
  4319. - * The suffix for stock status filter that may be added to the query beside the filter query.
  4320. + * The suffix for stock status filter that may be added to the query beside the filter query
  4321. * Used when showing of Out of Stock products is disabled.
  4322. */
  4323. const STOCK_FILTER_SUFFIX = '_stock';
  4324.  
  4325. /**
  4326. - * Returns alias of the filter in database.
  4327. - *
  4328. * @param \Magento\Framework\Search\Request\FilterInterface $filter
  4329. - *
  4330. * @return string alias of the filter in database
  4331. */
  4332. public function getAlias(\Magento\Framework\Search\Request\FilterInterface $filter)
  4333. @@ -41,7 +39,6 @@ class AliasResolver
  4334. $alias = $field . RequestGenerator::FILTER_SUFFIX;
  4335. break;
  4336. }
  4337. -
  4338. return $alias;
  4339. }
  4340. }
  4341. diff --git a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/Preprocessor.php b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/Preprocessor.php
  4342. index 05652445264..27a80aba56a 100644
  4343. --- a/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/Preprocessor.php
  4344. +++ b/vendor/magento/module-catalog-search/Model/Adapter/Mysql/Filter/Preprocessor.php
  4345. @@ -8,8 +8,11 @@ namespace Magento\CatalogSearch\Model\Adapter\Mysql\Filter;
  4346. use Magento\Catalog\Api\Data\ProductInterface;
  4347. use Magento\Catalog\Model\Product;
  4348. use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
  4349. +use Magento\CatalogInventory\Model\Stock;
  4350. use Magento\CatalogSearch\Model\Search\TableMapper;
  4351. use Magento\Eav\Model\Config;
  4352. +use Magento\Framework\App\Config\ScopeConfigInterface;
  4353. +use Magento\Framework\App\ObjectManager;
  4354. use Magento\Framework\App\ResourceConnection;
  4355. use Magento\Framework\App\ScopeResolverInterface;
  4356. use Magento\Framework\DB\Adapter\AdapterInterface;
  4357. @@ -17,11 +20,8 @@ use Magento\Framework\EntityManager\MetadataPool;
  4358. use Magento\Framework\Search\Adapter\Mysql\ConditionManager;
  4359. use Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface;
  4360. use Magento\Framework\Search\Request\FilterInterface;
  4361. -use Magento\Store\Model\Store;
  4362. -use Magento\CatalogInventory\Model\Stock;
  4363. -use Magento\Framework\App\Config\ScopeConfigInterface;
  4364. -use Magento\Framework\App\ObjectManager;
  4365. use Magento\Store\Model\ScopeInterface;
  4366. +use Magento\Store\Model\Store;
  4367.  
  4368. /**
  4369. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  4370. @@ -64,22 +64,11 @@ class Preprocessor implements PreprocessorInterface
  4371. private $metadataPool;
  4372.  
  4373. /**
  4374. - * @deprecated
  4375. - *
  4376. - * @var TableMapper
  4377. - */
  4378. - private $tableMapper;
  4379. -
  4380. - /**
  4381. - * Scope config.
  4382. - *
  4383. * @var ScopeConfigInterface
  4384. */
  4385. private $scopeConfig;
  4386.  
  4387. /**
  4388. - * Resolving table alias for Search Request filter.
  4389. - *
  4390. * @var AliasResolver
  4391. */
  4392. private $aliasResolver;
  4393. @@ -91,8 +80,9 @@ class Preprocessor implements PreprocessorInterface
  4394. * @param ResourceConnection $resource
  4395. * @param TableMapper $tableMapper
  4396. * @param string $attributePrefix
  4397. - * @param ScopeConfigInterface $scopeConfig
  4398. - * @param AliasResolver $aliasResolver
  4399. + * @param ScopeConfigInterface|null $scopeConfig
  4400. + * @param AliasResolver|null $aliasResolver
  4401. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  4402. */
  4403. public function __construct(
  4404. ConditionManager $conditionManager,
  4405. @@ -110,7 +100,6 @@ class Preprocessor implements PreprocessorInterface
  4406. $this->resource = $resource;
  4407. $this->connection = $resource->getConnection();
  4408. $this->attributePrefix = $attributePrefix;
  4409. - $this->tableMapper = $tableMapper;
  4410. $this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
  4411. $this->aliasResolver = $aliasResolver ?: ObjectManager::getInstance()->get(AliasResolver::class);
  4412. }
  4413. @@ -264,8 +253,6 @@ class Preprocessor implements PreprocessorInterface
  4414. }
  4415.  
  4416. /**
  4417. - * Checks if it is necessary to show out of stock products.
  4418. - *
  4419. * @return bool
  4420. */
  4421. private function isAddStockFilter()
  4422. @@ -274,7 +261,6 @@ class Preprocessor implements PreprocessorInterface
  4423. 'cataloginventory/options/show_out_of_stock',
  4424. ScopeInterface::SCOPE_STORE
  4425. );
  4426. -
  4427. return false === $isShowOutOfStock;
  4428. }
  4429.  
  4430. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Fulltext.php b/vendor/magento/module-catalog-search/Model/Indexer/Fulltext.php
  4431. index 0783bdb424e..fff770bc446 100644
  4432. --- a/vendor/magento/module-catalog-search/Model/Indexer/Fulltext.php
  4433. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Fulltext.php
  4434. @@ -6,11 +6,16 @@
  4435. namespace Magento\CatalogSearch\Model\Indexer;
  4436.  
  4437. use Magento\CatalogSearch\Model\Indexer\Fulltext\Action\FullFactory;
  4438. +use Magento\CatalogSearch\Model\Indexer\Scope\State;
  4439. use Magento\CatalogSearch\Model\ResourceModel\Fulltext as FulltextResource;
  4440. -use \Magento\Framework\Search\Request\Config as SearchRequestConfig;
  4441. +use Magento\Framework\App\ObjectManager;
  4442. +use Magento\Framework\Search\Request\Config as SearchRequestConfig;
  4443. use Magento\Framework\Search\Request\DimensionFactory;
  4444. use Magento\Store\Model\StoreManagerInterface;
  4445.  
  4446. +/**
  4447. + * Provide functionality for Fulltext Search indexing
  4448. + */
  4449. class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface
  4450. {
  4451. /**
  4452. @@ -18,34 +23,51 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\F
  4453. */
  4454. const INDEXER_ID = 'catalogsearch_fulltext';
  4455.  
  4456. - /** @var array index structure */
  4457. + /**
  4458. + * @var array index structure
  4459. + */
  4460. protected $data;
  4461.  
  4462. /**
  4463. * @var IndexerHandlerFactory
  4464. */
  4465. private $indexerHandlerFactory;
  4466. +
  4467. /**
  4468. * @var StoreManagerInterface
  4469. */
  4470. private $storeManager;
  4471. +
  4472. /**
  4473. - * @var DimensionFactory
  4474. + * @var \Magento\Framework\Search\Request\DimensionFactory
  4475. */
  4476. private $dimensionFactory;
  4477. +
  4478. /**
  4479. - * @var Full
  4480. + * @var \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\Full
  4481. */
  4482. private $fullAction;
  4483. +
  4484. /**
  4485. * @var FulltextResource
  4486. */
  4487. private $fulltextResource;
  4488. +
  4489. /**
  4490. - * @var SearchRequestConfig
  4491. + * @var \Magento\Framework\Search\Request\Config
  4492. */
  4493. private $searchRequestConfig;
  4494.  
  4495. + /**
  4496. + * @var IndexSwitcherInterface
  4497. + */
  4498. + private $indexSwitcher;
  4499. +
  4500. + /**
  4501. + * @var \Magento\CatalogSearch\Model\Indexer\Scope\State
  4502. + */
  4503. + private $indexScopeState;
  4504. +
  4505. /**
  4506. * @param FullFactory $fullActionFactory
  4507. * @param IndexerHandlerFactory $indexerHandlerFactory
  4508. @@ -54,6 +76,8 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\F
  4509. * @param FulltextResource $fulltextResource
  4510. * @param SearchRequestConfig $searchRequestConfig
  4511. * @param array $data
  4512. + * @param IndexSwitcherInterface $indexSwitcher
  4513. + * @param Scope\State $indexScopeState
  4514. */
  4515. public function __construct(
  4516. FullFactory $fullActionFactory,
  4517. @@ -62,7 +86,9 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\F
  4518. DimensionFactory $dimensionFactory,
  4519. FulltextResource $fulltextResource,
  4520. SearchRequestConfig $searchRequestConfig,
  4521. - array $data
  4522. + array $data,
  4523. + IndexSwitcherInterface $indexSwitcher = null,
  4524. + State $indexScopeState = null
  4525. ) {
  4526. $this->fullAction = $fullActionFactory->create(['data' => $data]);
  4527. $this->indexerHandlerFactory = $indexerHandlerFactory;
  4528. @@ -71,6 +97,14 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\F
  4529. $this->fulltextResource = $fulltextResource;
  4530. $this->searchRequestConfig = $searchRequestConfig;
  4531. $this->data = $data;
  4532. + if (null === $indexSwitcher) {
  4533. + $indexSwitcher = ObjectManager::getInstance()->get(IndexSwitcherInterface::class);
  4534. + }
  4535. + if (null === $indexScopeState) {
  4536. + $indexScopeState = ObjectManager::getInstance()->get(State::class);
  4537. + }
  4538. + $this->indexSwitcher = $indexSwitcher;
  4539. + $this->indexScopeState = $indexScopeState;
  4540. }
  4541.  
  4542. /**
  4543. @@ -106,10 +140,14 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\F
  4544. 'data' => $this->data
  4545. ]);
  4546. foreach ($storeIds as $storeId) {
  4547. - $dimension = $this->dimensionFactory->create(['name' => 'scope', 'value' => $storeId]);
  4548. - $saveHandler->cleanIndex([$dimension]);
  4549. - $saveHandler->saveIndex([$dimension], $this->fullAction->rebuildStoreIndex($storeId));
  4550. + $dimensions = [$this->dimensionFactory->create(['name' => 'scope', 'value' => $storeId])];
  4551. + $this->indexScopeState->useTemporaryIndex();
  4552. +
  4553. + $saveHandler->cleanIndex($dimensions);
  4554. + $saveHandler->saveIndex($dimensions, $this->fullAction->rebuildStoreIndex($storeId));
  4555.  
  4556. + $this->indexSwitcher->switchIndex($dimensions);
  4557. + $this->indexScopeState->useRegularIndex();
  4558. }
  4559. $this->fulltextResource->resetSearchResults();
  4560. $this->searchRequestConfig->reset();
  4561. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/IndexStructure.php b/vendor/magento/module-catalog-search/Model/Indexer/IndexStructure.php
  4562. index 43c3eb670f4..92eff50cfc1 100644
  4563. --- a/vendor/magento/module-catalog-search/Model/Indexer/IndexStructure.php
  4564. +++ b/vendor/magento/module-catalog-search/Model/Indexer/IndexStructure.php
  4565. @@ -12,6 +12,7 @@ use Magento\Framework\DB\Ddl\Table;
  4566. use Magento\Framework\Search\Request\Dimension;
  4567. use Magento\Framework\Indexer\IndexStructureInterface;
  4568. use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver;
  4569. +use Magento\Framework\Search\Request\IndexScopeResolverInterface;
  4570.  
  4571. class IndexStructure implements IndexStructureInterface
  4572. {
  4573. @@ -19,6 +20,7 @@ class IndexStructure implements IndexStructureInterface
  4574. * @var Resource
  4575. */
  4576. private $resource;
  4577. +
  4578. /**
  4579. * @var IndexScopeResolver
  4580. */
  4581. @@ -26,11 +28,11 @@ class IndexStructure implements IndexStructureInterface
  4582.  
  4583. /**
  4584. * @param ResourceConnection $resource
  4585. - * @param IndexScopeResolver $indexScopeResolver
  4586. + * @param IndexScopeResolverInterface $indexScopeResolver
  4587. */
  4588. public function __construct(
  4589. ResourceConnection $resource,
  4590. - IndexScopeResolver $indexScopeResolver
  4591. + IndexScopeResolverInterface $indexScopeResolver
  4592. ) {
  4593. $this->resource = $resource;
  4594. $this->indexScopeResolver = $indexScopeResolver;
  4595. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherInterface.php b/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherInterface.php
  4596. new file mode 100644
  4597. index 00000000000..ba5fb461dde
  4598. --- /dev/null
  4599. +++ b/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherInterface.php
  4600. @@ -0,0 +1,22 @@
  4601. +<?php
  4602. +/**
  4603. + * Copyright © 2016 Magento. All rights reserved.
  4604. + * See COPYING.txt for license details.
  4605. + */
  4606. +namespace Magento\CatalogSearch\Model\Indexer;
  4607. +
  4608. +/**
  4609. + * Provides a functionality to replace main index with its temporary representation
  4610. + */
  4611. +interface IndexSwitcherInterface
  4612. +{
  4613. + /**
  4614. + * Switch current index with temporary index
  4615. + *
  4616. + * It will drop current index table and rename temporary index table to the current index table.
  4617. + *
  4618. + * @param array $dimensions
  4619. + * @return void
  4620. + */
  4621. + public function switchIndex(array $dimensions);
  4622. +}
  4623. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherProxy.php b/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherProxy.php
  4624. new file mode 100644
  4625. index 00000000000..2ce093ed99e
  4626. --- /dev/null
  4627. +++ b/vendor/magento/module-catalog-search/Model/Indexer/IndexSwitcherProxy.php
  4628. @@ -0,0 +1,100 @@
  4629. +<?php
  4630. +/**
  4631. + * Copyright © 2016 Magento. All rights reserved.
  4632. + * See COPYING.txt for license details.
  4633. + */
  4634. +
  4635. +namespace Magento\CatalogSearch\Model\Indexer;
  4636. +
  4637. +use Magento\Framework\App\Config\ScopeConfigInterface;
  4638. +use Magento\Framework\ObjectManagerInterface;
  4639. +use Magento\Store\Model\ScopeInterface;
  4640. +
  4641. +/**
  4642. + * Proxy for adapter-specific index switcher
  4643. + */
  4644. +class IndexSwitcherProxy implements IndexSwitcherInterface
  4645. +{
  4646. + /**
  4647. + * Object Manager instance
  4648. + *
  4649. + * @var ObjectManagerInterface
  4650. + */
  4651. + private $objectManager = null;
  4652. +
  4653. + /**
  4654. + * Instance name to create
  4655. + *
  4656. + * @var string
  4657. + */
  4658. + private $handlers;
  4659. +
  4660. + /**
  4661. + * @var ScopeConfigInterface
  4662. + */
  4663. + private $scopeConfig;
  4664. +
  4665. + /**
  4666. + * Configuration path by which current indexer handler stored
  4667. + *
  4668. + * @var string
  4669. + */
  4670. + private $configPath;
  4671. +
  4672. + /**
  4673. + * Factory constructor
  4674. + *
  4675. + * @param ObjectManagerInterface $objectManager
  4676. + * @param ScopeConfigInterface $scopeConfig
  4677. + * @param string $configPath
  4678. + * @param string[] $handlers
  4679. + */
  4680. + public function __construct(
  4681. + ObjectManagerInterface $objectManager,
  4682. + ScopeConfigInterface $scopeConfig,
  4683. + $configPath,
  4684. + array $handlers = []
  4685. + ) {
  4686. + $this->objectManager = $objectManager;
  4687. + $this->scopeConfig = $scopeConfig;
  4688. + $this->configPath = $configPath;
  4689. + $this->handlers = $handlers;
  4690. + }
  4691. +
  4692. + /**
  4693. + * {@inheritDoc}
  4694. + *
  4695. + * As index switcher is an optional part of the search SPI, it may be not defined by a search engine.
  4696. + * It is especially reasonable for search engines with pre-defined indexes declaration (like old SOLR and Sphinx)
  4697. + * which cannot create temporary indexes on the fly.
  4698. + * That's the reason why this method do nothing for the case
  4699. + * when switcher is not defined for a specific search engine.
  4700. + */
  4701. + public function switchIndex(array $dimensions)
  4702. + {
  4703. + $currentHandler = $this->scopeConfig->getValue($this->configPath, ScopeInterface::SCOPE_STORE);
  4704. + if (!isset($this->handlers[$currentHandler])) {
  4705. + return;
  4706. + }
  4707. + $this->create($currentHandler)->switchIndex($dimensions);
  4708. + }
  4709. +
  4710. + /**
  4711. + * Create indexer handler
  4712. + *
  4713. + * @param string $handler
  4714. + * @return IndexSwitcherInterface
  4715. + */
  4716. + private function create($handler)
  4717. + {
  4718. + $indexSwitcher = $this->objectManager->create($this->handlers[$handler]);
  4719. +
  4720. + if (!$indexSwitcher instanceof IndexSwitcherInterface) {
  4721. + throw new \InvalidArgumentException(
  4722. + $handler . ' index switcher doesn\'t implement ' . IndexSwitcherInterface::class
  4723. + );
  4724. + }
  4725. +
  4726. + return $indexSwitcher;
  4727. + }
  4728. +}
  4729. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/IndexerHandler.php b/vendor/magento/module-catalog-search/Model/Indexer/IndexerHandler.php
  4730. index 2d98f3c06b6..5051b76a41d 100644
  4731. --- a/vendor/magento/module-catalog-search/Model/Indexer/IndexerHandler.php
  4732. +++ b/vendor/magento/module-catalog-search/Model/Indexer/IndexerHandler.php
  4733. @@ -7,13 +7,11 @@ namespace Magento\CatalogSearch\Model\Indexer;
  4734.  
  4735. use Magento\Eav\Model\Config;
  4736. use Magento\Framework\App\ResourceConnection;
  4737. -use Magento\Framework\DB\Adapter\AdapterInterface;
  4738. use Magento\Framework\Indexer\SaveHandler\IndexerInterface;
  4739. use Magento\Framework\Indexer\IndexStructureInterface;
  4740. use Magento\Framework\Search\Request\Dimension;
  4741. use Magento\Framework\Search\Request\IndexScopeResolverInterface;
  4742. use Magento\Framework\Indexer\SaveHandler\Batch;
  4743. -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver;
  4744.  
  4745. class IndexerHandler implements IndexerInterface
  4746. {
  4747. @@ -62,7 +60,7 @@ class IndexerHandler implements IndexerInterface
  4748. * @param ResourceConnection $resource
  4749. * @param Config $eavConfig
  4750. * @param Batch $batch
  4751. - * @param \Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver $indexScopeResolver
  4752. + * @param IndexScopeResolverInterface $indexScopeResolver
  4753. * @param array $data
  4754. * @param int $batchSize
  4755. */
  4756. @@ -71,7 +69,7 @@ class IndexerHandler implements IndexerInterface
  4757. ResourceConnection $resource,
  4758. Config $eavConfig,
  4759. Batch $batch,
  4760. - IndexScopeResolver $indexScopeResolver,
  4761. + IndexScopeResolverInterface $indexScopeResolver,
  4762. array $data,
  4763. $batchSize = 100
  4764. ) {
  4765. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexSwitcher.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexSwitcher.php
  4766. new file mode 100644
  4767. index 00000000000..87a7b7110d3
  4768. --- /dev/null
  4769. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexSwitcher.php
  4770. @@ -0,0 +1,76 @@
  4771. +<?php
  4772. +/**
  4773. + * Copyright © 2016 Magento. All rights reserved.
  4774. + * See COPYING.txt for license details.
  4775. + */
  4776. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  4777. +
  4778. +use Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface;
  4779. +use Magento\Framework\App\ResourceConnection;
  4780. +use Magento\Framework\Search\Request\IndexScopeResolverInterface;
  4781. +
  4782. +/**
  4783. + * Provides a functionality to replace main index with its temporary representation
  4784. + */
  4785. +class IndexSwitcher implements IndexSwitcherInterface
  4786. +{
  4787. + /**
  4788. + * @var Resource
  4789. + */
  4790. + private $resource;
  4791. +
  4792. + /**
  4793. + * @var ScopeProxy
  4794. + */
  4795. + private $resolver;
  4796. +
  4797. + /**
  4798. + * @var State
  4799. + */
  4800. + private $state;
  4801. +
  4802. + /**
  4803. + * @param ResourceConnection $resource
  4804. + * @param IndexScopeResolverInterface $indexScopeResolver
  4805. + * @param State $state
  4806. + */
  4807. + public function __construct(
  4808. + ResourceConnection $resource,
  4809. + IndexScopeResolverInterface $indexScopeResolver,
  4810. + State $state
  4811. + ) {
  4812. + $this->resource = $resource;
  4813. + $this->resolver = $indexScopeResolver;
  4814. + $this->state = $state;
  4815. + }
  4816. +
  4817. + /**
  4818. + * {@inheritdoc}
  4819. + * @throws IndexTableNotExistException
  4820. + */
  4821. + public function switchIndex(array $dimensions)
  4822. + {
  4823. + if (State::USE_TEMPORARY_INDEX === $this->state->getState()) {
  4824. + $index = \Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID;
  4825. +
  4826. + $temporalIndexTable = $this->resolver->resolve($index, $dimensions);
  4827. + if (!$this->resource->getConnection()->isTableExists($temporalIndexTable)) {
  4828. + throw new IndexTableNotExistException(
  4829. + __(
  4830. + "Temporary table for index $index doesn't exist,"
  4831. + . " which is inconsistent with state of scope resolver"
  4832. + )
  4833. + );
  4834. + }
  4835. +
  4836. + $this->state->useRegularIndex();
  4837. + $tableName = $this->resolver->resolve($index, $dimensions);
  4838. + if ($this->resource->getConnection()->isTableExists($tableName)) {
  4839. + $this->resource->getConnection()->dropTable($tableName);
  4840. + }
  4841. +
  4842. + $this->resource->getConnection()->renameTable($temporalIndexTable, $tableName);
  4843. + $this->state->useTemporaryIndex();
  4844. + }
  4845. + }
  4846. +}
  4847. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexTableNotExistException.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexTableNotExistException.php
  4848. new file mode 100644
  4849. index 00000000000..6974f8c278a
  4850. --- /dev/null
  4851. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/IndexTableNotExistException.php
  4852. @@ -0,0 +1,18 @@
  4853. +<?php
  4854. +/**
  4855. + * Copyright © 2016 Magento. All rights reserved.
  4856. + * See COPYING.txt for license details.
  4857. + */
  4858. +
  4859. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  4860. +
  4861. +
  4862. +use Magento\Framework\Exception\LocalizedException;
  4863. +
  4864. +/**
  4865. + * Exception which represents situation where temporary index table should be used somewhere,
  4866. + * but it does not exist in a database
  4867. + */
  4868. +class IndexTableNotExistException extends LocalizedException
  4869. +{
  4870. +}
  4871. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/ScopeProxy.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/ScopeProxy.php
  4872. new file mode 100644
  4873. index 00000000000..14832af303b
  4874. --- /dev/null
  4875. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/ScopeProxy.php
  4876. @@ -0,0 +1,76 @@
  4877. +<?php
  4878. +/**
  4879. + * Copyright © 2016 Magento. All rights reserved.
  4880. + * See COPYING.txt for license details.
  4881. + */
  4882. +
  4883. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  4884. +
  4885. +
  4886. +use Magento\Framework\Search\Request\Dimension;
  4887. +
  4888. +/**
  4889. + * Implementation of IndexScopeResolverInterface which resolves index scope dynamically
  4890. + * depending on current scope state
  4891. + */
  4892. +class ScopeProxy implements \Magento\Framework\Search\Request\IndexScopeResolverInterface
  4893. +{
  4894. + /**
  4895. + * Object Manager instance
  4896. + *
  4897. + * @var \Magento\Framework\ObjectManagerInterface
  4898. + */
  4899. + private $objectManager;
  4900. +
  4901. + /**
  4902. + * @var array
  4903. + */
  4904. + private $states = [];
  4905. +
  4906. + /**
  4907. + * @var State
  4908. + */
  4909. + private $scopeState;
  4910. +
  4911. + /**
  4912. + * Factory constructor
  4913. + *
  4914. + * @param \Magento\Framework\ObjectManagerInterface $objectManager
  4915. + * @param State $scopeState
  4916. + * @param array $states
  4917. + */
  4918. + public function __construct(
  4919. + \Magento\Framework\ObjectManagerInterface $objectManager,
  4920. + State $scopeState,
  4921. + array $states
  4922. + ) {
  4923. + $this->objectManager = $objectManager;
  4924. + $this->scopeState = $scopeState;
  4925. + $this->states = $states;
  4926. + }
  4927. +
  4928. + /**
  4929. + * Creates class instance with specified parameters
  4930. + *
  4931. + * @param string $state
  4932. + * @return \Magento\Framework\Search\Request\IndexScopeResolverInterface
  4933. + * @throws UnknownStateException
  4934. + */
  4935. + private function create($state)
  4936. + {
  4937. + if (!array_key_exists($state, $this->states)) {
  4938. + throw new UnknownStateException(__("Requested resolver for unknown indexer state: $state"));
  4939. + }
  4940. + return $this->objectManager->create($this->states[$state]);
  4941. + }
  4942. +
  4943. + /**
  4944. + * @param string $index
  4945. + * @param Dimension[] $dimensions
  4946. + * @return string
  4947. + */
  4948. + public function resolve($index, array $dimensions)
  4949. + {
  4950. + return $this->create($this->scopeState->getState())->resolve($index, $dimensions);
  4951. + }
  4952. +}
  4953. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/State.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/State.php
  4954. new file mode 100644
  4955. index 00000000000..2bba29ae8d8
  4956. --- /dev/null
  4957. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/State.php
  4958. @@ -0,0 +1,65 @@
  4959. +<?php
  4960. +/**
  4961. + * Copyright © 2016 Magento. All rights reserved.
  4962. + * See COPYING.txt for license details.
  4963. + */
  4964. +
  4965. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  4966. +
  4967. +
  4968. +use Magento\Framework\App\ResourceConnection;
  4969. +use Magento\Framework\App\ScopeResolverInterface;
  4970. +use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver;
  4971. +use Magento\Framework\Search\Request\Dimension;
  4972. +use Magento\Framework\Search\Request\IndexScopeResolverInterface;
  4973. +
  4974. +/**
  4975. + * This class represents state that defines which table should be used during indexation process
  4976. + *
  4977. + * There are two possible states:
  4978. + * - use_temporary_table
  4979. + * - use_main_table
  4980. + *
  4981. + * The 'use_main_table' state means that default indexer table should be used.
  4982. + *
  4983. + * The 'use_temporary_table' state is an opposite for 'use_main_table'
  4984. + * which means that default indexer table should be left unchanged during indexation
  4985. + * and temporary table should be used instead.
  4986. + *
  4987. + */
  4988. +class State
  4989. +{
  4990. + const USE_TEMPORARY_INDEX = 'use_temporary_table';
  4991. + const USE_REGULAR_INDEX = 'use_main_table';
  4992. +
  4993. + /**
  4994. + * @var string
  4995. + */
  4996. + private $state = self::USE_REGULAR_INDEX;
  4997. +
  4998. + /**
  4999. + * Set the state to use temporary Index
  5000. + * @return void
  5001. + */
  5002. + public function useTemporaryIndex()
  5003. + {
  5004. + $this->state = self::USE_TEMPORARY_INDEX;
  5005. + }
  5006. +
  5007. + /**
  5008. + * Set the state to use regular Index
  5009. + * @return void
  5010. + */
  5011. + public function useRegularIndex()
  5012. + {
  5013. + $this->state = self::USE_REGULAR_INDEX;
  5014. + }
  5015. +
  5016. + /**
  5017. + * @return string
  5018. + */
  5019. + public function getState()
  5020. + {
  5021. + return $this->state;
  5022. + }
  5023. +}
  5024. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/TemporaryResolver.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/TemporaryResolver.php
  5025. new file mode 100644
  5026. index 00000000000..51037eb637c
  5027. --- /dev/null
  5028. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/TemporaryResolver.php
  5029. @@ -0,0 +1,43 @@
  5030. +<?php
  5031. +/**
  5032. + * Copyright © 2016 Magento. All rights reserved.
  5033. + * See COPYING.txt for license details.
  5034. + */
  5035. +
  5036. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  5037. +
  5038. +
  5039. +use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver;
  5040. +use Magento\Framework\Search\Request\Dimension;
  5041. +
  5042. +/**
  5043. + * Resolves name of a temporary table for indexation
  5044. + */
  5045. +class TemporaryResolver implements \Magento\Framework\Search\Request\IndexScopeResolverInterface
  5046. +{
  5047. + /**
  5048. + * @var IndexScopeResolver
  5049. + */
  5050. + private $indexScopeResolver;
  5051. +
  5052. + /**
  5053. + * @inheritDoc
  5054. + */
  5055. + public function __construct(IndexScopeResolver $indexScopeResolver)
  5056. + {
  5057. + $this->indexScopeResolver = $indexScopeResolver;
  5058. + }
  5059. +
  5060. + /**
  5061. + * @param string $index
  5062. + * @param Dimension[] $dimensions
  5063. + * @return string
  5064. + */
  5065. + public function resolve($index, array $dimensions)
  5066. + {
  5067. + $tableName = $this->indexScopeResolver->resolve($index, $dimensions);
  5068. + $tableName .= \Magento\Framework\Indexer\Table\StrategyInterface::TMP_SUFFIX;
  5069. +
  5070. + return $tableName;
  5071. + }
  5072. +}
  5073. diff --git a/vendor/magento/module-catalog-search/Model/Indexer/Scope/UnknownStateException.php b/vendor/magento/module-catalog-search/Model/Indexer/Scope/UnknownStateException.php
  5074. new file mode 100644
  5075. index 00000000000..04803ef2748
  5076. --- /dev/null
  5077. +++ b/vendor/magento/module-catalog-search/Model/Indexer/Scope/UnknownStateException.php
  5078. @@ -0,0 +1,18 @@
  5079. +<?php
  5080. +/**
  5081. + * Copyright © 2016 Magento. All rights reserved.
  5082. + * See COPYING.txt for license details.
  5083. + */
  5084. +
  5085. +namespace Magento\CatalogSearch\Model\Indexer\Scope;
  5086. +
  5087. +
  5088. +use Magento\Framework\Exception\LocalizedException;
  5089. +
  5090. +/**
  5091. + * Exception for situation where used state which is not defined in configuration
  5092. + */
  5093. +class UnknownStateException extends LocalizedException
  5094. +{
  5095. +
  5096. +}
  5097. diff --git a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/ExclusionStrategy.php b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/ExclusionStrategy.php
  5098. index 03675f27cac..9575f6efe51 100644
  5099. --- a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/ExclusionStrategy.php
  5100. +++ b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/ExclusionStrategy.php
  5101. @@ -9,27 +9,21 @@ namespace Magento\CatalogSearch\Model\Search\FilterMapper;
  5102. use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
  5103.  
  5104. /**
  5105. - * Strategy which processes exclusions from general rules.
  5106. + * Strategy which processes exclusions from general rules
  5107. */
  5108. class ExclusionStrategy implements FilterStrategyInterface
  5109. {
  5110. /**
  5111. - * Resource connection.
  5112. - *
  5113. * @var \Magento\Framework\App\ResourceConnection
  5114. */
  5115. - private $resourceConnection;
  5116. + private $resourceConnection;
  5117.  
  5118. /**
  5119. - * Resolving table alias for Search Request filter.
  5120. - *
  5121. * @var AliasResolver
  5122. */
  5123. private $aliasResolver;
  5124.  
  5125. /**
  5126. - * Store manager interface.
  5127. - *
  5128. * @var \Magento\Store\Model\StoreManagerInterface
  5129. */
  5130. private $storeManager;
  5131. @@ -62,7 +56,9 @@ class ExclusionStrategy implements FilterStrategyInterface
  5132. $alias = $this->aliasResolver->getAlias($filter);
  5133. $tableName = $this->resourceConnection->getTableName('catalog_product_index_price');
  5134. $select->joinInner(
  5135. - [$alias => $tableName],
  5136. + [
  5137. + $alias => $tableName
  5138. + ],
  5139. $this->resourceConnection->getConnection()->quoteInto(
  5140. 'search_index.entity_id = price_index.entity_id AND price_index.website_id = ?',
  5141. $this->storeManager->getWebsite()->getId()
  5142. @@ -74,13 +70,14 @@ class ExclusionStrategy implements FilterStrategyInterface
  5143. $alias = $this->aliasResolver->getAlias($filter);
  5144. $tableName = $this->resourceConnection->getTableName('catalog_category_product_index');
  5145. $select->joinInner(
  5146. - [$alias => $tableName],
  5147. + [
  5148. + $alias => $tableName
  5149. + ],
  5150. 'search_index.entity_id = category_ids_index.product_id',
  5151. []
  5152. );
  5153. $isApplied = true;
  5154. }
  5155. -
  5156. return $isApplied;
  5157. }
  5158. }
  5159. diff --git a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterContext.php b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterContext.php
  5160. index e1901afce4f..d8d3efc65e7 100644
  5161. --- a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterContext.php
  5162. +++ b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterContext.php
  5163. @@ -6,47 +6,38 @@
  5164.  
  5165. namespace Magento\CatalogSearch\Model\Search\FilterMapper;
  5166.  
  5167. +
  5168. use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
  5169. use Magento\Eav\Model\Config as EavConfig;
  5170. use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
  5171.  
  5172. /**
  5173. - * FilterContext represents a Context of the Strategy pattern.
  5174. - * Its responsibility is to choose appropriate strategy to apply passed filter to the Select.
  5175. + * FilterContext represents a Context of the Strategy pattern
  5176. + * Its responsibility is to choose appropriate strategy to apply passed filter to the Select
  5177. */
  5178. class FilterContext implements FilterStrategyInterface
  5179. {
  5180. /**
  5181. - * Strategy which processes exclusions from general rules.
  5182. - *
  5183. * @var ExclusionStrategy
  5184. */
  5185. private $exclusionStrategy;
  5186.  
  5187. /**
  5188. - * Eav attributes config.
  5189. - *
  5190. * @var EavConfig
  5191. */
  5192. private $eavConfig;
  5193.  
  5194. /**
  5195. - * Strategy for handling dropdown or multi-select attributes.
  5196. - *
  5197. * @var TermDropdownStrategy
  5198. */
  5199. private $termDropdownStrategy;
  5200.  
  5201. /**
  5202. - * Strategy for handling static attributes.
  5203. - *
  5204. * @var StaticAttributeStrategy
  5205. */
  5206. private $staticAttributeStrategy;
  5207.  
  5208. /**
  5209. - * Resolving table alias for Search Request filter.
  5210. - *
  5211. * @var AliasResolver
  5212. */
  5213. private $aliasResolver;
  5214. @@ -83,7 +74,6 @@ class FilterContext implements FilterStrategyInterface
  5215.  
  5216. if (!$isApplied) {
  5217. $attribute = $this->getAttributeByCode($filter->getField());
  5218. -
  5219. if ($attribute) {
  5220. if ($filter->getType() === \Magento\Framework\Search\Request\FilterInterface::TYPE_TERM
  5221. && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
  5222. @@ -99,12 +89,8 @@ class FilterContext implements FilterStrategyInterface
  5223. }
  5224.  
  5225. /**
  5226. - * Returns attribute by attribute_code.
  5227. - *
  5228. * @param string $field
  5229. - *
  5230. * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
  5231. - *
  5232. * @throws \Magento\Framework\Exception\LocalizedException
  5233. */
  5234. private function getAttributeByCode($field)
  5235. diff --git a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterStrategyInterface.php b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterStrategyInterface.php
  5236. index 0e41e0cd69f..92b06154977 100644
  5237. --- a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterStrategyInterface.php
  5238. +++ b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/FilterStrategyInterface.php
  5239. @@ -7,16 +7,13 @@
  5240. namespace Magento\CatalogSearch\Model\Search\FilterMapper;
  5241.  
  5242. /**
  5243. - * FilterStrategyInterface provides the interface to work with strategies.
  5244. + * FilterStrategyInterface provides the interface to work with strategies
  5245. */
  5246. interface FilterStrategyInterface
  5247. {
  5248. /**
  5249. - * Applies filter.
  5250. - *
  5251. * @param \Magento\Framework\Search\Request\FilterInterface $filter
  5252. * @param \Magento\Framework\DB\Select $select
  5253. - *
  5254. * @return bool is filter was applied
  5255. */
  5256. public function apply(
  5257. diff --git a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/StaticAttributeStrategy.php b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/StaticAttributeStrategy.php
  5258. index a930219d2e2..bb4a18ce163 100644
  5259. --- a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/StaticAttributeStrategy.php
  5260. +++ b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/StaticAttributeStrategy.php
  5261. @@ -10,27 +10,21 @@ use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver;
  5262. use Magento\Eav\Model\Config as EavConfig;
  5263.  
  5264. /**
  5265. - * This strategy handles static attributes.
  5266. + * This strategy handles static attributes
  5267. */
  5268. class StaticAttributeStrategy implements FilterStrategyInterface
  5269. {
  5270. /**
  5271. - * Resource connection.
  5272. - *
  5273. * @var \Magento\Framework\App\ResourceConnection
  5274. */
  5275. private $resourceConnection;
  5276.  
  5277. /**
  5278. - * Resolving table alias for Search Request filter.
  5279. - *
  5280. * @var AliasResolver
  5281. */
  5282. private $aliasResolver;
  5283.  
  5284. /**
  5285. - * Eav attributes config.
  5286. - *
  5287. * @var EavConfig
  5288. */
  5289. private $eavConfig;
  5290. @@ -65,17 +59,12 @@ class StaticAttributeStrategy implements FilterStrategyInterface
  5291. . $this->resourceConnection->getConnection()->quoteIdentifier("$alias.entity_id"),
  5292. []
  5293. );
  5294. -
  5295. return true;
  5296. }
  5297.  
  5298. /**
  5299. - * Returns attribute by attribute_code.
  5300. - *
  5301. * @param string $field
  5302. - *
  5303. * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
  5304. - *
  5305. * @throws \Magento\Framework\Exception\LocalizedException
  5306. */
  5307. private function getAttributeByCode($field)
  5308. diff --git a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/TermDropdownStrategy.php b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/TermDropdownStrategy.php
  5309. index a0f7f706b41..917450044a6 100644
  5310. --- a/vendor/magento/module-catalog-search/Model/Search/FilterMapper/TermDropdownStrategy.php
  5311. +++ b/vendor/magento/module-catalog-search/Model/Search/FilterMapper/TermDropdownStrategy.php
  5312. @@ -23,36 +23,26 @@ use Magento\Store\Model\StoreManagerInterface;
  5313. class TermDropdownStrategy implements FilterStrategyInterface
  5314. {
  5315. /**
  5316. - * Resolving table alias for Search Request filter.
  5317. - *
  5318. * @var AliasResolver
  5319. */
  5320. private $aliasResolver;
  5321.  
  5322. /**
  5323. - * Store manager.
  5324. - *
  5325. * @var StoreManagerInterface
  5326. */
  5327. private $storeManager;
  5328.  
  5329. /**
  5330. - * Eav attributes config.
  5331. - *
  5332. * @var EavConfig
  5333. */
  5334. private $eavConfig;
  5335.  
  5336. /**
  5337. - * Resource connection.
  5338. - *
  5339. * @var ResourceConnection
  5340. */
  5341. private $resourceConnection;
  5342.  
  5343. /**
  5344. - * Scope config.
  5345. - *
  5346. * @var ScopeConfigInterface
  5347. */
  5348. private $scopeConfig;
  5349. @@ -63,6 +53,7 @@ class TermDropdownStrategy implements FilterStrategyInterface
  5350. * @param EavConfig $eavConfig
  5351. * @param ScopeConfigInterface $scopeConfig
  5352. * @param AliasResolver $aliasResolver
  5353. + * @SuppressWarnings(Magento.TypeDuplication)
  5354. */
  5355. public function __construct(
  5356. StoreManagerInterface $storeManager,
  5357. @@ -79,13 +70,7 @@ class TermDropdownStrategy implements FilterStrategyInterface
  5358. }
  5359.  
  5360. /**
  5361. - * Applies filter.
  5362. - *
  5363. - * @param \Magento\Framework\Search\Request\FilterInterface $filter
  5364. - * @param \Magento\Framework\DB\Select $select
  5365. - *
  5366. - * @return bool is filter was applied
  5367. - *
  5368. + * {@inheritDoc}
  5369. * @throws \Magento\Framework\Exception\LocalizedException
  5370. */
  5371. public function apply(
  5372. @@ -105,11 +90,12 @@ class TermDropdownStrategy implements FilterStrategyInterface
  5373. $joinCondition,
  5374. []
  5375. );
  5376. -
  5377. if ($this->isAddStockFilter()) {
  5378. $stockAlias = $alias . AliasResolver::STOCK_FILTER_SUFFIX;
  5379. $select->joinLeft(
  5380. - [$stockAlias => $this->resourceConnection->getTableName('cataloginventory_stock_status')],
  5381. + [
  5382. + $stockAlias => $this->resourceConnection->getTableName('cataloginventory_stock_status'),
  5383. + ],
  5384. sprintf('%2$s.product_id = %1$s.source_id', $alias, $stockAlias),
  5385. []
  5386. );
  5387. @@ -119,12 +105,8 @@ class TermDropdownStrategy implements FilterStrategyInterface
  5388. }
  5389.  
  5390. /**
  5391. - * Returns attribute by attribute code.
  5392. - *
  5393. * @param string $field
  5394. - *
  5395. * @return \Magento\Catalog\Model\ResourceModel\Eav\Attribute
  5396. - *
  5397. * @throws \Magento\Framework\Exception\LocalizedException
  5398. */
  5399. private function getAttributeByCode($field)
  5400. @@ -133,8 +115,6 @@ class TermDropdownStrategy implements FilterStrategyInterface
  5401. }
  5402.  
  5403. /**
  5404. - * Check if it is necessary to show out of stock products.
  5405. - *
  5406. * @return bool
  5407. */
  5408. private function isAddStockFilter()
  5409. diff --git a/vendor/magento/module-catalog-search/Model/Search/IndexBuilder.php b/vendor/magento/module-catalog-search/Model/Search/IndexBuilder.php
  5410. index 03129b0d698..05995895ed3 100644
  5411. --- a/vendor/magento/module-catalog-search/Model/Search/IndexBuilder.php
  5412. +++ b/vendor/magento/module-catalog-search/Model/Search/IndexBuilder.php
  5413. @@ -21,7 +21,7 @@ use Magento\CatalogInventory\Model\Stock;
  5414. use Magento\Framework\App\ScopeResolverInterface;
  5415.  
  5416. /**
  5417. - * Build base Query for Index.
  5418. + * Build base Query for Index
  5419. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  5420. */
  5421. class IndexBuilder implements IndexBuilderInterface
  5422. @@ -148,7 +148,7 @@ class IndexBuilder implements IndexBuilderInterface
  5423. {
  5424. if ($this->stockConfiguration === null) {
  5425. $this->stockConfiguration = \Magento\Framework\App\ObjectManager::getInstance()
  5426. - ->get(\Magento\CatalogInventory\Api\StockConfigurationInterface::class);
  5427. + ->get('Magento\CatalogInventory\Api\StockConfigurationInterface');
  5428. }
  5429. return $this->stockConfiguration;
  5430. }
  5431. diff --git a/vendor/magento/module-catalog-search/Model/Search/TableMapper.php b/vendor/magento/module-catalog-search/Model/Search/TableMapper.php
  5432. index 2b8b79127c9..e96c6a36e20 100644
  5433. --- a/vendor/magento/module-catalog-search/Model/Search/TableMapper.php
  5434. +++ b/vendor/magento/module-catalog-search/Model/Search/TableMapper.php
  5435. @@ -24,7 +24,7 @@ use Magento\Framework\App\ObjectManager;
  5436. /**
  5437. * Responsibility of the TableMapper is to collect all filters from the search query
  5438. * and pass them one by one for processing in the FilterContext,
  5439. - * which will apply them to the Select.
  5440. + * which will apply them to the Select
  5441. *
  5442. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  5443. * @SuppressWarnings(PHPMD.NPathComplexity)
  5444. @@ -32,8 +32,6 @@ use Magento\Framework\App\ObjectManager;
  5445. class TableMapper
  5446. {
  5447. /**
  5448. - * Resource connection.
  5449. - *
  5450. * @var AppResource
  5451. */
  5452. private $resource;
  5453. @@ -44,49 +42,36 @@ class TableMapper
  5454. private $storeManager;
  5455.  
  5456. /**
  5457. - * @deprecated
  5458. - *
  5459. - * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection
  5460. - */
  5461. - private $attributeCollection;
  5462. -
  5463. - /**
  5464. - * Eav attribute config.
  5465. - *
  5466. * @var EavConfig
  5467. */
  5468. - private $eavConfig;
  5469. + private $eavConfig;
  5470.  
  5471. /**
  5472. - * Scope config.
  5473. - *
  5474. * @var ScopeConfigInterface
  5475. */
  5476. private $scopeConfig;
  5477.  
  5478. /**
  5479. - * FilterStrategyInterface provides the interface to work with strategies.
  5480. - *
  5481. * @var FilterStrategyInterface
  5482. */
  5483. private $filterStrategy;
  5484.  
  5485. /**
  5486. - * Table alias resolver for Search Request filter.
  5487. - *
  5488. * @var AliasResolver
  5489. */
  5490. private $aliasResolver;
  5491.  
  5492. /**
  5493. - * TableMapper constructor.
  5494. * @param AppResource $resource
  5495. * @param StoreManagerInterface $storeManager
  5496. * @param CollectionFactory $attributeCollectionFactory
  5497. - * @param EavConfig|null $eavConfig
  5498. - * @param ScopeConfigInterface|null $scopeConfig
  5499. - * @param FilterStrategyInterface|null $filterStrategy
  5500. - * @param AliasResolver|null $aliasResolver
  5501. + * @param EavConfig $eavConfig
  5502. + * @param ScopeConfigInterface $scopeConfig
  5503. + * @param FilterStrategyInterface $filterStrategy
  5504. + * @param AliasResolver $aliasResolver
  5505. + *
  5506. + * Added for backwards compatibility(can not delete parameter from constructor)
  5507. + * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  5508. */
  5509. public function __construct(
  5510. AppResource $resource,
  5511. @@ -99,7 +84,6 @@ class TableMapper
  5512. ) {
  5513. $this->resource = $resource;
  5514. $this->storeManager = $storeManager;
  5515. - $this->attributeCollection = $attributeCollectionFactory->create();
  5516. $this->eavConfig = $eavConfig ?: ObjectManager::getInstance()->get(EavConfig::class);
  5517. $this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
  5518. $this->filterStrategy = $filterStrategy ?: ObjectManager::getInstance()->get(FilterStrategyInterface::class);
  5519. @@ -107,21 +91,16 @@ class TableMapper
  5520. }
  5521.  
  5522. /**
  5523. - * Adds tables to select.
  5524. - *
  5525. * @param Select $select
  5526. * @param RequestInterface $request
  5527. - *
  5528. * @return Select
  5529. */
  5530. public function addTables(Select $select, RequestInterface $request)
  5531. {
  5532. $appliedFilters = [];
  5533. $filters = $this->getFiltersFromQuery($request->getQuery());
  5534. -
  5535. foreach ($filters as $filter) {
  5536. $alias = $this->aliasResolver->getAlias($filter);
  5537. -
  5538. if (!array_key_exists($alias, $appliedFilters)) {
  5539. $isApplied = $this->filterStrategy->apply($filter, $select);
  5540. if ($isApplied) {
  5541. @@ -152,7 +131,7 @@ class TableMapper
  5542. * @param RequestQueryInterface $query
  5543. * @return FilterInterface[]
  5544. */
  5545. - private function getFiltersFromQuery(RequestQueryInterface $query)
  5546. + private function getFiltersFromQuery(RequestQueryInterface $query)
  5547. {
  5548. $filters = [];
  5549. switch ($query->getType()) {
  5550. @@ -180,6 +159,7 @@ class TableMapper
  5551. default:
  5552. break;
  5553. }
  5554. +
  5555. return $filters;
  5556. }
  5557.  
  5558. diff --git a/vendor/magento/module-catalog-search/etc/di.xml b/vendor/magento/module-catalog-search/etc/di.xml
  5559. index 25993adf353..dc104cc7816 100644
  5560. --- a/vendor/magento/module-catalog-search/etc/di.xml
  5561. +++ b/vendor/magento/module-catalog-search/etc/di.xml
  5562. @@ -12,6 +12,7 @@
  5563. <preference for="Magento\Framework\Search\Dynamic\DataProviderInterface" type="Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider" />
  5564. <preference for="Magento\Framework\Search\Adapter\OptionsInterface" type="Magento\CatalogSearch\Model\Adapter\Options" />
  5565. <preference for="Magento\CatalogSearch\Model\Search\FilterMapper\FilterStrategyInterface" type="Magento\CatalogSearch\Model\Search\FilterMapper\FilterContext"/>
  5566. + <preference for="\Magento\CatalogSearch\Model\Indexer\IndexSwitcherInterface" type="\Magento\CatalogSearch\Model\Indexer\IndexSwitcherProxy"/>
  5567. <type name="Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory">
  5568. <arguments>
  5569. <argument name="configPath" xsi:type="const">Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH</argument>
  5570. @@ -20,6 +21,14 @@
  5571. </argument>
  5572. </arguments>
  5573. </type>
  5574. + <type name="Magento\CatalogSearch\Model\Indexer\IndexSwitcherProxy">
  5575. + <arguments>
  5576. + <argument name="configPath" xsi:type="const">Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH</argument>
  5577. + <argument name="handlers" xsi:type="array">
  5578. + <item name="mysql" xsi:type="string">\Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher</item>
  5579. + </argument>
  5580. + </arguments>
  5581. + </type>
  5582. <type name="Magento\CatalogSearch\Model\Indexer\IndexStructureFactory">
  5583. <arguments>
  5584. <argument name="configPath" xsi:type="const">Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH</argument>
  5585. @@ -246,4 +255,27 @@
  5586. </argument>
  5587. </arguments>
  5588. </type>
  5589. + <type name="\Magento\CatalogSearch\Model\Indexer\IndexerHandler">
  5590. + <arguments>
  5591. + <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument>
  5592. + </arguments>
  5593. + </type>
  5594. + <type name="\Magento\CatalogSearch\Model\Indexer\IndexStructure">
  5595. + <arguments>
  5596. + <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument>
  5597. + </arguments>
  5598. + </type>
  5599. + <type name="\Magento\CatalogSearch\Model\Indexer\Scope\IndexSwitcher">
  5600. + <arguments>
  5601. + <argument name="indexScopeResolver" xsi:type="object">\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy</argument>
  5602. + </arguments>
  5603. + </type>
  5604. + <type name="\Magento\CatalogSearch\Model\Indexer\Scope\ScopeProxy">
  5605. + <arguments>
  5606. + <argument name="states" xsi:type="array">
  5607. + <item name="use_temporary_table" xsi:type="string">\Magento\CatalogSearch\Model\Indexer\Scope\TemporaryResolver</item>
  5608. + <item name="use_main_table" xsi:type="string">\Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver</item>
  5609. + </argument>
  5610. + </arguments>
  5611. + </type>
  5612. </config>
  5613. diff --git a/vendor/magento/module-catalog-widget/Model/Rule/Condition/Product.php b/vendor/magento/module-catalog-widget/Model/Rule/Condition/Product.php
  5614. index 7b4ecf5ffe9..f441135e7bf 100644
  5615. --- a/vendor/magento/module-catalog-widget/Model/Rule/Condition/Product.php
  5616. +++ b/vendor/magento/module-catalog-widget/Model/Rule/Condition/Product.php
  5617. @@ -12,6 +12,7 @@ namespace Magento\CatalogWidget\Model\Rule\Condition;
  5618.  
  5619. /**
  5620. * Class Product
  5621. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  5622. */
  5623. class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct
  5624. {
  5625. diff --git a/vendor/magento/module-configurable-product/Model/ResourceModel/Indexer/Stock/Configurable.php b/vendor/magento/module-configurable-product/Model/ResourceModel/Indexer/Stock/Configurable.php
  5626. index ada5d90b938..0b8eaead585 100644
  5627. --- a/vendor/magento/module-configurable-product/Model/ResourceModel/Indexer/Stock/Configurable.php
  5628. +++ b/vendor/magento/module-configurable-product/Model/ResourceModel/Indexer/Stock/Configurable.php
  5629. @@ -13,9 +13,44 @@ namespace Magento\ConfigurableProduct\Model\ResourceModel\Indexer\Stock;
  5630. * @author Magento Core Team <core@magentocommerce.com>
  5631. */
  5632. use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
  5633. +use Magento\CatalogInventory\Model\Indexer\Stock\Action\Full;
  5634. +use Magento\Framework\App\ObjectManager;
  5635.  
  5636. +/**
  5637. + * Stock indexer for configurable product.
  5638. + *
  5639. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  5640. + */
  5641. class Configurable extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\DefaultStock
  5642. {
  5643. + /**
  5644. + * @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
  5645. + */
  5646. + private $activeTableSwitcher;
  5647. +
  5648. + /**
  5649. + * Configurable constructor.
  5650. + * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  5651. + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
  5652. + * @param \Magento\Eav\Model\Config $eavConfig
  5653. + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  5654. + * @param null $connectionName
  5655. + * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
  5656. + */
  5657. + public function __construct(
  5658. + \Magento\Framework\Model\ResourceModel\Db\Context $context,
  5659. + \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
  5660. + \Magento\Eav\Model\Config $eavConfig,
  5661. + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  5662. + $connectionName = null,
  5663. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
  5664. + ) {
  5665. + parent::__construct($context, $tableStrategy, $eavConfig, $scopeConfig, $connectionName);
  5666. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
  5667. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
  5668. + );
  5669. + }
  5670. +
  5671. /**
  5672. * Get the select object for get stock status by configurable product ids
  5673. *
  5674. @@ -27,7 +62,10 @@ class Configurable extends \Magento\CatalogInventory\Model\ResourceModel\Indexer
  5675. {
  5676. $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
  5677. $connection = $this->getConnection();
  5678. - $idxTable = $usePrimaryTable ? $this->getMainTable() : $this->getIdxTable();
  5679. + $table = $this->getActionType() === Full::ACTION_TYPE
  5680. + ? $this->activeTableSwitcher->getAdditionalTableName($this->getMainTable())
  5681. + : $this->getMainTable();
  5682. + $idxTable = $usePrimaryTable ? $table : $this->getIdxTable();
  5683. $select = parent::_getStockStatusSelect($entityIds, $usePrimaryTable);
  5684. $select->reset(
  5685. \Magento\Framework\DB\Select::COLUMNS
  5686. diff --git a/vendor/magento/module-configurable-product/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/vendor/magento/module-configurable-product/Model/ResourceModel/Product/Indexer/Price/Configurable.php
  5687. index 7f4f0f9e937..75cc5a8c958 100644
  5688. --- a/vendor/magento/module-configurable-product/Model/ResourceModel/Product/Indexer/Price/Configurable.php
  5689. +++ b/vendor/magento/module-configurable-product/Model/ResourceModel/Product/Indexer/Price/Configurable.php
  5690. @@ -28,7 +28,7 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
  5691. * @param \Magento\Eav\Model\Config $eavConfig
  5692. * @param \Magento\Framework\Event\ManagerInterface $eventManager
  5693. * @param \Magento\Framework\Module\Manager $moduleManager
  5694. - * @param string $connectionName
  5695. + * @param string|null $connectionName
  5696. * @param StoreResolverInterface $storeResolver
  5697. */
  5698. public function __construct(
  5699. @@ -41,8 +41,9 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
  5700. StoreResolverInterface $storeResolver = null
  5701. ) {
  5702. parent::__construct($context, $tableStrategy, $eavConfig, $eventManager, $moduleManager, $connectionName);
  5703. - $this->storeResolver = $storeResolver ?:
  5704. - \Magento\Framework\App\ObjectManager::getInstance()->get(StoreResolverInterface::class);
  5705. + $this->storeResolver = $storeResolver ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
  5706. + StoreResolverInterface::class
  5707. + );
  5708. }
  5709.  
  5710. /**
  5711. @@ -50,18 +51,11 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
  5712. *
  5713. * @return $this
  5714. * @throws \Exception
  5715. + * @deprecated
  5716. */
  5717. public function reindexAll()
  5718. {
  5719. - $this->tableStrategy->setUseIdxTable(true);
  5720. - $this->beginTransaction();
  5721. - try {
  5722. - $this->reindex();
  5723. - $this->commit();
  5724. - } catch (\Exception $e) {
  5725. - $this->rollBack();
  5726. - throw $e;
  5727. - }
  5728. + parent::reindexAll();
  5729. return $this;
  5730. }
  5731.  
  5732. @@ -70,10 +64,11 @@ class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\
  5733. *
  5734. * @param int|array $entityIds
  5735. * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable
  5736. + * @deprecated
  5737. */
  5738. public function reindexEntity($entityIds)
  5739. {
  5740. - $this->reindex($entityIds);
  5741. + parent::reindexEntity($entityIds);
  5742. return $this;
  5743. }
  5744.  
  5745. diff --git a/vendor/magento/module-configurable-product/etc/di.xml b/vendor/magento/module-configurable-product/etc/di.xml
  5746. index 66d6073f75d..92c9f6762d0 100644
  5747. --- a/vendor/magento/module-configurable-product/etc/di.xml
  5748. +++ b/vendor/magento/module-configurable-product/etc/di.xml
  5749. @@ -168,4 +168,17 @@
  5750. </argument>
  5751. </arguments>
  5752. </type>
  5753. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator">
  5754. + <arguments>
  5755. + <argument name="estimators" xsi:type="array">
  5756. + <item name="configurable" xsi:type="object">Magento\Catalog\Model\Indexer\Price\CompositeProductBatchSizeManagement</item>
  5757. + </argument>
  5758. + </arguments>
  5759. + </type>
  5760. + <type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable">
  5761. + <arguments>
  5762. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  5763. + <argument name="connectionName" xsi:type="string">indexer</argument>
  5764. + </arguments>
  5765. + </type>
  5766. </config>
  5767. diff --git a/vendor/magento/module-downloadable/Model/ResourceModel/Indexer/Price.php b/vendor/magento/module-downloadable/Model/ResourceModel/Indexer/Price.php
  5768. index 843e690e342..2df2382931e 100644
  5769. --- a/vendor/magento/module-downloadable/Model/ResourceModel/Indexer/Price.php
  5770. +++ b/vendor/magento/module-downloadable/Model/ResourceModel/Indexer/Price.php
  5771. @@ -19,18 +19,11 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D
  5772. *
  5773. * @throws \Exception
  5774. * @return $this
  5775. + * @deprecated
  5776. */
  5777. public function reindexAll()
  5778. {
  5779. - $this->tableStrategy->setUseIdxTable(true);
  5780. - $this->beginTransaction();
  5781. - try {
  5782. - $this->reindex();
  5783. - $this->commit();
  5784. - } catch (\Exception $e) {
  5785. - $this->rollBack();
  5786. - throw $e;
  5787. - }
  5788. + parent::reindexAll();
  5789. return $this;
  5790. }
  5791.  
  5792. @@ -39,10 +32,12 @@ class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\D
  5793. *
  5794. * @param int|array $entityIds
  5795. * @return $this
  5796. + * @deprecated
  5797. */
  5798. public function reindexEntity($entityIds)
  5799. {
  5800. - return $this->reindex($entityIds);
  5801. + parent::reindexEntity($entityIds);
  5802. + return $this;
  5803. }
  5804.  
  5805. /**
  5806. diff --git a/vendor/magento/module-downloadable/etc/di.xml b/vendor/magento/module-downloadable/etc/di.xml
  5807. index 84b6de602ac..d399806bfba 100644
  5808. --- a/vendor/magento/module-downloadable/etc/di.xml
  5809. +++ b/vendor/magento/module-downloadable/etc/di.xml
  5810. @@ -123,4 +123,10 @@
  5811. </argument>
  5812. </arguments>
  5813. </type>
  5814. + <type name="Magento\Downloadable\Model\ResourceModel\Indexer\Price">
  5815. + <arguments>
  5816. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  5817. + <argument name="connectionName" xsi:type="string">indexer</argument>
  5818. + </arguments>
  5819. + </type>
  5820. </config>
  5821. diff --git a/vendor/magento/module-grouped-product/Model/ResourceModel/Indexer/Stock/Grouped.php b/vendor/magento/module-grouped-product/Model/ResourceModel/Indexer/Stock/Grouped.php
  5822. index 740dec1aa27..c17597ab252 100644
  5823. --- a/vendor/magento/module-grouped-product/Model/ResourceModel/Indexer/Stock/Grouped.php
  5824. +++ b/vendor/magento/module-grouped-product/Model/ResourceModel/Indexer/Stock/Grouped.php
  5825. @@ -12,9 +12,44 @@
  5826. namespace Magento\GroupedProduct\Model\ResourceModel\Indexer\Stock;
  5827.  
  5828. use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
  5829. +use Magento\Framework\App\ObjectManager;
  5830. +use Magento\CatalogInventory\Model\Indexer\Stock\Action\Full;
  5831.  
  5832. +/**
  5833. + * Stock indexer for grouped product.
  5834. + *
  5835. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  5836. + */
  5837. class Grouped extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\DefaultStock
  5838. {
  5839. + /**
  5840. + * @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
  5841. + */
  5842. + private $activeTableSwitcher;
  5843. +
  5844. + /**
  5845. + * Grouped constructor.
  5846. + * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  5847. + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy
  5848. + * @param \Magento\Eav\Model\Config $eavConfig
  5849. + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  5850. + * @param null $connectionName
  5851. + * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
  5852. + */
  5853. + public function __construct(
  5854. + \Magento\Framework\Model\ResourceModel\Db\Context $context,
  5855. + \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
  5856. + \Magento\Eav\Model\Config $eavConfig,
  5857. + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  5858. + $connectionName = null,
  5859. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
  5860. + ) {
  5861. + parent::__construct($context, $tableStrategy, $eavConfig, $scopeConfig, $connectionName);
  5862. + $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
  5863. + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
  5864. + );
  5865. + }
  5866. +
  5867. /**
  5868. * Get the select object for get stock status by grouped product ids
  5869. *
  5870. @@ -25,7 +60,10 @@ class Grouped extends \Magento\CatalogInventory\Model\ResourceModel\Indexer\Stoc
  5871. protected function _getStockStatusSelect($entityIds = null, $usePrimaryTable = false)
  5872. {
  5873. $connection = $this->getConnection();
  5874. - $idxTable = $usePrimaryTable ? $this->getMainTable() : $this->getIdxTable();
  5875. + $table = $this->getActionType() === Full::ACTION_TYPE
  5876. + ? $this->activeTableSwitcher->getAdditionalTableName($this->getMainTable())
  5877. + : $this->getMainTable();
  5878. + $idxTable = $usePrimaryTable ? $table : $this->getIdxTable();
  5879. $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
  5880. $select = parent::_getStockStatusSelect($entityIds, $usePrimaryTable);
  5881. $select->reset(
  5882. diff --git a/vendor/magento/module-grouped-product/Model/ResourceModel/Product/Indexer/Price/Grouped.php b/vendor/magento/module-grouped-product/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  5883. index eaed75a967c..55882b40b47 100644
  5884. --- a/vendor/magento/module-grouped-product/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  5885. +++ b/vendor/magento/module-grouped-product/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  5886. @@ -12,23 +12,21 @@ use Magento\Catalog\Api\Data\ProductInterface;
  5887.  
  5888. class Grouped extends DefaultPrice implements GroupedInterface
  5889. {
  5890. + /**
  5891. + * Prefix for temporary table support.
  5892. + */
  5893. + const TRANSIT_PREFIX = 'transit_';
  5894. +
  5895. /**
  5896. * Reindex temporary (price result data) for all products
  5897. *
  5898. * @throws \Exception
  5899. * @return \Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped
  5900. + * @deprecated
  5901. */
  5902. public function reindexAll()
  5903. {
  5904. - $this->tableStrategy->setUseIdxTable(true);
  5905. - $this->beginTransaction();
  5906. - try {
  5907. - $this->_prepareGroupedProductPriceData();
  5908. - $this->commit();
  5909. - } catch (\Exception $e) {
  5910. - $this->rollBack();
  5911. - throw $e;
  5912. - }
  5913. + parent::reindexAll();
  5914. return $this;
  5915. }
  5916.  
  5917. @@ -37,26 +35,72 @@ class Grouped extends DefaultPrice implements GroupedInterface
  5918. *
  5919. * @param int|array $entityIds
  5920. * @return \Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped
  5921. + * @deprecated
  5922. */
  5923. public function reindexEntity($entityIds)
  5924. {
  5925. - $this->_prepareGroupedProductPriceData($entityIds);
  5926. -
  5927. + parent::reindexEntity($entityIds);
  5928. return $this;
  5929. }
  5930.  
  5931. + /**
  5932. + * @inheritdoc
  5933. + */
  5934. + protected function reindex($entityIds = null)
  5935. + {
  5936. + $this->_prepareGroupedProductPriceData($entityIds);
  5937. + }
  5938. +
  5939. /**
  5940. * Calculate minimal and maximal prices for Grouped products
  5941. * Use calculated price for relation products
  5942. *
  5943. * @param int|array $entityIds the parent entity ids limitation
  5944. - * @return \Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped
  5945. + * @return $this
  5946. */
  5947. protected function _prepareGroupedProductPriceData($entityIds = null)
  5948. {
  5949. if (!$this->hasEntity() && empty($entityIds)) {
  5950. return $this;
  5951. }
  5952. +
  5953. + $connection = $this->getConnection();
  5954. + $table = $this->getIdxTable();
  5955. +
  5956. + if (!$this->tableStrategy->getUseIdxTable()) {
  5957. + $additionalIdxTable = $connection->getTableName(self::TRANSIT_PREFIX . $this->getIdxTable());
  5958. + $connection->createTemporaryTableLike($additionalIdxTable, $table);
  5959. + $query = $connection->insertFromSelect(
  5960. + $this->_prepareGroupedProductPriceDataSelect($entityIds),
  5961. + $additionalIdxTable,
  5962. + []
  5963. + );
  5964. + $connection->query($query);
  5965. +
  5966. + $select = $connection->select()->from($additionalIdxTable);
  5967. + $query = $connection->insertFromSelect(
  5968. + $select,
  5969. + $table,
  5970. + [],
  5971. + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
  5972. + );
  5973. + $connection->query($query);
  5974. + $connection->dropTemporaryTable($additionalIdxTable);
  5975. + } else {
  5976. + $query = $this->_prepareGroupedProductPriceDataSelect($entityIds)->insertFromSelect($table);
  5977. + $connection->query($query);
  5978. + }
  5979. + return $this;
  5980. + }
  5981. +
  5982. + /**
  5983. + * Prepare data index select for Grouped products prices
  5984. + *
  5985. + * @param int|array $entityIds the parent entity ids limitation
  5986. + * @return \Magento\Framework\DB\Select
  5987. + */
  5988. + protected function _prepareGroupedProductPriceDataSelect($entityIds = null)
  5989. + {
  5990. $connection = $this->getConnection();
  5991. $table = $this->getIdxTable();
  5992. $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
  5993. @@ -123,10 +167,6 @@ class Grouped extends DefaultPrice implements GroupedInterface
  5994. 'store_field' => new \Zend_Db_Expr('cs.store_id')
  5995. ]
  5996. );
  5997. -
  5998. - $query = $select->insertFromSelect($table);
  5999. - $connection->query($query);
  6000. -
  6001. - return $this;
  6002. + return $select;
  6003. }
  6004. }
  6005. diff --git a/vendor/magento/module-grouped-product/etc/di.xml b/vendor/magento/module-grouped-product/etc/di.xml
  6006. index 788052d07fc..17c9a644b7b 100644
  6007. --- a/vendor/magento/module-grouped-product/etc/di.xml
  6008. +++ b/vendor/magento/module-grouped-product/etc/di.xml
  6009. @@ -89,4 +89,11 @@
  6010. </type>
  6011. <preference for="Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\GroupedInterface"
  6012. type="Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped"/>
  6013. + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator">
  6014. + <arguments>
  6015. + <argument name="estimators" xsi:type="array">
  6016. + <item name="grouped" xsi:type="object">Magento\Catalog\Model\Indexer\Price\CompositeProductBatchSizeManagement</item>
  6017. + </argument>
  6018. + </arguments>
  6019. + </type>
  6020. </config>
  6021. diff --git a/vendor/magento/module-indexer/Model/Indexer.php b/vendor/magento/module-indexer/Model/Indexer.php
  6022. index feea37a2636..e799ab04a71 100644
  6023. --- a/vendor/magento/module-indexer/Model/Indexer.php
  6024. +++ b/vendor/magento/module-indexer/Model/Indexer.php
  6025. @@ -59,6 +59,7 @@ class Indexer extends \Magento\Framework\DataObject implements IdxInterface
  6026. protected $indexersFactory;
  6027.  
  6028. /**
  6029. + * Indexer constructor.
  6030. * @param ConfigInterface $config
  6031. * @param ActionFactory $actionFactory
  6032. * @param StructureFactory $structureFactory
  6033. @@ -413,7 +414,7 @@ class Indexer extends \Magento\Framework\DataObject implements IdxInterface
  6034. $state->setStatus(StateInterface::STATUS_VALID);
  6035. $state->save();
  6036. $this->getView()->resume();
  6037. - } catch (\Exception $exception) {
  6038. + } catch (\Throwable $exception) {
  6039. $state->setStatus(StateInterface::STATUS_INVALID);
  6040. $state->save();
  6041. $this->getView()->resume();
  6042. @@ -436,7 +437,7 @@ class Indexer extends \Magento\Framework\DataObject implements IdxInterface
  6043.  
  6044. /**
  6045. * Regenerate rows in index by ID list
  6046. - *5
  6047. + *
  6048. * @param int[] $ids
  6049. * @return void
  6050. */
  6051. diff --git a/vendor/magento/module-indexer/etc/di.xml b/vendor/magento/module-indexer/etc/di.xml
  6052. index 1d3f125406f..7cb8971dfda 100644
  6053. --- a/vendor/magento/module-indexer/etc/di.xml
  6054. +++ b/vendor/magento/module-indexer/etc/di.xml
  6055. @@ -55,4 +55,5 @@
  6056. </argument>
  6057. </arguments>
  6058. </type>
  6059. + <preference for="Magento\Framework\Indexer\BatchSizeManagementInterface" type="Magento\Framework\Indexer\BatchSizeManagement" />
  6060. </config>
  6061. diff --git a/vendor/magento/module-indexer/etc/module.xml b/vendor/magento/module-indexer/etc/module.xml
  6062. index a2beac15990..27c6a47d56a 100644
  6063. --- a/vendor/magento/module-indexer/etc/module.xml
  6064. +++ b/vendor/magento/module-indexer/etc/module.xml
  6065. @@ -6,7 +6,7 @@
  6066. */
  6067. -->
  6068. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  6069. - <module name="Magento_Indexer" setup_version="2.0.0">
  6070. + <module name="Magento_Indexer" setup_version="2.0.1.1.2">
  6071. <sequence>
  6072. <module name="Magento_Store"/>
  6073. <module name="Magento_AdminNotification"/>
  6074. diff --git a/vendor/magento/framework/Indexer/BatchProvider.php b/vendor/magento/framework/Indexer/BatchProvider.php
  6075. new file mode 100644
  6076. index 00000000000..9f8a1b1ace4
  6077. --- /dev/null
  6078. +++ b/vendor/magento/framework/Indexer/BatchProvider.php
  6079. @@ -0,0 +1,64 @@
  6080. +<?php
  6081. +/**
  6082. + * Copyright © Magento, Inc. All rights reserved.
  6083. + * See COPYING.txt for license details.
  6084. + */
  6085. +namespace Magento\Framework\Indexer;
  6086. +
  6087. +use \Magento\Framework\DB\Adapter\AdapterInterface;
  6088. +
  6089. +/**
  6090. + * Generator of consecutive entity ID ranges that must be handled as a batch.
  6091. + *
  6092. + * Some ranges may contain non existent entity IDs.
  6093. + * So the code that uses the generator must check if any entities were loaded during batch load.
  6094. + */
  6095. +class BatchProvider implements BatchProviderInterface
  6096. +{
  6097. + /**
  6098. + * @inheritdoc
  6099. + */
  6100. + public function getBatches(AdapterInterface $adapter, $tableName, $linkField, $batchSize)
  6101. + {
  6102. + $maxLinkFieldValue = $adapter->fetchOne(
  6103. + $adapter->select()->from(
  6104. + ['entity' => $tableName],
  6105. + [
  6106. + 'max_value' => new \Zend_Db_Expr('MAX(entity.' . $linkField . ')')
  6107. + ]
  6108. + )
  6109. + );
  6110. +
  6111. + /** @var int $truncatedBatchSize size of the last batch that is smaller than expected batch size */
  6112. + $truncatedBatchSize = $maxLinkFieldValue % $batchSize;
  6113. + /** @var int $fullBatchCount count of the batches that have expected batch size */
  6114. + $fullBatchCount = ($maxLinkFieldValue - $truncatedBatchSize) / $batchSize;
  6115. +
  6116. + for ($batchIndex = 0; $batchIndex < $fullBatchCount; $batchIndex ++) {
  6117. + yield ['from' => $batchIndex * $batchSize + 1, 'to' => ($batchIndex + 1) * $batchSize];
  6118. + }
  6119. + // return the last batch if it has smaller size
  6120. + if ($truncatedBatchSize > 0) {
  6121. + yield ['from' => $fullBatchCount * $batchSize + 1, 'to' => $maxLinkFieldValue];
  6122. + }
  6123. + }
  6124. +
  6125. + /**
  6126. + * @inheritdoc
  6127. + */
  6128. + public function getBatchIds(
  6129. + \Magento\Framework\DB\Adapter\AdapterInterface $connection,
  6130. + \Magento\Framework\DB\Select $select,
  6131. + array $batch
  6132. + ) {
  6133. + $betweenCondition = sprintf(
  6134. + '(%s BETWEEN %s AND %s)',
  6135. + 'entity_id',
  6136. + $connection->quote($batch['from']),
  6137. + $connection->quote($batch['to'])
  6138. + );
  6139. +
  6140. + $ids = $connection->fetchCol($select->where($betweenCondition));
  6141. + return array_map('intval', $ids);
  6142. + }
  6143. +}
  6144. diff --git a/vendor/magento/framework/Indexer/BatchProviderInterface.php b/vendor/magento/framework/Indexer/BatchProviderInterface.php
  6145. new file mode 100644
  6146. index 00000000000..09972f48bfd
  6147. --- /dev/null
  6148. +++ b/vendor/magento/framework/Indexer/BatchProviderInterface.php
  6149. @@ -0,0 +1,39 @@
  6150. +<?php
  6151. +/**
  6152. + * Copyright © Magento, Inc. All rights reserved.
  6153. + * See COPYING.txt for license details.
  6154. + */
  6155. +namespace Magento\Framework\Indexer;
  6156. +
  6157. +use Magento\Framework\DB\Adapter\AdapterInterface;
  6158. +use Magento\Framework\DB\Select;
  6159. +
  6160. +/**
  6161. + * Generator of consecutive entity ID ranges that must be handled as a batch.
  6162. + *
  6163. + * Can be used during indexation process to split large amount of data into batches
  6164. + * and process them one by one in order to reduce memory consumption and improve overall performance.
  6165. + */
  6166. +interface BatchProviderInterface
  6167. +{
  6168. + /**
  6169. + * Retrieve batches (entity ID ranges) from the given table.
  6170. + *
  6171. + * @param AdapterInterface $adapter database adapter.
  6172. + * @param string $tableName target table name.
  6173. + * @param string $linkField field that is used as a record identifier.
  6174. + * @param int $batchSize size of the single range.
  6175. + * @return \Generator generator that produces entity ID ranges in the format of ['from' => ..., 'to' => ...]
  6176. + */
  6177. + public function getBatches(AdapterInterface $adapter, $tableName, $linkField, $batchSize);
  6178. +
  6179. + /**
  6180. + * Get list of entity ids based on batch
  6181. + *
  6182. + * @param AdapterInterface $connection
  6183. + * @param Select $select
  6184. + * @param array $batch
  6185. + * @return array
  6186. + */
  6187. + public function getBatchIds(AdapterInterface $connection, Select $select, array $batch);
  6188. +}
  6189. diff --git a/vendor/magento/framework/Indexer/BatchSizeManagement.php b/vendor/magento/framework/Indexer/BatchSizeManagement.php
  6190. new file mode 100644
  6191. index 00000000000..2733aae4bd5
  6192. --- /dev/null
  6193. +++ b/vendor/magento/framework/Indexer/BatchSizeManagement.php
  6194. @@ -0,0 +1,65 @@
  6195. +<?php
  6196. +/**
  6197. + * Copyright © Magento, Inc. All rights reserved.
  6198. + * See COPYING.txt for license details.
  6199. + */
  6200. +
  6201. +namespace Magento\Framework\Indexer;
  6202. +
  6203. +/**
  6204. + * Class set MEMORY table size for indexer processes according batch size and index row size.
  6205. + */
  6206. +class BatchSizeManagement implements \Magento\Framework\Indexer\BatchSizeManagementInterface
  6207. +{
  6208. + /**
  6209. + * @var \Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface
  6210. + */
  6211. + private $rowSizeEstimator;
  6212. +
  6213. + /**
  6214. + * @var \Psr\Log\LoggerInterface
  6215. + */
  6216. + private $logger;
  6217. +
  6218. + /**
  6219. + * CompositeProductBatchSizeCalculator constructor.
  6220. + * @param \Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface $rowSizeEstimator
  6221. + * @param \Psr\Log\LoggerInterface $logger
  6222. + */
  6223. + public function __construct(
  6224. + \Magento\Framework\Indexer\IndexTableRowSizeEstimatorInterface $rowSizeEstimator,
  6225. + \Psr\Log\LoggerInterface $logger
  6226. + ) {
  6227. + $this->rowSizeEstimator = $rowSizeEstimator;
  6228. + $this->logger = $logger;
  6229. + }
  6230. +
  6231. + /**
  6232. + * @inheritdoc
  6233. + */
  6234. + public function ensureBatchSize(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $batchSize)
  6235. + {
  6236. + $rowMemory = $this->rowSizeEstimator->estimateRowSize();
  6237. +
  6238. + $maxHeapTableSize = $connection->fetchOne('SELECT @@max_heap_table_size;');
  6239. + $tmpTableSize = $connection->fetchOne('SELECT @@tmp_table_size;');
  6240. + $bufferPoolSize = $connection->fetchOne('SELECT @@innodb_buffer_pool_size;');
  6241. + $maxMemoryTableSize = min($maxHeapTableSize, $tmpTableSize);
  6242. +
  6243. + $size = (int) ($rowMemory * $batchSize);
  6244. +
  6245. + // Log warning if allocated memory for temp table greater than 20% of innodb_buffer_pool_size
  6246. + if ($size > $bufferPoolSize * .2) {
  6247. + $message = 'Memory size allocated for the temporary table is more than 20% of innodb_buffer_pool_size. ' .
  6248. + 'Please update innodb_buffer_pool_size or decrease batch size value '.
  6249. + '(which decreases memory usages for the temporary table). ' .
  6250. + 'Current batch size: %1; Allocated memory size: %2 bytes; InnoDB buffer pool size: %3 bytes.';
  6251. + $this->logger->warning(new \Magento\Framework\Phrase($message, [$batchSize, $size, $bufferPoolSize]));
  6252. + }
  6253. +
  6254. + if ($maxMemoryTableSize < $size) {
  6255. + $connection->query('SET SESSION tmp_table_size = ' . $size . ';');
  6256. + $connection->query('SET SESSION max_heap_table_size = ' . $size . ';');
  6257. + }
  6258. + }
  6259. +}
  6260. diff --git a/vendor/magento/framework/Indexer/BatchSizeManagementInterface.php b/vendor/magento/framework/Indexer/BatchSizeManagementInterface.php
  6261. new file mode 100644
  6262. index 00000000000..ac5b5dae291
  6263. --- /dev/null
  6264. +++ b/vendor/magento/framework/Indexer/BatchSizeManagementInterface.php
  6265. @@ -0,0 +1,24 @@
  6266. +<?php
  6267. +/**
  6268. + * Copyright © Magento, Inc. All rights reserved.
  6269. + * See COPYING.txt for license details.
  6270. + */
  6271. +namespace Magento\Framework\Indexer;
  6272. +
  6273. +use \Magento\Framework\DB\Adapter\AdapterInterface;
  6274. +
  6275. +/**
  6276. + * Batch size manager can be used to ensure that MEMORY table has enough memory for data in batch.
  6277. + * @api
  6278. + */
  6279. +interface BatchSizeManagementInterface
  6280. +{
  6281. + /**
  6282. + * Ensure memory size for data in batch.
  6283. + *
  6284. + * @param AdapterInterface $adapter database adapter.
  6285. + * @param int $batchSize
  6286. + * @return void
  6287. + */
  6288. + public function ensureBatchSize(\Magento\Framework\DB\Adapter\AdapterInterface $adapter, $batchSize);
  6289. +}
  6290. diff --git a/vendor/magento/framework/Indexer/IndexTableRowSizeEstimator.php b/vendor/magento/framework/Indexer/IndexTableRowSizeEstimator.php
  6291. new file mode 100644
  6292. index 00000000000..d26c85a6d02
  6293. --- /dev/null
  6294. +++ b/vendor/magento/framework/Indexer/IndexTableRowSizeEstimator.php
  6295. @@ -0,0 +1,34 @@
  6296. +<?php
  6297. +/**
  6298. + * Copyright © Magento, Inc. All rights reserved.
  6299. + * See COPYING.txt for license details.
  6300. + */
  6301. +
  6302. +namespace Magento\Framework\Indexer;
  6303. +
  6304. +/**
  6305. + * Generic implementation for row size estimation.
  6306. + */
  6307. +class IndexTableRowSizeEstimator implements IndexTableRowSizeEstimatorInterface
  6308. +{
  6309. + /**
  6310. + * @var int
  6311. + */
  6312. + private $rowMemorySize;
  6313. +
  6314. + /**
  6315. + * @param int $rowMemorySize
  6316. + */
  6317. + public function __construct($rowMemorySize)
  6318. + {
  6319. + $this->rowMemorySize = $rowMemorySize;
  6320. + }
  6321. +
  6322. + /**
  6323. + * @inheritdoc
  6324. + */
  6325. + public function estimateRowSize()
  6326. + {
  6327. + return $this->rowMemorySize;
  6328. + }
  6329. +}
  6330. diff --git a/vendor/magento/framework/Indexer/IndexTableRowSizeEstimatorInterface.php b/vendor/magento/framework/Indexer/IndexTableRowSizeEstimatorInterface.php
  6331. new file mode 100644
  6332. index 00000000000..c2c25ef4969
  6333. --- /dev/null
  6334. +++ b/vendor/magento/framework/Indexer/IndexTableRowSizeEstimatorInterface.php
  6335. @@ -0,0 +1,21 @@
  6336. +<?php
  6337. +/**
  6338. + * Copyright © Magento, Inc. All rights reserved.
  6339. + * See COPYING.txt for license details.
  6340. + */
  6341. +
  6342. +namespace Magento\Framework\Indexer;
  6343. +
  6344. +/**
  6345. + * Calculate memory size for entity according different dimensions.
  6346. + * @api
  6347. + */
  6348. +interface IndexTableRowSizeEstimatorInterface
  6349. +{
  6350. + /**
  6351. + * Calculate memory size for entity row.
  6352. + *
  6353. + * @return float
  6354. + */
  6355. + public function estimateRowSize();
  6356. +}
  6357. diff --git a/vendor/magento/framework/Indexer/ScopeResolver/IndexScopeResolver.php b/vendor/magento/framework/Indexer/ScopeResolver/IndexScopeResolver.php
  6358. index 20365b399fc..77f2c7a1b64 100644
  6359. --- a/vendor/magento/framework/Indexer/ScopeResolver/IndexScopeResolver.php
  6360. +++ b/vendor/magento/framework/Indexer/ScopeResolver/IndexScopeResolver.php
  6361. @@ -52,6 +52,7 @@ class IndexScopeResolver implements IndexScopeResolverInterface
  6362. $tableNameParts[] = $dimension->getName() . $dimension->getValue();
  6363. }
  6364. }
  6365. +
  6366. return $this->resource->getTableName(implode('_', $tableNameParts));
  6367. }
  6368.  
  6369. @@ -63,10 +64,12 @@ class IndexScopeResolver implements IndexScopeResolverInterface
  6370. */
  6371. private function getScopeId($dimension)
  6372. {
  6373. - if (is_numeric($dimension->getValue())) {
  6374. - return $dimension->getValue();
  6375. - } else {
  6376. - return $this->scopeResolver->getScope($dimension->getValue())->getId();
  6377. + $scopeId = $dimension->getValue();
  6378. +
  6379. + if (!is_numeric($scopeId)) {
  6380. + $scopeId = $this->scopeResolver->getScope($scopeId)->getId();
  6381. }
  6382. +
  6383. + return $scopeId;
  6384. }
  6385. }
  6386. diff --git a/vendor/magento/framework/Search/Adapter/Mysql/Adapter.php b/vendor/magento/framework/Search/Adapter/Mysql/Adapter.php
  6387. index b348d5a454b..d89b7eaa13d 100644
  6388. --- a/vendor/magento/framework/Search/Adapter/Mysql/Adapter.php
  6389. +++ b/vendor/magento/framework/Search/Adapter/Mysql/Adapter.php
  6390. @@ -70,12 +70,7 @@ class Adapter implements AdapterInterface
  6391. }
  6392.  
  6393. /**
  6394. - * Process Search Request.
  6395. - *
  6396. - * @param RequestInterface $request
  6397. - *
  6398. - * @return \Magento\Framework\Search\Response\QueryResponse
  6399. - *
  6400. + * {@inheritdoc}
  6401. * @throws \LogicException
  6402. */
  6403. public function query(RequestInterface $request)
  6404. diff --git a/vendor/magento/framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php b/vendor/magento/framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
  6405. index 239bb22ee77..864dfc45b2c 100644
  6406. --- a/vendor/magento/framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
  6407. +++ b/vendor/magento/framework/Search/Adapter/Mysql/Aggregation/Builder/Metrics.php
  6408. @@ -10,14 +10,14 @@ use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface;
  6409. class Metrics
  6410. {
  6411. /**
  6412. - * Available metrics.
  6413. + * Available metrics
  6414. *
  6415. * @var string[]
  6416. */
  6417. private $allowedMetrics = ['count', 'sum', 'min', 'max', 'avg'];
  6418.  
  6419. /**
  6420. - * Build metrics for Select->columns.
  6421. + * Build metrics for Select->columns
  6422. *
  6423. * @param RequestBucketInterface $bucket
  6424. * @return string[]
  6425. diff --git a/vendor/magento/module-advanced-catalog/Model/Indexer/Table/Strategy.php b/vendor/magento/module-advanced-catalog/Model/Indexer/Table/Strategy.php
  6426. index 0da6535c26e..3c25541c924 100644
  6427. --- a/vendor/magento/module-advanced-catalog/Model/Indexer/Table/Strategy.php
  6428. +++ b/vendor/magento/module-advanced-catalog/Model/Indexer/Table/Strategy.php
  6429. @@ -5,15 +5,39 @@
  6430. */
  6431. namespace Magento\AdvancedCatalog\Model\Indexer\Table;
  6432.  
  6433. +use Magento\Framework\App\ObjectManager;
  6434. +
  6435. /**
  6436. * Class Strategy
  6437. *
  6438. * @author Magento Core Team <core@magentocommerce.com>
  6439. + * @deprecated logic moved to catalog module
  6440. + * @see \Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy
  6441. */
  6442. class Strategy extends \Magento\Framework\Indexer\Table\Strategy
  6443. {
  6444. const TEMP_SUFFIX = '_temp';
  6445.  
  6446. + /**
  6447. + * @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy
  6448. + */
  6449. + private $tableStrategy;
  6450. +
  6451. + /**
  6452. + * Strategy constructor.
  6453. + * @param \Magento\Framework\App\ResourceConnection $resource
  6454. + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy|null $tableStrategy
  6455. + */
  6456. + public function __construct(
  6457. + \Magento\Framework\App\ResourceConnection $resource,
  6458. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy $tableStrategy = null
  6459. + ) {
  6460. + parent::__construct($resource);
  6461. + $this->tableStrategy = $tableStrategy ?: ObjectManager::getInstance()->get(
  6462. + \Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy::class
  6463. + );
  6464. + }
  6465. +
  6466. /**
  6467. * Prepare index table name
  6468. *
  6469. @@ -23,15 +47,6 @@ class Strategy extends \Magento\Framework\Indexer\Table\Strategy
  6470. */
  6471. public function prepareTableName($tablePrefix)
  6472. {
  6473. - if ($this->getUseIdxTable()) {
  6474. - return $tablePrefix . self::IDX_SUFFIX;
  6475. - } else {
  6476. - $this->resource->getConnection('indexer')->createTemporaryTableLike(
  6477. - $this->resource->getTableName($tablePrefix . self::TEMP_SUFFIX),
  6478. - $this->resource->getTableName($tablePrefix . self::TMP_SUFFIX),
  6479. - true
  6480. - );
  6481. - return $tablePrefix . self::TEMP_SUFFIX;
  6482. - }
  6483. + return $this->tableStrategy->prepareTableName($tablePrefix);
  6484. }
  6485. }
  6486. diff --git a/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  6487. index 478b195cef7..f4dee8e8b95 100644
  6488. --- a/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  6489. +++ b/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php
  6490. @@ -8,53 +8,21 @@ namespace Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Eav;
  6491. /**
  6492. * Catalog Product Eav Select and Multiply Select Attributes Indexer resource model
  6493. *
  6494. - * @author Magento Core Team <core@magentocommerce.com>
  6495. + * @deprecated Logic moved to parent class implementation
  6496. + * @see \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source
  6497. */
  6498. class Source extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source
  6499. {
  6500. - const TRANSIT_PREFIX = 'transit_';
  6501. -
  6502. /**
  6503. * Prepare data index for product relations
  6504. *
  6505. * @param array $parentIds the parent entity ids limitation
  6506. * @return $this
  6507. + * @deprecated
  6508. */
  6509. protected function _prepareRelationIndex($parentIds = null)
  6510. {
  6511. - $connection = $this->getConnection();
  6512. - $idxTable = $this->getIdxTable();
  6513. -
  6514. - if (!$this->tableStrategy->getUseIdxTable()) {
  6515. - $additionalIdxTable = $connection->getTableName(self::TRANSIT_PREFIX . $this->getIdxTable());
  6516. - $connection->createTemporaryTableLike($additionalIdxTable, $idxTable);
  6517. -
  6518. - $query = $connection->insertFromSelect(
  6519. - $this->_prepareRelationIndexSelect($parentIds),
  6520. - $additionalIdxTable,
  6521. - []
  6522. - );
  6523. - $connection->query($query);
  6524. -
  6525. - $select = $connection->select()->from($additionalIdxTable);
  6526. - $query = $connection->insertFromSelect(
  6527. - $select,
  6528. - $idxTable,
  6529. - [],
  6530. - \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
  6531. - );
  6532. - $connection->query($query);
  6533. -
  6534. - $connection->dropTemporaryTable($additionalIdxTable);
  6535. - } else {
  6536. - $query = $connection->insertFromSelect(
  6537. - $this->_prepareRelationIndexSelect($parentIds),
  6538. - $idxTable,
  6539. - [],
  6540. - \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
  6541. - );
  6542. - $connection->query($query);
  6543. - }
  6544. + parent::_prepareRelationIndex($parentIds);
  6545. return $this;
  6546. }
  6547. }
  6548. diff --git a/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Price/Grouped.php b/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  6549. index 5f71b385826..f9b564a2876 100644
  6550. --- a/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  6551. +++ b/vendor/magento/module-advanced-catalog/Model/ResourceModel/Product/Indexer/Price/Grouped.php
  6552. @@ -9,44 +9,15 @@ namespace Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Price;
  6553.  
  6554. use Magento\Catalog\Api\Data\ProductInterface;
  6555.  
  6556. +/**
  6557. + * @deprecated logic moved to default price indexer.
  6558. + * @see \Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped
  6559. + */
  6560. class Grouped extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice
  6561. {
  6562. const TRANSIT_PREFIX = 'transit_';
  6563. const LINK_TYPE_GROUPED = 3;
  6564.  
  6565. - /**
  6566. - * Reindex temporary (price result data) for all products
  6567. - *
  6568. - * @throws \Exception
  6569. - * @return $this
  6570. - */
  6571. - public function reindexAll()
  6572. - {
  6573. - $this->tableStrategy->setUseIdxTable(true);
  6574. - $this->beginTransaction();
  6575. - try {
  6576. - $this->_prepareGroupedProductPriceData();
  6577. - $this->commit();
  6578. - } catch (\Exception $e) {
  6579. - $this->rollBack();
  6580. - throw $e;
  6581. - }
  6582. - return $this;
  6583. - }
  6584. -
  6585. - /**
  6586. - * Reindex temporary (price result data) for defined product(s)
  6587. - *
  6588. - * @param int|array $entityIds
  6589. - * @return $this
  6590. - */
  6591. - public function reindexEntity($entityIds)
  6592. - {
  6593. - $this->_prepareGroupedProductPriceData($entityIds);
  6594. -
  6595. - return $this;
  6596. - }
  6597. -
  6598. /**
  6599. * Calculate minimal and maximal prices for Grouped products
  6600. * Use calculated price for relation products
  6601. @@ -165,4 +136,12 @@ class Grouped extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price
  6602. );
  6603. return $select;
  6604. }
  6605. +
  6606. + /**
  6607. + * @inheritdoc
  6608. + */
  6609. + protected function reindex($entityIds = null)
  6610. + {
  6611. + $this->_prepareGroupedProductPriceData($entityIds);
  6612. + }
  6613. }
  6614. diff --git a/vendor/magento/module-advanced-catalog/etc/di.xml b/vendor/magento/module-advanced-catalog/etc/di.xml
  6615. index 5a8f894d3e5..7aef529f80c 100644
  6616. --- a/vendor/magento/module-advanced-catalog/etc/di.xml
  6617. +++ b/vendor/magento/module-advanced-catalog/etc/di.xml
  6618. @@ -7,48 +7,4 @@
  6619. -->
  6620. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
  6621. <type name="Magento\AdvancedCatalog\Model\Indexer\Table\Strategy" shared="false" />
  6622. - <preference for="Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source" type="Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Eav\Source" />
  6623. - <type name="Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Eav\Source">
  6624. - <arguments>
  6625. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6626. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6627. - </arguments>
  6628. - </type>
  6629. - <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice">
  6630. - <arguments>
  6631. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6632. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6633. - </arguments>
  6634. - </type>
  6635. - <preference for="Magento\GroupedProduct\Model\ResourceModel\Product\Indexer\Price\Grouped" type="Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Price\Grouped" />
  6636. - <type name="Magento\AdvancedCatalog\Model\ResourceModel\Product\Indexer\Price\Grouped">
  6637. - <arguments>
  6638. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6639. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6640. - </arguments>
  6641. - </type>
  6642. - <type name="Magento\Bundle\Model\ResourceModel\Indexer\Price">
  6643. - <arguments>
  6644. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6645. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6646. - </arguments>
  6647. - </type>
  6648. - <type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable">
  6649. - <arguments>
  6650. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6651. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6652. - </arguments>
  6653. - </type>
  6654. - <type name="Magento\Downloadable\Model\ResourceModel\Indexer\Price">
  6655. - <arguments>
  6656. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6657. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6658. - </arguments>
  6659. - </type>
  6660. - <type name="Magento\GiftCard\Model\ResourceModel\Indexer\Price">
  6661. - <arguments>
  6662. - <argument name="tableStrategy" xsi:type="object">Magento\AdvancedCatalog\Model\Indexer\Table\Strategy</argument>
  6663. - <argument name="connectionName" xsi:type="string">indexer</argument>
  6664. - </arguments>
  6665. - </type>
  6666. </config>
  6667. diff --git a/vendor/magento/module-advanced-search/Model/ResourceModel/Index.php b/vendor/magento/module-advanced-search/Model/ResourceModel/Index.php
  6668. index 8f7804fba62..6eb9f34d8c7 100644
  6669. --- a/vendor/magento/module-advanced-search/Model/ResourceModel/Index.php
  6670. +++ b/vendor/magento/module-advanced-search/Model/ResourceModel/Index.php
  6671. @@ -36,9 +36,9 @@ class Index extends AbstractDb
  6672. MetadataPool $metadataPool,
  6673. $connectionName = null
  6674. ) {
  6675. + parent::__construct($context, $connectionName);
  6676. $this->storeManager = $storeManager;
  6677. $this->metadataPool = $metadataPool;
  6678. - parent::__construct($context, $connectionName);
  6679. }
  6680.  
  6681. /**
  6682. diff --git a/vendor/magento/module-catalog-rule-staging/Setup/UpgradeSchema.php b/vendor/magento/module-catalog-rule-staging/Setup/UpgradeSchema.php
  6683. new file mode 100644
  6684. index 00000000000..768f22beb3b
  6685. --- /dev/null
  6686. +++ b/vendor/magento/module-catalog-rule-staging/Setup/UpgradeSchema.php
  6687. @@ -0,0 +1,36 @@
  6688. +<?php
  6689. +/**
  6690. + * Copyright © Magento, Inc. All rights reserved.
  6691. + * See COPYING.txt for license details.
  6692. + */
  6693. +
  6694. +namespace Magento\CatalogRuleStaging\Setup;
  6695. +
  6696. +use Magento\Framework\Setup\UpgradeSchemaInterface;
  6697. +use Magento\Framework\Setup\ModuleContextInterface;
  6698. +use Magento\Framework\Setup\SchemaSetupInterface;
  6699. +
  6700. +class UpgradeSchema implements UpgradeSchemaInterface
  6701. +{
  6702. + /**
  6703. + * {@inheritdoc}
  6704. + */
  6705. + public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
  6706. + {
  6707. + $setup->startSetup();
  6708. +
  6709. + if (version_compare($context->getVersion(), '2.0.0.1.2', '<')) {
  6710. + $connection = $setup->getConnection();
  6711. + $connection->dropForeignKey(
  6712. + $setup->getTable('catalogrule_group_website'),
  6713. + $setup->getFkName(
  6714. + 'catalogrule_group_website',
  6715. + 'rule_id',
  6716. + 'sequence_catalogrule',
  6717. + 'sequence_value'
  6718. + )
  6719. + );
  6720. + }
  6721. + $setup->endSetup();
  6722. + }
  6723. +}
  6724. diff --git a/vendor/magento/module-catalog-rule-staging/etc/module.xml b/vendor/magento/module-catalog-rule-staging/etc/module.xml
  6725. index d357a65a2ff..547e0a9659c 100644
  6726. --- a/vendor/magento/module-catalog-rule-staging/etc/module.xml
  6727. +++ b/vendor/magento/module-catalog-rule-staging/etc/module.xml
  6728. @@ -6,7 +6,7 @@
  6729. */
  6730. -->
  6731. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  6732. - <module name="Magento_CatalogRuleStaging" setup_version="2.0.0">
  6733. + <module name="Magento_CatalogRuleStaging" setup_version="2.0.0.1.2">
  6734. <sequence>
  6735. <module name="Magento_Staging"/>
  6736. <module name="Magento_CatalogRule"/>
  6737. diff --git a/vendor/magento/module-catalog-staging/Setup/UpgradeSchema.php b/vendor/magento/module-catalog-staging/Setup/UpgradeSchema.php
  6738. index f1967de20f1..28678702132 100644
  6739. --- a/vendor/magento/module-catalog-staging/Setup/UpgradeSchema.php
  6740. +++ b/vendor/magento/module-catalog-staging/Setup/UpgradeSchema.php
  6741. @@ -26,11 +26,26 @@ class UpgradeSchema implements UpgradeSchemaInterface
  6742. */
  6743. public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
  6744. {
  6745. - $this->addIndexIfNotExist(
  6746. - $setup,
  6747. - 'catalog_product_entity',
  6748. - ['entity_id', 'created_in', 'updated_in']
  6749. - );
  6750. + $setup->startSetup();
  6751. + if (version_compare($context->getVersion(), '2.1.1', '<')) {
  6752. + $this->addIndexIfNotExist(
  6753. + $setup,
  6754. + 'catalog_product_entity',
  6755. + ['entity_id', 'created_in', 'updated_in']
  6756. + );
  6757. + }
  6758. +
  6759. + if (version_compare($context->getVersion(), '2.1.1.1.2', '<')) {
  6760. + $setup->getConnection()->dropForeignKey(
  6761. + $setup->getTable('catalog_product_index_price'),
  6762. + $setup->getFkName(
  6763. + 'catalog_product_index_price',
  6764. + 'entity_id',
  6765. + 'sequence_product',
  6766. + 'sequence_value'
  6767. + )
  6768. + );
  6769. + }
  6770. }
  6771.  
  6772. /**
  6773. diff --git a/vendor/magento/module-catalog-staging/etc/module.xml b/vendor/magento/module-catalog-staging/etc/module.xml
  6774. index d3bb700ced4..ad3f51121c1 100644
  6775. --- a/vendor/magento/module-catalog-staging/etc/module.xml
  6776. +++ b/vendor/magento/module-catalog-staging/etc/module.xml
  6777. @@ -6,7 +6,7 @@
  6778. */
  6779. -->
  6780. <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
  6781. - <module name="Magento_CatalogStaging" setup_version="2.1.1">
  6782. + <module name="Magento_CatalogStaging" setup_version="2.1.1.1.2">
  6783. <sequence>
  6784. <module name="Magento_Catalog"/>
  6785. <module name="Magento_CatalogInventory"/>
  6786. diff --git a/vendor/magento/module-elasticsearch/Model/ResourceModel/Index.php b/vendor/magento/module-elasticsearch/Model/ResourceModel/Index.php
  6787. index f384260ad84..869b9e89f02 100644
  6788. --- a/vendor/magento/module-elasticsearch/Model/ResourceModel/Index.php
  6789. +++ b/vendor/magento/module-elasticsearch/Model/ResourceModel/Index.php
  6790. @@ -42,6 +42,7 @@ class Index extends \Magento\AdvancedSearch\Model\ResourceModel\Index
  6791. * @param CategoryRepositoryInterface $categoryRepository
  6792. * @param Config $eavConfig
  6793. * @param null $connectionName
  6794. + * @SuppressWarnings(Magento.TypeDuplication)
  6795. */
  6796. public function __construct(
  6797. Context $context,
  6798. @@ -55,7 +56,12 @@ class Index extends \Magento\AdvancedSearch\Model\ResourceModel\Index
  6799. $this->productRepository = $productRepository;
  6800. $this->categoryRepository = $categoryRepository;
  6801. $this->eavConfig = $eavConfig;
  6802. - parent::__construct($context, $storeManager, $metadataPool, $connectionName);
  6803. + parent::__construct(
  6804. + $context,
  6805. + $storeManager,
  6806. + $metadataPool,
  6807. + $connectionName
  6808. + );
  6809. }
  6810.  
  6811. /**
  6812. diff --git a/vendor/magento/module-gift-card/etc/di.xml b/vendor/magento/module-gift-card/etc/di.xml
  6813. index 53233e3ab39..2de0249cded 100644
  6814. --- a/vendor/magento/module-gift-card/etc/di.xml
  6815. +++ b/vendor/magento/module-gift-card/etc/di.xml
  6816. @@ -149,4 +149,10 @@
  6817. </argument>
  6818. </arguments>
  6819. </type>
  6820. + <type name="Magento\GiftCard\Model\ResourceModel\Indexer\Price">
  6821. + <arguments>
  6822. + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument>
  6823. + <argument name="connectionName" xsi:type="string">indexer</argument>
  6824. + </arguments>
  6825. + </type>
  6826. </config>
Add Comment
Please, Sign In to add comment