<?php
namespace PortalBundle\Controller;
use CoreBundle\Component\CoreFormFactory;
use CoreBundle\Entity\Dealer;
use CoreBundle\Entity\Vehicles\InStock;
use CoreBundle\Entity\Vehicles\RecommendGroup;
use CoreBundle\Factory\InStockVehicle;
use CoreBundle\Model\Vehicles\Repository;
use CoreBundle\Model\Vehicles\Vehicle;
use CoreBundle\Model\Vehicles\VehicleType;
use DcSiteBundle\Model\Pagination;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use PortalBundle\Model\Catalog;
use PortalBundle\Model\SeoMetaTag;
use PortalBundle\Services\CatalogService;
use PortalBundle\Services\ServiceService;
use PortalBundle\Services\VehicleFilterService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\RouterInterface;
class StockController extends BaseController
{
private Catalog $modelCatalog;
private CatalogService $catalogService;
private InStockVehicle $inStockVehicle;
private SeoMetaTag $seoMetaTag;
public function __construct(CoreFormFactory $coreFormFactory, RequestStack $requestStack,
RouterInterface $router, Repository $vehicleRepository, ServiceService $serviceService,
Catalog $modelCatalog, CatalogService $catalogService, InStockVehicle $inStockVehicle,
SeoMetaTag $seoMetaTag)
{
parent::__construct($coreFormFactory, $requestStack, $router, $vehicleRepository, $serviceService);
$this->modelCatalog = $modelCatalog;
$this->catalogService = $catalogService;
$this->inStockVehicle = $inStockVehicle;
$this->seoMetaTag = $seoMetaTag;
}
const PRE_PAGES = 15;
const MAX_PAGINATION_BUTTON = 5;
/**
* @param Request $request
* @return Response
* @throws Exception
*/
public function inStock(Request $request, Pagination $paginationModel, EntityManagerInterface $em)
{
$routeParams = $request->attributes->get('_route_params');
$routeParams['brand'] = $request->query->get('brand');
$routeParams['model'] = $request->query->get('model');
$params = $request->query->all();
$param = null;
$value = null;
$model = '';
$brand = '';
$type = $request->get('type');
$state = $request->get('state');
if ($request->get('m-brand')) {
$brand = array_key_first($request->get('m-brand'));
}
if ($request->get('m-model')) {
$model = array_key_first($request->get('m-model'));
}
if (isset($params['dynamic'])) {
$param = array_key_first($params['dynamic']);
if (isset($params['dynamic'][$param])) {
$value = array_key_first($params['dynamic'][$param]);
}
}
if ($brand && $brand === 'all') {
throw new NotFoundHttpException();
}
$vehicles = $this->modelCatalog->findStockByParams($routeParams, $params, self::PRE_PAGES);
$allBrands = $em->getRepository(InStock::class)->gatAllBrands();
if (!$vehicles['data']) {
$vehicles = $this->modelCatalog->noFindStockVehicleByParams($routeParams, $params, self::PRE_PAGES);
}
/** @var InStock $vehicle */
$result = [];
foreach ($vehicles['data'] as $vehicle) {
$inStockModel = $this->inStockVehicle->createByEntity($vehicle[0]);
$vehicle = $this->modelCatalog->getInStockVehicleByCatalog($this->getUser(), $inStockModel);
$result[] = $vehicle;
}
$typeData = VehicleType::getTypeDataByUrl($type);
if (!$typeData) {
throw new NotFoundHttpException();
}
$vehicleTypeId = $typeData['id'];
$catalogNav = $this->modelCatalog->getStockCatalogNav($type, $state, $brand, $params, $value);
$brandEm = $em->getRepository(\CoreBundle\Entity\Brand::class)->getBrandByUrl($brand);
$pagination = $paginationModel->initPagination($vehicles['count'], self::PRE_PAGES, 5);
$filters = $this->catalogService->getFilters($params, $request->getLocale(), $state, $vehicleTypeId, $brand, $model, $param, $value, $routeParams);
$catalogCharacteristic = $this->catalogService->catalogCharacteristic($vehicleTypeId, false);
$dealers = $em->getRepository(Dealer::class)->getDealerByBrandUrl($brandEm);
$dealers = array_filter($dealers, fn($dealer) => $dealer->getId() !== 39 && $dealer->getId() !== 16);
return $this->basePortalRender('@Portal/Car/new-in-stock-catalog.html.twig', [
'count' => $vehicles['count'],
'result' => $result,
'allBrands' => $allBrands,
'filters' => $filters,
'perPage' => self::PRE_PAGES,
'type' => $type,
'state' => $state,
'baseParams' => $routeParams,
'searchParams' => $params,
'catalogNav' => $catalogNav,
'pagination' => $pagination,
'page' => $request->query->get('page') ?: 1,
'dealers' => $dealers,
'locale' => $request->getLocale(),
'seoMeta' => $this->seoMetaTag->buildSeoMetaGetParams($request, $routeParams, $params, $param, $value),
'brand' => $brand,
'model' => $model,
'param' => $param,
'value' => $value,
'year' => ($param === 1000) ? $param : $value,
'seo_year' => date('Y'),
'valueParam' => $catalogCharacteristic[$param][$value] ?? null,
'userId' => $this->getUser()
? $this->getUser()->getId()
: null,
]);
}
public function inStockApi(Request $request, Pagination $paginationModel, InStockVehicle $inStockVehicle)
{
$routeParams = $request->attributes->get('_route_params');
$routeParams['brand'] = $request->query->get('brand');
$routeParams['model'] = $request->query->get('model');
$params = $request->query->all();
$param = null;
$value = null;
$model = '';
$brand = '';
$type = $request->get('type');
$state = $request->get('state');
if ($request->get('m-brand')) {
$brand = array_key_first($request->get('m-brand'));
}
if ($request->get('m-model')) {
$model = array_key_first($request->get('m-model'));
}
if (isset($params['dynamic'])) {
$param = array_key_first($params['dynamic']);
if (isset($params['dynamic'][$param])) {
$value = array_key_first($params['dynamic'][$param]);
}
}
if ($brand && $brand === 'all') {
throw new NotFoundHttpException();
}
$vehicles = $this->modelCatalog->findStockByParams($routeParams, $params, self::PRE_PAGES);
if (!$vehicles['data']) {
$vehicles = $this->modelCatalog->noFindStockVehicleByParams($routeParams, $params, self::PRE_PAGES);
}
/** @var InStock $vehicle */
$result = [];
foreach ($vehicles['data'] as $vehicle) {
$inStockModel = $inStockVehicle->createByEntity($vehicle[0]);
$vehicle = $this->modelCatalog->getInStockVehicleByCatalog($this->getUser(), $inStockModel);
$result[] = $vehicle;
}
$typeData = VehicleType::getTypeDataByUrl($type);
if (!$typeData) {
throw new NotFoundHttpException();
}
$vehicleTypeId = $typeData['id'];
$pagination = $paginationModel->initPagination($vehicles['count'], self::PRE_PAGES, 5);
$filters = $this->catalogService->getFilters($params, $request->getLocale(), $state, $vehicleTypeId, $brand, $model, $param, $value, $routeParams);
if ($request->isXmlHttpRequest()) {
return $this->json([
'vehicles' => $this->catalogService->getStockAjaxResult($result, $request->getLocale()),
'pagination' => $pagination,
'count' => $vehicles['count'],
'searchFilters' => $filters
]);
}
return false;
}
/**
* @param Request $request
* @return JsonResponse
*/
public function buildStockFilters(Request $request): JsonResponse
{
$filters = $this->modelCatalog->buildStockFilters($request->request->all(), $request->getLocale());
return $this->json($filters);
}
/**
* @param Request $request
* @return JsonResponse
*/
public function buildUrl(Request $request)
{
$params = $request->request->all();
$type = $params['type'];
$state = $params['state'];
$brand = $params['brand'] ?? null;
$model = $params['model'] ?? null;
$isAjax = $params['isAjax'] ?? null;
if (is_array($brand) && count($brand) == 1) {
$brand = array_keys($brand)[0];
}
if (is_array($model) && count($model) == 1) {
$model = array_keys($model)[0];
}
$baseRouteParams = [
'type' => $type,
'state' => $state,
];
$getParams = [];
foreach ($params as $key => $row) {
if (!in_array($key, ['type', 'state', 'brand', 'model', 'dynamic']) && $row) {
$getParams[$key] = $row;
}
}
$getParams['hasNDS'] = true;
$getParams['isSelect'] = true;
$getParams['inStock'] = true;
if (is_array($brand)) {
$getParams['m-brand'] = $brand;
$brand = null;
} else if ($brand) {
$getParams['m-brand'] = [$brand => true];
}
if (is_array($model)) {
$getParams['m-model'] = $model;
$model = null;
} else if ($model) {
$getParams['m-model'] = [$model => true];
$model = null;
}
$dynamic = [];
if (isset($params['dynamic'])) {
foreach ($params['dynamic'] as $id => $values) {
if (array_key_exists('from', $values) || array_key_exists('to', $values)) {
$dynamic[$id] = $values;
} else {
foreach ($values as $url => $v) {
if ($v != 'false') {
$dynamic[$id][$url] = 1;
}
}
}
}
}
$catalogCharacteristic = array_flip($this->modelCatalog->getCatalogCharacteristicsId());
if (!$brand && !$model && (!count($dynamic) || empty(array_intersect_key($dynamic, $catalogCharacteristic)))) {
$url = $this->router->generate(
'portal_in_stock_filter_catalog',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
$apiUrl = $this->router->generate(
'portal_in_stock_filter_catalog_api',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
return $this->json(['url' => $url, 'apiUrl' => $apiUrl]);
}
if (!$brand && !$model && count($dynamic)) {
$dId = key($dynamic);
$value = key($dynamic[$dId]);
if (!count($dynamic[$dId])) {
unset($dynamic[$dId]);
}
$url = $this->router->generate(
'portal_in_stock_filter_catalog',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
$apiUrl = $this->router->generate(
'portal_in_stock_filter_catalog_api',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
return $this->json(['url' => $url, 'apiUrl' => $apiUrl]);
}
if ($model) {
$baseRouteParams['model'] = $model;
$baseRouteParams['brand'] = $brand;
$url = $this->router->generate(
'portal_in_stock_filter_catalog',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
$apiUrl = $this->router->generate(
'portal_in_stock_filter_catalog_api',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
return $this->json(['url' => $url, 'apiUrl' => $apiUrl]);
}
if ($brand) {
$baseRouteParams['brand'] = $brand;
$url = $this->router->generate(
'portal_in_stock_filter_catalog',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
$apiUrl = $this->router->generate(
'portal_in_stock_filter_catalog_api',
array_merge($baseRouteParams, $getParams, ['dynamic' => $dynamic])
);
return $this->json(['url' => $url, 'apiUrl' => $apiUrl]);
}
}
public function catalogCategory(Request $request, $url, EntityManagerInterface $em, \CoreBundle\Factory\Vehicle $vehicleFactory): Response
{
$dealers = $em->getRepository(Dealer::class)->getCarDealer();
$recommends = $em->getRepository(RecommendGroup::class)->findBy(['state' => 1]);
$recommendGroup = $em->getRepository(RecommendGroup::class)->findOneBy(['url' => $url]);
$recommendGroupVehicles = $em->getRepository(\CoreBundle\Entity\Vehicles\Vehicle::class)->getVehicleByRecommendGroupUrl(['url' => $url]);
$vehicles = $vehicleFactory->createByEntities($recommendGroupVehicles);
$sort = $request->get('sort');
usort($vehicles, function (Vehicle $a, Vehicle $b) use ($sort) {
switch ($sort) {
case 'price-DESC':
return $a->fullPrice() < $b->fullPrice();
default:
return $a->fullPrice() > $b->fullPrice();
}
});
$seoMeta = [];
$urn = preg_replace('/^(\/?ua\/|\/?ru\/)/', '/', $request->getRequestUri());
$seo = $em->getRepository(\CoreBundle\Entity\SeoMetaTag::class)->findOneBy(['domain' => $request->getHost(), 'urn' => $urn]);
if ($seo && $seo->getState()) {
$seoMeta = [
'title' => $seo->getTitle($request->getLocale()),
'description' => $seo->getDescription($request->getLocale()),
'h1' => $seo->getH1($request->getLocale()),
'robots' => $seo->getRobots(),
];
}
return $this->basePortalRender('@Portal/Car/category.html.twig', [
'dealers' => $dealers,
'recommends' => $recommends,
'recommendGroup' => $recommendGroup,
'vehicles' => $vehicles,
'url' => $url,
'seoMeta' => $seoMeta,
]);
}
//TODO remove this magic numbers
private function createPaginator($data, $page = 1, $limit = 21): array
{
$maxPages = 10;
$paginator = [
'total' => ceil(count($data) / $limit),
'current' => $page,
];
if ($paginator['total'] > $maxPages && $page > floor($maxPages / 2)) {
$paginator['start'] = $page - floor($maxPages / 2);
$paginator['end'] = $paginator['start'] + $maxPages - 1;
} else {
$paginator['start'] = 1;
$paginator['end'] = min($paginator['total'], $maxPages);
}
return $paginator;
}
public function getChangeFilter(VehicleFilterService $vehicleFilterService): JsonResponse
{
return $this->json(['success' => true, 'filter' => $vehicleFilterService->initFilter()]);
}
public function initVehicleFilterUrl(VehicleFilterService $vehicleFilterService): JsonResponse
{
return $this->json(['success' => true, 'filterUrl' => $vehicleFilterService->getUrl()]);
}
public function vehicleColor(): JsonResponse
{
return $this->json([
'success' => true,
'image' => $this->modelCatalog->getVehicleImageColor(),
]);
}
}