Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Full.php
Go to the documentation of this file.
1 <?php
7 
16 
22 class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
23 {
27  private $metadataPool;
28 
32  private $batchSizeCalculator;
33 
37  private $batchProvider;
38 
42  private $activeTableSwitcher;
43 
47  private $productMetaDataCached;
48 
52  private $dimensionCollectionFactory;
53 
57  private $dimensionTableMaintainer;
58 
62  private $processManager;
63 
82  public function __construct(
85  \Magento\Directory\Model\CurrencyFactory $currencyFactory,
86  \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
87  \Magento\Framework\Stdlib\DateTime $dateTime,
88  \Magento\Catalog\Model\Product\Type $catalogProductType,
89  \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory,
90  \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource,
91  \Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
92  \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator $batchSizeCalculator = null,
93  \Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
94  \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null,
95  \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory = null,
96  \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $dimensionTableMaintainer = null,
97  \Magento\Indexer\Model\ProcessManager $processManager = null
98  ) {
99  parent::__construct(
100  $config,
102  $currencyFactory,
103  $localeDate,
104  $dateTime,
105  $catalogProductType,
106  $indexerPriceFactory,
107  $defaultIndexerResource
108  );
109  $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(
110  \Magento\Framework\EntityManager\MetadataPool::class
111  );
112  $this->batchSizeCalculator = $batchSizeCalculator ?: ObjectManager::getInstance()->get(
113  \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator::class
114  );
115  $this->batchProvider = $batchProvider ?: ObjectManager::getInstance()->get(
116  \Magento\Framework\Indexer\BatchProviderInterface::class
117  );
118  $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
119  \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
120  );
121  $this->dimensionCollectionFactory = $dimensionCollectionFactory ?: ObjectManager::getInstance()->get(
122  \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class
123  );
124  $this->dimensionTableMaintainer = $dimensionTableMaintainer ?: ObjectManager::getInstance()->get(
125  \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class
126  );
127  $this->processManager = $processManager ?: ObjectManager::getInstance()->get(
128  \Magento\Indexer\Model\ProcessManager::class
129  );
130  }
131 
140  public function execute($ids = null)
141  {
142  try {
143  //Prepare indexer tables before full reindex
144  $this->prepareTables();
145 
147  foreach ($this->getTypeIndexers(true) as $typeId => $priceIndexer) {
148  if ($priceIndexer instanceof DimensionalIndexerInterface) {
149  //New price reindex mechanism
150  $this->reindexProductTypeWithDimensions($priceIndexer, $typeId);
151  continue;
152  }
153 
154  $priceIndexer->getTableStrategy()->setUseIdxTable(false);
155 
156  //Old price reindex mechanism
157  $this->reindexProductType($priceIndexer, $typeId);
158  }
159 
160  //Final replacement of tables from replica to main
161  $this->switchTables();
162  } catch (\Exception $e) {
163  throw new LocalizedException(__($e->getMessage()), $e);
164  }
165  }
166 
173  private function prepareTables()
174  {
175  $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false);
176 
177  $this->_prepareWebsiteDateTable();
178 
179  $this->truncateReplicaTables();
180  }
181 
188  private function truncateReplicaTables()
189  {
190  foreach ($this->dimensionCollectionFactory->create() as $dimension) {
191  $dimensionTable = $this->dimensionTableMaintainer->getMainReplicaTable($dimension);
192  $this->_defaultIndexerResource->getConnection()->truncateTable($dimensionTable);
193  }
194  }
195 
205  private function reindexProductTypeWithDimensions(DimensionalIndexerInterface $priceIndexer, string $typeId)
206  {
207  $userFunctions = [];
208  foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
209  $userFunctions[] = function () use ($priceIndexer, $dimensions, $typeId) {
210  return $this->reindexByBatches($priceIndexer, $dimensions, $typeId);
211  };
212  }
213  $this->processManager->execute($userFunctions);
214  }
215 
226  private function reindexByBatches(DimensionalIndexerInterface $priceIndexer, array $dimensions, string $typeId)
227  {
228  foreach ($this->getBatchesForIndexer($typeId) as $batch) {
229  $this->reindexByBatchWithDimensions($priceIndexer, $batch, $dimensions, $typeId);
230  }
231  }
232 
241  private function getBatchesForIndexer(string $typeId)
242  {
243  $connection = $this->_defaultIndexerResource->getConnection();
244  return $this->batchProvider->getBatches(
245  $connection,
246  $this->getProductMetaData()->getEntityTable(),
247  $this->getProductMetaData()->getIdentifierField(),
248  $this->batchSizeCalculator->estimateBatchSize(
249  $connection,
250  $typeId
251  )
252  );
253  }
254 
266  private function reindexByBatchWithDimensions(
267  DimensionalIndexerInterface $priceIndexer,
268  array $batch,
269  array $dimensions,
270  string $typeId
271  ) {
272  $entityIds = $this->getEntityIdsFromBatch($typeId, $batch);
273 
274  if (!empty($entityIds)) {
275  $this->dimensionTableMaintainer->createMainTmpTable($dimensions);
276  $temporaryTable = $this->dimensionTableMaintainer->getMainTmpTable($dimensions);
277  $this->_emptyTable($temporaryTable);
278 
279  $priceIndexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false));
280 
281  // Sync data from temp table to index table
282  $this->_insertFromTable(
283  $temporaryTable,
284  $this->dimensionTableMaintainer->getMainReplicaTable($dimensions)
285  );
286  }
287  }
288 
298  private function reindexProductType(PriceInterface $priceIndexer, string $typeId)
299  {
300  foreach ($this->getBatchesForIndexer($typeId) as $batch) {
301  $this->reindexBatch($priceIndexer, $batch, $typeId);
302  }
303  }
304 
315  private function reindexBatch(PriceInterface $priceIndexer, array $batch, string $typeId)
316  {
317  $entityIds = $this->getEntityIdsFromBatch($typeId, $batch);
318 
319  if (!empty($entityIds)) {
320  // Temporary table will created if not exists
321  $idxTableName = $this->_defaultIndexerResource->getIdxTable();
322  $this->_emptyTable($idxTableName);
323 
324  if ($priceIndexer->getIsComposite()) {
325  $this->_copyRelationIndexData($entityIds);
326  }
327 
328  // Reindex entities by id
329  $priceIndexer->reindexEntity($entityIds);
330 
331  // Sync data from temp table to index table
332  $this->_insertFromTable($idxTableName, $this->getReplicaTable());
333 
334  // Drop temporary index table
335  $this->_defaultIndexerResource->getConnection()->dropTable($idxTableName);
336  }
337  }
338 
348  private function getEntityIdsFromBatch(string $typeId, array $batch)
349  {
350  $connection = $this->_defaultIndexerResource->getConnection();
351 
352  // Get entity ids from batch
354  ->select()
355  ->distinct(true)
356  ->from(
357  ['e' => $this->getProductMetaData()->getEntityTable()],
358  $this->getProductMetaData()->getIdentifierField()
359  )
360  ->where('type_id = ?', $typeId);
361 
362  return $this->batchProvider->getBatchIds($connection, $select, $batch);
363  }
364 
371  private function getProductMetaData()
372  {
373  if ($this->productMetaDataCached === null) {
374  $this->productMetaDataCached = $this->metadataPool->getMetadata(ProductInterface::class);
375  }
376 
377  return $this->productMetaDataCached;
378  }
379 
386  private function getReplicaTable()
387  {
388  return $this->activeTableSwitcher->getAdditionalTableName(
389  $this->_defaultIndexerResource->getMainTable()
390  );
391  }
392 
398  private function switchTables()
399  {
400  // Switch dimension tables
401  $mainTablesByDimension = [];
402 
403  foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
404  $mainTablesByDimension[] = $this->dimensionTableMaintainer->getMainTable($dimensions);
405 
406  //Move data from indexers with old realisation
407  $this->moveDataFromReplicaTableToReplicaTables($dimensions);
408  }
409 
410  if (count($mainTablesByDimension) > 0) {
411  $this->activeTableSwitcher->switchTable(
412  $this->_defaultIndexerResource->getConnection(),
413  $mainTablesByDimension
414  );
415  }
416  }
417 
426  private function moveDataFromReplicaTableToReplicaTables(array $dimensions)
427  {
428  if (!$dimensions) {
429  return;
430  }
431  $select = $this->dimensionTableMaintainer->getConnection()->select()->from(
432  $this->dimensionTableMaintainer->getMainReplicaTable([])
433  );
434 
435  $check = clone $select;
436  $check->reset('columns')->columns('count(*)');
437 
438  if (!$this->dimensionTableMaintainer->getConnection()->query($check)->fetchColumn()) {
439  return;
440  }
441 
442  $replicaTablesByDimension = $this->dimensionTableMaintainer->getMainReplicaTable($dimensions);
443 
444  foreach ($dimensions as $dimension) {
445  if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) {
446  $select->where('website_id = ?', $dimension->getValue());
447  }
448  if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) {
449  $select->where('customer_group_id = ?', $dimension->getValue());
450  }
451  }
452 
453  $this->dimensionTableMaintainer->getConnection()->query(
454  $this->dimensionTableMaintainer->getConnection()->insertFromSelect(
455  $select,
456  $replicaTablesByDimension,
457  [],
458  \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
459  )
460  );
461  }
462 
468  protected function getIndexTargetTable()
469  {
470  return $this->activeTableSwitcher->getAdditionalTableName($this->_defaultIndexerResource->getMainTable());
471  }
472 }
_insertFromTable($sourceTable, $destTable, $where=null)
$config
Definition: fraud_order.php:17
$storeManager
__()
Definition: __.php:13
__construct(\Magento\Framework\App\Config\ScopeConfigInterface $config, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Directory\Model\CurrencyFactory $currencyFactory, \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, \Magento\Framework\Stdlib\DateTime $dateTime, \Magento\Catalog\Model\Product\Type $catalogProductType, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource, \Magento\Framework\EntityManager\MetadataPool $metadataPool=null, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator $batchSizeCalculator=null, \Magento\Framework\Indexer\BatchProviderInterface $batchProvider=null, \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher=null, \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory=null, \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $dimensionTableMaintainer=null, \Magento\Indexer\Model\ProcessManager $processManager=null)
Definition: Full.php:82
$connection
Definition: bulk.php:13
$dateTime