vendor/store.shopware.com/ndsrecipemanager/src/Controller/NdsRecipeManagerController.php line 118

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Nds\RecipeManager\Controller;
  3. use Shopware\Core\Framework\Context;
  4. use Shopware\Storefront\Page\MetaInformation;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Shopware\Storefront\Page\GenericPageLoader;
  8. use Symfony\Component\Routing\Annotation\Route;
  9. use Nds\RecipeManager\Core\Content\Recipe\RecipeEntity;
  10. use Shopware\Storefront\Controller\StorefrontController;
  11. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  12. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  13. use Shopware\Core\System\SystemConfig\SystemConfigService;
  14. use Nds\RecipeManager\Core\Content\Category\CategoryEntity;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  16. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
  19. use Shopware\Core\Content\Cms\SalesChannel\SalesChannelCmsPageLoaderInterface;
  20. use Nds\RecipeManager\Core\Content\Recipe\Aggregate\RecipeTranslation\RecipeTranslationEntity;
  21. use Nds\RecipeManager\Core\Content\Category\Aggregate\CategoryTranslation\CategoryTranslationEntity;
  22. /**
  23.  * @RouteScope(scopes={"storefront"})
  24.  */
  25. class NdsRecipeManagerController extends StorefrontController
  26. {
  27.     protected GenericPageLoader $genericPageLoader;
  28.     protected SystemConfigService $systemConfigService;
  29.     protected EntityRepository $recipeRepository;
  30.     protected EntityRepository $recipeTranslationRepository;
  31.     protected EntityRepository $categoryRepository;
  32.     protected EntityRepository $categoryTranslationRepository;
  33.     protected EntityRepository $tagRepository;
  34.     protected SalesChannelCmsPageLoaderInterface $cmsPageLoader;
  35.     public function __construct(
  36.         EntityRepository $recipeRepository,
  37.         EntityRepository $recipeTranslationRepository,
  38.         EntityRepository $categoryRepository,
  39.         EntityRepository $categoryTranslationRepository,
  40.         EntityRepository $tagRepository,
  41.         GenericPageLoader $genericPageLoader,
  42.         SystemConfigService $systemConfigService
  43.     ) {
  44.         $this->recipeRepository $recipeRepository;
  45.         $this->recipeTranslationRepository $recipeTranslationRepository;
  46.         $this->categoryRepository $categoryRepository;
  47.         $this->categoryTranslationRepository $categoryTranslationRepository;
  48.         $this->tagRepository $tagRepository;
  49.         $this->genericPageLoader $genericPageLoader;
  50.         $this->systemConfigService $systemConfigService;
  51.     }
  52.     /**
  53.      * @Route("/rcp_category/{slug}", name="rcp.frontend.category", methods={"GET"})
  54.      */
  55.     public function category(Request $requestContext $contextSalesChannelContext $salesChannelContextstring $slug): Response
  56.     {
  57.         $criteria = new Criteria();
  58.         $criteria
  59.             ->addFilter(new EqualsFilter('slug'$slug))
  60.             ->addFilter(new EqualsFilter('active''1'))
  61.             ->addAssociation('recipes');
  62.         /** @var CategoryEntity $category */
  63.         $category $this->categoryRepository->search(
  64.             $criteria,
  65.             $context
  66.         )->first();
  67.         if (! $category) {
  68.             /** @var CategoryEntity $categoryTranslation */
  69.             $categoryTranslation $this->categoryRepository->search(
  70.                 new Criteria([$this->getCategoryIdBySlug($slug$context)]),
  71.                 $context
  72.             )->first();
  73.             if ($categoryTranslation) {
  74.                 $url $request->attributes->get('sw-sales-channel-base-url') . '/' $categoryTranslation->getSlug();
  75.                 return $this->redirect($url);
  76.             }
  77.             throw $this->createNotFoundException('The category ' $slug ' does not exist');
  78.         }
  79.         $page $this->genericPageLoader->load($request$salesChannelContext);
  80.         $page->setMetaInformation((new MetaInformation())->assign([
  81.             'metaTitle' => empty($category->getTranslation('metaTitle'))
  82.                 ? $category->getTranslation('name')
  83.                 : $category->getTranslation('metaTitle'),
  84.             'metaDescription' => $category->getTranslation('metaDescription') ?? $category->getTranslation('description') ?? '',
  85.             'robots' => $category->getRobots() ?? '',
  86.         ]));
  87.         return $this->renderStorefront(
  88.             '@Storefront/rcpmanager/page/recipe-list.html.twig',
  89.             [
  90.                 'page' => $page,
  91.                 'items' => $category,
  92.             ]
  93.         );
  94.     }
  95.     /**
  96.      * @Route("/rcp_tag/{slug}", name="rcp.frontend.tag", methods={"GET"})
  97.      */
  98.     public function tag(Request $requestContext $contextSalesChannelContext $salesChannelContextstring $slug): Response
  99.     {
  100.         $criteria = new Criteria();
  101.         $criteria
  102.             ->addFilter(new EqualsFilter('slug'$slug))
  103.             ->addFilter(new EqualsFilter('active''1'))
  104.             ->addAssociation('recipes');
  105.         $tag $this->tagRepository->search(
  106.             $criteria,
  107.             $context
  108.         )->first();
  109.         if (! $tag) {
  110.             throw $this->createNotFoundException('The tag-slug: ' $slug ' does not exist');
  111.         }
  112.         $page $this->genericPageLoader->load($request$salesChannelContext);
  113.         return $this->renderStorefront(
  114.             '@Storefront/rcpmanager/page/recipe-list.html.twig',
  115.             [
  116.                 'page' => $page,
  117.                 'items' => $tag,
  118.             ]
  119.         );
  120.     }
  121.     /**
  122.      * @Route("/rcp_recipe/{slug}", name="rcp.frontend.recipe", methods={"GET"})
  123.      */
  124.     public function recipe(Request $requestContext $contextSalesChannelContext $salesChannelContextstring $slug): Response
  125.     {
  126.         $recipe $this->getRecipe($slug$context);
  127.         if (! $recipe) {
  128.             /** @var RecipeEntity $recipeTranslation */
  129.             $recipeTranslation $this->recipeRepository->search(
  130.                 new Criteria([$this->getRecipeIdBySlug($slug$context)]),
  131.                 $context
  132.             )->first();
  133.             if ($recipeTranslation) {
  134.                 $url $request->attributes->get('sw-sales-channel-base-url') . '/' $recipeTranslation->getSlug();
  135.                 return $this->redirect($url);
  136.             }
  137.             throw $this->createNotFoundException('The recipe ' $slug ' does not exist');
  138.         }
  139.         $page $this->genericPageLoader->load($request$salesChannelContext);
  140.         $page->setMetaInformation((new MetaInformation())->assign([
  141.             'metaTitle' => empty($recipe->getTranslation('metaTitle'))
  142.                 ? $recipe->getTranslation('name')
  143.                 : $recipe->getTranslation('metaTitle'),
  144.             'metaDescription' => $this->getMetaDescription($recipe),
  145.             'robots' => $recipe->getRobots() ?? '',
  146.         ]));
  147.         return $this->renderStorefront(
  148.             '@Storefront/rcpmanager/page/detail.html.twig',
  149.             [
  150.                 'page' => $page,
  151.                 'recipe' => $recipe,
  152.                 'backLink' => $request->headers->get('referer'),
  153.                 'schemaJson' => $this->getSchemaJson($recipe),
  154.             ]
  155.         );
  156.     }
  157.     protected function getRecipe(string $slugContext $context): ?RecipeEntity
  158.     {
  159.         $criteria = new Criteria();
  160.         $criteria
  161.             ->addFilter(new EqualsFilter('slug'$slug))
  162.             ->addFilter(new EqualsFilter('active''1'))
  163.             ->addAssociations(
  164.                 [
  165.                     'relatedRecipes',
  166.                     'relatedRecipes.relatedRecipe',
  167.                     'tags',
  168.                     'categories',
  169.                     'ingredients',
  170.                     'ingredients.product',
  171.                     'ingredients.unit',
  172.                     'media',
  173.                     'cover',
  174.                 ]
  175.             );
  176.         $criteria->getAssociation('ingredients')->addSorting(new FieldSorting('position'FieldSorting::ASCENDING));
  177.         $criteria->getAssociation('relatedRecipes')->addSorting(new FieldSorting('position'FieldSorting::ASCENDING));
  178.         $criteria->getAssociation('media')->addSorting(new FieldSorting('position'FieldSorting::ASCENDING));
  179.         return $this->recipeRepository->search(
  180.             $criteria,
  181.             $context
  182.         )->first();
  183.     }
  184.     protected function getCategoryIdBySlug(string $slugContext $context): ?string
  185.     {
  186.         $criteria = new Criteria();
  187.         $criteria
  188.             ->addFilter(new EqualsFilter('slug'$slug));
  189.         /** @var CategoryTranslationEntity $categoryTranslation */
  190.         $categoryTranslation $this->categoryTranslationRepository->search(
  191.             $criteria,
  192.             $context
  193.         )->first();
  194.         if ($categoryTranslation === null) {
  195.             return null;
  196.         }
  197.         return $categoryTranslation->getNdsRcpCategoryId();
  198.     }
  199.     protected function getRecipeIdBySlug(string $slugContext $context): ?string
  200.     {
  201.         $criteria = new Criteria();
  202.         $criteria
  203.             ->addFilter(new EqualsFilter('slug'$slug));
  204.         /** @var RecipeTranslationEntity $recipeTranslation */
  205.         $recipeTranslation $this->recipeTranslationRepository->search(
  206.             $criteria,
  207.             $context
  208.         )->first();
  209.         if ($recipeTranslation === null) {
  210.             return null;
  211.         }
  212.         return $recipeTranslation->getNdsRcpRecipeId();
  213.     }
  214.     protected function getMetaDescription($recipe): string
  215.     {
  216.         if ($recipe->getTranslation('metaDescription') !== null) {
  217.             return $recipe->getTranslation('metaDescription');
  218.         }
  219.         if ($recipe->getTranslation('description') !== null) {
  220.             return $recipe->getTranslation('description');
  221.         }
  222.         return '';
  223.     }
  224.     protected function getSchemaJson($recipe): string
  225.     {
  226.         $schemaJson['@context'] = 'https://schema.org';
  227.         $schemaJson['@type'] = 'Recipe';
  228.         $recipeName $recipe->getTranslation('name');
  229.         $recipeSubhead = empty($recipe->getTranslation('subhead')) ? '' ' - ' $recipe->getTranslation('subhead');
  230.         $schemaJson['name'] = $recipeName $recipeSubhead;
  231.         if (! empty($recipe->getTranslation('description'))) {
  232.             $schemaJson['description'] = $recipe->getTranslation('description');
  233.         }
  234.         if (! empty($recipe->coverId)) {
  235.             foreach ($recipe->media as $media) {
  236.                 if ($recipe->coverId === $media->mediaId) {
  237.                     $coverMedia $media->media;
  238.                     $schemaJson['image'] = $coverMedia->getUrl();
  239.                     continue;
  240.                 }
  241.             }
  242.         }
  243.         if (! empty($recipe->getTranslation('preparation'))) {
  244.             $schemaJson['recipeInstructions'] = $recipe->getPreparation();
  245.         }
  246.         if (! empty($recipe->getIngredients())) {
  247.             $ingredientList = [];
  248.             foreach ($recipe->getIngredients() as $ingredient) {
  249.                 $ingredientUnits $ingredient->getQuantity();
  250.                 if ($ingredient->getUnit()) {
  251.                     $ingredientUnits .= ' ' $ingredient->getUnit()->getTranslation('value');
  252.                 }
  253.                 if (! empty($ingredient->getName())) {
  254.                     $ingredientName $ingredient->getTranslation('name');
  255.                 } elseif (! empty($ingredient->getProductId()) && $ingredient->product !== null) {
  256.                     $ingredientName $ingredient->product->getTranslation('name');
  257.                 } else {
  258.                     continue;
  259.                 }
  260.                 $ingredientList[] = $ingredientUnits ' ' $ingredientName;
  261.             }
  262.             if (! empty($ingredientList)) {
  263.                 $schemaJson['recipeIngredient'] = $ingredientList;
  264.             }
  265.         }
  266.         if ($recipe->getCategories()->count()) {
  267.             $categoryList = [];
  268.             foreach ($recipe->getCategories() as $category) {
  269.                 $categoryList[] = $category->getTranslation('name');
  270.             }
  271.             $schemaJson['recipeCategory'] = implode(','$categoryList);
  272.         }
  273.         if (! empty($recipe->getPreparationTime())) {
  274.             $schemaJson['totalTime'] = $this->Iso8601($recipe->getPreparationTime());
  275.         }
  276.         if ($recipe->hasNutritionalValues()) {
  277.             $nutritionalList array_merge(['@type' => 'NutritionInformation'], $this->nutritionInformation($recipe));
  278.             $schemaJson['nutrition'] = $nutritionalList;
  279.         }
  280.         return json_encode($schemaJson);
  281.     }
  282.     protected function Iso8601($time): string
  283.     {
  284.         $time = (int) $time;
  285.         $time *= 60;
  286.         $units = [
  287.             'Y' => 365 24 3600,
  288.             'D' => 24 3600,
  289.             'H' => 3600,
  290.             'M' => 60,
  291.             'S' => 1,
  292.         ];
  293.         $str 'P';
  294.         $isTime false;
  295.         foreach ($units as $unitName => $unit) {
  296.             $quot = (int) ($time $unit);
  297.             $time -= $quot $unit;
  298.             $unit $quot;
  299.             if ($unit 0) {
  300.                 if (! $isTime && \in_array($unitName, ['H''M''S'], true)) { // There may be a better way to do this
  301.                     $str .= 'T';
  302.                     $isTime true;
  303.                 }
  304.                 $str .= (string) $unit $unitName;
  305.             }
  306.         }
  307.         return $str;
  308.     }
  309.     protected function nutritionInformation(RecipeEntity $recipe): array
  310.     {
  311.         $ret = [];
  312.         if ($recipe->getCalories()) {
  313.             $ret['calories'] = number_format($recipe->getCalories(), 1',''.') . ' kcal';
  314.         }
  315.         if ($recipe->getCarbohydrates()) {
  316.             $ret['carbohydrateContent'] = number_format($recipe->getCarbohydrates(), 1',''.') . ' g';
  317.         }
  318.         if ($recipe->getFat()) {
  319.             $ret['fatContent'] = number_format($recipe->getCarbohydrates(), 1',''.') . ' g';
  320.         }
  321.         if ($recipe->getProtein()) {
  322.             $ret['proteinContent'] = number_format($recipe->getProtein(), 1',''.') . ' g';
  323.         }
  324.         return $ret;
  325.     }
  326. }