src/Controller/Addon/SmartSuggestionController.php line 48

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Addon;
  3. use App\Controller\BaseApiController;
  4. use App\Entity\Config\SmartAlternativeConfigRuleTranslation;
  5. use App\Exception\AdminException;
  6. use App\Exception\ShoptetAddonException;
  7. use App\Repository\Config\SmartAlternativeConfigRuleCategoryRepository;
  8. use App\Repository\Config\SmartAlternativeConfigRuleRepository;
  9. use App\Service\AdminCacheService;
  10. use App\Service\ConfigRuleService;
  11. use App\Service\ShoptetApiService;
  12. use App\Service\ShoptetProductsService;
  13. use Symfony\Component\HttpFoundation\JsonResponse;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\Messenger\MessageBusInterface;
  17. use Symfony\Component\Routing\Annotation\Route;
  18. use Symfony\Contracts\Service\Attribute\Required;
  19. use Twig\Environment;
  20. #[Route(path'/suggestions'name'suggestions_')]
  21. class SmartSuggestionController extends BaseApiController
  22. {
  23.     #[Required]
  24.     public ShoptetProductsService $productsService;
  25.     #[Required]
  26.     public AdminCacheService $cacheService;
  27.     #[Required]
  28.     public ShoptetApiService $apiService;
  29.     #[Required]
  30.     public ConfigRuleService $ruleService;
  31.     #[Required]
  32.     public SmartAlternativeConfigRuleRepository $ruleRepository;
  33.     #[Required]
  34.     public SmartAlternativeConfigRuleCategoryRepository $ruleCategoryRepository;
  35.     #[Required]
  36.     public Environment $twig;
  37.     #[Route(path'/{_locale}/{eshopId}/{productId}'name"main"requirements: ['_locale' => 'cs|sk|en|de|vi|pl|hu|ro'], methods: ['GET'])]
  38.     public function getSuggestions(Request $requestMessageBusInterface $messageBusint $eshopIdstring $productId): Response
  39.     {
  40.         $locale $request->getLocale();
  41.         $installation $this->findInstallation($eshopId);
  42.         $currencyOverride $request->query->get("currencyCode");
  43.         if (!$installation) {
  44.             throw new ShoptetAddonException(
  45.                 404,
  46.                 "Installation for shoptet ID $eshopId does not exist. Could not find any smart suggestions.",
  47.                 "smart_suggestions.no_installation"
  48.             );
  49.         }
  50.         try {
  51.             $config $this->getConfig($installation$eshopId$messageBus);
  52.         } catch (AdminException $exception) {
  53.             $this->convertAdminExceptionToApiException($exception);
  54.         }
  55.         if (!$config->isIsActive()) {
  56.             return new Response(null204);
  57.         }
  58.         if ($config->getProductsExpiry() === null) {
  59.             if (!$config->isIsProductsRetrieved())
  60.                 $this->productsService->retrieveAllProducts($installation);
  61.             throw new ShoptetAddonException(
  62.                 400,
  63.                 "Products are not yet retrieved for this eshop. Could not find any smart suggestions.",
  64.                 "smart_suggestions.no_product_list"
  65.             );
  66.         }
  67.         $foreignLanguagesActive $this->apiService->checkModuleExists($eshopId$installation"foreignLanguages");
  68.         $productDetail $this->cacheService->getProductDetail($productId$locale$eshopId$installation$foreignLanguagesActive);
  69.         if (!$productDetail) {
  70.             throw new ShoptetAddonException(
  71.                 404,
  72.                 "Product with $productId was not found. Could not find any smart suggestions.",
  73.                 "smart_suggestions.product_not_found"
  74.             );
  75.         }
  76.         $ruleCategory $this->findActiveRuleCategoryRecursively($productDetail$installation);
  77.         if ($ruleCategory === null) {
  78.             try {
  79.                 $rule $this->ruleService->getGlobalConfigRule($installation->getConfig()->getId());
  80.                 // Check if global rule is activated
  81.                 if (!$rule->isIsGlobalActivated() && $rule->isIsGlobal()) {
  82.                     return new Response(null204);
  83.                 }
  84.             } catch (AdminException $exception) {
  85.                 throw new ShoptetAddonException($exception->getStatusCode(), $exception->getMessage(), $exception->getErrorSlug());
  86.             }
  87.         } else {
  88.             $rule $ruleCategory->getRule();
  89.         }
  90.         if ($config->willProductsExpire())
  91.             $this->productsService->retrieveAllProducts($installation);
  92.         if (
  93.             $rule->isIsStockStatusVisitedSuggestion()
  94.             && !$this->productsService->checkProductStockStatusId($productDetail["variants"][0], $this->cacheService->getDefaultStockStatuses($eshopId$installation$locale), $rule->getStockStatusVisitedIds())
  95.         )
  96.             return new Response(null204);
  97.         $suggestions $this->cacheService->getSmartSuggestions($eshopId$locale$productDetail$installation$rule$ruleCategory$currencyOverride);
  98.         // Get title for the suggestion
  99.         /** @var SmartAlternativeConfigRuleTranslation $ruleTranslation */
  100.         $ruleTranslation $rule->translate($locale);
  101.         $title $ruleTranslation->getSectionTitle();
  102.         $template $request->query->get("template");
  103.         return new JsonResponse([
  104.             "title" => $title,
  105.             "html" => $this->twig->render("suggestions/suggestions.html.twig", ["products" => $suggestions"template" => $template]),
  106.             "customHtmlSelector" => $config->getCustomHtmlSelector(),
  107.         ]);
  108.     }
  109.     /**
  110.      * Recursively (iteratively) find the active rule category by traversing up the category tree.
  111.      */
  112.     private function findActiveRuleCategoryRecursively(array $productDetail$installation)
  113.     {
  114.         // Start with the product's default category
  115.         $currentCategoryGuid $productDetail["defaultCategory"]["guid"] ?? null;
  116.         $visited = [];
  117.         while ($currentCategoryGuid) {
  118.             if (in_array($currentCategoryGuid$visitedtrue)) {
  119.                 break;
  120.             }
  121.             $visited[] = $currentCategoryGuid;
  122.             $ruleCategory $this->ruleCategoryRepository->getRuleActiveCategory($currentCategoryGuid);
  123.             if ($ruleCategory !== null) {
  124.                 return $ruleCategory;
  125.             }
  126.             // Find parent guid
  127.             $parentGuid null;
  128.             // Try to find parent in productDetail categories
  129.             if (isset($productDetail["categories"])) {
  130.                 foreach ($productDetail["categories"] as $cat) {
  131.                     if (($cat["guid"] ?? null) === $currentCategoryGuid) {
  132.                         $parentGuid $cat["parentGuid"] ?? null;
  133.                         break;
  134.                     }
  135.                 }
  136.             }
  137.             // If not found, fetch from API
  138.             if ($parentGuid === null) {
  139.                 $categoryData $this->cacheService->getNextCategoryGuid($currentCategoryGuid$installation);
  140.                 $parentGuid $categoryData["parentGuid"] ?? null;
  141.             }
  142.             $currentCategoryGuid $parentGuid;
  143.         }
  144.         return null;
  145.     }
  146. }