![]() 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/ResourceModel/Product/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Catalog\Model\ResourceModel\Product; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Catalog\Model\AbstractModel; use Magento\Catalog\Model\Factory; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\Type; use Magento\Catalog\Model\Product\TypeTransitionManager; use Magento\Catalog\Model\ResourceModel\AbstractResource; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface; use Magento\Eav\Model\Entity\Context; use Magento\Framework\DataObject; use Magento\Framework\Stdlib\DateTime\DateTime; use Magento\Store\Model\StoreManagerInterface; /** * Catalog Product Mass processing resource model * * @author Magento Core Team <[email protected]> * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Action extends AbstractResource { /** * @var DateTime */ private $dateTime; /** * @var ProductCollectionFactory */ private $productCollectionFactory; /** * @var TypeTransitionManager */ private $typeTransitionManager; /** * Entity type id values to save * * @var array */ private $typeIdValuesToSave = []; /** * @param Context $context * @param StoreManagerInterface $storeManager * @param Factory $modelFactory * @param UniqueValidationInterface $uniqueValidator * @param DateTime $dateTime * @param CollectionFactory $productCollectionFactory * @param TypeTransitionManager $typeTransitionManager * @param array $data */ public function __construct( Context $context, StoreManagerInterface $storeManager, Factory $modelFactory, UniqueValidationInterface $uniqueValidator, DateTime $dateTime, ProductCollectionFactory $productCollectionFactory, TypeTransitionManager $typeTransitionManager, $data = [] ) { parent::__construct($context, $storeManager, $modelFactory, $data, $uniqueValidator); $this->dateTime = $dateTime; $this->productCollectionFactory = $productCollectionFactory; $this->typeTransitionManager = $typeTransitionManager; } /** * Initialize connection * * @return void */ protected function _construct() { $resource = $this->_resource; $this->setType( Product::ENTITY )->setConnection( $resource->getConnection('catalog') ); } /** * Update attribute values for entity list per store * * @param array $entityIds * @param array $attrData * @param int $storeId * @return $this * @throws \Exception */ public function updateAttributes($entityIds, $attrData, $storeId) { $object = new DataObject(); $object->setStoreId($storeId); $attrData[ProductInterface::UPDATED_AT] = $this->dateTime->gmtDate(); $this->getConnection()->beginTransaction(); try { foreach ($attrData as $attrCode => $value) { if ($attrCode === ProductAttributeInterface::CODE_HAS_WEIGHT) { $this->updateHasWeightAttribute($entityIds, $value); continue; } $attribute = $this->getAttribute($attrCode); if (!$attribute->getAttributeId()) { continue; } $i = 0; foreach ($entityIds as $entityId) { $i++; $object->setId($entityId); $object->setEntityId($entityId); // collect data for save $this->_saveAttributeValue($object, $attribute, $value); // save collected data every 1000 rows if ($i % 1000 == 0) { $this->_processAttributeValues(); } } $this->_processAttributeValues(); } $this->getConnection()->commit(); } catch (\Exception $e) { $this->getConnection()->rollBack(); throw $e; } return $this; } /** * Insert or Update attribute data * * @param AbstractModel $object * @param AbstractAttribute $attribute * @param mixed $value * @return $this */ protected function _saveAttributeValue($object, $attribute, $value) { $connection = $this->getConnection(); $storeId = (int) $this->_storeManager->getStore($object->getStoreId())->getId(); $table = $attribute->getBackend()->getTable(); $entityId = $this->resolveEntityId($object->getId()); /** * If we work in single store mode all values should be saved just * for default store id * In this case we clear all not default values */ if ($this->_storeManager->hasSingleStore() && !$attribute->isStatic()) { $storeId = $this->getDefaultStoreId(); $connection->delete( $table, [ 'attribute_id = ?' => $attribute->getAttributeId(), $this->getLinkField() . ' = ?' => $entityId, 'store_id <> ?' => $storeId ] ); } $data = $attribute->isStatic() ? new DataObject( [ $this->getLinkField() => $entityId, $attribute->getAttributeCode() => $this->_prepareValueForSave($value, $attribute), ] ) : new DataObject( [ 'attribute_id' => $attribute->getAttributeId(), 'store_id' => $storeId, $this->getLinkField() => $entityId, 'value' => $this->_prepareValueForSave($value, $attribute), ] ); $bind = $this->_prepareDataForTable($data, $table); if ($attribute->isScopeStore() || $attribute->isStatic()) { /** * Update attribute value for store */ $this->_attributeValuesToSave[$table][] = $bind; } elseif ($attribute->isScopeWebsite() && $storeId != $this->getDefaultStoreId()) { /** * Update attribute value for website */ $storeIds = $this->_storeManager->getStore($storeId)->getWebsite()->getStoreIds(true); foreach ($storeIds as $storeId) { $bind['store_id'] = (int) $storeId; $this->_attributeValuesToSave[$table][] = $bind; } } else { /** * Update global attribute value */ $bind['store_id'] = $this->getDefaultStoreId(); $this->_attributeValuesToSave[$table][] = $bind; } return $this; } /** * Resolve entity id for current entity * * @param int $entityId * * @return int */ protected function resolveEntityId($entityId) { if ($this->getIdFieldName() == $this->getLinkField()) { return $entityId; } $select = $this->getConnection()->select(); $tableName = $this->_resource->getTableName('catalog_product_entity'); $select->from($tableName, [$this->getLinkField()]) ->where('entity_id = ?', $entityId); return $this->getConnection()->fetchOne($select); } /** * Process product_has_weight attribute update * * @param array $entityIds * @param string $value */ private function updateHasWeightAttribute($entityIds, $value): void { $productCollection = $this->productCollectionFactory->create(); $productCollection->addIdFilter($entityIds); // Type can be changed depending on weight only between simple and virtual products $productCollection->addFieldToFilter( Product::TYPE_ID, [ 'in' => [ Type::TYPE_SIMPLE, Type::TYPE_VIRTUAL ] ] ); $productCollection->addFieldToSelect(Product::TYPE_ID); $i = 0; foreach ($productCollection->getItems() as $product) { $product->setData(ProductAttributeInterface::CODE_HAS_WEIGHT, $value); $oldTypeId = $product->getTypeId(); $this->typeTransitionManager->processProduct($product); if ($oldTypeId !== $product->getTypeId()) { $i++; $this->saveTypeIdValue($product); // save collected data every 1000 rows if ($i % 1000 === 0) { $this->processTypeIdValues(); } } } $this->processTypeIdValues(); } /** * Save type id value to be updated * * @param Product $product * @return $this */ private function saveTypeIdValue($product): self { $typeId = $product->getTypeId(); if (!array_key_exists($typeId, $this->typeIdValuesToSave)) { $this->typeIdValuesToSave[$typeId] = []; } $this->typeIdValuesToSave[$typeId][] = $product->getId(); return $this; } /** * Update type id values * * @return $this */ private function processTypeIdValues(): self { $connection = $this->getConnection(); $table = $this->getTable('catalog_product_entity'); foreach ($this->typeIdValuesToSave as $typeId => $entityIds) { $connection->update( $table, ['type_id' => $typeId], ['entity_id IN (?)' => $entityIds] ); } $this->typeIdValuesToSave = []; return $this; } }