123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\CatalogInventory\Model;
- use Magento\Catalog\Model\Product\Type as ProductType;
- use Magento\Catalog\Model\Product\Website as ProductWebsite;
- use Magento\Catalog\Model\ProductFactory;
- use Magento\CatalogInventory\Api\StockIndexInterface;
- use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface;
- use Magento\Catalog\Api\ProductRepositoryInterface;
- use Magento\Catalog\Model\Product\Attribute\Source\Status;
- /**
- * Class StockIndex
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
- class StockIndex implements StockIndexInterface
- {
- /**
- * @var StockRegistryProviderInterface
- */
- protected $stockRegistryProvider;
- /**
- * @var ProductRepositoryInterface
- */
- protected $productRepository;
- /**
- * @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Status
- */
- protected $stockStatusResource;
- /**
- * @var ProductType
- */
- protected $productType;
- /**
- * Retrieve website models
- *
- * @var array
- */
- protected $websites;
- /**
- * Product Type Instances cache
- *
- * @var array
- */
- protected $productTypes = [];
- /**
- * @param StockRegistryProviderInterface $stockRegistryProvider
- * @param ProductRepositoryInterface $productRepository
- * @param ProductWebsite $productWebsite
- * @param ProductType $productType
- */
- public function __construct(
- StockRegistryProviderInterface $stockRegistryProvider,
- ProductRepositoryInterface $productRepository,
- ProductWebsite $productWebsite,
- ProductType $productType
- ) {
- $this->stockRegistryProvider = $stockRegistryProvider;
- $this->productRepository = $productRepository;
- $this->productWebsite = $productWebsite;
- $this->productType = $productType;
- }
- /**
- * Rebuild stock index of the given website
- *
- * @param int $productId
- * @param int $scopeId
- * @deprecated 100.1.0
- * @return true
- * @SuppressWarnings(PHPMD.UnusedLocalVariable)
- */
- public function rebuild($productId = null, $scopeId = null)
- {
- if ($productId !== null) {
- $this->updateProductStockStatus($productId, $scopeId);
- } else {
- $lastProductId = 0;
- while (true) {
- /** @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Status $resource */
- $resource = $this->getStockStatusResource();
- $productCollection = $resource->getProductCollection($lastProductId);
- if (!$productCollection) {
- break;
- }
- foreach ($productCollection as $productId => $productType) {
- $lastProductId = $productId;
- $this->updateProductStockStatus($productId, $scopeId);
- }
- }
- }
- return true;
- }
- /**
- * Update product status from stock item
- *
- * @param int $productId
- * @param int $websiteId
- * @deprecated 100.1.0
- * @return void
- */
- public function updateProductStockStatus($productId, $websiteId)
- {
- $item = $this->stockRegistryProvider->getStockItem($productId, $websiteId);
- $status = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK;
- $qty = 0;
- if ($item->getItemId()) {
- $status = $item->getIsInStock();
- $qty = $item->getQty();
- }
- $this->processChildren($productId, $item->getWebsiteId(), $qty, $status);
- $this->processParents($productId, $item->getWebsiteId());
- }
- /**
- * Process children stock status
- *
- * @param int $productId
- * @param int $websiteId
- * @param int $qty
- * @param int $status
- * @return $this
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- protected function processChildren(
- $productId,
- $websiteId,
- $qty = 0,
- $status = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK
- ) {
- if ($status == \Magento\CatalogInventory\Model\Stock\Status::STATUS_OUT_OF_STOCK) {
- $this->getStockStatusResource()->saveProductStatus($productId, $status, $qty, $websiteId);
- return;
- }
- $statuses = [];
- $websitesWithStores = $this->getWebsitesWithDefaultStores($websiteId);
- foreach (array_keys($websitesWithStores) as $websiteId) {
- /* @var $website \Magento\Store\Model\Website */
- $statuses[$websiteId] = $status;
- }
- /** @var \Magento\Catalog\Model\Product $product */
- $product = $this->productRepository->getById($productId);
- $typeInstance = $product->getTypeInstance();
- $requiredChildrenIds = $typeInstance->getChildrenIds($productId, true);
- if ($requiredChildrenIds) {
- $childrenIds = [];
- foreach ($requiredChildrenIds as $groupedChildrenIds) {
- $childrenIds = array_merge($childrenIds, $groupedChildrenIds);
- }
- $childrenWebsites = $this->productWebsite->getWebsites($childrenIds);
- foreach ($websitesWithStores as $websiteId => $storeId) {
- $childrenStatus = $this->getStockStatusResource()->getProductStatus($childrenIds, $storeId);
- $childrenStock = $this->getStockStatusResource()->getProductsStockStatuses($childrenIds, $websiteId);
- $websiteStatus = $statuses[$websiteId];
- foreach ($requiredChildrenIds as $groupedChildrenIds) {
- $optionStatus = false;
- foreach ($groupedChildrenIds as $childId) {
- if (isset($childrenStatus[$childId])
- && isset($childrenWebsites[$childId])
- && in_array($websiteId, $childrenWebsites[$childId])
- && $childrenStatus[$childId] == Status::STATUS_ENABLED
- && isset($childrenStock[$childId])
- && $childrenStock[$childId] == \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK
- ) {
- $optionStatus = true;
- }
- }
- $websiteStatus = $websiteStatus && $optionStatus;
- }
- $statuses[$websiteId] = (int)$websiteStatus;
- }
- }
- foreach ($statuses as $websiteId => $websiteStatus) {
- $this->getStockStatusResource()->saveProductStatus($productId, $websiteStatus, $qty, $websiteId);
- }
- }
- /**
- * Retrieve website models
- *
- * @param int|null $websiteId
- * @return array
- */
- protected function getWebsitesWithDefaultStores($websiteId = null)
- {
- if ($this->websites === null) {
- /** @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Status $resource */
- $resource = $this->getStockStatusResource();
- $this->websites = $resource->getWebsiteStores();
- }
- $websites = $this->websites;
- if ($websiteId !== null && isset($this->websites[$websiteId])) {
- $websites = [$websiteId => $this->websites[$websiteId]];
- }
- return $websites;
- }
- /**
- * Process Parents by child
- *
- * @param int $productId
- * @param int $websiteId
- * @return $this
- */
- protected function processParents($productId, $websiteId)
- {
- $parentIds = [];
- foreach ($this->getProductTypeInstances() as $typeInstance) {
- /* @var $typeInstance AbstractType */
- $parentIds = array_merge($parentIds, $typeInstance->getParentIdsByChild($productId));
- }
- if (!$parentIds) {
- return $this;
- }
- foreach ($parentIds as $parentId) {
- $item = $this->stockRegistryProvider->getStockItem($parentId, $websiteId);
- $status = \Magento\CatalogInventory\Model\Stock\Status::STATUS_IN_STOCK;
- $qty = 0;
- if ($item->getItemId()) {
- $status = $item->getIsInStock();
- $qty = $item->getQty();
- }
- $this->processChildren($parentId, $websiteId, $qty, $status);
- }
- }
- /**
- * Retrieve Product Type Instances
- * as key - type code, value - instance model
- *
- * @return array
- */
- protected function getProductTypeInstances()
- {
- if (empty($this->productTypes)) {
- $productEmulator = new \Magento\Framework\DataObject();
- foreach (array_keys($this->productType->getTypes()) as $typeId) {
- $productEmulator->setTypeId($typeId);
- $this->productTypes[$typeId] = $this->productType->factory($productEmulator);
- }
- }
- return $this->productTypes;
- }
- /**
- * @return \Magento\CatalogInventory\Model\ResourceModel\Stock\Status
- */
- protected function getStockStatusResource()
- {
- if (empty($this->stockStatusResource)) {
- $this->stockStatusResource = \Magento\Framework\App\ObjectManager::getInstance()->get(
- \Magento\CatalogInventory\Model\ResourceModel\Stock\Status::class
- );
- }
- return $this->stockStatusResource;
- }
- }
|