src/DcSiteBundle/Controller/BaseDcController.php line 270

Open in your IDE?
  1. <?php
  2. namespace DcSiteBundle\Controller;
  3. use CoreBundle\Component\CoreFormFactory;
  4. use CoreBundle\Component\FormManager;
  5. use CoreBundle\Controller\ViDiController;
  6. use CoreBundle\Entity\Dealer;
  7. use CoreBundle\Entity\Model;
  8. use CoreBundle\Factory\Vehicle as VehicleFactory;
  9. use CoreBundle\Model\Api\OnlineService\ApiServer1C;
  10. use CoreBundle\Model\Vehicles\AbstractVehicle;
  11. use CoreBundle\Model\Vehicles\InStockVehicle;
  12. use CoreBundle\Model\Vehicles\Repository;
  13. use CoreBundle\Model\Vehicles\Vehicle;
  14. use CoreBundle\Services\MediaExtensionVidi;
  15. use DateTime;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Exception;
  18. use MyBundle\Entity\Basket;
  19. use PortalBundle\Model\SeoMetaTag;
  20. use Symfony\Component\Filesystem\Filesystem;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\HttpFoundation\RequestStack;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  26. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  27. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  28. use Symfony\Component\Routing\RouterInterface;
  29. use Symfony\Component\String\UnicodeString;
  30. use Twig\Environment;
  31. class BaseDcController extends ViDiController
  32. {
  33.     protected SeoMetaTag $seoMetaTag;
  34.     protected RequestStack $requestStack;
  35.     protected RouterInterface $router;
  36.     protected FormManager $formManager;
  37.     protected EntityManagerInterface $em;
  38.     protected ApiServer1C $apiServer1C;
  39.     protected SessionInterface $session;
  40.     protected Filesystem $filesystem;
  41.     protected MediaExtensionVidi $mediaExtensionVidi;
  42.     protected Repository $vehicleRepository;
  43.     protected VehicleFactory $vehicleFactory;
  44.     protected Environment $twig;
  45.     public function __construct(CoreFormFactory    $coreFormFactorySeoMetaTag $seoMetaTagRequestStack $requestStack,
  46.                                 RouterInterface    $routerFormManager $formManagerEntityManagerInterface $em,
  47.                                 ApiServer1C        $apiServer1CSessionInterface $sessionFilesystem $filesystem,
  48.                                 MediaExtensionVidi $mediaExtensionVidiRepository $vehicleRepository,
  49.                                 VehicleFactory     $vehicleFactoryEnvironment $twig)
  50.     {
  51.         parent::__construct($coreFormFactory);
  52.         $this->seoMetaTag $seoMetaTag;
  53.         $this->router $router;
  54.         $this->formManager $formManager;
  55.         $this->em $em;
  56.         $this->apiServer1C $apiServer1C;
  57.         $this->session $session;
  58.         $this->filesystem $filesystem;
  59.         $this->mediaExtensionVidi $mediaExtensionVidi;
  60.         $this->vehicleRepository $vehicleRepository;
  61.         $this->vehicleFactory $vehicleFactory;
  62.         $this->twig $twig;
  63.         $this->requestStack $requestStack;
  64.     }
  65.     const DEALER_CITY_ID 3;
  66.     /**
  67.      * @var array
  68.      */
  69.     private static $dealers = [];
  70.     private $js = [];
  71.     private $baseJs = [];
  72.     private $jsParams = [];
  73.     protected function sendSmsLead(Request $request): JsonResponse
  74.     {
  75.         $formName '';
  76.         $formPhone '';
  77.         $formData = [
  78.             'vin' => '''visit_date' => '''model' => '''brand' => '''year' => '''data' => []
  79.         ];
  80.         try {
  81.             if (empty($request->get('vin'))) {
  82.                 throw new Exception("Не вказано 'vin'");
  83.             }
  84.             if (empty($request->get('visitDate'))) {
  85.                 throw new Exception("Не вказано 'visitDate'");
  86.             }
  87.             $formData['vin'] = $request->get('vin');
  88.             $formData['visit_date'] = str_replace('%''-'$request->get('visitDate'));
  89.             $arr $this->apiServer1C->getHistory($formData['vin']);
  90.             if (empty($arr)) {
  91.                 throw new Exception("Не знайдено '{$formData['vin']}'");
  92.             }
  93.             if (!empty($arr['ModelID'])) {
  94.                 /**
  95.                  * @var $model Model
  96.                  */
  97.                 $model $this->em
  98.                     ->getRepository(Model::class)
  99.                     ->findOneBy(['uid_1c' => $arr['ModelID']]);
  100.                 if (!empty($model)) {
  101.                     $formData['model'] = $model->getTitle();
  102.                     $formData['brand'] = $model->getBrand()->getName();
  103.                 }
  104.             }
  105.             if (!empty($arr['LastOwner'])) {
  106.                 $formName $arr['LastOwner'];
  107.             }
  108.             if (!empty($arr['Phone'])) {
  109.                 $formPhone $arr['Phone'];
  110.             }
  111.             if (!empty($arr['Year'])) {
  112.                 $formData['year'] = $arr['Year'];
  113.             }
  114.             if (!empty($arr['data'])) {
  115.                 $formData['data'] = $arr['data'];
  116.             }
  117.             $this->formManager->saveSmsLeadForm(
  118.                 $request,
  119.                 $this->getDealer(),
  120.                 $formName,
  121.                 $formPhone,
  122.                 $formData
  123.             );
  124.             return $this->success();
  125.         } catch (Exception $e) {
  126.             return $this->error($e);
  127.         }
  128.     }
  129.     protected function checkSend(Request $request): bool
  130.     {
  131.         $vin $request->get('vin');
  132.         $visitDate str_replace('%''-'$request->get('visitDate'));
  133.         $toCheck md5($vin $visitDate);
  134.         $inSes $this->session->get('nselectcheck');
  135.         $inSes is_array($inSes) ? $inSes : [];
  136.         if (!in_array($toCheck$inSes)) {
  137.             $inSes[] = $toCheck;
  138.             $this->session->set('nselectcheck'$inSes);
  139.             return false;
  140.         } else {
  141.             return true;
  142.         }
  143.     }
  144.     public function getDealer(): Dealer
  145.     {
  146.         $request $this->requestStack->getCurrentRequest();
  147.         $host $request->getHost();
  148.         if (!isset(self::$dealers[md5($host)])) {
  149.             $dealerId $request->get('dealerId');
  150.             if ($host == 'vidi.ua' && !is_null($dealerId)) {
  151.                 $findDealer = ['id' => $request->get('dealerId')];
  152.             } else {
  153.                 $host $this->isDealerShop($host);
  154.                 $findDealer = ['domain' => $host];
  155.             }
  156.             $Dealer $this->em->getRepository(Dealer::class)->findOneBy($findDealer);
  157.             if (!$Dealer) {
  158.                 throw new NotFoundHttpException();
  159.             }
  160.             self::$dealers[md5($host)] = $Dealer;
  161.         }
  162.         return self::$dealers[md5($host)];
  163.     }
  164.     private function isDealerShop($host)
  165.     {
  166.         return str_replace("shop."""$host);
  167.     }
  168.     protected function webpUpdate(Request $request$url$manager)
  169.     {
  170.         $userAgent $request->server->get('HTTP_USER_AGENT');
  171.         preg_match("/(MSIE|Opera|Firefox|Chrome|Version)(?:\/| )([0-9.]+)/"$userAgent$browser_info);
  172.         $browser $browser_info[1] ?? false;
  173.         if (!$browser) {
  174.             return $url;
  175.         }
  176.         if ($browser == 'Version' || $browser == 'MSIE') {
  177.             return $url;
  178.         }
  179.         $basePath $this->getParameter('kernel.project_dir') . '/public';
  180.         $path $basePath $url '.webp';
  181.         if (file_exists($path)) {
  182.             return $manager->getUrl($url '.webp');
  183.         }
  184.         $im = @imagecreatefrompng($basePath $url);
  185.         if (!$im) {
  186.             $im = @imagecreatefromjpeg($basePath $url);
  187.         }
  188.         if ($im) {
  189.             $newUrl $url '.webp';
  190.             if (imagewebp($im$path)) {
  191.                 imagedestroy($im);
  192.                 return $manager->getUrl($newUrl);
  193.             } else {
  194.                 imagedestroy($im);
  195.                 return $manager->getUrl($url);
  196.             }
  197.         }
  198.         return $url;
  199.     }
  200.     protected function baseDcRender($view, array $parameters = [], Response $response null): ?Response
  201.     {
  202.         $request $this->requestStack->getCurrentRequest();
  203.         $dealer $this->getDealer();
  204.         $seoMeta $this->seoMetaTag->getSeoMeta($request);
  205.         $subdomain explode('.'$request->server->get('HTTP_HOST'))[0];
  206.         $basketCount = [];
  207.         if ($this->getUser()) {
  208.             $basketCount $this->em->getRepository(Basket::class)->getBasketCountByDealerUser($this->getDealer(), $this->getUser());
  209.         } else {
  210.             $guestBasket $this->session->get('guest_basket', []);
  211.             if ($guestBasket && isset($guestBasket[$this->getDealer()->getId()])) {
  212.                 $basket $guestBasket[$this->getDealer()->getId()];
  213.                 $basketCount['count'] = 0;
  214.                 foreach ($basket as $accessory) {
  215.                     $basketCount['count'] += intval($accessory['count']);
  216.                 }
  217.             }
  218.         }
  219.         $basketCount = ($basketCount) ? $basketCount['count'] : 0;
  220.         $isSubdomainShop $subdomain === "shop";
  221.         $utmData $this->getUtmData();
  222.         $parameters array_merge($parameters, [
  223.             'dealer' => $this->getDealer(),
  224.             'basketCount' => $basketCount,
  225.             'dealerCityNihgtBooking' => self::DEALER_CITY_ID,
  226.             'backLoginUrl' => $request->getUri(),
  227.             'seoMeta' => $seoMeta,
  228.             'isSubdomainShop' => $isSubdomainShop,
  229.             'currentYear' => (new DateTime('now'))->format('Y'),
  230.             'utmData' => $utmData,
  231.         ]);
  232.         $helpCrunchParams $this->getParameter('help_crunch_params')[$dealer->getUniqueId()] ?? null;
  233.         if ($helpCrunchParams) {
  234.             $parameters array_merge($parameters, ['helpCrunch' => $helpCrunchParams]);
  235.         }
  236.         $content $this->twig->render($view$parameters);
  237.         if (null === $response) {
  238.             $response = new Response();
  239.         }
  240.         return $response->setContent($content);
  241.     }
  242.     protected function getMpdfTempDir(): string
  243.     {
  244.         $newTempDir $this->getParameter('file_directory_mpdf');
  245.         if (!$this->filesystem->exists($newTempDir)) {
  246.             $this->filesystem-- > mkdir($newTempDir0777);
  247.         }
  248.         return $newTempDir;
  249.     }
  250.     public function getCarStructuredDataCarInStock(Request $requestInStockVehicle $item): bool|string
  251.     {
  252.         $twig $this->mediaExtensionVidi;
  253.         $router $this->router;
  254.         $routerCurrent $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  255.         $routerCurrentParams = [
  256.             'car' => $item->getUrl(),
  257.             'url' => $item->getUrl(),
  258.             'category' => $item->getCategory()->getUrl()
  259.         ];
  260.         if ($routerCurrent == 'suzuki_card_moto') {
  261.             $routerCurrentParams = [
  262.                 'moto' => $item->getUrl()
  263.             ];
  264.         }
  265.         $images = [];
  266.         $gallery $item->getGallery();
  267.         if (!empty($gallery)) {
  268.             $gallery $gallery->getGalleryItems();
  269.             if (!empty($gallery)) {
  270.                 $images $gallery->toArray();
  271.             }
  272.         }
  273.         $images array_reduce($images, function ($rows$row) use ($request$twig) {
  274.             $rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
  275.             return $rows;
  276.         }, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
  277.         $characteristics $item->getCharacterisaticsByGroup($request->getLocale());
  278.         $characteristicsSize $characteristics[1] ?? [];
  279.         $characteristicsSizeNumberOfDoors array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
  280.         $characteristicsSizeNumberOfDoors array_values($characteristicsSizeNumberOfDoors);
  281.         $characteristicsSizeVehicleSeatingCapacity array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
  282.         $characteristicsSizeVehicleSeatingCapacity array_values($characteristicsSizeVehicleSeatingCapacity);
  283.         switch ($item->getDriveUnitType()->getId()) {
  284.             case 13:
  285.                 $driveWheelConfiguration 'AllWheelDriveConfiguration'// Повний
  286.                 break;
  287.             case 3:
  288.                 $driveWheelConfiguration 'FrontWheelDriveConfiguration'// Передній
  289.                 break;
  290.             case 11:
  291.                 $driveWheelConfiguration 'RearWheelDriveConfiguration'// Задній
  292.                 break;
  293.             case 27:
  294.                 $driveWheelConfiguration 'FourWheelDriveConfiguration'// AWD
  295.                 break;
  296.             default:
  297.                 $driveWheelConfiguration 'undefined';
  298.                 break;
  299.         }
  300.         return json_encode([
  301.             "@context" => "http://schema.org",
  302.             "@type" => "Car",
  303.             "name" => $item->getFullName(),
  304.             "vehicleIdentificationNumber" => $item->getVin() ?? '00000000000000000',
  305.             "image" => $images,
  306.             "url" => $router->generate($routerCurrent$routerCurrentParamsUrlGeneratorInterface::ABSOLUTE_URL),
  307.             "offers" => [
  308.                 "@type" => "Offer",
  309.                 "availability" => "http://schema.org/InStock",
  310.                 "price" => $item->price(),
  311.                 "priceCurrency" => "UAH"
  312.             ],
  313.             "itemCondition" => "https://schema.org/NewCondition",
  314.             "brand" => [
  315.                 "@type" => "Brand",
  316.                 "name" => $item->getBrand()->getName()
  317.             ],
  318.             "model" => $item->getModelName(),
  319.             "vehicleConfiguration" => $item->getEquipment()->getTitle(),
  320.             "vehicleModelDate" => $item->getYear(),
  321.             "mileageFromOdometer" => [
  322.                 "@type" => "QuantitativeValue",
  323.                 "value" => 0,
  324.                 "unitCode" => 'KMT'
  325.             ],
  326.             "color" => $item->getColor(),
  327.             "vehicleInteriorColor" => $item->getColor(),
  328.             "vehicleInteriorType" => 'Standard',
  329.             "bodyType" => $item->getBodyTypeName($request->getLocale()),
  330.             "driveWheelConfiguration" => $driveWheelConfiguration,
  331.             "vehicleEngine" => [
  332.                 "@type" => "EngineSpecification",
  333.                 "engineType" => $item->getFuelTypeName($request->getLocale()),
  334.             ],
  335.             "vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
  336.             "numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
  337.             "vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
  338.         ], JSON_UNESCAPED_SLASHES);
  339.     }
  340.     public function getCarStructuredDataCarUsed(Request $requestAbstractVehicle $item): bool|string
  341.     {
  342.         $twig $this->mediaExtensionVidi;
  343.         $router $this->router;
  344.         $routerCurrent $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  345.         $routerCurrentParams = [
  346.             'id' => $item->getVehicleId(),
  347.             'url' => $item->getUrl()
  348.         ];
  349.         if ($routerCurrent == 'suzuki_card_moto') {
  350.             $routerCurrentParams = [
  351.                 'moto' => $item->getUrl()
  352.             ];
  353.         }
  354.         $images array_reduce(($item->getGallery()) ? $item->getGallery()->getGalleryItems()->toArray() : [], function ($rows$row) use ($request$twig) {
  355.             $rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
  356.             return $rows;
  357.         }, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
  358.         $characteristics $item->getCharacterisaticsWithGroup($request->getLocale());
  359.         $characteristicsSize $characteristics[1] ?? [];
  360.         $characteristicsSizeNumberOfDoors array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
  361.         $characteristicsSizeNumberOfDoors array_values($characteristicsSizeNumberOfDoors);
  362.         $characteristicsSizeVehicleSeatingCapacity array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
  363.         $characteristicsSizeVehicleSeatingCapacity array_values($characteristicsSizeVehicleSeatingCapacity);
  364.         return json_encode([
  365.             "@context" => "http://schema.org",
  366.             "@type" => "Car",
  367.             "name" => $item->getFullName(),
  368.             "vehicleIdentificationNumber" => $item->getVIN() ?? '00000000000000000',
  369.             "image" => $images,
  370.             "url" => $router->generate($routerCurrent$routerCurrentParamsUrlGeneratorInterface::ABSOLUTE_URL),
  371.             "offers" => [
  372.                 "@type" => "Offer",
  373.                 "availability" => "http://schema.org/InStock",
  374.                 "price" => $item->price(),
  375.                 "priceCurrency" => "UAH"
  376.             ],
  377.             "itemCondition" => "https://schema.org/UsedCondition",
  378.             "brand" => [
  379.                 "@type" => "Brand",
  380.                 "name" => $item->getBrand()->getName()
  381.             ],
  382.             "model" => $item->getModelName(),
  383.             "vehicleConfiguration" => $item->getEquipment()->getTitle(),
  384.             "vehicleModelDate" => $item->getYear(),
  385.             "mileageFromOdometer" => [
  386.                 "@type" => "QuantitativeValue",
  387.                 "value" => $item->getMileage(),
  388.                 "unitCode" => 'KMT'
  389.             ],
  390.             "color" => $item->getBodyColor($request->getLocale()),
  391.             "vehicleInteriorColor" => $item->getBodyColor($request->getLocale()),
  392.             "vehicleInteriorType" => 'Standard',
  393.             "bodyType" => $item->getBodyTypeName($request->getLocale()),
  394.             "driveWheelConfiguration" => $item->getDriveUnitTypeName($request->getLocale()),
  395.             "vehicleEngine" => [
  396.                 "@type" => "EngineSpecification",
  397.                 "engineType" => $item->getFuelTypeName($request->getLocale()),
  398.             ],
  399.             "vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
  400.             "numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
  401.             "vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
  402.         ], JSON_UNESCAPED_SLASHES);
  403.     }
  404.     public function getCarPageStructuredData(Request $requestVehicle $vehicle): string
  405.     {
  406.         $twig $this->mediaExtensionVidi;
  407.         $router $this->router;
  408.         $currentRoute $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  409.         if ($vehicle->getDealer()->getUrl() !== 'land-rover') {
  410.             $homepageRoute $router->generate(
  411.                 preg_replace('([^a-zA-Z])''_'$vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
  412.             );
  413.         } else {
  414.             $homepageRoute $router->generate(
  415.                 preg_replace('([^a-zA-Z])'''$vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
  416.             );
  417.         }
  418.         $params = [
  419.             'car' => $vehicle->getUrl(),
  420.             'url' => $vehicle->getUrl(),
  421.             'category' => $vehicle->getCategory() ? $vehicle->getCategory()->getUrl() : '',
  422.         ];
  423.         if ($currentRoute == 'suzuki_card_moto') {
  424.             $params = ['moto' => $vehicle->getUrl()];
  425.         }
  426.         $images = [
  427.             $request->getSchemeAndHttpHost() . $twig->getPath($vehicle->getPreview(), 'reference'),
  428.         ];
  429.         $gallery $vehicle->getGallery();
  430.         if ($gallery) {
  431.             foreach ($gallery->getGalleryItems() as $galleryItem) {
  432.                 $images[] = $request->getSchemeAndHttpHost() . $twig->getPath($galleryItem->getMedia(), 'reference');
  433.             }
  434.         }
  435.         return json_encode([
  436.             "@context" => "http://schema.org",
  437.             "@type" => "Product",
  438.             "image" => $images,
  439.             "brand" => [
  440.                 "@type" => "Brand",
  441.                 "name" => $vehicle->getBrand()->getName(),
  442.             ],
  443.             "manufacturer" => [
  444.                 "@type" => "Corporation",
  445.                 "name" => $vehicle->getBrand()->getName()
  446.             ],
  447.             "description" => $vehicle->seoDescription($request->getLocale()),
  448.             "sku" => $vehicle->getVehicleId(),
  449.             "name" => $vehicle->getFullName(),
  450.             "offers" => [
  451.                 "@type" => "AggregateOffer",
  452.                 "availability" => "http://schema.org/InStock",
  453.                 "priceCurrency" => "UAH",
  454.                 "price" => $vehicle->price(),
  455.                 "lowPrice" => $vehicle->minPrice(),
  456.                 "highPrice" => $vehicle->maxPrice(),
  457.             ],
  458.             "itemCondition" => "http://schema.org/NewCondition",
  459.             "url" => $router->generate($currentRoute$paramsUrlGeneratorInterface::ABSOLUTE_URL)
  460.         ], JSON_UNESCAPED_SLASHES);
  461.     }
  462.     public function getModelMenuItems($locale$format null$categId false): array
  463.     {
  464.         $cars $this->vehicleRepository->getNewByDealer($this->getDealer());
  465.         $categories = [];
  466.         /** @var \CoreBundle\Entity\Vehicles\Vehicle $car */
  467.         foreach ($cars as $car) {
  468.             $vehicleModel $this->vehicleFactory->createByEntity($car);
  469.             if (!$vehicleModel) {
  470.                 continue;
  471.             }
  472.             $categoryId $car->getCategory() ? $car->getCategory()->getId() : null;
  473.             if ($categId && $categoryId != $categId) continue;
  474.             $key array_search($categoryIdarray_column($categories'id'));
  475.             $format $format ?: 'menu';
  476.             $oneCar = [
  477.                 'id' => $vehicleModel->getVehicleId(),
  478.                 'title' => $vehicleModel->getModelName(),
  479.                 'customTitle' => $vehicleModel->getCustomName($locale),
  480.                 'isNew' => $vehicleModel->isNew(),
  481.                 'isPreOrder' => $vehicleModel->isPreOrder(),
  482.                 'onTestDrive' => $vehicleModel->getTestDrive(),
  483.                 'position' => $vehicleModel->getPosition(),
  484.                 'url' => $vehicleModel->getUrl(),
  485.                 'hasHybrid' => $vehicleModel->hasHybrid(),
  486.                 'price' => round($vehicleModel->price()),
  487.                 'image' => $vehicleModel->getPreviewPath($format),
  488.                 'image_webp' => $vehicleModel->getPreviewPathWebp($format),
  489.                 'modelId' => $vehicleModel->getModel()->getId(),
  490.                 'preorderPrice' => $vehicleModel->getPreorderPrice(),
  491.             ];
  492.             if ($key === false && $car->getCategory()) {
  493.                 $category = [
  494.                     'id' => $categoryId,
  495.                     'title' => $vehicleModel->getCategory()->getTitle($locale),
  496.                     'position' => $vehicleModel->getCategory()->getPosition(),
  497.                     'url' => $vehicleModel->getCategory()->getUrl(),
  498.                     'cars' => []
  499.                 ];
  500.                 $category['cars'][] = $oneCar;
  501.                 $categories[] = $category;
  502.             } else {
  503.                 $categories[$key]['cars'][] = $oneCar;
  504.             }
  505.         }
  506.         $positionC = [];
  507.         foreach ($categories as $k => &$row) {
  508.             $position = [];
  509.             foreach ($row['cars'] as $key => $car) {
  510.                 $position[$key] = $car['position'];
  511.             }
  512.             $positionC[$k] = $row['position'];
  513.             array_multisort($positionSORT_ASC$row['cars']);
  514.         }
  515.         array_multisort($positionCSORT_ASC$categories);
  516.         return $categories;
  517.     }
  518.     protected function removeBOM($str ""): bool|string
  519.     {
  520.         if (substr($str03) == pack('CCC'0xef0xbb0xbf)) {
  521.             $str substr($str3);
  522.         }
  523.         return $str;
  524.     }
  525.     public function getUtmData(): string
  526.     {
  527.         $request $this->requestStack->getCurrentRequest();
  528.         if (!$request) {
  529.             return json_encode([], JSON_UNESCAPED_SLASHES JSON_PRETTY_PRINT);
  530.         }
  531.         $utmData = [];
  532.         $utmTags = ['utm_source''utm_medium''utm_campaign''utm_term''utm_content'];
  533.         foreach ($utmTags as $tag) {
  534.             $pascalCaseTag = (new UnicodeString($tag))->camel()->title()->toString();
  535.             $utmData[$pascalCaseTag] = $request->query->get($tag'');
  536.         }
  537.         $utmData['BpmRef'] = $request->headers->get('referer''');
  538.         $utmData['BpmHref'] = $request->getUri();
  539.         return json_encode($utmData,  JSON_UNESCAPED_SLASHES JSON_PRETTY_PRINT);
  540.     }
  541. }