<?php
namespace App\Ecommerce\Controller;
use App\Form\Type\WatchesFilterType;
use App\Model\SearchHistory;
use App\Service\WishListService;
use App\Website\LinkGenerator\CategoryLinkGenerator;
use App\Website\Tool\Text;
use Carbon\Carbon;
use CoreShop\Bundle\FrontendBundle\Controller\CategoryController as BaseCategoryController;
use CoreShop\Component\Core\Model\CategoryInterface;
use CoreShop\Component\Index\Condition\LikeCondition;
use CoreShop\Component\Index\Factory\FilteredListingFactoryInterface;
use CoreShop\Component\Index\Filter\FilterProcessorInterface;
use CoreShop\Component\Index\Listing\ListingInterface;
use CoreShop\Component\Index\Model\FilterInterface;
use CoreShop\Component\Index\Order\SimpleOrder;
use CoreShop\Component\SEO\SEOPresentationInterface;
use CoreShop\Component\Tracking\Tracker\TrackerInterface;
use Doctrine\Common\Collections\Criteria;
use Exception;
use Pimcore\Model\DataObject\CoreShopCategory;
use Pimcore\Model\DataObject\CoreShopProduct;
use Pimcore\Model\Site;
use Pimcore\Twig\Extension\Templating\Placeholder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class CategoryController extends BaseCategoryController
{
private const FILTER_ID = 'watchesfilter';
protected CoreShopCategory $defaultCategory;
protected array $allowedFilters = [];
protected array $filterintervals = [];
public function __construct(
array $validSortProperties,
string $defaultSortName,
string $defaultSortDirection,
private readonly ParameterBagInterface $parameterBag,
)
{
parent::__construct($validSortProperties, $defaultSortName, $defaultSortDirection);
if (Site::isSiteRequest()) {
throw $this->createNotFoundException('Page not found!');
}
$this->defaultCategory = CoreShopCategory::getByWorkingName('SEIKO', 1);
}
/**
* @param Request $request
* @param Placeholder $placeholder
* @param CategoryLinkGenerator $generator
* @return Response
* @Route("/e-boutique", name="e_boutique", methods={"GET"})
*/
public function eboutiqueAction(Request $request, Placeholder $placeholder, CategoryLinkGenerator $generator): Response
{
return $this->redirect($generator->generate($this->defaultCategory));
}
/**
* @param Request $request
* @param Placeholder $placeholder
* @param CategoryLinkGenerator $generator
* @return Response
* @Route("{path}~c{category}", name="category-list-redirect", defaults={"path"=""}, requirements={"path"=".*?", "category"="\d+"})
*/
public function listRedirectAction(Request $request, Placeholder $placeholder, CategoryLinkGenerator $generator): Response
{
//https://seikoboutique.hu/e-boutique/seiko/prospex/alpinist~c375272 old url, id changed
//https://seikoboutique.hu/e-boutique/seiko/prospex/zend/alpinist~c546013 old url, id changed
$category = CoreShopCategory::getById($request->get('category'));
if ($category instanceof CoreShopCategory) {
return $this->redirect($generator->generate($category));
}
throw $this->createNotFoundException('Page not found!');
}
/**
* @param Request $request
* @param Placeholder $placeholder
* @param CategoryLinkGenerator $generator
* @param WishListService $wishListService
* @return Response
* @Route("{path}-c{category}", name="category-list", defaults={"path"=""}, requirements={"path"=".*?", "category"="\d+"})
*/
public function listAction(Request $request, Placeholder $placeholder, CategoryLinkGenerator $generator, WishListService $wishListService): Response
{
$category = CoreShopCategory::getById($request->get('category'));
if (!$category instanceof CoreShopCategory ||
!$category->getFilter() instanceof FilterInterface ||
!(new CoreShopProduct\Listing())->filterByCategories($category)->count()
) {
return $this->redirect($generator->generate($this->defaultCategory));
}
$session = $request->getSession();
$defaultPerPage = $this->getConfigurationService()->getForStore('system.category.list.per_page.default');
if (!$session->has('perPage')) {
$session->set('perPage', $defaultPerPage);
}
if (!$session->has('sort')) {
$session->set('sort', $this->defaultSortName . '_' . $this->defaultSortDirection);
}
$perPage = $this->getParameterFromRequest($request, 'perPage');
if ($perPage) {
$session->set('perPage', $perPage);
$request->attributes->set('page', 1);
}
$sort = $this->getParameterFromRequest($request, 'sort');
if ($sort) {
$session->set('sort', $sort);
$request->attributes->set('page', 1);
}
$request->attributes->set('perPage', $session->get('perPage'));
$request->attributes->set('sort', $session->get('sort'));
// no comment...
if ($request->getLocale() == 'hu') {
$request->setLocale('hu_HU');
}
$placeholder('breadcrumbCategory')->set($category);
return $this->detail($request, $category, $wishListService, $generator);
}
/**
* @param Request $request
* @param CategoryLinkGenerator $generator
* @return Response
* @Route("/{path}~c{category}/share-search-result", name="shareSearchResultRedirect", methods={"GET"}, requirements={"path"=".*?", "category"="\d+"})
*/
public function shareSearchResultRedirect(Request $request, CategoryLinkGenerator $generator): Response
{
$category = CoreShopCategory::getById($request->get('category'));
if ($category instanceof CoreShopCategory) {
return $this->redirect($generator->generate($this->defaultCategory) . '/share-search-result', 301);
}
throw $this->createNotFoundException('Page not found!');
}
/**
* @param Request $request
* @return Response
* @Route("/{path}-c{category}/share-search-result", name="shareSearchResult", methods={"GET"}, requirements={"path"=".*?", "category"="\d+"})
*/
public function shareSearchResult(Request $request): Response
{
$filter = $request->getSession()->get("watchesfilter");
$currentSearch = new searchHistory();
if (isset($filter["category"])) {
$currentSearch->setCategory($filter["category"]);
} else {
return new Response();
}
if (isset($filter["filterData"])) {
$currentSearch->setFilterFromArray($filter["filterData"]);
} else {
return new Response();
}
$searchHistory = searchHistory::findCategoryFilter($currentSearch->getCategory(), $currentSearch->getFilter());
if ($searchHistory and $searchHistory->getId()) {
$res = sprintf("?filter=%s", (string)$searchHistory->getId());
} else {
$currentSearch->generateUuid();
$currentSearch->save();
$res = sprintf("?filter=%s", (string)$currentSearch->getId());
}
return new Response($res);
}
public function detail(Request $request, CategoryInterface $category = null, WishListService $wishListService = null, CategoryLinkGenerator $generator = null): Response
{
$this->denyAccessUnlessGranted('CORESHOP_CATEGORY_SHOW');
$listModeDefault = $this->getConfigurationService()->getForStore('system.category.list.mode');
$gridPerPageAllowed = $this->getConfigurationService()->getForStore('system.category.grid.per_page');
$gridPerPageDefault = $this->getConfigurationService()->getForStore('system.category.grid.per_page.default');
$listPerPageAllowed = $this->getConfigurationService()->getForStore('system.category.list.per_page');
$listPerPageDefault = $this->getConfigurationService()->getForStore('system.category.list.per_page.default');
$displaySubCategories = $this->getConfigurationService()->getForStore('system.category.list.include_subcategories');
$variantMode = $this->getConfigurationService()->getForStore('system.category.variant_mode');
$page = (int)$this->getParameterFromRequest($request, 'page', 1) ?: 1;
$type = $this->getParameterFromRequest($request, 'type', $listModeDefault);
$defaultPerPage = $type === 'list' ? $listPerPageDefault : $gridPerPageDefault;
$allowedPerPage = $type === 'list' ? $listPerPageAllowed : $gridPerPageAllowed;
$perPage = (int)$this->getParameterFromRequest($request, 'perPage', $defaultPerPage) ?: 15;
$this->validateCategory($request, $category);
$viewParameters = [];
$filterData = [];
$session = $request->getSession();
if ($request->isMethod(Request::METHOD_POST) && $filter = $request->get(self::FILTER_ID)) {
unset($filter['_token']);
$listing = new CoreShopProduct\Listing();
$listing->setLimit(1);
$listing->setOrderKey('wholesalePrice');
$listing->filterByCategories($category);
$min = $listing->setOrder(Criteria::ASC)->current()->getWholesalePrice() / 100;
$max = $listing->setOrder(Criteria::DESC)->current()->getWholesalePrice() / 100;
if (empty($filter['search'])) {
unset($filter['search']);
} else {
$filter['search'] = trim(strip_tags($filter['search']));
}
$minValue = $min;
if (!empty($filter['price']['min'])) {
$minValue = (int)$filter['price']['min'];
if ($minValue < $min || $minValue > $max) {
unset($filter['price']['min']);
} else {
$filter['price']['min'] = $minValue;
}
} else {
unset($filter['price']['min']);
}
if (!empty($filter['price']['max'])) {
$maxValue = (int)$filter['price']['max'];
if ($maxValue < $min || $maxValue > $max) {
unset($filter['price']['max']);
} elseif ($maxValue < $minValue) {
$filter['price']['max'] = $minValue;
} else {
$filter['price']['max'] = $maxValue;
}
} else {
unset($filter['price']['max']);
}
if (!empty($filter['price']['outlet']) && filter_var($filter['price']['outlet'], FILTER_VALIDATE_BOOLEAN)) {
$filter['price']['outlet'] = true;
} else {
unset($filter['price']['outlet']);
}
if ($session->has(self::FILTER_ID) && !$filter) {
$session->remove(self::FILTER_ID);
}
if ($filter) {
$session->set(self::FILTER_ID, ['category' => $category->getId(), 'filterData' => $filter]);
}
return $this->redirect($generator->generate($category));
}
if ($request->get('filter')) {
try {
$filter = $request->get('filter');
if (filter_var($filter, FILTER_VALIDATE_INT) !== false) {
$searchHistory = searchHistory::getById($filter);
if ($searchHistory and $searchHistory->getId()) {
$session->set(self::FILTER_ID, ['category' => $searchHistory->getCategory(), 'filterData' => $searchHistory->getFilter()]);
return $this->redirect($generator->generate($category));
}
}
$searchHistory = searchHistory::getByUuId($filter);
if ($searchHistory and $searchHistory->getId()) {
$session->set(self::FILTER_ID, ['category' => $searchHistory->getCategory(), 'filterData' => $searchHistory->getFilter()]);
return $this->redirect($generator->generate($category));
}
} catch (Exception $e) {
}
}
if ($session->has(self::FILTER_ID)) {
$sessionFilter = $session->get(self::FILTER_ID);
if (!empty($sessionFilter['category']) &&
!empty($sessionFilter['filterData']) &&
$sessionFilter['category'] === $category->getId() &&
count($sessionFilter['filterData'])
) {
$filterData = $sessionFilter['filterData'];
} else {
$session->remove(self::FILTER_ID);
}
}
if ($request->get('reset-filter')) {
$session->remove(self::FILTER_ID);
$filterData = [];
if (!$request->isXmlHttpRequest()) {
return $this->redirect($generator->generate($category));
}
}
$form = $this->container->get('form.factory')->createNamed(self::FILTER_ID, WatchesFilterType::class, $filterData, [
'category' => $category
]);
$filteredList = $this->get(FilteredListingFactoryInterface::class)->createList($category->getFilter(), $request->request);
$filteredList->setLocale($request->getLocale());
$filteredList->setVariantMode($variantMode ?: ListingInterface::VARIANT_MODE_HIDE);
$filteredList->addCondition(new LikeCondition('stores', 'both', sprintf('%1$s%2$s%1$s', ',', $this->getContext()->getStore()->getId())), 'stores');
$filteredList->addCondition(new LikeCondition('parentCategoryIds', 'both', (string)$category->getId()), 'parentCategoryIds');
$filteredList->addSeikoFilterConditions($filterData, $this->allowedFilters, $this->filterintervals);
$defaultSortKey = $this->defaultSortName . '_' . $this->defaultSortDirection;
$sort = $this->getParameterFromRequest($request, 'sort', $defaultSortKey);
$sortParsed = $this->parseSorting($sort);
if ($sortParsed['name'] == 'creationDate') {
$filteredList->addOrder(new SimpleOrder('newsfromdate', $sortParsed['direction']));
$filteredList->addOrder(new SimpleOrder('name', $sortParsed['direction']));
$filteredList->addOrder(new SimpleOrder('creationDate', $sortParsed['direction']));
} elseif ($sortParsed['name'] == 'collection') {
$filteredList->addOrder(new SimpleOrder('collection', $sortParsed['direction']));
$filteredList->addOrder(new SimpleOrder('name', $sortParsed['direction']));
$filteredList->addOrder(new SimpleOrder('creationDate', $sortParsed['direction']));
} else {
$filteredList->addOrder(new SimpleOrder($sortParsed['name'], $sortParsed['direction']));
$filteredList->addOrder(new SimpleOrder('name', $sortParsed['direction']));
}
$currentFilter = $this->get(FilterProcessorInterface::class)->processConditions($category->getFilter(), $filteredList, $request->query);
$preparedConditions = $this->get(FilterProcessorInterface::class)->prepareConditionsForRendering($category->getFilter(), $filteredList, $currentFilter);
$paginator = $this->getPaginator()->paginate($filteredList, $page, $perPage);
$viewParameters['list'] = $filteredList;
$viewParameters['filter'] = $category->getFilter();
$viewParameters['currentFilter'] = $currentFilter;
$viewParameters['paginator'] = $paginator;
$viewParameters['conditions'] = $preparedConditions;
$viewParameters['category'] = $category;
$viewParameters['page'] = $page;
$viewParameters['perPage'] = $perPage;
$viewParameters['type'] = $type;
$viewParameters['perPageAllowed'] = $allowedPerPage;
$viewParameters['sort'] = $sort;
$viewParameters['sortDirection'] = $sortParsed['direction'];
$viewParameters['validSortElements'] = $this->validSortProperties;
$viewParameters['filterForm'] = $form->createView();
$viewParameters['filterData'] = $filterData;
$viewParameters['resetFilter'] = uniqid(Carbon::now()->getTimestamp());
$viewParameters['filterlink'] = true;
if ($filterData) {
$viewParameters['filterlink'] = true;
$session->set('filterLinkData', true);
}
$productList = new CoreShopProduct\Listing();
$productList->setGroupBy('brand');
$products = $productList->load();
$viewParameters['categoriesTab'] = [];
foreach ($products as $product) {
$categ = CoreShopCategory::getByWorkingName($product->getBrand(), 1);
if ($categ instanceof CoreShopCategory) {
$name = $categ->getWorkingName();
if (in_array(mb_strtoupper($name), array_map(function($e) { return mb_strtoupper($e); }, $this->parameterBag->get('app.categories.tab')))) {
$viewParameters['categoriesTab'][$name] = [
'path' => $generator->generate($categ),
'name' => Text::toCamelCase($categ->getWorkingName())
];
}
}
}
$wishlist = [];
$this->get(TrackerInterface::class)->trackProductImpression([
'itemlist' => $paginator->getItems(),
'item_list_name' => $category->getName(),
'item_list_id' => $category->getId()
]);
$request->getSession()->set('ga4_select_item', [
'item_list_name' => $category->getName(),
'item_list_id' => $category->getId()
]);
foreach ($paginator as $product) {
$wishlist[$product->getId()] = $wishListService->hasItem($product);
}
$viewParameters['wishlist'] = $wishlist;
$this->get(SEOPresentationInterface::class)->updateSeoMetadata($category);
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'success' => true,
'filterLink' => $viewParameters['filterlink'],
'filters' => $this->renderView($this->templateConfigurator->findTemplate('Category/_filter.html'), $viewParameters),
'products' => $this->renderView($this->templateConfigurator->findTemplate('Category/_productlist.html'), $viewParameters)
]);
}
return $this->render($this->templateConfigurator->findTemplate('Category/index.html'), $viewParameters);
}
public function setAllowedFilters(array $filters): void
{
$this->allowedFilters = $filters;
}
public function setFilterIntervals(array $filterintervals): void
{
$this->filterintervals = $filterintervals;
}
}