![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-catalog/Model/Indexer/Category/Flat/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model\Indexer\Category\Flat; use Magento\Catalog\Api\Data\CategoryInterface; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\ResourceModel\Helper; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\EntityManager\EntityMetadata; use Magento\Framework\EntityManager\MetadataPool; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; /** * Abstract action class for category flat indexers. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AbstractAction { /** * Suffix for table to show it is temporary */ public const TEMPORARY_TABLE_SUFFIX = '_tmp'; /** * @var array */ protected $attributeCodes; /** * @var Resource */ protected $resource; /** * @var StoreManagerInterface */ protected $storeManager; /** * Catalog resource helper * * @var Helper */ protected $resourceHelper; /** * Flat columns * * @var array */ protected $columns = []; /** * @var AdapterInterface */ protected $connection; /** * @var EntityMetadata */ protected $categoryMetadata; /** * Static columns to skip * * @var array */ protected $skipStaticColumns = []; /** * @var SkipStaticColumnsProvider */ private $skipStaticColumnsProvider; /** * @param ResourceConnection $resource * @param StoreManagerInterface $storeManager * @param Helper $resourceHelper * @param MetadataPool|null $metadataPool * @param SkipStaticColumnsProvider|null $skipStaticColumnsProvider */ public function __construct( ResourceConnection $resource, StoreManagerInterface $storeManager, Helper $resourceHelper, MetadataPool $metadataPool = null, SkipStaticColumnsProvider $skipStaticColumnsProvider = null ) { $this->resource = $resource; $this->connection = $resource->getConnection(); $this->storeManager = $storeManager; $this->resourceHelper = $resourceHelper; $metadataPool = $metadataPool ?? ObjectManager::getInstance()->get(MetadataPool::class); $this->categoryMetadata = $metadataPool->getMetadata(CategoryInterface::class); $this->skipStaticColumnsProvider = $skipStaticColumnsProvider ?? ObjectManager::getInstance()->get(SkipStaticColumnsProvider::class); $this->columns = array_merge($this->getStaticColumns(), $this->getEavColumns()); } /** * Add suffix to table name to show it is temporary * * @param string $tableName * @return string */ protected function addTemporaryTableSuffix($tableName) { return $tableName . self::TEMPORARY_TABLE_SUFFIX; } /** * Retrieve list of columns for flat structure * * @return array */ public function getColumns() { return $this->columns; } /** * Return name of table for given $storeId. * * @param integer $storeId * @return string */ public function getMainStoreTable($storeId = Store::DEFAULT_STORE_ID) { if (is_string($storeId)) { $storeId = (int) $storeId; } $suffix = sprintf('store_%d', $storeId); return $this->connection->getTableName($this->getTableName('catalog_category_flat_' . $suffix)); } /** * Return structure for flat catalog table * * @param string $tableName * @return Table * @throws \Zend_Db_Exception */ protected function getFlatTableStructure($tableName) { $table = $this->connection->newTable( $tableName )->setComment( 'Catalog Category Flat' ); //Adding columns foreach ($this->getColumns() as $fieldName => $fieldProp) { $default = $fieldProp['default']; if ($fieldProp['type'][0] == Table::TYPE_TIMESTAMP && $default == 'CURRENT_TIMESTAMP' ) { $default = Table::TIMESTAMP_INIT; } $table->addColumn( $fieldName, $fieldProp['type'][0], $fieldProp['type'][1], [ 'nullable' => $fieldProp['nullable'], 'unsigned' => $fieldProp['unsigned'], 'default' => $default, 'primary' => isset($fieldProp['primary']) ? $fieldProp['primary'] : false ], $fieldProp['comment'] != '' ? $fieldProp['comment'] : ucwords(str_replace('_', ' ', $fieldName)) ); } // Adding indexes $table->addIndex( $this->connection->getIndexName($tableName, ['entity_id']), ['entity_id'], ['type' => 'primary'] ); $table->addIndex( $this->connection->getIndexName($tableName, ['store_id']), ['store_id'], ['type' => 'index'] ); $table->addIndex( $this->connection->getIndexName($tableName, ['path']), ['path'], ['type' => 'index'] ); $table->addIndex( $this->connection->getIndexName($tableName, ['level']), ['level'], ['type' => 'index'] ); return $table; } /** * Return array of static columns * * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function getStaticColumns() { $columns = []; $describe = $this->connection->describeTable( $this->connection->getTableName($this->getTableName('catalog_category_entity')) ); foreach ($describe as $column) { if (in_array($column['COLUMN_NAME'], $this->getSkipStaticColumns())) { continue; } $isUnsigned = ''; $options = null; $ddlType = $this->resourceHelper->getDdlTypeByColumnType($column['DATA_TYPE']); $column['DEFAULT'] = $column['DEFAULT'] ? trim($column['DEFAULT'], "' ") : ''; switch ($ddlType) { case Table::TYPE_SMALLINT: case Table::TYPE_INTEGER: case Table::TYPE_BIGINT: $isUnsigned = (bool)$column['UNSIGNED']; if ($column['DEFAULT'] === '') { $column['DEFAULT'] = null; } $options = null; if ($column['SCALE'] > 0) { $ddlType = Table::TYPE_DECIMAL; } else { break; } // fall-through intentional case Table::TYPE_DECIMAL: $options = $column['PRECISION'] . ',' . $column['SCALE']; $isUnsigned = null; if ($column['DEFAULT'] === '') { $column['DEFAULT'] = null; } break; case Table::TYPE_TEXT: $options = $column['LENGTH']; $isUnsigned = null; break; case Table::TYPE_TIMESTAMP: $options = null; $isUnsigned = null; break; case Table::TYPE_DATETIME: $isUnsigned = null; break; } $columns[$column['COLUMN_NAME']] = [ 'type' => [$ddlType, $options], 'unsigned' => $isUnsigned, 'nullable' => $column['NULLABLE'], 'default' => $column['DEFAULT'] === null ? false : $column['DEFAULT'], 'comment' => $column['COLUMN_NAME'], ]; } $columns['store_id'] = [ 'type' => [Table::TYPE_SMALLINT, 5], 'unsigned' => true, 'nullable' => false, 'default' => '0', 'comment' => 'Store Id', ]; return $columns; } /** * Return array of eav columns, skip attribute with static type * * @return array */ protected function getEavColumns() { $columns = []; foreach ($this->getAttributes() as $attribute) { if ($attribute['backend_type'] == 'static') { continue; } $columns[$attribute['attribute_code']] = []; switch ($attribute['backend_type']) { case 'varchar': $columns[$attribute['attribute_code']] = [ 'type' => [Table::TYPE_TEXT, 255], 'unsigned' => null, 'nullable' => true, 'default' => null, 'comment' => (string)$attribute['frontend_label'], ]; break; case 'int': $columns[$attribute['attribute_code']] = [ 'type' => [Table::TYPE_INTEGER, null], 'unsigned' => null, 'nullable' => true, 'default' => null, 'comment' => (string)$attribute['frontend_label'], ]; break; case 'text': $columns[$attribute['attribute_code']] = [ 'type' => [Table::TYPE_TEXT, '64k'], 'unsigned' => null, 'nullable' => true, 'default' => null, 'comment' => (string)$attribute['frontend_label'], ]; break; case 'datetime': $columns[$attribute['attribute_code']] = [ 'type' => [Table::TYPE_DATETIME, null], 'unsigned' => null, 'nullable' => true, 'default' => null, 'comment' => (string)$attribute['frontend_label'], ]; break; case 'decimal': $columns[$attribute['attribute_code']] = [ 'type' => [Table::TYPE_DECIMAL, '12,4'], 'unsigned' => null, 'nullable' => true, 'default' => null, 'comment' => (string)$attribute['frontend_label'], ]; break; } } return $columns; } /** * Return array of attribute codes for entity type 'catalog_category' * * @return array */ protected function getAttributes() { if ($this->attributeCodes === null) { $select = $this->connection->select()->from( $this->connection->getTableName($this->getTableName('eav_entity_type')), [] )->join( $this->connection->getTableName($this->getTableName('eav_attribute')), $this->connection->getTableName( $this->getTableName('eav_attribute') ) . '.entity_type_id = ' . $this->connection->getTableName( $this->getTableName('eav_entity_type') ) . '.entity_type_id', $this->connection->getTableName($this->getTableName('eav_attribute')) . '.*' )->where( $this->connection->getTableName( $this->getTableName('eav_entity_type') ) . '.entity_type_code = ?', Category::ENTITY ); $this->attributeCodes = []; foreach ($this->connection->fetchAll($select) as $attribute) { $this->attributeCodes[$attribute['attribute_id']] = $attribute; } } return $this->attributeCodes; } /** * Return attribute values for given entities and store * * @param array $entityIds * @param integer $storeId * @return array */ protected function getAttributeValues($entityIds, $storeId) { if (!is_array($entityIds)) { $entityIds = [$entityIds]; } $values = []; $linkIds = $this->getLinkIds($entityIds); foreach ($linkIds as $linkId) { $values[$linkId] = []; } $attributes = $this->getAttributes(); $attributesType = ['varchar', 'int', 'decimal', 'text', 'datetime']; $linkField = $this->categoryMetadata->getLinkField(); foreach ($attributesType as $type) { foreach ($this->getAttributeTypeValues($type, $entityIds, $storeId) as $row) { if (isset($row[$linkField], $row['attribute_id'])) { $attributeId = $row['attribute_id']; if (isset($attributes[$attributeId])) { $attributeCode = $attributes[$attributeId]['attribute_code']; $values[$row[$linkField]][$attributeCode] = $row['value']; } } } } return $values; } /** * Translate entity ids into link ids * * Used for rows with no EAV attributes set. * * @param array $entityIds * @return array */ private function getLinkIds(array $entityIds) { $linkField = $this->categoryMetadata->getLinkField(); if ($linkField === 'entity_id') { return $entityIds; } $select = $this->connection->select()->from( ['e' => $this->connection->getTableName($this->getTableName('catalog_category_entity'))], [$linkField] )->where( 'e.entity_id IN (?)', $entityIds, \Zend_Db::INT_TYPE ); return $this->connection->fetchCol($select); } /** * Return attribute values for given entities and store of specific attribute type * * @param string $type * @param array $entityIds * @param integer $storeId * @return array */ protected function getAttributeTypeValues($type, $entityIds, $storeId) { $linkField = $this->categoryMetadata->getLinkField(); $select = $this->connection->select()->from( [ 'def' => $this->connection->getTableName($this->getTableName('catalog_category_entity_' . $type)), ], [$linkField, 'attribute_id'] )->joinLeft( [ 'e' => $this->connection->getTableName($this->getTableName('catalog_category_entity')) ], "def.{$linkField} = e.{$linkField}" )->joinLeft( [ 'store' => $this->connection->getTableName( $this->getTableName('catalog_category_entity_' . $type) ), ], "store.{$linkField} = def.{$linkField} AND store.attribute_id = def.attribute_id " . 'AND store.store_id = ' . $storeId, [ 'value' => $this->connection->getCheckSql( 'store.value_id > 0', $this->connection->quoteIdentifier('store.value'), $this->connection->quoteIdentifier('def.value') ) ] )->where( "e.entity_id IN (?)", $entityIds, \Zend_Db::INT_TYPE )->where( 'def.store_id IN (?)', [Store::DEFAULT_STORE_ID, $storeId], \Zend_Db::INT_TYPE ); return $this->connection->fetchAll($select); } /** * Prepare array of column and columnValue pairs * * @param array $data * @return array */ protected function prepareValuesToInsert($data) { $values = []; foreach (array_keys($this->getColumns()) as $column) { if (isset($data[$column])) { $values[$column] = $data[$column]; } else { $values[$column] = null; } } return $values; } /** * Get table name * * @param string $name * @return string */ protected function getTableName($name) { return $this->resource->getTableName($name); } /** * Gets skipped static columns. * * @return array */ private function getSkipStaticColumns() { if ($this->skipStaticColumns === []) { $this->skipStaticColumns = $this->skipStaticColumnsProvider->get(); } return $this->skipStaticColumns; } }