<?php
namespace DcSiteBundle\Controller;
use CoreBundle\Component\CoreFormFactory;
use CoreBundle\Component\FormManager;
use CoreBundle\Controller\ViDiController;
use CoreBundle\Entity\Dealer;
use CoreBundle\Entity\Model;
use CoreBundle\Factory\Vehicle as VehicleFactory;
use CoreBundle\Model\Api\OnlineService\ApiServer1C;
use CoreBundle\Model\Vehicles\AbstractVehicle;
use CoreBundle\Model\Vehicles\InStockVehicle;
use CoreBundle\Model\Vehicles\Repository;
use CoreBundle\Model\Vehicles\Vehicle;
use CoreBundle\Services\MediaExtensionVidi;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use MyBundle\Entity\Basket;
use PortalBundle\Model\SeoMetaTag;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\String\UnicodeString;
use Twig\Environment;
class BaseDcController extends ViDiController
{
protected SeoMetaTag $seoMetaTag;
protected RequestStack $requestStack;
protected RouterInterface $router;
protected FormManager $formManager;
protected EntityManagerInterface $em;
protected ApiServer1C $apiServer1C;
protected SessionInterface $session;
protected Filesystem $filesystem;
protected MediaExtensionVidi $mediaExtensionVidi;
protected Repository $vehicleRepository;
protected VehicleFactory $vehicleFactory;
protected Environment $twig;
public function __construct(CoreFormFactory $coreFormFactory, SeoMetaTag $seoMetaTag, RequestStack $requestStack,
RouterInterface $router, FormManager $formManager, EntityManagerInterface $em,
ApiServer1C $apiServer1C, SessionInterface $session, Filesystem $filesystem,
MediaExtensionVidi $mediaExtensionVidi, Repository $vehicleRepository,
VehicleFactory $vehicleFactory, Environment $twig)
{
parent::__construct($coreFormFactory);
$this->seoMetaTag = $seoMetaTag;
$this->router = $router;
$this->formManager = $formManager;
$this->em = $em;
$this->apiServer1C = $apiServer1C;
$this->session = $session;
$this->filesystem = $filesystem;
$this->mediaExtensionVidi = $mediaExtensionVidi;
$this->vehicleRepository = $vehicleRepository;
$this->vehicleFactory = $vehicleFactory;
$this->twig = $twig;
$this->requestStack = $requestStack;
}
const DEALER_CITY_ID = 3;
/**
* @var array
*/
private static $dealers = [];
private $js = [];
private $baseJs = [];
private $jsParams = [];
protected function sendSmsLead(Request $request): JsonResponse
{
$formName = '';
$formPhone = '';
$formData = [
'vin' => '', 'visit_date' => '', 'model' => '', 'brand' => '', 'year' => '', 'data' => []
];
try {
if (empty($request->get('vin'))) {
throw new Exception("Не вказано 'vin'");
}
if (empty($request->get('visitDate'))) {
throw new Exception("Не вказано 'visitDate'");
}
$formData['vin'] = $request->get('vin');
$formData['visit_date'] = str_replace('%', '-', $request->get('visitDate'));
$arr = $this->apiServer1C->getHistory($formData['vin']);
if (empty($arr)) {
throw new Exception("Не знайдено '{$formData['vin']}'");
}
if (!empty($arr['ModelID'])) {
/**
* @var $model Model
*/
$model = $this->em
->getRepository(Model::class)
->findOneBy(['uid_1c' => $arr['ModelID']]);
if (!empty($model)) {
$formData['model'] = $model->getTitle();
$formData['brand'] = $model->getBrand()->getName();
}
}
if (!empty($arr['LastOwner'])) {
$formName = $arr['LastOwner'];
}
if (!empty($arr['Phone'])) {
$formPhone = $arr['Phone'];
}
if (!empty($arr['Year'])) {
$formData['year'] = $arr['Year'];
}
if (!empty($arr['data'])) {
$formData['data'] = $arr['data'];
}
$this->formManager->saveSmsLeadForm(
$request,
$this->getDealer(),
$formName,
$formPhone,
$formData
);
return $this->success();
} catch (Exception $e) {
return $this->error($e);
}
}
protected function checkSend(Request $request): bool
{
$vin = $request->get('vin');
$visitDate = str_replace('%', '-', $request->get('visitDate'));
$toCheck = md5($vin . $visitDate);
$inSes = $this->session->get('nselectcheck');
$inSes = is_array($inSes) ? $inSes : [];
if (!in_array($toCheck, $inSes)) {
$inSes[] = $toCheck;
$this->session->set('nselectcheck', $inSes);
return false;
} else {
return true;
}
}
public function getDealer(): Dealer
{
$request = $this->requestStack->getCurrentRequest();
$host = $this->modifyHost($request->getHost());
if (!isset(self::$dealers[md5($host)])) {
$dealerId = $request->get('dealerId');
if ($host == 'vidi.ua' && !is_null($dealerId)) {
$findDealer = ['id' => $request->get('dealerId')];
} else {
$host = $this->isDealerShop($host);
$findDealer = ['domain' => $host];
}
$Dealer = $this->em->getRepository(Dealer::class)->findOneBy($findDealer);
if (!$Dealer) {
throw new NotFoundHttpException();
}
self::$dealers[md5($host)] = $Dealer;
}
return self::$dealers[md5($host)];
}
private function isDealerShop($host)
{
return str_replace("shop.", "", $host);
}
protected function webpUpdate(Request $request, $url, $manager)
{
$userAgent = $request->server->get('HTTP_USER_AGENT');
preg_match("/(MSIE|Opera|Firefox|Chrome|Version)(?:\/| )([0-9.]+)/", $userAgent, $browser_info);
$browser = $browser_info[1] ?? false;
if (!$browser) {
return $url;
}
if ($browser == 'Version' || $browser == 'MSIE') {
return $url;
}
$basePath = $this->getParameter('kernel.root_dir') . '/../public';
$path = $basePath . $url . '.webp';
if (file_exists($path)) {
return $manager->getUrl($url . '.webp');
}
$im = @imagecreatefrompng($basePath . $url);
if (!$im) {
$im = @imagecreatefromjpeg($basePath . $url);
}
if ($im) {
$newUrl = $url . '.webp';
if (imagewebp($im, $path)) {
imagedestroy($im);
return $manager->getUrl($newUrl);
} else {
imagedestroy($im);
return $manager->getUrl($url);
}
}
return $url;
}
private function modifyHost($host): mixed
{
if ($_ENV['APP_ENV'] == 'dev') {
$host = str_replace($this->getParameter('host'), 'vidi.ua', $host);
}
return $host;
}
protected function baseDcRender($view, array $parameters = [], Response $response = null): ?Response
{
$request = $this->requestStack->getCurrentRequest();
$dealer = $this->getDealer();
$seoMeta = $this->seoMetaTag->getSeoMeta($request);
$subdomain = explode('.', $request->server->get('HTTP_HOST'))[0];
$basketCount = [];
if ($this->getUser()) {
$basketCount = $this->em->getRepository(Basket::class)->getBasketCountByDealerUser($this->getDealer(), $this->getUser());
} else {
$guestBasket = $this->session->get('guest_basket', []);
if ($guestBasket && isset($guestBasket[$this->getDealer()->getId()])) {
$basketCount['count'] = count($guestBasket[$this->getDealer()->getId()]);
}
}
$basketCount = ($basketCount) ? $basketCount['count'] : 0;
$isSubdomainShop = $subdomain === "shop";
$utmData = $this->getUtmData();
$parameters = array_merge($parameters, [
'dealer' => $this->getDealer(),
'basketCount' => $basketCount,
'dealerCityNihgtBooking' => self::DEALER_CITY_ID,
'backLoginUrl' => $request->getUri(),
'seoMeta' => $seoMeta,
'isSubdomainShop' => $isSubdomainShop,
'currentYear' => (new DateTime('now'))->format('Y'),
'utmData' => $utmData,
]);
$helpCrunchParams = $this->getParameter('help_crunch_params')[$dealer->getUniqueId()] ?? null;
if ($helpCrunchParams) {
$parameters = array_merge($parameters, ['helpCrunch' => $helpCrunchParams]);
}
$content = $this->twig->render($view, $parameters);
if (null === $response) {
$response = new Response();
}
return $response->setContent($content);
}
protected function getMpdfTempDir(): string
{
$newTempDir = $this->getParameter('file_directory_mpdf');
if (!$this->filesystem->exists($newTempDir)) {
$this->filesystem-- > mkdir($newTempDir, 0777);
}
return $newTempDir;
}
public function getCarStructuredDataCarInStock(Request $request, InStockVehicle $item): bool|string
{
$twig = $this->mediaExtensionVidi;
$router = $this->router;
$routerCurrent = $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
$routerCurrentParams = [
'car' => $item->getUrl(),
'url' => $item->getUrl(),
'category' => $item->getCategory()->getUrl()
];
if ($routerCurrent == 'suzuki_card_moto') {
$routerCurrentParams = [
'moto' => $item->getUrl()
];
}
$images = [];
$gallery = $item->getGallery();
if (!empty($gallery)) {
$gallery = $gallery->getGalleryItems();
if (!empty($gallery)) {
$images = $gallery->toArray();
}
}
$images = array_reduce($images, function ($rows, $row) use ($request, $twig) {
$rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
return $rows;
}, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
$characteristics = $item->getCharacterisaticsByGroup($request->getLocale());
$characteristicsSize = $characteristics[1] ?? [];
$characteristicsSizeNumberOfDoors = array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
$characteristicsSizeNumberOfDoors = array_values($characteristicsSizeNumberOfDoors);
$characteristicsSizeVehicleSeatingCapacity = array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
$characteristicsSizeVehicleSeatingCapacity = array_values($characteristicsSizeVehicleSeatingCapacity);
switch ($item->getDriveUnitType()->getId()) {
case 13:
$driveWheelConfiguration = 'AllWheelDriveConfiguration'; // Повний
break;
case 3:
$driveWheelConfiguration = 'FrontWheelDriveConfiguration'; // Передній
break;
case 11:
$driveWheelConfiguration = 'RearWheelDriveConfiguration'; // Задній
break;
case 27:
$driveWheelConfiguration = 'FourWheelDriveConfiguration'; // AWD
break;
default:
$driveWheelConfiguration = 'undefined';
break;
}
return json_encode([
"@context" => "http://schema.org",
"@type" => "Car",
"name" => $item->getFullName(),
"vehicleIdentificationNumber" => $item->getVin() ?? '00000000000000000',
"image" => $images,
"url" => $router->generate($routerCurrent, $routerCurrentParams, UrlGeneratorInterface::ABSOLUTE_URL),
"offers" => [
"@type" => "Offer",
"availability" => "http://schema.org/InStock",
"price" => $item->price(),
"priceCurrency" => "UAH"
],
"itemCondition" => "https://schema.org/NewCondition",
"brand" => [
"@type" => "Brand",
"name" => $item->getBrand()->getName()
],
"model" => $item->getModelName(),
"vehicleConfiguration" => $item->getEquipment()->getTitle(),
"vehicleModelDate" => $item->getYear(),
"mileageFromOdometer" => [
"@type" => "QuantitativeValue",
"value" => 0,
"unitCode" => 'KMT'
],
"color" => $item->getColor(),
"vehicleInteriorColor" => $item->getColor(),
"vehicleInteriorType" => 'Standard',
"bodyType" => $item->getBodyTypeName($request->getLocale()),
"driveWheelConfiguration" => $driveWheelConfiguration,
"vehicleEngine" => [
"@type" => "EngineSpecification",
"engineType" => $item->getFuelTypeName($request->getLocale()),
],
"vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
"numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
"vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
], JSON_UNESCAPED_SLASHES);
}
public function getCarStructuredDataCarUsed(Request $request, AbstractVehicle $item): bool|string
{
$twig = $this->mediaExtensionVidi;
$router = $this->router;
$routerCurrent = $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
$routerCurrentParams = [
'id' => $item->getVehicleId(),
'url' => $item->getUrl()
];
if ($routerCurrent == 'suzuki_card_moto') {
$routerCurrentParams = [
'moto' => $item->getUrl()
];
}
$images = array_reduce(($item->getGallery()) ? $item->getGallery()->getGalleryItems()->toArray() : [], function ($rows, $row) use ($request, $twig) {
$rows[] = $request->getSchemeAndHttpHost() . $twig->getPath($row->getMedia(), 'reference');
return $rows;
}, [$request->getSchemeAndHttpHost() . $twig->getPath($item->getPreview(), 'reference')]);
$characteristics = $item->getCharacterisaticsWithGroup($request->getLocale());
$characteristicsSize = $characteristics[1] ?? [];
$characteristicsSizeNumberOfDoors = array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 15);
$characteristicsSizeNumberOfDoors = array_values($characteristicsSizeNumberOfDoors);
$characteristicsSizeVehicleSeatingCapacity = array_filter($characteristicsSize['characteristics'], fn($row) => $row['id'] === 20);
$characteristicsSizeVehicleSeatingCapacity = array_values($characteristicsSizeVehicleSeatingCapacity);
return json_encode([
"@context" => "http://schema.org",
"@type" => "Car",
"name" => $item->getFullName(),
"vehicleIdentificationNumber" => $item->getVIN() ?? '00000000000000000',
"image" => $images,
"url" => $router->generate($routerCurrent, $routerCurrentParams, UrlGeneratorInterface::ABSOLUTE_URL),
"offers" => [
"@type" => "Offer",
"availability" => "http://schema.org/InStock",
"price" => $item->price(),
"priceCurrency" => "UAH"
],
"itemCondition" => "https://schema.org/UsedCondition",
"brand" => [
"@type" => "Brand",
"name" => $item->getBrand()->getName()
],
"model" => $item->getModelName(),
"vehicleConfiguration" => $item->getEquipment()->getTitle(),
"vehicleModelDate" => $item->getYear(),
"mileageFromOdometer" => [
"@type" => "QuantitativeValue",
"value" => $item->getMileage(),
"unitCode" => 'KMT'
],
"color" => $item->getBodyColor($request->getLocale()),
"vehicleInteriorColor" => $item->getBodyColor($request->getLocale()),
"vehicleInteriorType" => 'Standard',
"bodyType" => $item->getBodyTypeName($request->getLocale()),
"driveWheelConfiguration" => $item->getDriveUnitTypeName($request->getLocale()),
"vehicleEngine" => [
"@type" => "EngineSpecification",
"engineType" => $item->getFuelTypeName($request->getLocale()),
],
"vehicleTransmission" => $item->getTransmissionTypeName($request->getLocale()),
"numberOfDoors" => $characteristicsSizeNumberOfDoors[0]['value'] ?? null,
"vehicleSeatingCapacity" => $characteristicsSizeVehicleSeatingCapacity[0]['value'] ?? null
], JSON_UNESCAPED_SLASHES);
}
public function getCarPageStructuredData(Request $request, Vehicle $vehicle): string
{
$twig = $this->mediaExtensionVidi;
$router = $this->router;
$currentRoute = $router->getMatcher()->match($router->getContext()->getPathInfo())['_route'];
if ($vehicle->getDealer()->getUrl() !== 'land-rover') {
$homepageRoute = $router->generate(
preg_replace('([^a-zA-Z])', '_', $vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
);
} else {
$homepageRoute = $router->generate(
preg_replace('([^a-zA-Z])', '', $vehicle->getDealer()->getUrl()) . '_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL
);
}
$params = [
'car' => $vehicle->getUrl(),
'url' => $vehicle->getUrl(),
'category' => $vehicle->getCategory() ? $vehicle->getCategory()->getUrl() : '',
];
if ($currentRoute == 'suzuki_card_moto') {
$params = ['moto' => $vehicle->getUrl()];
}
$images = [
$request->getSchemeAndHttpHost() . $twig->getPath($vehicle->getPreview(), 'reference'),
];
$gallery = $vehicle->getGallery();
if ($gallery) {
foreach ($gallery->getGalleryItems() as $galleryItem) {
$images[] = $request->getSchemeAndHttpHost() . $twig->getPath($galleryItem->getMedia(), 'reference');
}
}
return json_encode([
"@context" => "http://schema.org",
"@type" => "Product",
"image" => $images,
"brand" => [
"@type" => "Brand",
"name" => $vehicle->getBrand()->getName(),
],
"manufacturer" => [
"@type" => "Corporation",
"name" => $vehicle->getBrand()->getName()
],
"description" => $vehicle->seoDescription($request->getLocale()),
"sku" => $vehicle->getVehicleId(),
"name" => $vehicle->getFullName(),
"offers" => [
"@type" => "AggregateOffer",
"availability" => "http://schema.org/InStock",
"priceCurrency" => "UAH",
"price" => $vehicle->price(),
"lowPrice" => $vehicle->minPrice(),
"highPrice" => $vehicle->maxPrice(),
],
"itemCondition" => "http://schema.org/NewCondition",
"url" => $router->generate($currentRoute, $params, UrlGeneratorInterface::ABSOLUTE_URL)
], JSON_UNESCAPED_SLASHES);
}
public function getModelMenuItems($locale, $format = null, $categId = false): array
{
$cars = $this->vehicleRepository->getNewByDealer($this->getDealer());
$categories = [];
/** @var \CoreBundle\Entity\Vehicles\Vehicle $car */
foreach ($cars as $car) {
$vehicleModel = $this->vehicleFactory->createByEntity($car);
if (!$vehicleModel) {
continue;
}
$categoryId = $car->getCategory() ? $car->getCategory()->getId() : null;
if ($categId && $categoryId != $categId) continue;
$key = array_search($categoryId, array_column($categories, 'id'));
$format = $format ?: 'menu';
$oneCar = [
'id' => $vehicleModel->getVehicleId(),
'title' => $vehicleModel->getModelName(),
'customTitle' => $vehicleModel->getCustomName($locale),
'isNew' => $vehicleModel->isNew(),
'isPreOrder' => $vehicleModel->isPreOrder(),
'onTestDrive' => $vehicleModel->getTestDrive(),
'position' => $vehicleModel->getPosition(),
'url' => $vehicleModel->getUrl(),
'hasHybrid' => $vehicleModel->hasHybrid(),
'price' => round($vehicleModel->price()),
'image' => $vehicleModel->getPreviewPath($format),
'image_webp' => $vehicleModel->getPreviewPathWebp($format),
'modelId' => $vehicleModel->getModel()->getId(),
'preorderPrice' => $vehicleModel->getPreorderPrice(),
];
if ($key === false && $car->getCategory()) {
$category = [
'id' => $categoryId,
'title' => $vehicleModel->getCategory()->getTitle($locale),
'position' => $vehicleModel->getCategory()->getPosition(),
'url' => $vehicleModel->getCategory()->getUrl(),
'cars' => []
];
$category['cars'][] = $oneCar;
$categories[] = $category;
} else {
$categories[$key]['cars'][] = $oneCar;
}
}
$positionC = [];
foreach ($categories as $k => &$row) {
$position = [];
foreach ($row['cars'] as $key => $car) {
$position[$key] = $car['position'];
}
$positionC[$k] = $row['position'];
array_multisort($position, SORT_ASC, $row['cars']);
}
array_multisort($positionC, SORT_ASC, $categories);
return $categories;
}
protected function removeBOM($str = ""): bool|string
{
if (substr($str, 0, 3) == pack('CCC', 0xef, 0xbb, 0xbf)) {
$str = substr($str, 3);
}
return $str;
}
protected function getUtmData(): string
{
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
return json_encode([], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
}
$utmData = [];
$utmTags = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
foreach ($utmTags as $tag) {
$pascalCaseTag = (new UnicodeString($tag))->camel()->title()->toString();
$utmData[$pascalCaseTag] = $request->query->get($tag, '');
}
$utmData['BpmRef'] = $request->headers->get('referer', '');
$utmData['BpmHref'] = $request->getUri();
return json_encode($utmData, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
}
}