From dc1c5d7ece6ceaedf2f2f5e748a1506035e4ce3c Mon Sep 17 00:00:00 2001 From: winniepukki <4bogaa25@solent.ac.uk> Date: Thu, 28 Jan 2021 10:05:38 +0200 Subject: [PATCH 1/3] Add configurable product stock counter with condition --- src/Model/Resolver/EntityUrl.php | 66 +++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/src/Model/Resolver/EntityUrl.php b/src/Model/Resolver/EntityUrl.php index 132f656..e2ee5e2 100644 --- a/src/Model/Resolver/EntityUrl.php +++ b/src/Model/Resolver/EntityUrl.php @@ -10,21 +10,23 @@ namespace ScandiPWA\UrlrewriteGraphQl\Model\Resolver; +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Magento\CatalogInventory\Api\StockStateInterface; +use Magento\CatalogInventory\Model\Stock\StockItemRepository; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; use Magento\UrlRewriteGraphQl\Model\Resolver\UrlRewrite\CustomUrlLocatorInterface; -use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\CatalogInventory\Model\Stock\StockItemRepository; -use Magento\Store\Model\ScopeInterface; /** * UrlRewrite field resolver, used for GraphQL request processing. @@ -71,6 +73,15 @@ class EntityUrl implements ResolverInterface */ private $scopeConfig; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var StockStateInterface + */ + private $stockState; /** * @param UrlFinderInterface $urlFinder @@ -80,6 +91,8 @@ class EntityUrl implements ResolverInterface * @param CategoryRepositoryInterface $categoryRepository * @param StockItemRepository $stockItemRepository * @param ScopeConfigInterface $scopeConfig + * @param ProductRepositoryInterface $productRepository + * @param StockStateInterface $stockState */ public function __construct( UrlFinderInterface $urlFinder, @@ -88,7 +101,9 @@ public function __construct( CollectionFactory $productCollectionFactory, CategoryRepositoryInterface $categoryRepository, StockItemRepository $stockItemRepository, - ScopeConfigInterface $scopeConfig + ScopeConfigInterface $scopeConfig, + ProductRepositoryInterface $productRepository, + StockStateInterface $stockState ) { $this->urlFinder = $urlFinder; $this->storeManager = $storeManager; @@ -97,6 +112,8 @@ public function __construct( $this->categoryRepository = $categoryRepository; $this->stockItemRepository = $stockItemRepository; $this->scopeConfig = $scopeConfig; + $this->productRepository = $productRepository; + $this->stockState = $stockState; } /** @@ -141,10 +158,16 @@ public function resolve( $product = $collection->addIdFilter($id)->getFirstItem(); $isInStock = false; - try { - $isInStock = $this->stockItemRepository->get($id)->getIsInStock(); - } catch (NoSuchEntityException $e) { - // Ignoring error is safe + $productType = $this->getProductType($id); + + if ($productType === 'configurable') { + $isInStock = $this->getConfigurableProductStockState($product); + } else { + try { + $isInStock = $this->stockItemRepository->get($id)->getIsInStock(); + } catch (NoSuchEntityException $e) { + // Ignoring error is safe + } } $isOutOfStockDisplay = $this->scopeConfig->getValue( @@ -239,4 +262,27 @@ private function sanitizeType(string $type) : string { return strtoupper(str_replace('-', '_', $type)); } + + private function getProductType($id): ?string + { + try { + return $this->productRepository->getById($id)->getTypeId(); + } catch (NoSuchEntityException $e) { + return null; + } + } + + private function getConfigurableProductStockState($product) : bool + { + $totalStock = 0; + if ($product->getTypeID() == 'configurable') { + $productTypeInstance = $product->getTypeInstance(); + $usedProducts = $productTypeInstance->getUsedProducts($product); + foreach ($usedProducts as $simple) { + $totalStock += $this->stockState->getStockQty($simple->getId(), $simple->getStore()->getWebsiteId()); + } + } + + return $totalStock > 0; + } } From cc1f0f822f206fe40117685f5135ffffc1e77aeb Mon Sep 17 00:00:00 2001 From: winniepukki <4bogaa25@solent.ac.uk> Date: Wed, 3 Feb 2021 19:01:27 +0200 Subject: [PATCH 2/3] Supplied logic with the bundle product type validation --- src/Model/Resolver/EntityUrl.php | 64 +++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/Model/Resolver/EntityUrl.php b/src/Model/Resolver/EntityUrl.php index e2ee5e2..0c0f71a 100644 --- a/src/Model/Resolver/EntityUrl.php +++ b/src/Model/Resolver/EntityUrl.php @@ -10,6 +10,9 @@ namespace ScandiPWA\UrlrewriteGraphQl\Model\Resolver; +use Magento\Bundle\Api\Data\LinkInterface; +use Magento\Bundle\Api\ProductLinkManagementInterface; +use Magento\Bundle\Api\ProductOptionRepositoryInterface; use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; @@ -83,6 +86,21 @@ class EntityUrl implements ResolverInterface */ private $stockState; + /** + * @var ProductLinkManagementInterface + */ + private $productLinkManagement; + + /** + * @var LinkInterface + */ + private $linkInterface; + + /** + * @var ProductOptionRepositoryInterface + */ + private $productOptionRepository; + /** * @param UrlFinderInterface $urlFinder * @param StoreManagerInterface $storeManager @@ -93,6 +111,9 @@ class EntityUrl implements ResolverInterface * @param ScopeConfigInterface $scopeConfig * @param ProductRepositoryInterface $productRepository * @param StockStateInterface $stockState + * @param ProductLinkManagementInterface $productLinkManagement + * @param LinkInterface $linkInterface + * @param ProductOptionRepositoryInterface $productOptionRepository */ public function __construct( UrlFinderInterface $urlFinder, @@ -103,7 +124,10 @@ public function __construct( StockItemRepository $stockItemRepository, ScopeConfigInterface $scopeConfig, ProductRepositoryInterface $productRepository, - StockStateInterface $stockState + StockStateInterface $stockState, + ProductLinkManagementInterface $productLinkManagement, + ProductOptionRepositoryInterface $productOptionRepository, + LinkInterface $linkInterface ) { $this->urlFinder = $urlFinder; $this->storeManager = $storeManager; @@ -114,6 +138,9 @@ public function __construct( $this->scopeConfig = $scopeConfig; $this->productRepository = $productRepository; $this->stockState = $stockState; + $this->productLinkManagement = $productLinkManagement; + $this->linkInterface = $linkInterface; + $this->productOptionRepository = $productOptionRepository; } /** @@ -158,10 +185,16 @@ public function resolve( $product = $collection->addIdFilter($id)->getFirstItem(); $isInStock = false; - $productType = $this->getProductType($id); + if ($this->isProductTypeBundle($product)) { + $productType = 'bundle'; + } else { + $productType = $this->getProductType($id); + } if ($productType === 'configurable') { $isInStock = $this->getConfigurableProductStockState($product); + } elseif ($productType === 'bundle') { + $isInStock = $this->getBundleProductsStockState($this->getBundleProductChildrenItems($product, $id)); } else { try { $isInStock = $this->stockItemRepository->get($id)->getIsInStock(); @@ -263,6 +296,33 @@ private function sanitizeType(string $type) : string return strtoupper(str_replace('-', '_', $type)); } + private function isProductTypeBundle($product) : bool + { + foreach ($product->getData() as $value) { + if ($value === 'bundle') { + return true; + } + } + } + + private function getBundleProductChildrenItems($product, $id) + { + $typeInstance = $product->getTypeInstance(); + return $typeInstance->getChildrenIds($id, true); + } + + private function getBundleProductsStockState($productsCollection) : bool + { + $total_stock = 0; + foreach ($productsCollection as $value) { + foreach ($value as $concreteIndex) { + $total_stock += $this->stockState->getStockQty($concreteIndex); + } + } + + return $total_stock > 0; + } + private function getProductType($id): ?string { try { From 324f42012a6cac949d406bbf87592e38caea2e0c Mon Sep 17 00:00:00 2001 From: Aleksandrs <4bogaa25@solent.ac.uk> Date: Tue, 16 Feb 2021 01:38:13 +0200 Subject: [PATCH 3/3] Refactored redundant methods and prettified code --- src/Model/Resolver/EntityUrl.php | 92 +++++++------------------------- 1 file changed, 18 insertions(+), 74 deletions(-) diff --git a/src/Model/Resolver/EntityUrl.php b/src/Model/Resolver/EntityUrl.php index 0c0f71a..6721218 100644 --- a/src/Model/Resolver/EntityUrl.php +++ b/src/Model/Resolver/EntityUrl.php @@ -10,11 +10,7 @@ namespace ScandiPWA\UrlrewriteGraphQl\Model\Resolver; -use Magento\Bundle\Api\Data\LinkInterface; -use Magento\Bundle\Api\ProductLinkManagementInterface; -use Magento\Bundle\Api\ProductOptionRepositoryInterface; use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\CatalogInventory\Api\StockStateInterface; @@ -76,31 +72,11 @@ class EntityUrl implements ResolverInterface */ private $scopeConfig; - /** - * @var ProductRepositoryInterface - */ - private $productRepository; - /** * @var StockStateInterface */ private $stockState; - /** - * @var ProductLinkManagementInterface - */ - private $productLinkManagement; - - /** - * @var LinkInterface - */ - private $linkInterface; - - /** - * @var ProductOptionRepositoryInterface - */ - private $productOptionRepository; - /** * @param UrlFinderInterface $urlFinder * @param StoreManagerInterface $storeManager @@ -109,11 +85,7 @@ class EntityUrl implements ResolverInterface * @param CategoryRepositoryInterface $categoryRepository * @param StockItemRepository $stockItemRepository * @param ScopeConfigInterface $scopeConfig - * @param ProductRepositoryInterface $productRepository * @param StockStateInterface $stockState - * @param ProductLinkManagementInterface $productLinkManagement - * @param LinkInterface $linkInterface - * @param ProductOptionRepositoryInterface $productOptionRepository */ public function __construct( UrlFinderInterface $urlFinder, @@ -123,11 +95,7 @@ public function __construct( CategoryRepositoryInterface $categoryRepository, StockItemRepository $stockItemRepository, ScopeConfigInterface $scopeConfig, - ProductRepositoryInterface $productRepository, - StockStateInterface $stockState, - ProductLinkManagementInterface $productLinkManagement, - ProductOptionRepositoryInterface $productOptionRepository, - LinkInterface $linkInterface + StockStateInterface $stockState ) { $this->urlFinder = $urlFinder; $this->storeManager = $storeManager; @@ -136,11 +104,7 @@ public function __construct( $this->categoryRepository = $categoryRepository; $this->stockItemRepository = $stockItemRepository; $this->scopeConfig = $scopeConfig; - $this->productRepository = $productRepository; $this->stockState = $stockState; - $this->productLinkManagement = $productLinkManagement; - $this->linkInterface = $linkInterface; - $this->productOptionRepository = $productOptionRepository; } /** @@ -185,22 +149,20 @@ public function resolve( $product = $collection->addIdFilter($id)->getFirstItem(); $isInStock = false; - if ($this->isProductTypeBundle($product)) { - $productType = 'bundle'; - } else { - $productType = $this->getProductType($id); - } - - if ($productType === 'configurable') { - $isInStock = $this->getConfigurableProductStockState($product); - } elseif ($productType === 'bundle') { - $isInStock = $this->getBundleProductsStockState($this->getBundleProductChildrenItems($product, $id)); - } else { - try { - $isInStock = $this->stockItemRepository->get($id)->getIsInStock(); - } catch (NoSuchEntityException $e) { - // Ignoring error is safe - } + switch ($product['type_id']) { + case 'configurable': + $isInStock = $this->getConfigurableProductStockState($product); + break; + case 'bundle': + $isInStock = $this->getBundleProductsStockState($this->getBundleProductChildrenItems($product, $id)); + break; + default: + try { + $isInStock = $this->stockItemRepository->get($id)->getIsInStock(); + } catch (NoSuchEntityException $e) { + // Ignoring error is safe + } + break; } $isOutOfStockDisplay = $this->scopeConfig->getValue( @@ -296,25 +258,16 @@ private function sanitizeType(string $type) : string return strtoupper(str_replace('-', '_', $type)); } - private function isProductTypeBundle($product) : bool - { - foreach ($product->getData() as $value) { - if ($value === 'bundle') { - return true; - } - } - } - private function getBundleProductChildrenItems($product, $id) { $typeInstance = $product->getTypeInstance(); return $typeInstance->getChildrenIds($id, true); } - private function getBundleProductsStockState($productsCollection) : bool + private function getBundleProductsStockState($childrenProductsCollection) : bool { $total_stock = 0; - foreach ($productsCollection as $value) { + foreach ($childrenProductsCollection as $value) { foreach ($value as $concreteIndex) { $total_stock += $this->stockState->getStockQty($concreteIndex); } @@ -323,19 +276,10 @@ private function getBundleProductsStockState($productsCollection) : bool return $total_stock > 0; } - private function getProductType($id): ?string - { - try { - return $this->productRepository->getById($id)->getTypeId(); - } catch (NoSuchEntityException $e) { - return null; - } - } - private function getConfigurableProductStockState($product) : bool { $totalStock = 0; - if ($product->getTypeID() == 'configurable') { + if ($product->getTypeID() === 'configurable') { $productTypeInstance = $product->getTypeInstance(); $usedProducts = $productTypeInstance->getUsedProducts($product); foreach ($usedProducts as $simple) {