custom/plugins/AcrisShopSwitchCS/src/Components/ShopSwitchHelperService.php line 61

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Acris\ShopSwitch\Components;
  3. use Acris\ShopSwitch\Components\Exception\ActiveDomainNotFoundException;
  4. use Acris\ShopSwitch\Components\ShopSwitch\ShopSwitchResult;
  5. use Acris\ShopSwitch\Components\ShopSwitch\ShopSwitchRouteResponse;
  6. use Acris\ShopSwitch\Components\Struct\AbstractPossibleStruct;
  7. use Acris\ShopSwitch\Components\Struct\PossibleCombinationCollection;
  8. use Acris\ShopSwitch\Components\Struct\PossibleCombinationStruct;
  9. use Acris\ShopSwitch\Components\Struct\PossibleCountryCollection;
  10. use Acris\ShopSwitch\Components\Struct\PossibleCountryStruct;
  11. use Acris\ShopSwitch\Components\Struct\PossibleLanguageCollection;
  12. use Acris\ShopSwitch\Components\Struct\PossibleLanguageStruct;
  13. use Acris\ShopSwitch\Custom\ShopSwitchRuleDefinition;
  14. use Acris\ShopSwitch\Custom\ShopSwitchRuleDomainEntity;
  15. use Acris\ShopSwitch\Custom\ShopSwitchRuleEntity;
  16. use Acris\ShopSwitch\Storefront\Controller\ShopSwitchController;
  17. use Shopware\Core\Framework\Context;
  18. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  20. use Shopware\Core\Framework\Struct\Collection;
  21. use Shopware\Core\SalesChannelRequest;
  22. use Shopware\Core\System\Country\CountryCollection;
  23. use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelDomain\SalesChannelDomainEntity;
  24. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  25. use Shopware\Core\System\SalesChannel\SalesChannelEntity;
  26. use Symfony\Component\HttpFoundation\Request;
  27. /**
  28.  * Helper Servce for ShopSwitchRoute!
  29.  * Aim: To reduce the amount of code in ShopSwitchroute
  30.  * Why: ShopSwitchRoute becomes too complex to maintain and create features.
  31.  * Dependent on ShopSwitchRoute
  32.  */
  33. class ShopSwitchHelperService
  34. {
  35.     private ShopSwitchRuleService $shopSwitchRuleService;
  36.     private EntityRepositoryInterface $salesChannelDomainRepository;
  37.     private SalesChannelCountryLanguageService $salesChannelCountryLanguageService;
  38.     public function __construct(
  39.         ShopSwitchRuleService              $shopSwitchRuleService,
  40.         EntityRepositoryInterface          $salesChannelDomainRepository,
  41.         SalesChannelCountryLanguageService $salesChannelCountryLanguageService
  42.     )
  43.     {
  44.         $this->shopSwitchRuleService $shopSwitchRuleService;
  45.         $this->salesChannelDomainRepository $salesChannelDomainRepository;
  46.         $this->salesChannelCountryLanguageService $salesChannelCountryLanguageService;
  47.     }
  48.     public function getValidResponse(string $activeDomainIdShopSwitchRuleEntity $activeRulestring $activeDomainUrlRequest $requestSalesChannelEntity $activeSalesChannelContext $contextShopSwitchRuleDomainEntity $activeRuleDomain, ?array $languageIds, ?string $countryIso): ShopSwitchRouteResponse
  49.     {
  50.         $defaultCountryId $activeRuleDomain->getDefaultShippingCountryId();
  51.         $activeDomainEntity $this->getDomainById($activeDomainId$context);
  52.         $possibleLanguageCollection $this->getPossibleLanguages($activeRule$request$activeDomainUrl$context$languageIds);
  53.         $possibleCountryCollection $this->getPossibleCountries($activeRule$request$activeDomainUrl$context$countryIso);
  54.         $possibleCountryCollectionForShipping $possibleCountryCollection;
  55.         // if only language redirect is wanted and switch type is not set only country, then set possible country collection to null
  56.         if($activeRule->getSwitchType() !== ShopSwitchRuleDefinition::SWITCH_TYPE_SET_ONLY_COUNTRY && $activeRule->getRuleDefinitionType() === ShopSwitchRuleDefinition::RULE_DEFINITION_TYPE_LANGUAGE) {
  57.             $possibleCountryCollection = new PossibleCountryCollection();
  58.         }
  59.         if(!empty($possibleCountries) && !empty($possibleLanguages)) {
  60.             $this->removeNotExistingCombinations($possibleCountryCollection$possibleLanguageCollection);
  61.         }
  62.         $possibleCombinationCollection $this->getPossibleCombinations($possibleCountryCollection$possibleLanguageCollection);
  63.         // if the country which was detected is not inside the possible countries of the sales channel, we want to take the best blacklist rule what we find
  64.         if($possibleCombinationCollection->count() === 0) {
  65.             $possibleCombinationCollection $this->getPossibleBlacklistCombination($activeRule$possibleCountryCollection);
  66.         }
  67.         $this->sortPossibleCombinationsByActiveDomain($possibleCombinationCollection$activeDomainUrl);
  68.         if($this->getStayOnPageWithoutAsk($activeRule$possibleCombinationCollection$activeDomainUrl$request$activeSalesChannel) === true) {
  69.             $countryId $this->getCountryId($possibleCombinationCollection$possibleCountryCollectionForShipping$activeDomainEntity->getUrl(), $defaultCountryId$context);
  70.             return new ShopSwitchRouteResponse(new ShopSwitchResult($activeDomainId$possibleCountryCollection$possibleLanguageCollection$activeRule$activeDomainUrltruenull$countryId));
  71.         }
  72.         if($activeRule->getSwitchType() === ShopSwitchRuleDefinition::SWITCH_TYPE_DIRECT) {
  73.             $redirectDomainUrl '';
  74.             $firstPossibleCombination $possibleCombinationCollection->first();
  75.             if($firstPossibleCombination instanceof PossibleCombinationStruct) {
  76.                 $redirectDomainUrl $firstPossibleCombination->getDomainUrl();
  77.                 if($firstPossibleCombination->getPossibleStruct() instanceof AbstractPossibleStruct && empty($firstPossibleCombination->getPossibleStruct()->getRuleDomainEntity()->getDefaultShippingCountryId()) === false) {
  78.                     $defaultCountryId $firstPossibleCombination->getPossibleStruct()->getRuleDomainEntity()->getDefaultShippingCountryId();
  79.                 }
  80.             }
  81.             $stayOnPageWithoutAsk false;
  82.             if(empty($redirectDomainUrl)) {
  83.                 $redirectDomainUrl $activeDomainUrl;
  84.             }
  85.             if($redirectDomainUrl === $activeDomainUrl) {
  86.                 $stayOnPageWithoutAsk true;
  87.             }
  88.             $countryId "";
  89.             // for redirect to external domain we don't want to get the shipping country as a parameter
  90.             if($stayOnPageWithoutAsk !== true && $this->isExternalRedirect($redirectDomainUrl$activeRule) !== true) {
  91.                 $countryId $this->getCountryId($possibleCombinationCollection$possibleCountryCollectionForShipping$activeDomainEntity->getUrl(), $defaultCountryId$context);
  92.             }
  93.             return new ShopSwitchRouteResponse(new ShopSwitchResult($activeDomainId$possibleCountryCollection$possibleLanguageCollection$activeRule$activeDomainUrl$stayOnPageWithoutAsk$redirectDomainUrl$countryId));
  94.         }
  95.         if($activeRule->getSwitchType() === ShopSwitchRuleDefinition::SWITCH_TYPE_SET_ONLY_COUNTRY) {
  96.             $stayOnPageWithoutAsk true;
  97.         } else {
  98.             $stayOnPageWithoutAsk false;
  99.         }
  100.         $countryId $this->getCountryId($possibleCombinationCollection$possibleCountryCollectionForShipping$activeDomainEntity->getUrl(), $defaultCountryId$context);
  101.         return new ShopSwitchRouteResponse(new ShopSwitchResult($activeDomainId$possibleCountryCollection$possibleLanguageCollection$activeRule$activeDomainUrl$stayOnPageWithoutAsk""$countryId));
  102.     }
  103.     public function getPossibleCountries(ShopSwitchRuleEntity $activeRuleRequest $requeststring $activeDomainUrlContext $context, ?string $countryIso): PossibleCountryCollection
  104.     {
  105.         // if only language is checked, we also want to find the correct shipping country
  106.         if($activeRule->getSwitchType() === ShopSwitchRuleDefinition::SWITCH_TYPE_SET_ONLY_COUNTRY
  107.             || $activeRule->getRuleDefinitionType() === ShopSwitchRuleDefinition::RULE_DEFINITION_TYPE_LANGUAGE) {
  108.             $possibleCountryCollection $this->shopSwitchRuleService->getPossibleCountriesOfSalesChannel($activeRule$context);
  109.         } else {
  110.             $possibleCountryCollection $this->shopSwitchRuleService->getPossibleCountriesOfRule($activeRule$activeDomainUrl$context$request);
  111.         }
  112.         $this->setActiveCountry($possibleCountryCollection$countryIso);
  113.         return $possibleCountryCollection;
  114.     }
  115.     public function getRawPossibleCountries(ShopSwitchRuleEntity $activeRuleRequest $requeststring $activeDomainUrlContext $context): PossibleCountryCollection
  116.     {
  117.         if($activeRule->getSwitchType() === ShopSwitchRuleDefinition::SWITCH_TYPE_SET_ONLY_COUNTRY) {
  118.             $possibleCountryCollection $this->shopSwitchRuleService->getPossibleCountriesOfSalesChannel($activeRule$context);
  119.         } else {
  120.             $possibleCountryCollection $this->shopSwitchRuleService->getPossibleCountriesOfRule($activeRule$activeDomainUrl$context$request);
  121.         }
  122.         return $possibleCountryCollection;
  123.     }
  124.     /**
  125.      * Gets possibleLanguages for ShopSwitchResult.
  126.      * @param ShopSwitchRuleEntity $activeRule
  127.      * @param Request $request
  128.      * @param string $activeDomainUrl
  129.      * @param Context $context
  130.      * @return array
  131.      */
  132.     public function getPossibleLanguages(ShopSwitchRuleEntity $activeRuleRequest $requeststring $activeDomainUrlContext $context, ?array $languageIds = []): PossibleLanguageCollection
  133.     {
  134.         if($activeRule->getRuleDefinitionType() === ShopSwitchRuleDefinition::RULE_DEFINITION_TYPE_LANGUAGE || $activeRule->getRuleDefinitionType() === ShopSwitchRuleDefinition::RULE_DEFINITION_TYPE_COUNTRY_LANGUAGE) {
  135.             $possibleLanguageCollection $this->shopSwitchRuleService->getPossibleLanguagesOfRule($activeRule$activeDomainUrl$context$request);
  136.             if(empty($languageIds) === false) {
  137.                 $this->setActiveLanguage($possibleLanguageCollection$languageIds);
  138.             }
  139.         } else {
  140.             $possibleLanguageCollection = new PossibleLanguageCollection();
  141.         }
  142.         return $possibleLanguageCollection;
  143.     }
  144.     public function getDomainByIdAndSalesChannelContext(string $activeDomainIdSalesChannelContext $salesChannelContext): SalesChannelDomainEntity
  145.     {
  146.         if($salesChannelContext->getSalesChannel()->getDomains() && $salesChannelContext->getSalesChannel()->getDomains()->has($activeDomainId)) {
  147.             return $salesChannelContext->getSalesChannel()->getDomains()->get($activeDomainId);
  148.         }
  149.         return $this->getDomainById($activeDomainId$salesChannelContext->getContext());
  150.     }
  151.     public function getDomainById(string $activeDomainIdContext $context): SalesChannelDomainEntity
  152.     {
  153.         /** @var SalesChannelDomainEntity $domainEntity */
  154.         $domainEntity $this->salesChannelDomainRepository->search(
  155.             (new Criteria([$activeDomainId]))
  156.                 ->addAssociation('salesChannel')
  157.                 ->addAssociation('salesChannel.domains')
  158.             , $context)->first();
  159.         if (empty($domainEntity) === true) {
  160.             throw new ActiveDomainNotFoundException();
  161.         }
  162.         return $domainEntity;
  163.     }
  164.     private function setActiveCountry(PossibleCountryCollection $possibleCountryCollection, ?string $countryIso): void
  165.     {
  166.         if ($countryIso === null) {
  167.             return;
  168.         }
  169.         /**
  170.          * @var string $key
  171.          * @var PossibleCountryStruct $possibleCountryStruct
  172.          */
  173.         foreach ($possibleCountryCollection->getElements() as $key => $possibleCountryStruct) {
  174.             if ($possibleCountryStruct->getIso() === $countryIso) {
  175.                 $possibleCountryStruct->setActive(true);
  176.             } else {
  177.                 $possibleCountryStruct->setActive(false);
  178.             }
  179.         }
  180.     }
  181.     private function setActiveLanguage(PossibleLanguageCollection $possibleLanguageCollection, array $languageIds): void
  182.     {
  183.         /**
  184.          * @var string $key
  185.          * @var PossibleLanguageStruct $possibleLanguageStruct
  186.          */
  187.         foreach ($possibleLanguageCollection->getElements() as $key => $possibleLanguageStruct) {
  188.             $possibleLanguageStruct->setActive(false);
  189.             foreach ($languageIds as $languageId) {
  190.                 if (strtolower($possibleLanguageStruct->getLanguageId()) === $languageId) {
  191.                     $possibleLanguageStruct->setActive(true);
  192.                     break;
  193.                 }
  194.             }
  195.         }
  196.     }
  197.     public function removeNotExistingCombinations(PossibleCountryCollection $possibleCountryCollectionPossibleLanguageCollection $possibleLanguageCollection)
  198.     {
  199.         foreach ($possibleCountryCollection->getElements() as $possibleCountryKey => $possibleCountry) {
  200.             foreach ($possibleLanguageCollection->getElements() as $possibleLanguageKey => $possibleLanguage) {
  201.                 foreach ($possibleCountry->getDomainUrls() as $domainUrlCountry) {
  202.                     foreach ($possibleLanguage->getDomainUrls() as $domainUrlLanguage) {
  203.                         if ($domainUrlCountry === $domainUrlLanguage) {
  204.                             continue 4;
  205.                         }
  206.                     }
  207.                 }
  208.             }
  209.             $possibleCountryCollection->remove($possibleCountryKey);
  210.         }
  211.         foreach ($possibleLanguageCollection->getElements() as $possibleLanguageKey => $possibleLanguage) {
  212.             foreach ($possibleCountryCollection->getElements() as $possibleCountryKey => $possibleCountry) {
  213.                 foreach ($possibleLanguage->getDomainUrls() as $domainUrlLanguage) {
  214.                     foreach ($possibleCountry->getDomainUrls() as $domainUrlCountry) {
  215.                         if ($domainUrlCountry === $domainUrlLanguage) {
  216.                             continue 4;
  217.                         }
  218.                     }
  219.                 }
  220.             }
  221.             $possibleLanguageCollection->remove($possibleLanguageKey);
  222.         }
  223.     }
  224.     public function getPossibleCombinations(PossibleCountryCollection $possibleCountryCollectionPossibleLanguageCollection $possibleLanguageCollection): PossibleCombinationCollection
  225.     {
  226.         $possibleCombinationCollection1 $this->getCombinationOfCollections($possibleCountryCollection$possibleLanguageCollection);
  227.         $possibleCombinationCollection2 $this->getCombinationOfCollections($possibleLanguageCollection$possibleCountryCollection);
  228.         return $this->mergeAndUniqueCombinations($possibleCombinationCollection1$possibleCombinationCollection2);
  229.     }
  230.     private function getCombinationOfCollections(Collection $collection1Collection $collection2): PossibleCombinationCollection
  231.     {
  232.         $possibleCombinationCollection = new PossibleCombinationCollection();
  233.         /** @var AbstractPossibleStruct $item1 */
  234.         foreach ($collection1->getElements() as $item1) {
  235.             if ($item1->isActive() !== true) {
  236.                 continue;
  237.             }
  238.             if ($collection2->count() === 0) {
  239.                 foreach ($item1->getDomainUrls() as $domainUrlItem1) {
  240.                     $possibleCombinationCollection->add(new PossibleCombinationStruct($domainUrlItem1$item1));
  241.                 }
  242.             } else {
  243.                 /** @var AbstractPossibleStruct $item2 */
  244.                 foreach ($collection2->getElements() as $item2) {
  245.                     if ($item2->isActive() !== true) {
  246.                         continue;
  247.                     }
  248.                     foreach ($item2->getDomainUrls() as $domainUrlItem2) {
  249.                         foreach ($item1->getDomainUrls() as $domainUrlItem1) {
  250.                             if ($domainUrlItem1 === $domainUrlItem2) {
  251.                                 $possibleCombinationCollection->add(new PossibleCombinationStruct($domainUrlItem1$item1));
  252.                             }
  253.                         }
  254.                     }
  255.                 }
  256.             }
  257.         }
  258.         return $possibleCombinationCollection;
  259.     }
  260.     private function mergeAndUniqueCombinations(PossibleCombinationCollection $possibleCombinationCollection1PossibleCombinationCollection $possibleCombinationCollection2): PossibleCombinationCollection
  261.     {
  262.         $possibleCombinationCollection $possibleCombinationCollection1;
  263.         foreach ($possibleCombinationCollection2->getElements() as $item2) {
  264.             foreach ($possibleCombinationCollection as $possibleCombinationStruct) {
  265.                 if($possibleCombinationStruct->getDomainUrl() === $item2->getDomainUrl()) {
  266.                     continue 2;
  267.                 }
  268.             }
  269.             $possibleCombinationCollection->add($item2);
  270.         }
  271.         return $possibleCombinationCollection;
  272.     }
  273.     private function getStayOnPageWithoutAsk(ShopSwitchRuleEntity $activeRulePossibleCombinationCollection $possibleCombinationCollectionstring $activeDomainUrlRequest $requestSalesChannelEntity $salesChannelEntity): bool
  274.     {
  275.         return $this->comesFromOwnDomain($request$activeRule) ||
  276.             (($activeRule->isAskIfMatch() === false || $activeRule->getSwitchType() === ShopSwitchRuleDefinition::SWITCH_TYPE_DIRECT)
  277.                 && $possibleCombinationCollection->hasUrl($activeDomainUrl) === true);
  278.     }
  279.     private function comesFromOwnDomain(Request $requestShopSwitchRuleEntity $activeRule): bool
  280.     {
  281.         if ($request->attributes->has(ShopSwitchController::SHOP_SWITCH_AJAX)) {
  282.             return false;
  283.         }
  284.         if (empty($referer $request->server->get('HTTP_REFERER')) === false) {
  285.             $referer rtrim($referer'/');
  286.             $currentDomainId $request->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_ID);
  287.             foreach ($activeRule->getDomains() as $domainEntity) {
  288.                 if ($domainEntity->getDomainId() === $currentDomainId || empty($domainEntity->getDomain()) || empty($domainEntity->getDomain()->getUrl())) {
  289.                     continue;
  290.                 }
  291.                 if (strpos($referer$domainEntity->getDomain()->getUrl()) === 0
  292.                     || strpos($domainEntity->getDomain()->getUrl(), $referer) === 0) {
  293.                     return true;
  294.                 }
  295.             }
  296.         }
  297.         return false;
  298.     }
  299.     public function getCountryId(PossibleCombinationCollection $possibleCombinationCollectionPossibleCountryCollection $possibleCountryCollectionstring $redirectDomainUrl, ?string $defaultCountryIdContext $context): string
  300.     {
  301.         $countryId $this->getCountryIdFromPossibleCombinations($possibleCombinationCollection$possibleCountryCollection);
  302.         // try to get first active county from
  303.         if (!$countryId) {
  304.             foreach ($possibleCountryCollection->getElements() as $possibleCountryStruct) {
  305.                 if ($possibleCountryStruct->isActive() === true) {
  306.                     if ($this->salesChannelCountryLanguageService->isCountryInSalesChannelDomain($possibleCountryStruct->getCountryId(), $redirectDomainUrl$context) === true) {
  307.                         return $possibleCountryStruct->getCountryId();
  308.                     }
  309.                 }
  310.             }
  311.             $countryId $defaultCountryId;
  312.         }
  313.         if (!$countryId) {
  314.             return "";
  315.         }
  316.         if ($this->salesChannelCountryLanguageService->isCountryInSalesChannelDomain($countryId$redirectDomainUrl$context) === true) {
  317.             return $countryId;
  318.         }
  319.         return "";
  320.     }
  321.     private function getCountryIdFromPossibleCombinations(PossibleCombinationCollection $possibleCombinationCollectionPossibleCountryCollection $possibleCountryCollection)
  322.     {
  323.         // if more countries match on more domains -> prefer the active one
  324.         foreach ($possibleCountryCollection->getElements() as $possibleCountryStruct) {
  325.             if ($possibleCountryStruct->isActive() === true) {
  326.                 foreach ($possibleCombinationCollection->getElements() as $possibleCombinationStruct) {
  327.                     if ($possibleCombinationStruct->getDomainUrl() === $possibleCountryStruct->getDomainUrl()) {
  328.                         return $possibleCountryStruct->getCountryId();
  329.                     }
  330.                 }
  331.             }
  332.         }
  333.         foreach ($possibleCountryCollection->getElements() as $possibleCountryStruct) {
  334.             foreach ($possibleCombinationCollection->getElements() as $possibleCombinationStruct) {
  335.                 if ($possibleCombinationStruct->getDomainUrl() === $possibleCountryStruct->getDomainUrl()) {
  336.                     return $possibleCountryStruct->getCountryId();
  337.                 }
  338.             }
  339.         }
  340.         return "";
  341.     }
  342.     public function sortPossibleCombinationsByActiveDomain(PossibleCombinationCollection $possibleCombinationCollectionstring $activeDomainUrl): void
  343.     {
  344.         $possibleCombinationCollection->sort(function (PossibleCombinationStruct $possibleCombinationStructAPossibleCombinationStruct $possibleCombinationStructB) use ($activeDomainUrl) {
  345.             if ($possibleCombinationStructA->getDomainUrl() === $activeDomainUrl) {
  346.                 return -1;
  347.             } elseif ($possibleCombinationStructB->getDomainUrl() === $activeDomainUrl) {
  348.                 return 1;
  349.             } else {
  350.                 return 0;
  351.             }
  352.         });
  353.     }
  354.     private function isExternalRedirect(?string $redirectDomainUrlShopSwitchRuleEntity $activeRule): bool
  355.     {
  356.         if (empty($redirectDomainUrl)) {
  357.             return false;
  358.         }
  359.         foreach ($activeRule->getDomains() as $domain) {
  360.             if ($domain->isActive() === true && $domain->getRedirectTo() === 'external' && $redirectDomainUrl === $domain->getExternalUrl()) {
  361.                 return true;
  362.             }
  363.         }
  364.         return false;
  365.     }
  366.     private function getPossibleBlacklistCombination(ShopSwitchRuleEntity $activeRulePossibleCountryCollection $possibleCountryCollection): PossibleCombinationCollection
  367.     {
  368.         $possibleCombinationCollection = new PossibleCombinationCollection();
  369.         foreach ($activeRule->getDomains() as $ruleDomainEntity) {
  370.             if(empty($ruleDomainEntity->getFoundUrl()) === true) continue;
  371.             if($ruleDomainEntity->getCountryBlacklist() instanceof CountryCollection && $ruleDomainEntity->getCountryBlacklist()->count() > 0) {
  372.                 if(empty($ruleDomainEntity->getDefaultShippingCountryId()) === false && $possibleCountryCollection->has($ruleDomainEntity->getDefaultShippingCountryId()) === true) {
  373.                     $possibleCountryStruct $possibleCountryCollection->get($ruleDomainEntity->getDefaultShippingCountryId());
  374.                     $possibleCountryStruct->setActive(true);
  375.                     $possibleCombinationCollection->add(new PossibleCombinationStruct($ruleDomainEntity->getFoundUrl(), $possibleCountryStruct));
  376.                 } else {
  377.                     $possibleCombinationCollection->add(new PossibleCombinationStruct($ruleDomainEntity->getFoundUrl()));
  378.                 }
  379.             }
  380.         }
  381.         return $possibleCombinationCollection;
  382.     }
  383. }