vendor/store.shopware.com/swagb2bplatform/components/InStock/BridgePlatform/SalesChannelProductRepositoryDecorator.php line 60

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\B2B\InStock\BridgePlatform;
  3. use Shopware\B2B\Shop\BridgePlatform\SalesChannelProductExtension;
  4. use Shopware\B2B\StoreFrontAuthentication\Framework\AuthenticationService;
  5. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\AntiJoinFilter;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\Filter;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult;
  17. use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
  18. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  19. use Shopware\Core\System\SystemConfig\SystemConfigService;
  20. use function end;
  21. use function explode;
  22. use function get_class;
  23. use function in_array;
  24. use function min;
  25. class SalesChannelProductRepositoryDecorator implements SalesChannelRepositoryInterface
  26. {
  27.     private const MAX_LINE_ITEM_QUANTITY_IN_CART_ROUTE 'core.cart.maxQuantity';
  28.     private const PRODUCT_IN_STOCKS_ID_FIELD 'product.b2bInStock.id';
  29.     private const PRODUCT_IN_STOCKS_AUTH_ID_FIELD 'product.b2bInStock.authId';
  30.     private const PRODUCT_IN_STOCKS_IN_STOCK_FIELD 'product.b2bInStock.inStock';
  31.     private const IN_STOCK_IN_STOCK_FIELD 'inStock';
  32.     private const IN_STOCK_AUTH_ID_FIELD 'authId';
  33.     private const PRODUCT_DEFINITION_STOCK_FIELDS = [
  34.         'availableStock',
  35.         'stock',
  36.     ];
  37.     private SalesChannelRepositoryInterface $decorated;
  38.     private AuthenticationService $authenticationService;
  39.     private SystemConfigService $systemConfigService;
  40.     public function __construct(
  41.         SalesChannelRepositoryInterface $decorated,
  42.         AuthenticationService $authenticationService,
  43.         SystemConfigService $systemConfigService
  44.     ) {
  45.         $this->decorated $decorated;
  46.         $this->authenticationService $authenticationService;
  47.         $this->systemConfigService $systemConfigService;
  48.     }
  49.     public function search(Criteria $criteriaSalesChannelContext $salesChannelContext): EntitySearchResult
  50.     {
  51.         if (!$this->authenticationService->isB2b()) {
  52.             return $this->decorated->search($criteria$salesChannelContext);
  53.         }
  54.         $this->prepareCriteriaForB2bInStock($criteria);
  55.         $searchResult $this->decorated->search($criteria$salesChannelContext);
  56.         $searchResult $this->getUpdatedSearchResult($searchResult$salesChannelContext);
  57.         return $searchResult;
  58.     }
  59.     public function aggregate(Criteria $criteriaSalesChannelContext $salesChannelContext): AggregationResultCollection
  60.     {
  61.         return $this->decorated->aggregate($criteria$salesChannelContext);
  62.     }
  63.     public function searchIds(Criteria $criteriaSalesChannelContext $salesChannelContext): IdSearchResult
  64.     {
  65.         if (!$this->authenticationService->isB2b()) {
  66.             return $this->decorated->searchIds($criteria$salesChannelContext);
  67.         }
  68.         $this->prepareCriteriaForB2bInStock($criteria);
  69.         return $this->decorated->searchIds($criteria$salesChannelContext);
  70.     }
  71.     /**
  72.      * @internal
  73.      */
  74.     protected function prepareCriteriaForB2bInStock(Criteria $criteria): void
  75.     {
  76.         $filters $criteria->getFilters();
  77.         $criteria->addAssociation(SalesChannelProductExtension::B2B_IN_STOCK_EXTENSION_NAME);
  78.         $associationCriteria $criteria->getAssociation(SalesChannelProductExtension::B2B_IN_STOCK_EXTENSION_NAME);
  79.         $associationCriteria->addFilter(new EqualsAnyFilter(self::IN_STOCK_AUTH_ID_FIELD, [
  80.             $this->authenticationService->getIdentity()->getAuthId()->getValue(),
  81.             $this->authenticationService->getIdentity()->getContextAuthId()->getValue(),
  82.         ]));
  83.         $criteria->resetFilters();
  84.         foreach ($filters as $filter) {
  85.             $criteria->addFilter($this->mapFilter($filter));
  86.             if ($associationFilter $this->getAssociationFilter($filter)) {
  87.                 $associationCriteria->addFilter($associationFilter);
  88.             }
  89.         }
  90.     }
  91.     /**
  92.      * @internal
  93.      */
  94.     protected function mapFilter(Filter $filter): Filter
  95.     {
  96.         // ignore inherited MultiFilter
  97.         if (in_array(
  98.             $class get_class($filter),
  99.             [MultiFilter::class, NotFilter::class, AntiJoinFilter::class],
  100.             true
  101.         )) {
  102.             $queries = [];
  103.             foreach ($filter->getQueries() as $query) {
  104.                 $queries[] = $this->mapFilter($query);
  105.             }
  106.             return new $class($filter->getOperator(), $queries);
  107.         }
  108.         if (!$this->isInStockFilter($filter)) {
  109.             return $filter;
  110.         }
  111.         return $this->buildInStockFilter($filter);
  112.     }
  113.     /**
  114.      * @internal
  115.      */
  116.     protected function isInStockFilter(Filter $filter): bool
  117.     {
  118.         return ($filter instanceof EqualsFilter || $filter instanceof RangeFilter || $filter instanceof EqualsAnyFilter)
  119.             && in_array($this->getNecessaryFieldValue($filter->getField()), self::PRODUCT_DEFINITION_STOCK_FIELDStrue);
  120.     }
  121.     /**
  122.      * @internal
  123.      */
  124.     private function buildInStockFilter(Filter $filter): Filter
  125.     {
  126.         return new MultiFilter(
  127.             MultiFilter::CONNECTION_OR,
  128.             [
  129.                 new MultiFilter(MultiFilter::CONNECTION_AND, [
  130.                     $filter,
  131.                     new EqualsFilter(self::PRODUCT_IN_STOCKS_ID_FIELDnull),
  132.                 ]),
  133.                 new MultiFilter(MultiFilter::CONNECTION_AND, [
  134.                     $this->mapInStockFilter(self::PRODUCT_IN_STOCKS_IN_STOCK_FIELD$filter),
  135.                     new NotFilter(NotFilter::CONNECTION_AND, [new EqualsFilter(self::PRODUCT_IN_STOCKS_ID_FIELDnull)]),
  136.                     new EqualsAnyFilter(self::PRODUCT_IN_STOCKS_AUTH_ID_FIELD, [
  137.                         $this->authenticationService->getIdentity()->getAuthId()->getValue(),
  138.                         $this->authenticationService->getIdentity()->getContextAuthId()->getValue(),
  139.                     ]),
  140.                 ]),
  141.             ]
  142.         );
  143.     }
  144.     /**
  145.      * @internal
  146.      */
  147.     protected function mapInStockFilter(string $fieldNameFilter $filter): Filter
  148.     {
  149.         if ($filter instanceof RangeFilter) {
  150.             return new RangeFilter($fieldName$filter->getParameters());
  151.         }
  152.         if ($filter instanceof EqualsFilter) {
  153.             return new EqualsFilter($fieldName$filter->getValue());
  154.         }
  155.         if ($filter instanceof EqualsAnyFilter) {
  156.             return new EqualsAnyFilter($fieldName$filter->getValue());
  157.         }
  158.         return $filter;
  159.     }
  160.     /**
  161.      * @internal
  162.      */
  163.     protected function getAssociationFilter(Filter $filter): ?Filter
  164.     {
  165.         // ignore inherited MultiFilter
  166.         if (in_array(
  167.             $class get_class($filter),
  168.             [MultiFilter::class, NotFilter::class, AntiJoinFilter::class],
  169.             true
  170.         )) {
  171.             $queries = [];
  172.             foreach ($filter->getQueries() as $query) {
  173.                 $associationFilter $this->getAssociationFilter($query);
  174.                 if (!$associationFilter) {
  175.                     continue;
  176.                 }
  177.                 $queries[] = $associationFilter;
  178.             }
  179.             if (!$queries) {
  180.                 return null;
  181.             }
  182.             return new $class($filter->getOperator(), $queries);
  183.         }
  184.         if (!$this->isInStockFilter($filter)) {
  185.             return null;
  186.         }
  187.         return $this->mapInStockFilter(self::IN_STOCK_IN_STOCK_FIELD$filter);
  188.     }
  189.     /**
  190.      * @internal
  191.      */
  192.     protected function getUpdatedSearchResult(
  193.         EntitySearchResult $searchResult,
  194.         SalesChannelContext $salesChannelContext
  195.     ): EntitySearchResult {
  196.         $maxLineItemQuantityInCart = (int) $this->systemConfigService
  197.             ->get(self::MAX_LINE_ITEM_QUANTITY_IN_CART_ROUTE$salesChannelContext->getSalesChannel()->getId());
  198.         /** @var SalesChannelProductEntity $product */
  199.         foreach ($searchResult->getIterator() as $product) {
  200.             /** @var B2bInStockCollection $b2bInStocks */
  201.             if (!($b2bInStocks $product->getExtension(SalesChannelProductExtension::B2B_IN_STOCK_EXTENSION_NAME))
  202.                 || $b2bInStocks->count() === 0) {
  203.                 continue;
  204.             }
  205.             $inStock $b2bInStocks->getBestMatchByAuthId(
  206.                 $this->authenticationService->getIdentity()->getAuthId()
  207.             );
  208.             $product->setAvailableStock($inStock);
  209.             $product->setStock($inStock);
  210.             $product->setAvailable((bool) $inStock);
  211.             $product->setMaxPurchase(min($inStock$maxLineItemQuantityInCart));
  212.         }
  213.         return $searchResult;
  214.     }
  215.     /**
  216.      * @internal
  217.      */
  218.     protected function getNecessaryFieldValue(string $field): string
  219.     {
  220.         $explodedField explode('.'$field);
  221.         return end($explodedField);
  222.     }
  223. }