src/Controller/HomepageController.php line 954

  1. <?php
  2. namespace App\Controller;
  3. use App\Repository\BlogKindRepository;
  4. use App\Repository\BlogRepository;
  5. use App\Repository\DealerOpenHourRepository;
  6. use App\Repository\DealerRepository;
  7. use App\Repository\DistrictRepository;
  8. use App\Repository\PageRepository;
  9. use App\Repository\PartnerRepository;
  10. use App\Repository\RegionRepository;
  11. use App\Repository\VehicleBodyRepository;
  12. use App\Repository\VehicleCategoryRepository;
  13. use App\Repository\VehicleFuelRepository;
  14. use App\Repository\VehicleKindRepository;
  15. use App\Repository\VehicleManufacturerRepository;
  16. use App\Repository\VehicleModelRepository;
  17. use App\Repository\VehiclePartKindRepository;
  18. use App\Repository\VehicleRepository;
  19. use App\Repository\VehicleTipRepository;
  20. use App\Service\VehicleSeoService;
  21. use DateTime;
  22. use DateTimeZone;
  23. use Knp\Component\Pager\PaginatorInterface;
  24. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  25. use Symfony\Component\HttpFoundation\Request;
  26. use Symfony\Component\HttpFoundation\Response;
  27. use Symfony\Component\Routing\Annotation\Route;
  28. /**
  29.  * @phpstan-type PlaceValue array{name: string, url: string}
  30.  * @phpstan-type Partner array{0: string, 1: string}
  31.  */
  32. class HomepageController extends AbstractController
  33. {
  34.     #[Route('/{idAutanet}/auto-{idTipCars}/{urlName}.html'name'page_vehicle_detail_redirect'methods: ['GET'])]
  35.     public function vehicleDetailRedirect(int $idAutanetint $idTipCarsstring $urlNameVehicleRepository $vehicleRepository): Response
  36.     {
  37.         $vehicle $vehicleRepository->findOneBy(['idImport' => $idTipCars]);
  38.         if ($vehicle) {
  39.             return $this->redirectToRoute('page_vehicle_detail',
  40.                 ['urlModel' => $vehicle->getModel()->getUrl(),
  41.                     'urlManufacturer' => $vehicle->getManufacturer()->getUrl(), 'id' => $vehicle->getId()]);
  42.         } else {
  43.             throw $this->createNotFoundException('Page old url vehicle no exist');
  44.         }
  45.     }
  46.     #[Route('/models'name'app_models'methods: ['GET'])]
  47.     public function getModels(Request $requestVehicleModelRepository $vehicleModelRepositoryVehicleManufacturerRepository $manufacturerRepository): Response
  48.     {
  49.         $models = [];
  50.         $manufacturerId $request->get('idManufacturer');
  51.         if ($manufacturerId) {
  52.             $manufacturer $manufacturerRepository->find($manufacturerId);
  53.             if ($manufacturer) {
  54.                 foreach ($vehicleModelRepository->findActive($manufacturer) as $model) {
  55.                     $models[] = [
  56.                         'id' => $model->getId(),
  57.                         'name' => $model->getName(),
  58.                         'url' => $model->getUrl(),
  59.                     ];
  60.                 }
  61.             }
  62.         }
  63.         return $this->json(compact('models'));
  64.     }
  65.     #[Route('/autobazary/{urlPlace}'name'page_dealer'defaults: ['urlPlace' => false], methods: ['GET'])]
  66.     public function dealers(string             $urlPlaceRequest $requestPaginatorInterface $paginator,
  67.                             DealerRepository   $dealerRepository,
  68.                             VehicleRepository  $vehicleRepository,
  69.                             DistrictRepository $districtRepository,
  70.                             RegionRepository   $regionRepository): Response
  71.     {
  72.         $parameters = [
  73.             'visible' => '1',
  74.             'excludeBasic' => true,
  75.         ];
  76.         $activePlace false;
  77.         if ($urlPlace) {
  78.             $dealer $dealerRepository->findOneBy(['url' => $urlPlace]);
  79.             if ($dealer) {
  80.                 return $this->redirectToRoute('page_dealer_detail', ['url' => $urlPlace], Response::HTTP_MOVED_PERMANENTLY);
  81.             }
  82.             if ('praha' === $urlPlace) {
  83.                 $urlPlace 'hlavni-mesto-praha';
  84.             }
  85.             if ('ostrava' === $urlPlace) {
  86.                 $urlPlace 'ostrava-mesto';
  87.             }
  88.             if ('brno' === $urlPlace) {
  89.                 $urlPlace = ['brno-mesto''brno-venkov'];
  90.             }
  91.             if ('plzen' === $urlPlace) {
  92.                 $urlPlace = ['plzen-mesto''plzen-jih''plzen-sever'];
  93.             }
  94.             if (!is_array($urlPlace) && $regionRepository->findOneBy(['url' => $urlPlace])) {
  95.                 $parameters['region'] = $urlPlace;
  96.                 $activePlace $regionRepository->findOneBy(['url' => $urlPlace]);
  97.             } else {
  98.                 $parameters['district'] = $urlPlace;
  99.                 if (is_array($urlPlace)) {
  100.                     $urlPlace $urlPlace[0];
  101.                 }
  102.                 $activePlace $districtRepository->findOneBy(['url' => $urlPlace]);
  103.             }
  104.             if (!$activePlace) {
  105.                 throw $this->createNotFoundException('The place does not exist');
  106.             }
  107.         }
  108.         if ($request->query->all()) {
  109.             $parameters += $request->query->all();
  110.         }
  111.         $pagination $paginator->paginate(
  112.             $dealerRepository->findQuery($parameters), /* query NOT result */
  113.             $request->query->getInt('page'1), /*page number*/
  114.             10 /*limit per page*/
  115.         );
  116.         $dealerMap = [];
  117.         foreach ($dealerRepository->findBy(['visible' => '1'], ['name' => 'ASC']) as $dealer) {
  118.             if ($dealer->isBasicAdvertising()) {
  119.                 continue;
  120.             }
  121.             $dealerMap[] = [
  122.                 'id' => $dealer->getId(),
  123.                 'lat' => $dealer->getLat(),
  124.                 'lng' => $dealer->getLng(),
  125.                 'street' => $dealer->getStreet(),
  126.                 'city' => $dealer->getCity(),
  127.                 'link' => $this->generateUrl('page_dealer_detail', ['url' => $dealer->getUrl()]),
  128.                 'name' => $dealer->getName(),
  129.                 'region' => $dealer->getDistrict()?->getRegion()?->getName() ?? '',
  130.                 'countVehicle' => $vehicleRepository->count(['dealer' => $dealer'visible' => '1']),
  131.             ];
  132.         }
  133.         return $this->render('homepage/dealer.html.twig', [
  134.             'dealers' => $pagination,
  135.             'urlPlace' => $urlPlace,
  136.             'dealerMap' => $dealerMap,
  137.             'selectPlaceValues' => $this->getSelectPlaceValues($regionRepository$districtRepository),
  138.             'activePlace' => $activePlace,
  139.         ]);
  140.     }
  141.     /**
  142.      * @param RegionRepository $regionRepository
  143.      * @param DistrictRepository $districtRepository
  144.      * @return array<int, PlaceValue>
  145.      */
  146.     private function getSelectPlaceValues(RegionRepository $regionRepositoryDistrictRepository $districtRepository): array
  147.     {
  148.         $selectPlaceValues = [];
  149.         foreach ($regionRepository->findBy([], ['name' => 'ASC']) as $region) {
  150.             if (strpos($region->getName(), 'Praha') !== false) {
  151.                 $selectPlaceValues[] = [
  152.                     'name' => 'Praha',
  153.                     'url' => 'praha'
  154.                 ];
  155.                 continue;
  156.             }
  157.             $selectPlaceValues[] = [
  158.                 'name' => $region->getName(),
  159.                 'url' => $region->getUrl()
  160.             ];
  161.         }
  162.         foreach ($districtRepository->findBy([], ['name' => 'ASC']) as $district) {
  163.             //if in name praha
  164.             if (strpos($district->getName(), 'Praha') !== false) {
  165.                 continue;
  166.             }
  167.             if (strpos($district->getName(), 'Ostrava') !== false) {
  168.                 $selectPlaceValues[] = [
  169.                     'name' => 'Ostrava',
  170.                     'url' => 'ostrava'
  171.                 ];
  172.                 continue;
  173.             }
  174.             if (strpos($district->getName(), 'Brno-venkov') !== false) {
  175.                 continue;
  176.             }
  177.             if (strpos($district->getName(), 'území Hlavního města Prahy') !== false) {
  178.                 continue;
  179.             }
  180.             if (strpos($district->getName(), 'Brno-město') !== false) {
  181.                 $selectPlaceValues[] = [
  182.                     'name' => 'Brno',
  183.                     'url' => 'brno'
  184.                 ];
  185.                 continue;
  186.             }
  187.             if (strpos($district->getName(), 'Plzeň-jih') !== false
  188.                 || strpos($district->getName(), 'Plzeň-sever') !== false) {
  189.                 continue;
  190.             }
  191.             if (strpos($district->getName(), 'Plzeň-město') !== false) {
  192.                 $selectPlaceValues[] = [
  193.                     'name' => 'Plzeň',
  194.                     'url' => 'plzen'
  195.                 ];
  196.                 continue;
  197.             }
  198.             $selectPlaceValues[] = [
  199.                 'name' => $district->getName(),
  200.                 'url' => $district->getUrl()
  201.             ];
  202.         }
  203.         return $selectPlaceValues;
  204.     }
  205.     #[Route(
  206.         path: [
  207.             '/autobazary/{url}/kontakt',
  208.             '/autobazary/{url}/kontakty',
  209.         ], name'page_dealer_detail_redirect_contact'methods: ['GET'])]
  210.     public function dealerDetailRedirectContact(string $url): Response
  211.     {
  212.         return $this->redirectToRoute('page_dealer_detail', ['url' => $url], Response::HTTP_MOVED_PERMANENTLY);
  213.     }
  214.     #[Route('/autobazary/{url}/vozidla'name'redirect_autobazary_vozidla'methods: ['GET'], priority10)]
  215.     public function redirectAutobazaryVozidla(string $url): Response
  216.     {
  217.         return $this->redirect(sprintf("/autobazar/%s/vozidla"$url), Response::HTTP_MOVED_PERMANENTLY);
  218.     }
  219.     #[Route(
  220.         path: [
  221.             '/autobazary/{url}/{urlManufacturer}',
  222.         ], name'page_dealer_detail_redirect'methods: ['GET'])]
  223.     public function dealerDetailRedirect(string $urlstring $urlManufacturer): Response
  224.     {
  225.         //http://127.0.0.1:8000/autobazary/ald-automotive/audi
  226.         $url '/autobazar/' $url '/vozidla/' $urlManufacturer;
  227.         return $this->redirect($urlResponse::HTTP_MOVED_PERMANENTLY);
  228.     }
  229.     #[Route('/autobazar/{url}'name'page_dealer_detail'methods: ['GET'])]
  230.     public function dealerDetail(string                   $url,
  231.                                  VehicleRepository        $vehicleRepository,
  232.                                  DealerOpenHourRepository $dealerOpenHourRepository,
  233.                                  DealerRepository         $dealerRepository,
  234.                                  VehicleTipRepository     $vehicleTipRepository
  235.     ): Response
  236.     {
  237.         $dealer $dealerRepository->findOneBy(['url' => $url]);
  238.         if (!$dealer) {
  239.             throw $this->createNotFoundException('The dealer does not exist');
  240.         }
  241.         $date = new DateTime('now', new DateTimeZone('Europe/Prague'));
  242.         $openTime $dealerOpenHourRepository->findBy(['dealer' => $dealer'summer' => $date->format('I')]);
  243.         $hasVehicleImport $dealer->getNameImportVehicle() !== null && !empty($dealer->getIdImportVehicle());
  244.         if (!$hasVehicleImport) {
  245.             $vehicles = [];
  246.             $vehicleTips $vehicleTipRepository->findRandVisible(6);
  247.         } else {
  248.             $vehicles $vehicleRepository->findBy(['dealer' => $dealer'visible' => true], ['createAt' => 'DESC'], 5);
  249.             $vehicleTips = [];
  250.         }
  251.         $dealerType $dealer->isAuthSeller() ? 'autosalon' 'autobazar';
  252.         $seoTitle sprintf('%s %s %s | Autanet.cz'$dealer->getName(), $dealerType$dealer->getCity());
  253.         if (!$hasVehicleImport) {
  254.             $seoDescription sprintf('%s %s %s – profil prodejce vozidel s kontaktními údaji, mapou, odkazem na webové stránky a provozní dobou.',
  255.                 $dealer->getName(), $dealerType$dealer->getCity());
  256.         } else {
  257.             $seoDescription sprintf('%s %s %s - novinky z nabídky inzerce, kontakty, mapa, provozní doba.',
  258.                 $dealer->getName(), $dealerType$dealer->getCity());
  259.         }
  260.         return $this->render('homepage/detailDealer.html.twig', [
  261.             'dealer' => $dealer,
  262.             'openTime' => $openTime,
  263.             'vehicles' => $vehicles,
  264.             'vehicleTips' => $vehicleTips,
  265.             'hasVehicleImport' => $hasVehicleImport,
  266.             'isBasicDealer' => $dealer->isBasicAdvertising(),
  267.             'seoTitle' => $seoTitle,
  268.             'seoDescription' => $seoDescription,
  269.         ]);
  270.     }
  271.     #[Route('clanky/{urlKind}/{urlManufacturer}'name'page_blog_universal'requirements: ['urlManufacturer' => '[a-z0-9\-]+'], methods: ['GET'], priority1)]
  272.     public function blogUniversal(string                        $urlKind,
  273.                                   string                        $urlManufacturer,
  274.                                   BlogKindRepository            $blogKindRepository,
  275.                                   BlogRepository                $blogRepository,
  276.                                   VehicleManufacturerRepository $manufacturerRepository,
  277.                                   VehicleModelRepository        $modelRepository,
  278.                                   Request                       $request,
  279.                                   PaginatorInterface            $paginator
  280.     ): Response
  281.     {
  282.         $blogKind $blogKindRepository->findOneBy(['url' => $urlKind]);
  283.         if (!$blogKind) {
  284.             throw $this->createNotFoundException('The blog kind does not exist');
  285.         }
  286.         if (str_contains($urlManufacturer'-')) {
  287.             [$manufacturerUrl$modelUrl] = $this->parseManufacturerAndModel($urlManufacturer$manufacturerRepository$blogKindRepository);
  288.         } else {
  289.             $manufacturerUrl $urlManufacturer;
  290.             $modelUrl null;
  291.         }
  292.         $manufacturer $manufacturerUrl $manufacturerRepository->findOneBy(['url' => $manufacturerUrl]) : null;
  293.         $model = ($modelUrl && $manufacturer) ? $modelRepository->findOneBy(['url' => $modelUrl'vehicleManufacturer' => $manufacturer]) : null;
  294.         $isTestyAut $blogKind->getUrl() === 'testy-aut';
  295.         $baseParameters = ['visible' => '1''urlKind' => $urlKind];
  296.         $notFoundMessage null;
  297.         $activeManufacturer null;
  298.         $activeModel null;
  299.         if (!$isTestyAut || !$manufacturer) {
  300.             $pagination $paginator->paginate(
  301.                 $blogRepository->findQuery($baseParameters),
  302.                 $request->query->getInt('page'1), 20
  303.             );
  304.             if (!$manufacturer) {
  305.                 $notFoundMessage "Testy pro požadovanou značku nebyly nalezeny. Zobrazujeme všechny testy aut.";
  306.             }
  307.         } else {
  308.             $manufacturerParameters array_merge($baseParameters, ['manufacturer' => $manufacturer->getId()]);
  309.             $manufacturerResults $blogRepository->findQueryWithManufacturer($manufacturerParameters);
  310.             if (empty($manufacturerResults)) {
  311.                 $pagination $paginator->paginate(
  312.                     $blogRepository->findQuery($baseParameters),
  313.                     $request->query->getInt('page'1), 20
  314.                 );
  315.                 $notFoundMessage "Testy pro požadovanou značku nebyly nalezeny. Zobrazujeme všechny testy aut.";
  316.             } else {
  317.                 $activeManufacturer $manufacturer;
  318.                 $paginateResults $manufacturerResults;
  319.                 $notFoundMessage $modelUrl "Testy pro hledaný model nebyly nalezeny. Zobrazujeme všechny testy této značky." null;
  320.                 if ($model) {
  321.                     $modelParameters array_merge($manufacturerParameters, ['model' => $model->getId()]);
  322.                     $modelResults $blogRepository->findQueryWithManufacturerAndModel($modelParameters);
  323.                     if (!empty($modelResults)) {
  324.                         $activeModel $model;
  325.                         $paginateResults $modelResults;
  326.                         $notFoundMessage null;
  327.                     }
  328.                 }
  329.                 $pagination $paginator->paginate($paginateResults$request->query->getInt('page'1), 20);
  330.             }
  331.         }
  332.         $manufacturers $manufacturerRepository->findByBlogKind($blogKind);
  333.         $models $manufacturer $modelRepository->findByManufacturerAndBlogKind($manufacturer$blogKind) : [];
  334.         $data = [
  335.             'blogs' => $pagination,
  336.             'blogKind' => $blogKind,
  337.             'manufacturers' => $manufacturers,
  338.             'models' => $models,
  339.             'activeManufacturer' => $activeManufacturer,
  340.             'activeModel' => $activeModel,
  341.             'notFoundMessage' => $notFoundMessage,
  342.         ];
  343.         return $this->render('homepage/blog.html.twig'$data);
  344.     }
  345.     #[Route('clanky/{urlKind}'name'page_blog'methods: ['GET'], priority0)]
  346.     public function blog(string         $urlKindBlogKindRepository $blogKindRepository,
  347.                          BlogRepository $blogRepositoryVehicleManufacturerRepository $manufacturerRepository,
  348.                          Request        $requestPaginatorInterface $paginator): Response
  349.     {
  350.         if ($urlKind == 'vsechny-clanky') {
  351.             $parameters = [
  352.                 'visible' => '1',
  353.                 'urlKind' => '',
  354.             ];
  355.             $blogKind false;
  356.         } else {
  357.             $parameters = [
  358.                 'visible' => '1',
  359.                 'urlKind' => $urlKind,
  360.             ];
  361.             $blogKind $blogKindRepository->findOneBy(['url' => $urlKind]);
  362.             if (!$blogKind) {
  363.                 throw $this->createNotFoundException('The blog kind does not exist');
  364.             }
  365.         }
  366.         $pagination $paginator->paginate(
  367.             $blogRepository->findQuery($parameters), /* query NOT result */
  368.             $request->query->getInt('page'1), /*page number*/
  369.             20 /*limit per page*/
  370.         );
  371.         $manufacturers = [];
  372.         $models = [];
  373.         if ($blogKind && $blogKind->getUrl() === 'testy-aut') {
  374.             $manufacturers $manufacturerRepository->findByBlogKind($blogKind);
  375.         }
  376.         return $this->render('homepage/blog.html.twig', [
  377.             'blogs' => $pagination,
  378.             'blogKind' => $blogKind,
  379.             'manufacturers' => $manufacturers,
  380.             'models' => $models,
  381.             'activeManufacturer' => null,
  382.             'activeModel' => null,
  383.             'notFoundMessage' => null,
  384.         ]);
  385.     }
  386.     #[Route(
  387.         path: [
  388.             '/autobazar/{url}/vozidla',
  389.             '/autobazar/{url}/vozidla/{urlManufacturer}',
  390.             '/autobazar/{url}/vozidla/{urlManufacturer}/{urlModel}'
  391.         ]
  392.         , name'page_dealer_vehicle'defaults: ['urlManufacturer' => null'urlModel' => null], methods: ['GET'])]
  393.     public function dealerVehicles(string                        $url,
  394.                                    string|null                   $urlManufacturer,
  395.                                    string|null                   $urlModel,
  396.                                    Request                       $request,
  397.                                    PaginatorInterface            $paginator,
  398.                                    VehicleRepository             $vehicleRepository,
  399.                                    VehicleManufacturerRepository $manufacturerRepository,
  400.                                    VehicleModelRepository        $vehicleModelRepository,
  401.                                    DealerRepository              $dealerRepository
  402.     ): Response
  403.     {
  404.         $dealer $dealerRepository->findOneBy(['url' => $url]);
  405.         if (!$dealer) {
  406.             throw $this->createNotFoundException('The dealer does not exist');
  407.         }
  408.         $parameters = [
  409.             'visible' => '1',
  410.             'dealer' => (string)$dealer->getId(),
  411.         ];
  412.         $manufacturer null;
  413.         if ($urlManufacturer) {
  414.             $manufacturer $manufacturerRepository->findOneBy(['url' => $urlManufacturer]);
  415.             if (!$manufacturer) {
  416.                 throw $this->createNotFoundException('The manufacturer does not exist');
  417.             }
  418.             $manufacturerId $parameters['manufacturer'] = $manufacturer->getId();
  419.         }
  420.         $model null;
  421.         if ($urlModel) {
  422.             $model $vehicleModelRepository->findOneBy(['url' => $urlModel]);
  423.             if (!$model) {
  424.                 throw $this->createNotFoundException('The model does not exist');
  425.             }
  426.             $parameters['model'] = $model->getId();
  427.         }
  428.         $pagination $paginator->paginate(
  429.             $vehicleRepository->findQuery($parameters), /* query NOT result */
  430.             $request->query->getInt('page'1), /*page number*/
  431.             10 /*limit per page*/
  432.         );
  433.         $dealerType $dealer->isAuthSeller() ? 'autosalon' 'autobazar';
  434.         $vehicleCount $pagination->getTotalItemCount();
  435.         if ($manufacturer && $model) {
  436.             $seoTitle sprintf('%s %s - nabídka vozidel %s %s | Autanet.cz',
  437.                 $dealer->getName(), $dealer->getCity(), $manufacturer->getName(), $model->getName());
  438.             $seoDescription sprintf('Nabídka %d vozidel %s %s z %su %s %s. Vybírejte z nabídky vozidel značky %s %s a dalších modelů.',
  439.                 $vehicleCount$manufacturer->getName(), $model->getName(), $dealerType$dealer->getName(), $dealer->getCity(),
  440.                 $manufacturer->getName(), $model->getName());
  441.         } elseif ($manufacturer) {
  442.             $seoTitle sprintf('%s %s - nabídka vozidel %s | Autanet.cz',
  443.                 $dealer->getName(), $dealer->getCity(), $manufacturer->getName());
  444.             $seoDescription sprintf('Nabídka %d vozidel %s z %su %s %s. Vybírejte z nabídky vozidel značky %s a dalších.',
  445.                 $vehicleCount$manufacturer->getName(), $dealerType$dealer->getName(), $dealer->getCity(), $manufacturer->getName());
  446.         } else {
  447.             $seoTitle sprintf('%s %s - nabídka vozidel | Autanet.cz'$dealer->getName(), $dealer->getCity());
  448.             $topManufacturers $manufacturerRepository->findByDealerActive($dealer);
  449.             $manufacturerNames array_slice(array_map(fn($m) => $m->getName(), $topManufacturers), 05);
  450.             $manufacturerList implode(', '$manufacturerNames);
  451.             $seoDescription sprintf('Nabídka %d vozidel z %su %s %s. Vybírejte z vozidel značek %s a dalších.',
  452.                 $vehicleCount$dealerType$dealer->getName(), $dealer->getCity(), $manufacturerList);
  453.         }
  454.         if ($manufacturer && $model) {
  455.             $seoH1 sprintf('Nabídka vozidel %s %s %s'$manufacturer->getName(), $model->getName(), $dealer->getName());
  456.         } elseif ($manufacturer) {
  457.             $seoH1 sprintf('Nabídka vozidel %s %s'$manufacturer->getName(), $dealer->getName());
  458.         } else {
  459.             $seoH1 sprintf('Nabídka vozidel %s'$dealer->getName());
  460.         }
  461.         return $this->render('homepage/vehicleDealer.html.twig', [
  462.             'dealer' => $dealer,
  463.             'activeManufacturer' => $manufacturer,
  464.             'activeModel' => $model,
  465.             'manufacturer' => $manufacturerRepository->findByDealerActive($dealer),
  466.             'model' => $vehicleModelRepository->findByDealerActive($dealer$manufacturer?->getId()),
  467.             'vehicles' => $pagination,
  468.             'seoTitle' => $seoTitle,
  469.             'seoDescription' => $seoDescription,
  470.             'seoH1' => $seoH1,
  471.         ]);
  472.     }
  473.     #[Route(path: [
  474.         '/nova/{urlKind}',
  475.         '/nova/{urlKind}/{urlManufacturer}',
  476.         '/nova/{urlKind}/{urlManufacturer}/{urlModel}',
  477.     ], name'app_search_redirect'defaults: ['urlManufacturer' => null'urlModel' => null], methods: ['GET'])]
  478.     public function redirectSearch(string $urlKindstring|null $urlManufacturerstring|null $urlModel): Response
  479.     {
  480.         if ($urlManufacturer and $urlModel) {
  481.             return $this->redirectToRoute('page_vehicle_search'compact('urlKind''urlManufacturer''urlModel'), Response::HTTP_MOVED_PERMANENTLY);
  482.         } elseif ($urlManufacturer) {
  483.             return $this->redirectToRoute('page_vehicle_search'compact('urlKind''urlManufacturer'), Response::HTTP_MOVED_PERMANENTLY);
  484.         } else {
  485.             return $this->redirectToRoute('page_vehicle_search'compact('urlKind'), Response::HTTP_MOVED_PERMANENTLY);
  486.         }
  487.     }
  488.     #[Route(path: [
  489.         '/{urlKind}',
  490.         '/{urlKind}/{urlManufacturer}',
  491.         '/{urlKind}/{urlManufacturer}/{urlModel}',
  492.     ], name'page_vehicle_search'defaults: ['urlManufacturer' => null'urlModel' => null], methods: ['GET'])]
  493.     public function vehicleSearch(string                        $urlKindstring|null $urlManufacturerstring|null $urlModelRequest $requestPaginatorInterface $paginator,
  494.                                   VehicleRepository             $vehicleRepository,
  495.                                   VehicleKindRepository         $vehicleKindRepository,
  496.                                   VehicleCategoryRepository     $vehicleCategoryRepository,
  497.                                   VehicleManufacturerRepository $manufacturerRepository,
  498.                                   VehicleModelRepository        $vehicleModelRepository,
  499.                                   VehicleBodyRepository         $vehicleBodyRepository,
  500.                                   VehicleFuelRepository         $vehicleFuelRepository,
  501.                                   RegionRepository              $regionRepository,
  502.                                   DistrictRepository            $districtRepository,
  503.                                   VehiclePartKindRepository     $vehiclePartKindRepository): Response
  504.     {
  505.         $parameters = [
  506.             'visible' => '1',
  507.         ];
  508.         $vehicleKind null;
  509.         $models = [];
  510.         $vehicleCategory null;
  511.         $manufacturer null;
  512.         $mileageValues = [
  513.             '0-10000' => 'do 10000 km',
  514.             '10000-30000' => '10 000 - 30 000 km',
  515.             '30000-50000' => '30 000 - 50 000 km',
  516.             '50000-100000' => '50 000 - 100 000 km',
  517.             '100000-150000' => '100 000 - 150 000 km',
  518.             '150000-200000' => '150 000 - 200 000 km',
  519.             '200000-300000' => '200 000 - 300 000 km',
  520.             '300000-10000000' => '300 000 a více km',
  521.         ];
  522.         $powerValues = [
  523.             '0-40' => 'do 40 kW',
  524.             '40-60' => '40 - 60 kW',
  525.             '60-80' => '60 - 80 kW',
  526.             '80-100' => '80 - 100 kW',
  527.             '100-125' => '100 - 125 kW',
  528.             '125-150' => '120 - 150 kW',
  529.             '150-200' => '150 - 200 kW',
  530.             '200-300' => '200 - 300 kW',
  531.             '300-2000' => 'nad 300 kW',
  532.         ];
  533.         $vehiclePartKindValues = [];
  534.         if ($urlKind) {
  535.             if ($urlKind == 'obytna-vozidla') {
  536.                 $powerValues = [
  537.                     '0-60' => 'do 60 kW',
  538.                     '60-80' => '60 - 80 kW',
  539.                     '80-100' => '80 - 100 kW',
  540.                     '100-125' => '100 - 125 kW',
  541.                     '125-150' => '125 - 150 kW',
  542.                     '150-200' => '150 - 200 kW',
  543.                     '200-300' => '200 - 300 kW',
  544.                     '300-2000' => 'nad 300 kW',
  545.                 ];
  546.             }
  547.             if ($urlKind == 'nakladni-vozidla') {
  548.                 $powerValues = [
  549.                     '0-100' => 'do 100 kW',
  550.                     '100-150' => '100 - 150 kW',
  551.                     '150-200' => '150 - 200 kW',
  552.                     '200-300' => '200 - 300 kW',
  553.                     '300-400' => '300 - 400 kW',
  554.                     '400-2000' => 'nad 400 kW',
  555.                 ];
  556.             }
  557.             if ($urlKind == 'motorky-skutry') {
  558.                 $mileageValues = [
  559.                     '0-10000' => 'do 10000 km',
  560.                     '10000-30000' => '10 000 - 30 000 km',
  561.                     '30000-50000' => '30 000 - 50 000 km',
  562.                     '50000-100000' => '50 000 - 100 000 km',
  563.                     '100000-150000' => '100 000 - 150 000 km',
  564.                     '150000-1000000' => '150 000 a více km',
  565.                 ];
  566.                 $powerValues = [
  567.                     '0-25' => 'do 25 kW',
  568.                     '25-50' => '25 - 50 kW',
  569.                     '50-75' => '50 - 75 kW',
  570.                     '75-100' => '75 - 100 kW',
  571.                     '100-125' => '100 - 125 kW',
  572.                     '125-150' => '125 - 150 kW',
  573.                     '150-2000' => 'nad 150 kW',
  574.                 ];
  575.             }
  576.             if ($urlKind == 'nahradni-dily' || $urlKind == 'prislusenstvi') {
  577.                 $vehicleCategory $vehicleCategoryRepository->findOneBy(['url' => $urlKind]);
  578.                 if ($vehicleCategory) {
  579.                     $parameters['category'] = $vehicleCategory->getId();
  580.                 } else {
  581.                     return $this->forward('App\Controller\HomepageController::blogDetail', ['url' => $urlKind,]);
  582.                 }
  583.                 $vehiclePartKindValues $vehiclePartKindRepository->findActiveCategory($vehicleCategory);
  584.             } else {
  585.                 $vehicleKind $vehicleKindRepository->findOneBy(['url' => $urlKind]);
  586.                 if ($vehicleKind) {
  587.                     $parameters['kind'] = $vehicleKind->getId();
  588.                 } else {
  589.                     return $this->forward('App\Controller\HomepageController::blogDetail', ['url' => $urlKind,]);
  590.                 }
  591.             }
  592.         }
  593.         if ($urlManufacturer) {
  594.             $manufacturer $manufacturerRepository->findOneBy(['url' => $urlManufacturer]);
  595.             if ($manufacturer) {
  596.                 $parameters['manufacturer'] = $manufacturer->getId();
  597.                 $models $vehicleModelRepository->findActive($manufacturer$vehicleCategory$vehicleKind);
  598.             } else {
  599.                 return $this->forward('App\Controller\HomepageController::page', ['url' => $urlKind,]);
  600.             }
  601.         }
  602.         $activeModel null;
  603.         if ($urlModel) {
  604.             $activeModel $vehicleModelRepository->findOneBy(['url' => $urlModel]);
  605.             if ($activeModel) {
  606.                 $parameters['model'] = $activeModel->getId();
  607.             } else {
  608.                 return $this->forward('App\Controller\HomepageController::page', ['url' => $urlKind,]);
  609.             }
  610.         }
  611.         $urlPlace $request->get('place');
  612.         if ($urlPlace) {
  613.             if ('praha' === $urlPlace) {
  614.                 $urlPlace 'hlavni-mesto-praha';
  615.             }
  616.             if ('ostrava' === $urlPlace) {
  617.                 $urlPlace 'ostrava-mesto';
  618.             }
  619.             if ('brno' === $urlPlace) {
  620.                 $urlPlace = ['brno-mesto''brno-venkov'];
  621.             }
  622.             if ('plzen' === $urlPlace) {
  623.                 $urlPlace = ['plzen-mesto''plzen-jih''plzen-sever'];
  624.             }
  625.             if (!is_array($urlPlace) && $regionRepository->findOneBy(['url' => $urlPlace])) {
  626.                 $parameters['region'] = $urlPlace;
  627.             } else {
  628.                 $parameters['district'] = $urlPlace;
  629.             }
  630.         }
  631.         if ($request->query->all()) {
  632.             $parameters += $request->query->all();
  633.         }
  634.         $pagination $paginator->paginate(
  635.             $vehicleRepository->findQuery($parameters), /* query NOT result */
  636.             $request->query->getInt('page'1), /*page number*/
  637.             20 /*limit per page*/
  638.         );
  639.         return $this->render('homepage/search.html.twig', [
  640.             'vehicles' => $pagination,
  641.             'activeKind' => $vehicleKind,
  642.             'baseUrl' => $vehicleCategory $vehicleCategory->getUrl() : $vehicleKind->getUrl(),
  643.             'activeCategory' => $vehicleCategory,
  644.             'activeManufacturer' => isset($parameters['manufacturer']) ? $manufacturerRepository->find($parameters['manufacturer']) : null,
  645.             'activeModel' => $activeModel,
  646.             'categories' => $vehicleCategoryRepository->findActive(),
  647.             'manufacturers' => $manufacturerRepository->findActive($vehicleKind$vehicleCategory),
  648.             'models' => $models,
  649.             'bodies' => $vehicleBodyRepository->findActive($vehicleKind$manufacturer$activeModel),
  650.             'fuels' => $vehicleFuelRepository->findActive(),
  651.             'gearbox' => $vehicleRepository->findActiveGearBox(),
  652.             'selectPlaceValues' => $this->getSelectPlaceValues($regionRepository$districtRepository),
  653.             'vehicleKind' => $vehicleKind,
  654.             'mileageValues' => $mileageValues,
  655.             'powerValues' => $powerValues,
  656.             'vehiclePartKindValues' => $vehiclePartKindValues
  657.         ]);
  658.     }
  659.     #[Route('/detail/{seoSlug}-{id}'name'page_vehicle_detail_seo'methods: ['GET'], requirements: ['seoSlug' => '.+''id' => '[0-9]+'], priority10)]
  660.     public function vehicleDetailSeo(string            $seoSlugint $idVehicleRepository $vehicleRepository,
  661.                                      VehicleSeoService $vehicleSeoServiceDealerOpenHourRepository $dealerOpenHourRepository): Response
  662.     {
  663.         $vehicle $vehicleRepository->find($id);
  664.         if (!$vehicle) {
  665.             throw $this->createNotFoundException('Vehicle not found');
  666.         }
  667.         if (!$vehicle->getSeoSlug()) {
  668.             $vehicleSeoService->generateSeoData($vehicle);
  669.         }
  670.         if ($vehicle->getSeoSlug() && $seoSlug !== $vehicle->getSeoSlug()) {
  671.             return $this->redirectToRoute('page_vehicle_detail_seo', [
  672.                 'seoSlug' => $vehicle->getSeoSlug(),
  673.                 'id' => $id
  674.             ], 301);
  675.         }
  676.         if (!$vehicle->isVisible()) {
  677.             $response $this->render('homepage/detailVehicleDisable.html.twig'compact('vehicle'));
  678.             $response->setStatusCode(404);
  679.             return $response;
  680.         }
  681.         $date = new DateTime('now', new DateTimeZone('Europe/Prague'));
  682.         $openTime $dealerOpenHourRepository->findBy(['dealer' => $vehicle->getDealer(), 'summer' => $date->format('I')]);
  683.         $vehicleOthers $vehicleRepository->findOtherDealerBody($vehicle4);
  684.         return $this->render('homepage/detailVehicle.html.twig'compact('vehicle''openTime''vehicleOthers'));
  685.     }
  686.     #[Route(
  687.         [
  688.             '/detail/{urlManufacturer}/{urlModel}/{id}',
  689.         ], name'page_vehicle_detail'defaults: ['urlModel' => null], methods: ['GET'])]
  690.     public function vehicleDetail(string                        $urlManufacturerstring $urlModelint $idVehicleRepository $vehicleRepository,
  691.                                   VehicleManufacturerRepository $vehicleManufacturerRepository,
  692.                                   VehicleModelRepository        $vehicleModelRepositoryDealerOpenHourRepository $dealerOpenHourRepository,
  693.                                   VehicleSeoService             $vehicleSeoService): Response
  694.     {
  695.         if ($urlModel) {
  696.             $vehicleModel $vehicleModelRepository->findOneBy(['url' => $urlModel]);
  697.         }
  698.         $manufacturer $vehicleManufacturerRepository->findOneBy(['url' => $urlManufacturer]);
  699.         if ($urlModel) {
  700.             $vehicle $vehicleRepository->findOneBy(['id' => $id'visible' => true'manufacturer' => $manufacturer'model' => $vehicleModel]);
  701.         } else {
  702.             $vehicle $vehicleRepository->findOneBy(['id' => $id'visible' => true'manufacturer' => $manufacturer]);
  703.         }
  704.         if ($urlModel) {
  705.             $disableVehicle $vehicleRepository->findOneBy(['id' => $id'visible' => false'manufacturer' => $manufacturer'model' => $vehicleModel]);
  706.         } else {
  707.             $disableVehicle $vehicleRepository->findOneBy(['id' => $id'visible' => false'manufacturer' => $manufacturer]);
  708.         }
  709.         if ($disableVehicle) {
  710.             $response $this->render('homepage/detailVehicleDisable.html.twig', [
  711.                 'vehicle' => $disableVehicle,
  712.             ]);
  713.             $response->setStatusCode(404);
  714.             return $response;
  715.         }
  716.         if (!$vehicle) {
  717.             throw $this->createNotFoundException('The vehicle does not exist');
  718.         }
  719.         if (!$vehicle->getSeoSlug()) {
  720.             $vehicleSeoService->generateSeoData($vehicle);
  721.         }
  722.         if ($vehicleSeoService->shouldRedirectToSeo($vehicle) && $vehicle->getSeoSlug()) {
  723.             return $this->redirectToRoute('page_vehicle_detail_seo', [
  724.                 'seoSlug' => $vehicle->getSeoSlug(),
  725.                 'id' => $id
  726.             ], 301);
  727.         }
  728.         $date = new DateTime('now', new DateTimeZone('Europe/Prague'));
  729.         $openTime $dealerOpenHourRepository->findBy(['dealer' => $vehicle->getDealer(), 'summer' => $date->format('I')]);
  730.         $vehicleOthers $vehicleRepository->findOtherDealerBody($vehicle4);
  731.         return $this->render('homepage/detailVehicle.html.twig', [
  732.             'vehicle' => $vehicle,
  733.             'openTime' => $openTime,
  734.             'vehicleOthers' => $vehicleOthers,
  735.         ]);
  736.     }
  737.     #[Route('/{url}'name'page'methods: ['GET'], priority: -2)]
  738.     public function page(string $urlPageRepository $pageRepository): Response
  739.     {
  740.         $page $pageRepository->findPage($url);
  741.         if (!$page) {
  742.             throw $this->createNotFoundException('Page no exist');
  743.         }
  744.         return $this->render('homepage/page.html.twig', [
  745.             'page' => $page,
  746.         ]);
  747.     }
  748.     #[Route('/{url}'name'page_blog_detail'methods: ['GET'], priority: -1)]
  749.     public function blogDetail(string $urlBlogRepository $blogRepositoryVehicleRepository $vehicleRepository): Response
  750.     {
  751.         $blog $blogRepository->findOneVisibleUrl($url);
  752.         if (!$blog) {
  753.             return $this->forward('App\Controller\HomepageController::page', [
  754.                 'url' => $url,
  755.             ]);
  756.         }
  757.         $vehicles $vehicleRepository->findRandActive($blog->getVehicleManufacturer(), $blog->getVehicleModel(), 3);
  758.         if (!$vehicles) {
  759.             $vehicles $vehicleRepository->findRandActive($blog->getVehicleManufacturer(), null3);
  760.             $isVehicleModel false;
  761.         } else {
  762.             $isVehicleModel true;
  763.         }
  764.         $blogOtherManufacturer $blogRepository->findRandActive($blog->getVehicleManufacturer(), $blog->getVehicleModel(), $blog->getId(), 3);
  765.         return $this->render('homepage/blogDetail.html.twig', [
  766.             'blog' => $blog,
  767.             'vehicles' => $vehicles,
  768.             'isVehicleModel' => $isVehicleModel,
  769.             'blogOtherManufacturer' => $blogOtherManufacturer,
  770.             'blogNew' => $blogRepository->findNewActive(3)
  771.         ]);
  772.     }
  773.     #[Route('/'name'app_homepage'methods: ['GET'])]
  774.     public function index(BlogRepository                $blogRepository,
  775.                           VehicleTipRepository          $vehicleTipRepository,
  776.                           VehicleManufacturerRepository $manufacturerRepository,
  777.                           PartnerRepository             $partnerRepository): Response
  778.     {
  779.         $manufacturers = [];
  780.         foreach ($manufacturerRepository->findActive() as $manufacturer) {
  781.             $manufacturers[] = [
  782.                 'id' => $manufacturer->getId(),
  783.                 'name' => $manufacturer->getName(),
  784.                 'url' => $manufacturer->getUrl(),
  785.             ];
  786.         }
  787.         return $this->render('homepage/index.html.twig', [
  788.             'partners' => $this->getPartners($partnerRepository),
  789.             'blogs' => $blogRepository->findHomepage(),
  790.             'vehicleTip' => $vehicleTipRepository->findRandVisible(),
  791.             'manufacturers' => $manufacturers,
  792.         ]);
  793.     }
  794.     /**
  795.      * @return array<int, array<string, string>>
  796.      */
  797.     private function getPartners(PartnerRepository $partnerRepository): array
  798.     {
  799.         $partners $partnerRepository->findAll();
  800.         $partnersData = [];
  801.         foreach ($partners as $partner) {
  802.             $partnersData[] = [
  803.                 $partner->getUrl(),
  804.                 'img/partner/' $partner->getLogo()
  805.             ];
  806.         }
  807.         shuffle($partnersData);
  808.         return $partnersData;
  809.     }
  810.     /**
  811.      * Rozdělí URL typu "bmw-rada-3" na výrobce "bmw" a model "rada-3"
  812.      * Použije přístup: najít všechny možné kandidáty na výrobce a vybrat nejdelší shodu
  813.      */
  814.     private function parseManufacturerAndModel(string $manufacturerAndModelVehicleManufacturerRepository $manufacturerRepositoryBlogKindRepository $blogKindRepository): array
  815.     {
  816.         $testyAutKind $blogKindRepository->findOneBy(['url' => 'testy-aut']);
  817.         if (!$testyAutKind) {
  818.             return [nullnull];
  819.         }
  820.         $manufacturers $manufacturerRepository->findByBlogKind($testyAutKind);
  821.         $manufacturerUrls array_map(fn($m) => $m->getUrl(), $manufacturers);
  822.         $candidates = [];
  823.         $urlParts explode('-'$manufacturerAndModel);
  824.         $countParts count($urlParts);
  825.         for ($i 1$i <= $countParts$i++) {
  826.             $candidateManufacturer implode('-'array_slice($urlParts0$i));
  827.             if (in_array($candidateManufacturer$manufacturerUrls)) {
  828.                 $candidates[] = $candidateManufacturer;
  829.             }
  830.         }
  831.         if (empty($candidates)) {
  832.             return [nullnull];
  833.         }
  834.         usort($candidates, fn($a$b) => strlen($b) <=> strlen($a));
  835.         $manufacturerUrl $candidates[0];
  836.         if ($manufacturerUrl === $manufacturerAndModel) {
  837.             return [$manufacturerUrlnull];
  838.         }
  839.         $modelUrl substr($manufacturerAndModelstrlen($manufacturerUrl) + 1);
  840.         return [$manufacturerUrl$modelUrl];
  841.     }
  842. }