src/DcSiteBundle/Controller/BaseDcController.php line 243

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.                 $basketCount['count'] = count($guestBasket[$this->getDealer()->getId()]);
  213.             }
  214.         }
  215.         $basketCount = ($basketCount) ? $basketCount['count'] : 0;
  216.         $isSubdomainShop $subdomain === "shop";
  217.         $utmData $this->getUtmData();
  218.         $parameters array_merge($parameters, [
  219.             'dealer' => $this->getDealer(),
  220.             'basketCount' => $basketCount,
  221.             'dealerCityNihgtBooking' => self::DEALER_CITY_ID,
  222.             'backLoginUrl' => $request->getUri(),
  223.             'seoMeta' => $seoMeta,
  224.             'isSubdomainShop' => $isSubdomainShop,
  225.             'currentYear' => (new DateTime('now'))->format('Y'),
  226.             'utmData' => $utmData,
  227.         ]);
  228.         $helpCrunchParams $this->getParameter('help_crunch_params')[$dealer->getUniqueId()] ?? null;
  229.         if ($helpCrunchParams) {
  230.             $parameters array_merge($parameters, ['helpCrunch' => $helpCrunchParams]);
  231.         }
  232.         $content $this->twig->render($view$parameters);
  233.         if (null === $response) {
  234.             $response = new Response();
  235.         }
  236.         return $response->setContent($content);
  237.     }
  238.     protected function getMpdfTempDir(): string
  239.     {
  240.         $newTempDir $this->getParameter('file_directory_mpdf');
  241.         if (!$this->filesystem->exists($newTempDir)) {
  242.             $this->filesystem-- > mkdir($newTempDir0777);
  243.         }
  244.         return $newTempDir;
  245.     }
  246.     public function getCarStructuredDataCarInStock(Request $requestInStockVehicle $item): bool|string
  247.     {
  248.         $twig $this->mediaExtensionVidi;
  249.         $router $this->router;
  250.         $routerCurrent $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  251.         $routerCurrentParams = [
  252.             'car' => $item->getUrl(),
  253.             'url' => $item->getUrl(),
  254.             'category' => $item->getCategory()->getUrl()
  255.         ];
  256.         if ($routerCurrent == 'suzuki_card_moto') {
  257.             $routerCurrentParams = [
  258.                 'moto' => $item->getUrl()
  259.             ];
  260.         }
  261.         $images = [];
  262.         $gallery $item->getGallery();
  263.         if (!empty($gallery)) {
  264.             $gallery $gallery->getGalleryItems();
  265.             if (!empty($gallery)) {
  266.                 $images $gallery->toArray();
  267.             }
  268.         }
  269.         $images array_reduce($images, function ($rows$row) use ($request$twig) {
  270.             $rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
  271.             return $rows;
  272.         }, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
  273.         $characteristics $item->getCharacterisaticsByGroup($request->getLocale());
  274.         $characteristicsSize $characteristics[1] ?? [];
  275.         $characteristicsSizeNumberOfDoors array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
  276.         $characteristicsSizeNumberOfDoors array_values($characteristicsSizeNumberOfDoors);
  277.         $characteristicsSizeVehicleSeatingCapacity array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
  278.         $characteristicsSizeVehicleSeatingCapacity array_values($characteristicsSizeVehicleSeatingCapacity);
  279.         switch ($item->getDriveUnitType()->getId()) {
  280.             case 13:
  281.                 $driveWheelConfiguration 'AllWheelDriveConfiguration'// Повний
  282.                 break;
  283.             case 3:
  284.                 $driveWheelConfiguration 'FrontWheelDriveConfiguration'// Передній
  285.                 break;
  286.             case 11:
  287.                 $driveWheelConfiguration 'RearWheelDriveConfiguration'// Задній
  288.                 break;
  289.             case 27:
  290.                 $driveWheelConfiguration 'FourWheelDriveConfiguration'// AWD
  291.                 break;
  292.             default:
  293.                 $driveWheelConfiguration 'undefined';
  294.                 break;
  295.         }
  296.         return json_encode([
  297.             "@context" => "http://schema.org",
  298.             "@type" => "Car",
  299.             "name" => $item->getFullName(),
  300.             "vehicleIdentificationNumber" => $item->getVin() ?? '00000000000000000',
  301.             "image" => $images,
  302.             "url" => $router->generate($routerCurrent$routerCurrentParamsUrlGeneratorInterface::ABSOLUTE_URL),
  303.             "offers" => [
  304.                 "@type" => "Offer",
  305.                 "availability" => "http://schema.org/InStock",
  306.                 "price" => $item->price(),
  307.                 "priceCurrency" => "UAH"
  308.             ],
  309.             "itemCondition" => "https://schema.org/NewCondition",
  310.             "brand" => [
  311.                 "@type" => "Brand",
  312.                 "name" => $item->getBrand()->getName()
  313.             ],
  314.             "model" => $item->getModelName(),
  315.             "vehicleConfiguration" => $item->getEquipment()->getTitle(),
  316.             "vehicleModelDate" => $item->getYear(),
  317.             "mileageFromOdometer" => [
  318.                 "@type" => "QuantitativeValue",
  319.                 "value" => 0,
  320.                 "unitCode" => 'KMT'
  321.             ],
  322.             "color" => $item->getColor(),
  323.             "vehicleInteriorColor" => $item->getColor(),
  324.             "vehicleInteriorType" => 'Standard',
  325.             "bodyType" => $item->getBodyTypeName($request->getLocale()),
  326.             "driveWheelConfiguration" => $driveWheelConfiguration,
  327.             "vehicleEngine" => [
  328.                 "@type" => "EngineSpecification",
  329.                 "engineType" => $item->getFuelTypeName($request->getLocale()),
  330.             ],
  331.             "vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
  332.             "numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
  333.             "vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
  334.         ], JSON_UNESCAPED_SLASHES);
  335.     }
  336.     public function getCarStructuredDataCarUsed(Request $requestAbstractVehicle $item): bool|string
  337.     {
  338.         $twig $this->mediaExtensionVidi;
  339.         $router $this->router;
  340.         $routerCurrent $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  341.         $routerCurrentParams = [
  342.             'id' => $item->getVehicleId(),
  343.             'url' => $item->getUrl()
  344.         ];
  345.         if ($routerCurrent == 'suzuki_card_moto') {
  346.             $routerCurrentParams = [
  347.                 'moto' => $item->getUrl()
  348.             ];
  349.         }
  350.         $images array_reduce(($item->getGallery()) ? $item->getGallery()->getGalleryItems()->toArray() : [], function ($rows$row) use ($request$twig) {
  351.             $rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
  352.             return $rows;
  353.         }, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
  354.         $characteristics $item->getCharacterisaticsWithGroup($request->getLocale());
  355.         $characteristicsSize $characteristics[1] ?? [];
  356.         $characteristicsSizeNumberOfDoors array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
  357.         $characteristicsSizeNumberOfDoors array_values($characteristicsSizeNumberOfDoors);
  358.         $characteristicsSizeVehicleSeatingCapacity array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
  359.         $characteristicsSizeVehicleSeatingCapacity array_values($characteristicsSizeVehicleSeatingCapacity);
  360.         return json_encode([
  361.             "@context" => "http://schema.org",
  362.             "@type" => "Car",
  363.             "name" => $item->getFullName(),
  364.             "vehicleIdentificationNumber" => $item->getVIN() ?? '00000000000000000',
  365.             "image" => $images,
  366.             "url" => $router->generate($routerCurrent$routerCurrentParamsUrlGeneratorInterface::ABSOLUTE_URL),
  367.             "offers" => [
  368.                 "@type" => "Offer",
  369.                 "availability" => "http://schema.org/InStock",
  370.                 "price" => $item->price(),
  371.                 "priceCurrency" => "UAH"
  372.             ],
  373.             "itemCondition" => "https://schema.org/UsedCondition",
  374.             "brand" => [
  375.                 "@type" => "Brand",
  376.                 "name" => $item->getBrand()->getName()
  377.             ],
  378.             "model" => $item->getModelName(),
  379.             "vehicleConfiguration" => $item->getEquipment()->getTitle(),
  380.             "vehicleModelDate" => $item->getYear(),
  381.             "mileageFromOdometer" => [
  382.                 "@type" => "QuantitativeValue",
  383.                 "value" => $item->getMileage(),
  384.                 "unitCode" => 'KMT'
  385.             ],
  386.             "color" => $item->getBodyColor($request->getLocale()),
  387.             "vehicleInteriorColor" => $item->getBodyColor($request->getLocale()),
  388.             "vehicleInteriorType" => 'Standard',
  389.             "bodyType" => $item->getBodyTypeName($request->getLocale()),
  390.             "driveWheelConfiguration" => $item->getDriveUnitTypeName($request->getLocale()),
  391.             "vehicleEngine" => [
  392.                 "@type" => "EngineSpecification",
  393.                 "engineType" => $item->getFuelTypeName($request->getLocale()),
  394.             ],
  395.             "vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
  396.             "numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
  397.             "vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
  398.         ], JSON_UNESCAPED_SLASHES);
  399.     }
  400.     public function getCarPageStructuredData(Request $requestVehicle $vehicle): string
  401.     {
  402.         $twig $this->mediaExtensionVidi;
  403.         $router $this->router;
  404.         $currentRoute $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
  405.         if ($vehicle->getDealer()->getUrl() !== 'land-rover') {
  406.             $homepageRoute $router->generate(
  407.                 preg_replace('([^a-zA-Z])''_'$vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
  408.             );
  409.         } else {
  410.             $homepageRoute $router->generate(
  411.                 preg_replace('([^a-zA-Z])'''$vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
  412.             );
  413.         }
  414.         $params = [
  415.             'car' => $vehicle->getUrl(),
  416.             'url' => $vehicle->getUrl(),
  417.             'category' => $vehicle->getCategory() ? $vehicle->getCategory()->getUrl() : '',
  418.         ];
  419.         if ($currentRoute == 'suzuki_card_moto') {
  420.             $params = ['moto' => $vehicle->getUrl()];
  421.         }
  422.         $images = [
  423.             $request->getSchemeAndHttpHost() . $twig->getPath($vehicle->getPreview(), 'reference'),
  424.         ];
  425.         $gallery $vehicle->getGallery();
  426.         if ($gallery) {
  427.             foreach ($gallery->getGalleryItems() as $galleryItem) {
  428.                 $images[] = $request->getSchemeAndHttpHost() . $twig->getPath($galleryItem->getMedia(), 'reference');
  429.             }
  430.         }
  431.         return json_encode([
  432.             "@context" => "http://schema.org",
  433.             "@type" => "Product",
  434.             "image" => $images,
  435.             "brand" => [
  436.                 "@type" => "Brand",
  437.                 "name" => $vehicle->getBrand()->getName(),
  438.             ],
  439.             "manufacturer" => [
  440.                 "@type" => "Corporation",
  441.                 "name" => $vehicle->getBrand()->getName()
  442.             ],
  443.             "description" => $vehicle->seoDescription($request->getLocale()),
  444.             "sku" => $vehicle->getVehicleId(),
  445.             "name" => $vehicle->getFullName(),
  446.             "offers" => [
  447.                 "@type" => "AggregateOffer",
  448.                 "availability" => "http://schema.org/InStock",
  449.                 "priceCurrency" => "UAH",
  450.                 "price" => $vehicle->price(),
  451.                 "lowPrice" => $vehicle->minPrice(),
  452.                 "highPrice" => $vehicle->maxPrice(),
  453.             ],
  454.             "itemCondition" => "http://schema.org/NewCondition",
  455.             "url" => $router->generate($currentRoute$paramsUrlGeneratorInterface::ABSOLUTE_URL)
  456.         ], JSON_UNESCAPED_SLASHES);
  457.     }
  458.     public function getModelMenuItems($locale$format null$categId false): array
  459.     {
  460.         $cars $this->vehicleRepository->getNewByDealer($this->getDealer());
  461.         $categories = [];
  462.         /** @var \CoreBundle\Entity\Vehicles\Vehicle $car */
  463.         foreach ($cars as $car) {
  464.             $vehicleModel $this->vehicleFactory->createByEntity($car);
  465.             if (!$vehicleModel) {
  466.                 continue;
  467.             }
  468.             $categoryId $car->getCategory() ? $car->getCategory()->getId() : null;
  469.             if ($categId && $categoryId != $categId) continue;
  470.             $key array_search($categoryIdarray_column($categories'id'));
  471.             $format $format ?: 'menu';
  472.             $oneCar = [
  473.                 'id' => $vehicleModel->getVehicleId(),
  474.                 'title' => $vehicleModel->getModelName(),
  475.                 'customTitle' => $vehicleModel->getCustomName($locale),
  476.                 'isNew' => $vehicleModel->isNew(),
  477.                 'isPreOrder' => $vehicleModel->isPreOrder(),
  478.                 'onTestDrive' => $vehicleModel->getTestDrive(),
  479.                 'position' => $vehicleModel->getPosition(),
  480.                 'url' => $vehicleModel->getUrl(),
  481.                 'hasHybrid' => $vehicleModel->hasHybrid(),
  482.                 'price' => round($vehicleModel->price()),
  483.                 'image' => $vehicleModel->getPreviewPath($format),
  484.                 'image_webp' => $vehicleModel->getPreviewPathWebp($format),
  485.                 'modelId' => $vehicleModel->getModel()->getId(),
  486.                 'preorderPrice' => $vehicleModel->getPreorderPrice(),
  487.             ];
  488.             if ($key === false && $car->getCategory()) {
  489.                 $category = [
  490.                     'id' => $categoryId,
  491.                     'title' => $vehicleModel->getCategory()->getTitle($locale),
  492.                     'position' => $vehicleModel->getCategory()->getPosition(),
  493.                     'url' => $vehicleModel->getCategory()->getUrl(),
  494.                     'cars' => []
  495.                 ];
  496.                 $category['cars'][] = $oneCar;
  497.                 $categories[] = $category;
  498.             } else {
  499.                 $categories[$key]['cars'][] = $oneCar;
  500.             }
  501.         }
  502.         $positionC = [];
  503.         foreach ($categories as $k => &$row) {
  504.             $position = [];
  505.             foreach ($row['cars'] as $key => $car) {
  506.                 $position[$key] = $car['position'];
  507.             }
  508.             $positionC[$k] = $row['position'];
  509.             array_multisort($positionSORT_ASC$row['cars']);
  510.         }
  511.         array_multisort($positionCSORT_ASC$categories);
  512.         return $categories;
  513.     }
  514.     protected function removeBOM($str ""): bool|string
  515.     {
  516.         if (substr($str03) == pack('CCC'0xef0xbb0xbf)) {
  517.             $str substr($str3);
  518.         }
  519.         return $str;
  520.     }
  521.     public function getUtmData(): string
  522.     {
  523.         $request $this->requestStack->getCurrentRequest();
  524.         if (!$request) {
  525.             return json_encode([], JSON_UNESCAPED_SLASHES JSON_PRETTY_PRINT);
  526.         }
  527.         $utmData = [];
  528.         $utmTags = ['utm_source''utm_medium''utm_campaign''utm_term''utm_content'];
  529.         foreach ($utmTags as $tag) {
  530.             $pascalCaseTag = (new UnicodeString($tag))->camel()->title()->toString();
  531.             $utmData[$pascalCaseTag] = $request->query->get($tag'');
  532.         }
  533.         $utmData['BpmRef'] = $request->headers->get('referer''');
  534.         $utmData['BpmHref'] = $request->getUri();
  535.         return json_encode($utmData,  JSON_UNESCAPED_SLASHES JSON_PRETTY_PRINT);
  536.     }
  537. }