/** * Prepare temporary flat tables * * @param int|string $storeId * @param array $changedIds * @param string $valueFieldSuffix * @param string $tableDropSuffix * @param bool $fillTmpTables * @return void */ public function build($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables) { $attributes = $this->_productIndexerHelper->getAttributes(); $eavAttributes = $this->_productIndexerHelper->getTablesStructure($attributes); $this->_createTemporaryFlatTable($storeId); if ($fillTmpTables) { $this->_fillTemporaryFlatTable($eavAttributes, $storeId, $valueFieldSuffix); //Update zero based attributes by values from current store $this->_updateTemporaryTableByStoreValues($eavAttributes, $changedIds, $storeId, $valueFieldSuffix); } $flatTable = $this->_productIndexerHelper->getFlatTableName($storeId); $flatDropName = $flatTable . $tableDropSuffix; $temporaryFlatTableName = $this->_getTemporaryTableName($this->_productIndexerHelper->getFlatTableName($storeId)); $this->_tableData->move($flatTable, $flatDropName, $temporaryFlatTableName); }
/** * Rebuild catalog flat index from scratch * * @param int $storeId * @param array $changedIds * @return void * @throws \Exception */ protected function _reindex($storeId, array $changedIds = []) { try { $this->_tableBuilder->build($storeId, $changedIds, $this->_valueFieldSuffix); $this->_flatTableBuilder->build($storeId, $changedIds, $this->_valueFieldSuffix, $this->_tableDropSuffix, true); $this->_updateRelationProducts($storeId, $changedIds); $this->_cleanRelationProducts($storeId); } catch (\Exception $e) { $attributes = $this->_productIndexerHelper->getAttributes(); $eavAttributes = $this->_productIndexerHelper->getTablesStructure($attributes); $this->_cleanOnFailure($eavAttributes, $storeId); throw $e; } }
/** * Prepare temporary tables only for first call of reindex all * * @param int $storeId * @param array $changedIds * @param string $valueFieldSuffix * @return void */ public function build($storeId, $changedIds, $valueFieldSuffix) { if ($this->_isExecuted) { return; } $entityTableName = $this->_productIndexerHelper->getTable('catalog_product_entity'); $attributes = $this->_productIndexerHelper->getAttributes(); $eavAttributes = $this->_productIndexerHelper->getTablesStructure($attributes); $entityTableColumns = $eavAttributes[$entityTableName]; $temporaryEavAttributes = $eavAttributes; //add status global value to the base table /* @var $status \Magento\Eav\Model\Entity\Attribute */ $status = $this->_productIndexerHelper->getAttribute('status'); $temporaryEavAttributes[$status->getBackendTable()]['status'] = $status; //Create list of temporary tables based on available attributes attributes $valueTables = []; foreach ($temporaryEavAttributes as $tableName => $columns) { $valueTables = array_merge($valueTables, $this->_createTemporaryTable($this->_getTemporaryTableName($tableName), $columns, $valueFieldSuffix)); } //Fill "base" table which contains all available products $this->_fillTemporaryEntityTable($entityTableName, $entityTableColumns, $changedIds); //Add primary key to "base" temporary table for increase speed of joins in future $this->_addPrimaryKeyToTable($this->_getTemporaryTableName($entityTableName)); unset($temporaryEavAttributes[$entityTableName]); foreach ($temporaryEavAttributes as $tableName => $columns) { $temporaryTableName = $this->_getTemporaryTableName($tableName); //Add primary key to temporary table for increase speed of joins in future $this->_addPrimaryKeyToTable($temporaryTableName); //Create temporary table for composite attributes if (isset($valueTables[$temporaryTableName . $valueFieldSuffix])) { $this->_addPrimaryKeyToTable($temporaryTableName . $valueFieldSuffix); } //Fill temporary tables with attributes grouped by it type $this->_fillTemporaryTable($tableName, $columns, $changedIds, $valueFieldSuffix, $storeId); } $this->_isExecuted = true; }
/** * Write single product into flat product table * * @param int $storeId * @param int $productId * @param string $valueFieldSuffix * @return \Magento\Catalog\Model\Indexer\Product\Flat */ public function write($storeId, $productId, $valueFieldSuffix = '') { $flatTable = $this->_productIndexerHelper->getFlatTableName($storeId); $attributes = $this->_productIndexerHelper->getAttributes(); $eavAttributes = $this->_productIndexerHelper->getTablesStructure($attributes); $updateData = array(); $describe = $this->_connection->describeTable($flatTable); foreach ($eavAttributes as $tableName => $tableColumns) { $columnsChunks = array_chunk($tableColumns, self::ATTRIBUTES_CHUNK_SIZE, true); foreach ($columnsChunks as $columns) { $select = $this->_connection->select(); $selectValue = $this->_connection->select(); $keyColumns = array('entity_id' => 'e.entity_id', 'attribute_id' => 't.attribute_id', 'value' => $this->_connection->getIfNullSql('`t2`.`value`', '`t`.`value`')); if ($tableName != $this->_productIndexerHelper->getTable('catalog_product_entity')) { $valueColumns = array(); $ids = array(); $select->from(array('e' => $this->_productIndexerHelper->getTable('catalog_product_entity')), $keyColumns); $selectValue->from(array('e' => $this->_productIndexerHelper->getTable('catalog_product_entity')), $keyColumns); /** @var $attribute \Magento\Catalog\Model\Resource\Eav\Attribute */ foreach ($columns as $columnName => $attribute) { if (isset($describe[$columnName])) { $ids[$attribute->getId()] = $columnName; } } $select->joinLeft(array('t' => $tableName), 'e.entity_id = t.entity_id ' . $this->_connection->quoteInto(' AND t.attribute_id IN (?)', array_keys($ids)) . ' AND t.store_id = 0', array())->joinLeft(array('t2' => $tableName), 't.entity_id = t2.entity_id ' . ' AND t.attribute_id = t2.attribute_id ' . $this->_connection->quoteInto(' AND t2.store_id = ?', $storeId), array())->where('e.entity_id = ' . $productId)->where('t.attribute_id IS NOT NULL'); $cursor = $this->_connection->query($select); while ($row = $cursor->fetch(\Zend_Db::FETCH_ASSOC)) { $updateData[$ids[$row['attribute_id']]] = $row['value']; $valueColumnName = $ids[$row['attribute_id']] . $valueFieldSuffix; if (isset($describe[$valueColumnName])) { $valueColumns[$row['value']] = $valueColumnName; } } //Update not simple attributes (eg. dropdown) if (!empty($valueColumns)) { $valueIds = array_keys($valueColumns); $select = $this->_connection->select()->from(array('t' => $this->_productIndexerHelper->getTable('eav_attribute_option_value')), array('t.option_id', 't.value'))->where($this->_connection->quoteInto('t.option_id IN (?)', $valueIds)); $cursor = $this->_connection->query($select); while ($row = $cursor->fetch(\Zend_Db::FETCH_ASSOC)) { $valueColumnName = $valueColumns[$row['option_id']]; if (isset($describe[$valueColumnName])) { $updateData[$valueColumnName] = $row['value']; } } } } else { $columnNames = array_keys($columns); $columnNames[] = 'attribute_set_id'; $columnNames[] = 'type_id'; $select->from(array('e' => $this->_productIndexerHelper->getTable('catalog_product_entity')), $columnNames)->where('e.entity_id = ' . $productId); $cursor = $this->_connection->query($select); $row = $cursor->fetch(\Zend_Db::FETCH_ASSOC); if (!empty($row)) { foreach ($row as $columnName => $value) { $updateData[$columnName] = $value; } } } } } if (!empty($updateData)) { $updateData += array('entity_id' => $productId); $updateFields = array(); foreach ($updateData as $key => $value) { $updateFields[$key] = $key; } $this->_connection->insertOnDuplicate($flatTable, $updateData, $updateFields); } return $this; }