Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Source.php
Go to the documentation of this file.
1 <?php
7 
10 
16 class Source extends AbstractEav
17 {
18  const TRANSIT_PREFIX = 'transit_';
19 
25  protected $_resourceHelper;
26 
37  public function __construct(
38  \Magento\Framework\Model\ResourceModel\Db\Context $context,
39  \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy,
40  \Magento\Eav\Model\Config $eavConfig,
41  \Magento\Framework\Event\ManagerInterface $eventManager,
42  \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper,
43  $connectionName = null
44  ) {
45  parent::__construct(
46  $context,
48  $eavConfig,
51  );
52  $this->_resourceHelper = $resourceHelper;
53  }
54 
60  protected function _construct()
61  {
62  $this->_init('catalog_product_index_eav', 'entity_id');
63  }
64 
71  protected function _getIndexableAttributes($multiSelect)
72  {
73  $select = $this->getConnection()->select()->from(
74  ['ca' => $this->getTable('catalog_eav_attribute')],
75  'attribute_id'
76  )->join(
77  ['ea' => $this->getTable('eav_attribute')],
78  'ca.attribute_id = ea.attribute_id',
79  []
80  )->where(
82  );
83 
84  if ($multiSelect == true) {
85  $select->where('ea.backend_type = ?', 'varchar')->where('ea.frontend_input = ?', 'multiselect');
86  } else {
87  $select->where('ea.backend_type = ?', 'int')->where('ea.frontend_input = ?', 'select');
88  }
89 
90  return $this->getConnection()->fetchCol($select);
91  }
92 
100  protected function _prepareIndex($entityIds = null, $attributeId = null)
101  {
102  $this->_prepareSelectIndex($entityIds, $attributeId);
103  $this->_prepareMultiselectIndex($entityIds, $attributeId);
104 
105  return $this;
106  }
107 
116  protected function _prepareSelectIndex($entityIds = null, $attributeId = null)
117  {
118  $connection = $this->getConnection();
119  $idxTable = $this->getIdxTable();
120  // prepare select attributes
121  $attrIds = $attributeId === null ? $this->_getIndexableAttributes(false) : [$attributeId];
122  if (!$attrIds) {
123  return $this;
124  }
125  $productIdField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
126  $attrIdsFlat = implode(',', array_map('intval', $attrIds));
127  $ifNullSql = $connection->getIfNullSql('pis.value', 'COALESCE(ds.value, dd.value)');
128 
130  $select = $connection->select()->distinct(true)->from(
131  ['s' => $this->getTable('store')],
132  []
133  )->joinLeft(
134  ['dd' => $this->getTable('catalog_product_entity_int')],
135  'dd.store_id = 0',
136  []
137  )->joinLeft(
138  ['ds' => $this->getTable('catalog_product_entity_int')],
139  "ds.store_id = s.store_id AND ds.attribute_id = dd.attribute_id AND " .
140  "ds.{$productIdField} = dd.{$productIdField}",
141  []
142  )->joinLeft(
143  ['d2d' => $this->getTable('catalog_product_entity_int')],
144  sprintf(
145  "d2d.store_id = 0 AND d2d.{$productIdField} = dd.{$productIdField} AND d2d.attribute_id = %s",
146  $this->_eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'status')->getId()
147  ),
148  []
149  )->joinLeft(
150  ['d2s' => $this->getTable('catalog_product_entity_int')],
151  "d2s.store_id = s.store_id AND d2s.attribute_id = d2d.attribute_id AND " .
152  "d2s.{$productIdField} = d2d.{$productIdField}",
153  []
154  )->joinLeft(
155  ['cpe' => $this->getTable('catalog_product_entity')],
156  "cpe.{$productIdField} = dd.{$productIdField}",
157  []
158  )->joinLeft(
159  ['pis' => $this->getTable('catalog_product_entity_int')],
160  "pis.{$productIdField} = cpe.{$productIdField} " .
161  "AND pis.attribute_id = dd.attribute_id AND pis.store_id = s.store_id",
162  []
163  )->where(
164  's.store_id != 0'
165  )->where(
166  '(ds.value IS NOT NULL OR dd.value IS NOT NULL)'
167  )->where(
168  (new \Zend_Db_Expr('COALESCE(d2s.value, d2d.value)')) . ' = ' . ProductStatus::STATUS_ENABLED
169  )->where(
170  "dd.attribute_id IN({$attrIdsFlat})"
171  )->where(
172  'NOT(pis.value IS NULL AND pis.value_id IS NOT NULL)'
173  )->where(
174  $ifNullSql . ' IS NOT NULL'
175  )->columns(
176  [
177  'cpe.entity_id',
178  'dd.attribute_id',
179  's.store_id',
180  'value' => new \Zend_Db_Expr('COALESCE(ds.value, dd.value)'),
181  'cpe.entity_id',
182  ]
183  );
184 
185  if ($entityIds !== null) {
186  $ids = implode(',', array_map('intval', $entityIds));
187  $select->where("cpe.entity_id IN({$ids})");
188  }
189 
193  $this->_eventManager->dispatch(
194  'prepare_catalog_product_index_select',
195  [
196  'select' => $select,
197  'entity_field' => new \Zend_Db_Expr('cpe.entity_id'),
198  'website_field' => new \Zend_Db_Expr('s.website_id'),
199  'store_field' => new \Zend_Db_Expr('s.store_id'),
200  ]
201  );
202  $query = $select->insertFromSelect($idxTable);
203  $connection->query($query);
204  return $this;
205  }
206 
214  protected function _prepareMultiselectIndex($entityIds = null, $attributeId = null)
215  {
216  $connection = $this->getConnection();
217 
218  // prepare multiselect attributes
219  $attrIds = $attributeId === null ? $this->_getIndexableAttributes(true) : [$attributeId];
220 
221  if (!$attrIds) {
222  return $this;
223  }
224  $productIdField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
225 
226  // load attribute options
227  $options = [];
228  $select = $connection->select()->from(
229  $this->getTable('eav_attribute_option'),
230  ['attribute_id', 'option_id']
231  )->where('attribute_id IN(?)', $attrIds);
232  $query = $select->query();
233  while ($row = $query->fetch()) {
234  $options[$row['attribute_id']][$row['option_id']] = true;
235  }
236 
237  // prepare get multiselect values query
238  $productValueExpression = $connection->getCheckSql('pvs.value_id > 0', 'pvs.value', 'pvd.value');
239  $select = $connection->select()->from(
240  ['pvd' => $this->getTable('catalog_product_entity_varchar')],
241  []
242  )->join(
243  ['cs' => $this->getTable('store')],
244  '',
245  []
246  )->joinLeft(
247  ['pvs' => $this->getTable('catalog_product_entity_varchar')],
248  "pvs.{$productIdField} = pvd.{$productIdField} AND pvs.attribute_id = pvd.attribute_id"
249  . ' AND pvs.store_id=cs.store_id',
250  []
251  )->joinLeft(
252  ['cpe' => $this->getTable('catalog_product_entity')],
253  "cpe.{$productIdField} = pvd.{$productIdField}",
254  []
255  )->where(
256  'pvd.store_id=?',
257  $connection->getIfNullSql('pvs.store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID)
258  )->where(
259  'cs.store_id!=?',
260  \Magento\Store\Model\Store::DEFAULT_STORE_ID
261  )->where(
262  'pvd.attribute_id IN(?)',
263  $attrIds
264  )->where(
265  'cpe.entity_id IS NOT NULL'
266  )->columns(
267  [
268  'entity_id' => 'cpe.entity_id',
269  'attribute_id' => 'attribute_id',
270  'store_id' => 'cs.store_id',
271  'value' => $productValueExpression,
272  'source_id' => 'cpe.entity_id',
273  ]
274  );
275 
276  $statusCond = $connection->quoteInto('=?', ProductStatus::STATUS_ENABLED);
277  $this->_addAttributeToSelect($select, 'status', "pvd.{$productIdField}", 'cs.store_id', $statusCond);
278 
279  if ($entityIds !== null) {
280  $select->where('cpe.entity_id IN(?)', $entityIds);
281  }
285  $this->_eventManager->dispatch(
286  'prepare_catalog_product_index_select',
287  [
288  'select' => $select,
289  'entity_field' => new \Zend_Db_Expr('cpe.entity_id'),
290  'website_field' => new \Zend_Db_Expr('cs.website_id'),
291  'store_field' => new \Zend_Db_Expr('cs.store_id'),
292  ]
293  );
294 
295  $this->saveDataFromSelect($select, $options);
296 
297  return $this;
298  }
299 
306  protected function _saveIndexData(array $data)
307  {
308  if (!$data) {
309  return $this;
310  }
311  $connection = $this->getConnection();
312  $connection->insertArray(
313  $this->getIdxTable(),
314  ['entity_id', 'attribute_id', 'store_id', 'value', 'source_id'],
315  $data
316  );
317  return $this;
318  }
319 
327  public function getIdxTable($table = null)
328  {
329  return $this->tableStrategy->getTableName('catalog_product_index_eav');
330  }
331 
337  private function saveDataFromSelect(\Magento\Framework\DB\Select $select, array $options)
338  {
339  $i = 0;
340  $data = [];
341  $query = $select->query();
342  while ($row = $query->fetch()) {
343  $values = explode(',', $row['value']);
344  foreach ($values as $valueId) {
345  if (isset($options[$row['attribute_id']][$valueId])) {
346  $data[] = [$row['entity_id'], $row['attribute_id'], $row['store_id'], $valueId, $row['source_id']];
347  $i++;
348  if ($i % 10000 == 0) {
349  $this->_saveIndexData($data);
350  $data = [];
351  }
352  }
353  }
354  }
355 
356  $this->_saveIndexData($data);
357  }
358 
365  protected function _prepareRelationIndex($parentIds = null)
366  {
367  $connection = $this->getConnection();
368  $idxTable = $this->getIdxTable();
369 
370  if (!$this->tableStrategy->getUseIdxTable()) {
371  $additionalIdxTable = $connection->getTableName(self::TRANSIT_PREFIX . $this->getIdxTable());
372  $connection->createTemporaryTableLike($additionalIdxTable, $idxTable);
373 
374  $query = $connection->insertFromSelect(
375  $this->_prepareRelationIndexSelect($parentIds),
376  $additionalIdxTable,
377  []
378  );
379  $connection->query($query);
380 
381  $select = $connection->select()->from($additionalIdxTable);
382  $query = $connection->insertFromSelect(
383  $select,
384  $idxTable,
385  [],
386  \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
387  );
388  $connection->query($query);
389 
390  $connection->dropTemporaryTable($additionalIdxTable);
391  } else {
392  $query = $connection->insertFromSelect(
393  $this->_prepareRelationIndexSelect($parentIds),
394  $idxTable,
395  [],
396  \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_IGNORE
397  );
398  $connection->query($query);
399  }
400  return $this;
401  }
402 }
_prepareIndex($entityIds=null, $attributeId=null)
Definition: Source.php:100
_addAttributeToSelect($select, $attrCode, $entity, $store, $condition=null, $required=false)
$values
Definition: options.phtml:88
__construct(\Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper, $connectionName=null)
Definition: Source.php:37
_prepareMultiselectIndex($entityIds=null, $attributeId=null)
Definition: Source.php:214
$connection
Definition: bulk.php:13
$table
Definition: trigger.php:14
$i
Definition: gallery.phtml:31