first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,636 @@
<?php
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Search\FulltextElastic;
use KupShop\CatalogBundle\Util\Product\ProductDiscountCalculator;
use KupShop\ContentBundle\Entity\ProductUnified;
use KupShop\I18nBundle\Entity\Country;
use KupShop\I18nBundle\Translations\ParametersListTranslation;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\CountryContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use Query\Operator;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Component\HttpFoundation\JsonResponse;
class AutocompleteView
{
public $query;
/** @var UrlFinder */
protected $urlFinder;
/** @required */
public CountryContext $countryContext;
/** @required */
public ProductDiscountCalculator $productDiscountCalculator;
public function __construct()
{
$this->query = new \Query();
}
public function handleAutocomplete()
{
$type = getVal('type');
// Remove '-' and '_', Capitalize each word
$type = strtr(ucwords(strtr($type, ['_' => ' ', '-' => ' '])), [' ' => '']);
if (empty($type)) {
return new JsonResponse();
}
$search = $this->prepareSearch(getVal('term'));
$this->query->limit = getVal('limit', 10) ?: 100;
$result = $this->handle($type, $search);
return new JsonResponse($result);
}
public function handle($type, $search)
{
// Store search term to query data
$this->query->data['search'] = $search;
$this->query->data['search_both'] = "%{$search}%";
$this->query->data['search_left'] = "{$search}%";
if (method_exists($this, 'handle'.ucfirst($type))) {
return call_user_func([$this, 'handle'.ucfirst($type)]);
}
return null;
}
public function handleProduct()
{
$this->query->fields = 'title as label';
$this->query->from = 'products p';
$this->query->where = 'p.figure="Y" AND p.title LIKE :search_both';
$this->query->order = 'p.title';
return $this->getQueryData();
}
public function handleProductCategories()
{
return $this->handleProductCategoriesFulltext();
}
public function handleProductCategoriesFulltext()
{
// Tady si schválně říkám o FulltextElastic a ne Interface, protože nechci aby mi přišel LuigisBox. Ten nepoužívá naše autocomplete
$fulltext = ServiceContainer::getService(FulltextElastic::class);
$fulltext->setCurlTimeout(10);
$term = $this->query->data['search'];
$enabledTopics = $fulltext->getIndexTypes();
if ($disabled_topics = Config::get()['Modules'][\Modules::SEARCH]['disabled_topics'] ?? null) {
$enabledTopics = array_values(array_diff($enabledTopics, $disabled_topics));
}
$multiSearchResult = $fulltext->search(
$term,
$this->getFulltextSearchConfig($enabledTopics),
$enabledTopics
);
return $this->processFulltextResults($multiSearchResult, $fulltext->multiSearchResultTotals);
}
public function handleDeliveryInPersonSellers(): array
{
if (!findModule(\Modules::SELLERS)) {
return [];
}
$this->query->fields = 'id, psc as value, title as name, CONCAT_WS(", ", psc, city, street, number) as address';
$this->query->from = 'sellers';
$search = get_search_query($this->query->data['search'], [
['field' => 'title', 'match' => 'both'],
['field' => 'psc', 'match' => 'both'],
['field' => 'city', 'match' => 'both'],
['field' => 'street', 'match' => 'both'],
]);
$this->query->data = $search['data'];
$this->query->where = $search['where'];
return $this->getQueryData();
}
public function handleDeliveryBalikDoRuky()
{
$this->query->fields = 'psc as value, name, region, time_zone, address';
$this->query->order = 'psc';
$this->query->from = '`kupshop_shared`.`delivery_balik_na_postu`';
$this->query->where = 'name LIKE :search_left OR psc LIKE :search_left';
return $this->getQueryData();
}
public function handleDeliveryBalikovna()
{
$this->query->fields = 'zip as value, name, city, city_part, address';
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_balikovna`';
$this->query->where = 'name LIKE :search_left OR city LIKE :search_left OR city_part LIKE :search_left OR address LIKE :search_both OR zip LIKE :search_left';
return $this->getQueryData();
}
public function handleDeliveryZasilkovna()
{
$this->query->fields = 'zip, name, hours, labelRouting, id as value';
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_zasilkovna`';
$this->query->where = '(name LIKE :search_both OR zip LIKE :search_both)';
$onlyVisible = getVal('onlyVisible', null, 'Y');
if ($onlyVisible == 'Y') {
$this->query->where .= " AND visible = 'Y' ";
}
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
if ($currency = getVal('currency')) {
$currencyCode = $currency;
} else {
$currencyContext = ServiceContainer::getService(\KupShop\KupShopBundle\Context\CurrencyContext::class);
$currencyCode = $currencyContext->getActiveId();
}
if (!empty($currencyCode)) {
switch ($currencyCode) {
case 'CZK': $this->query->where .= ' AND country=\'cz\'';
break;
case 'EUR': $this->query->where .= ' AND country=\'sk\'';
break;
case 'HUF': $this->query->where .= ' AND country=\'hu\'';
break;
case 'RON': $this->query->where .= ' AND country=\'ro\'';
break;
case 'PLN': $this->query->where .= ' AND country=\'pl\'';
break;
}
}
return $this->getQueryData();
}
public function handleDeliveryPplparcelshop()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_pplparcelshop`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$countries = "'".implode("','", array_map(function (Country $c) {return $c->getId(); }, $this->countryContext->getSupported()))."'";
if ($country = getVal('country')) {
$countries = "'{$country}'";
}
if (!empty($countries)) {
$this->query->where .= ' AND country IN ('.$countries.')';
}
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryUlozenka()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_ulozenka`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryInTime()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_intime`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryDpdpickup()
{
$this->query->fields = 'place, zip, city, street, id as value';
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_dpdpickup`';
$this->query->where = '(LPAD(zip, 5, 0) LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR place LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliverySpbalikobox()
{
$this->query->fields = 'zip, city, street, type, id as value, name';
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_sp_balikobox`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryGlsparcelshop()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_glsparcelshop`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryGeispoint()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_geispoint`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleDeliveryPaczkomaty()
{
$this->query->fields = "zip, city, street, type, id as value, CONCAT(city, ', ', street, ', ', name) AS name";
$this->query->order = 'zip';
$this->query->from = '`kupshop_shared`.`delivery_paczkomaty`';
$this->query->where = '(zip LIKE :search_both OR city LIKE :search_both OR street LIKE :search_both OR name LIKE :search_both)';
$except = getVal('except');
if (!empty($except)) {
$except = array_filter(
explode(',', $except),
function ($id) {
return (is_numeric($id)) ? true : false;
}
);
$this->query->where .= ' AND id NOT IN ('.implode(',', $except).')';
}
return $this->getQueryData();
}
public function handleParameterValues(): array
{
$term = $this->query->data['search'] ?? '';
$search = [$term];
if (getVal('fulltext')) {
$search = array_filter(explode(' ', $term));
}
$qb = sqlQueryBuilder()
->select('pl.id as value, pl.position')
->from('parameters_list', 'pl')
->andWhere(Operator::equals(['pl.id_parameter' => getVal('parameterId')]))
->andWhere(
Translation::joinTranslatedFields(
ParametersListTranslation::class,
function (QueryBuilder $qb, $columnName, $translatedField) use ($search) {
$searchField = Operator::coalesce($translatedField, "pl.{$columnName}");
$andX = [];
foreach ($search as $value) {
$andX[] = Operator::like([$searchField => "%{$value}%"]);
}
$qb->andWhere(Operator::andX($andX));
}, ['value' => 'name']
)
)
->orderBy('position');
if ($limit = getVal('limit')) {
$qb->setMaxResults((int) $limit);
}
return $qb->execute()->fetchAllAssociative();
}
public function getQueryData()
{
return sqlFetchAll($this->query->execute());
}
public function prepareSearch($search)
{
$search = trim(urldecode($search));
return $search;
}
protected function processProducts(array $sphinxResult)
{
$productList = $this->getProductList();
$sphinxIds = array_keys($sphinxResult);
$productList->andSpec(function (\Query\QueryBuilder $qb) use ($sphinxIds) {
$qb->setParameter('productIds', $sphinxIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
return $qb->expr()->in('p.id', ':productIds');
});
$productList->orderBy('FIELD(p.id, :productIds)');
$productList->fetchProducers();
$productList->fetchImages(2);
$productList->fetchSets();
$productList->fetchStoresInStore();
return array_map(function (\Product $product) {
return $this->getProductResult($product);
}, $productList->getProducts()->getValues());
}
protected function processSections(array $sphinxResult)
{
foreach ($sphinxResult as &$section) {
$section['label'] = $section['path'] ?? '';
}
return array_values($sphinxResult);
}
protected function processProducers(array $sphinxResult)
{
foreach ($sphinxResult as &$producer) {
$producer['label'] = $producer['name'] ?? '';
}
return array_values($sphinxResult);
}
protected function processArticles(array $result)
{
foreach ($result as &$article) {
$article['label'] = $article['title'];
}
return array_values($result);
}
protected function processPages(array $result): array
{
foreach ($result as &$page) {
$page['label'] = $page['name'];
}
return array_values($result);
}
protected function getProductList(): \ProductList
{
$productList = ServiceContainer::getService(\KupShop\CatalogBundle\ProductList\ProductList::class);
$productList->applyDefaultFilterParams();
return $productList;
}
protected function getProductResult(\Product $product): array
{
$productPrice = $product['productPrice'];
$price = $productPrice['price_with_vat'];
$priceWithoutVat = $productPrice['price_without_vat'];
$productDiscountResult = $this->productDiscountCalculator->calculate(
new ProductUnified($product)
);
$priceOriginal = $productPrice->getOriginalPrice()->getPriceWithoutDiscount();
return [
'id' => $product->id,
'image' => ($product->image ? $this->urlFinder->staticUrl($product->image['src']) : ''),
'label' => $product->title,
'discount' => $product->discount->asFloat(),
'price' => printPrice($price),
'price_without_vat' => printPrice($priceWithoutVat),
'price_array' => $product->price_array,
'priceOriginal' => printPrice($priceOriginal),
'annotation' => $product->descr,
'producer' => $product->producer ?? [],
'inStore' => $product->inStore,
'deliveryTime' => $product->deliveryTime,
'deliveryTimeText' => $product->deliveryTimeText,
'deliveryTimeRaw' => $product->deliveryTimeRaw,
'storesInStore' => $product->storesInStore ?? [],
'productDiscount' => [
'discount' => $productDiscountResult->discount->asFloat(),
'priceForDiscount' => $productDiscountResult->priceForDiscount ? printPrice($productDiscountResult->priceForDiscount) : null,
'priceOriginal' => $productDiscountResult->priceOriginal ? printPrice($productDiscountResult->priceOriginal) : null,
'priceCommon' => $productDiscountResult->priceCommon ? printPrice($productDiscountResult->priceCommon) : null,
],
'campaign_codes' => $product->campaign_codes ?? [],
];
}
/**
* @required
*/
public function setUrlFinder(UrlFinder $urlFinder): void
{
$this->urlFinder = $urlFinder;
}
public function getFulltextSearchConfig(array $enabledTopics): array
{
$maxResults = 6;
$config = [];
foreach ($enabledTopics as $type) {
$config[$type] = [
'count' => $maxResults,
'offset' => 0,
];
}
$config[FulltextElastic::INDEX_PRODUCTS]['order'] = '-weight';
return $config;
}
public function processFulltextResults(array $multiSearchResult, array $totals): array
{
$result = [];
foreach ($multiSearchResult as $type => $results) {
if (!$results) {
continue;
}
switch ($type) {
case FulltextElastic::INDEX_PRODUCTS:
$result['Produkty'] = [
'label' => 'Produkty',
'rows' => $totals[$type] ?? 0,
'items' => $this->processProducts($results),
];
break;
case FulltextElastic::INDEX_SECTIONS:
$result['Kategorie'] = [
'label' => 'Kategorie',
// min(total, 20), protoze SearchView zobrazuje max 20 vysledku
'rows' => min($totals[$type] ?? 0, 20),
'items' => $this->processSections($results),
];
break;
case FulltextElastic::INDEX_PRODUCERS:
$result['Vyrobci'] = [
'label' => 'Výrobci',
// min(total, 20), protoze SearchView zobrazuje max 20 vysledku
'rows' => min($totals[$type] ?? 0, 20),
'items' => $this->processProducers($results),
];
break;
case FulltextElastic::INDEX_ARTICLES:
$result['Clanky'] = [
'label' => 'Články',
// min(total, 20), protoze SearchView zobrazuje max 20 vysledku
'rows' => min($totals[$type] ?? 0, 20),
'items' => $this->processArticles($results),
];
break;
case FulltextElastic::INDEX_PAGES:
$result['Stranky'] = [
'label' => 'Stránky',
// min(total, 20), protoze SearchView zobrazuje max 20 vysledku
'rows' => min($totals[$type] ?? 0, 20),
'items' => $this->processPages($results),
];
break;
default:
$result[$type] = [
'label' => '$type',
// min(total, 20), protoze SearchView zobrazuje max 20 vysledku
'rows' => min($totals[$type] ?? 0, 20),
'items' => $results,
];
}
}
return $result;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Created by PhpStorm.
* User: ondra
* Date: 19.1.18
* Time: 12:30.
*/
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Section\SectionTree;
use KupShop\ComponentsBundle\View\ComponentsViewInterface;
use KupShop\ComponentsBundle\View\ComponentsViewTrait;
use KupShop\KupShopBundle\Views\View;
class CategoryListView extends View implements ComponentsViewInterface
{
use ComponentsViewTrait;
protected string $entrypoint = 'section_list';
protected $template = 'category_list.tpl';
public function getTemplate(): string
{
if (findModule(\Modules::COMPONENTS)) {
return 'view/section_list.html.twig';
}
return parent::getTemplate();
}
/**
* @var SectionTree
*/
private $sectionTree;
public function __construct(SectionTree $sectionTree)
{
$this->sectionTree = $sectionTree;
}
public function getBodyVariables()
{
$vars = parent::getBodyVariables();
if (!findModule(\Modules::COMPONENTS)) {
$vars['category_list'] = $this->sectionTree->getTree();
}
return $vars;
}
public function getTitle()
{
return translate('title', 'category_list');
}
public function getBreadcrumbs()
{
return getReturnNavigation(-1, 'NO_TYPE', [$this->getTitle()]);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\View;
interface CategoryRequestHandler
{
public const SEARCH_CATEGORY_ID = -1;
/** @param string $campaign */
public function setCampaign($campaign);
/** @param int|string $producerId */
public function setProducerId($producerId);
/** @param int|string $parameterValueId */
public function setParameterValueId($parameterValueId);
/** @param int|string $categoryId */
public function setCategoryId($categoryId);
public function setFilterData(array $filterData): self;
public function getCorrectUrl(): ?string;
/**
* @param array|mixed $indexedFilterData filterData {@see \Filter::setFilterData()} from indexed_filter
*/
public function setParsedURLData($indexedFilterData);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\CatalogBundle\Util\ActiveCategory;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class FavoriteView extends CategoryView
{
protected $template = 'category.favorites.tpl';
public function __construct(EventDispatcherInterface $dispatcher, ProductList $productList, ActiveCategory $activeCategory)
{
parent::__construct($dispatcher, $productList, $activeCategory);
$this->proxyCacheEnabled = false;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Repository\ProducersRepository;
use KupShop\ComponentsBundle\View\ComponentsViewInterface;
use KupShop\KupShopBundle\Views\View;
use Symfony\Contracts\Service\Attribute\Required;
class ProducersListView extends View implements ComponentsViewInterface
{
protected $template = 'producers.tpl';
protected string $entrypoint = 'producers';
#[Required]
public ProducersRepository $producersRepository;
public function __construct()
{
$this->proxyCacheEnabled = findModule(\Modules::PROXY_CACHE, 'content');
}
public function getBodyVariables(): array
{
$vars = parent::getBodyVariables();
$vars['producers'] = $this->producersRepository->getProducers();
return $vars;
}
public function fetchPhotos($size = 0): array
{
$this->producersRepository->setImageSize($size);
return $this->producersRepository->getProducers(true);
}
public function getTitle()
{
return translate('returnNav', 'producers');
}
public function getWpjToolbar(): array
{
$arr = [
'url' => getAdminUrl('list', ['type' => 'producers']),
'title' => 'Upravit výrobce',
'translateUrl' => getAdminUrl('list', [
'type' => 'translateProducers',
'iframe' => 1,
]),
'translateTitle' => 'Překlad výrobců',
];
return array_merge(parent::getWpjToolbar(), $arr);
}
/**
* @return ProducersListView
*/
public function setSorting($sorting)
{
$this->producersRepository->setSorting($sorting);
return $this;
}
public function getTemplates(): iterable
{
yield $this->template;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Util\ReviewsUtil;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Views\View;
class ReviewsListView extends View
{
protected $template = 'reviews/reviews.list.tpl';
private int $page = 1;
public function __construct(private readonly ReviewsUtil $reviewsUtil)
{
}
public function setPage(int $page): self
{
$this->page = $page;
return $this;
}
public function getTitle()
{
return translate('reviewsList', 'reviews');
}
public function getBodyVariables(): array
{
$vars = parent::getBodyVariables();
$pager = $this->getPager();
$languageContext = Contexts::get(LanguageContext::class);
[$_, $reviews] = $this->reviewsUtil->getReviews(
$languageContext->getActiveId(),
$this->getReviewsLanguages(),
spec: $pager->getSpec()
);
$vars['reviews'] = $reviews;
$vars['pager'] = $pager;
return $vars;
}
protected function getReviewsLanguages(): array
{
return [];
}
protected function getItemsOnPage(): int
{
return 50;
}
private function getPager(): \Pager
{
$totals = $this->reviewsUtil->getReviewsTotals();
$pager = new \Pager(page: $this->page);
$pager->setOnPage($this->getItemsOnPage());
$pager->setTotal($totals['count']);
return $pager;
}
}

View File

@@ -0,0 +1,248 @@
<?php
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Util\ReviewsUtil;
use KupShop\ContentBundle\Util\Captcha;
use KupShop\ContentBundle\View\Exception\ValidationException;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use Product;
use Query\Operator;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Service\Attribute\Required;
class ReviewsView extends View
{
use \DatabaseCommunication;
use RequestTrait;
protected ReviewsUtil $reviewsUtil;
// tohle by bylo potřeba asi udělat jinak ?? > ale na X shopech bych ideálně potřeboval tuhle šablonu pro přidání hodnocení
protected $template = 'focus/focus.review-form.tpl';
private $user;
private $checkUserLog;
protected $productId;
/**
* @var SessionInterface
*/
protected $session;
#[Required]
public function setReviewsUtil(ReviewsUtil $reviewsUtil): void
{
$this->reviewsUtil = $reviewsUtil;
}
public function getBodyVariables()
{
$vars = [];
if (!$this->productId) {
$this->productId = $this->request->get('id_product');
}
$product = $this->getProduct();
if (!$product) {
return $vars;
}
$review = $this->reviewsUtil;
$fields = ['id_product', 'id_product_variation', 'date', 'rating', 'summary', 'pros', 'cons',
'id_user', 'figure', 'id_order', 'data', 'source', ];
if (findModule(\Modules::SALES)) {
$fields[] = 'id_sale';
}
$vars['product'] = $product;
$vars['id_product_variation'] = null;
$vars['date'] = date('Y-m-d H:i:s');
$vars['figure'] = ReviewsUtil::RANK_UNCONFIRMED;
$vars['id_user'] = null;
$vars['verified'] = false;
$vars['data'] = null;
$vars['source'] = null;
if ($name = $this->request->get('name')) {
$fields[] = 'name';
$vars['name'] = $name;
}
$data = $this->request->request->all();
$boughtProduct = null;
if (!empty($data['email']) && !empty($data['order_no'])) {
$vars['data']['email'] = $data['email'];
$vars['data']['order_no'] = $data['order_no'];
// nacteni objednavky pro uzivatele bez registrace
$boughtProduct = $review->hasUserBoughtProduct($this->productId, null, $data['email'], $data['order_no']);
if ($boughtProduct) {
$this->user = \User::createFromSpec(Operator::equals(['email' => $data['email']]));
$vars['id_user'] = $this->user ? $this->user->id : null;
$this->setTemplate('block.reviews.form.tpl');
} else {
$vars['error'] = translate('error_order_not_found', 'returns');
}
} else {
$user = $this->getUser();
$vars['id_user'] = $user ? $user->id : null;
$boughtProduct = $review->hasUserBoughtProduct($this->productId, $vars['id_user']);
}
if ($boughtProduct) {
$vars['verified'] = true;
// possible types: order, sale
$vars["id_{$boughtProduct['type']}"] = $boughtProduct['id'];
if ($this->productId != $boughtProduct['id_product']) {
$this->setProductId($boughtProduct['id_product']);
$vars['product'] = $this->getProduct();
}
}
// Allow rating only once per product
if ($review->hasUserAlreadyRated($this->productId, $vars['id_user'])) {
$vars['already_rated'] = true;
return $vars;
}
$acn = $data['acn'] ?? null;
if ($acn == 'SendReview') {
// Rating is missing
if (!$this->request->get('rating')) {
return $vars;
}
if ($this->checkCaptcha($data)) {
$this->addErrorMessage(translate('errorCaptcha', 'form'));
$vars['error'] = translate('errorCaptcha', 'form');
$vars['data'] = $data;
return $vars;
}
$data = array_merge($this->request->request->all(), $vars);
if (findModule(\Modules::TRANSLATIONS)) {
$languagesContext = ServiceContainer::getService(LanguageContext::class);
$data['id_language'] = $languagesContext->getActiveId();
$fields[] = 'id_language';
}
if (!$this->addReview($review, $data, $fields)) {
return $vars;
}
$vars['sent'] = true;
return $vars;
}
$verified_only = \Settings::getDefault()['review_verified_only'] ?? 'N';
if (($verified_only == 'Y') && !$vars['verified']) {
$this->setTemplate('focus/focus.review-verify-form.tpl');
}
return $vars;
}
public function setCheckUserLog($checkUserLog)
{
$this->checkUserLog = $checkUserLog;
return $this;
}
protected function addReview(ReviewsUtil $review, array $data, array $fields): ?int
{
$reviewId = sqlGetConnection()->transactional(
function () use ($review, $data, $fields) {
if (!empty($data['data'])) {
$data['data'] = json_encode($data['data']);
}
$this->insertSQL('reviews', $this->filterFields($data, $fields));
$reviewId = (int) sqlInsertId();
// Confirm review without comments
if (!$review->hasComment($data)) {
$this->updateSQL('reviews', ['figure' => ReviewsUtil::RANK_CONFIRMED], ['id' => $reviewId]);
}
return $reviewId;
}
);
$this->session->set(
'review',
[
'email' => getVal('email', $data),
'firstname' => getVal('name', $data),
]
);
return $reviewId;
}
protected function checkUserLog()
{
if ($this->checkUserLog) {
// Allow rating only to logged in users
if (!$this->getUser()) {
redirection('LOGIN');
}
}
}
protected function checkCaptcha(array $data)
{
// Check CAPTCHA
if (!$this->getUser()) {
try {
Captcha::checkCaptcha($data, 'shared');
} catch (ValidationException $e) {
return 1;
}
return 0;
}
}
private function getUser()
{
if ($this->user) {
return $this->user;
}
return $this->user = \User::getCurrentUser();
}
/**
* @required
*/
public function setSession(SessionInterface $session)
{
$this->session = $session;
}
public function setProductId(int $id): void
{
$this->productId = $id;
}
private function getProduct(): ?\Product
{
if ($this->productId) {
$product = new \Product();
if ($product->createFromDB($this->productId)) {
return $product;
}
}
return null;
}
}

View File

@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\CatalogBundle\Section\SectionTree;
use KupShop\KupShopBundle\Views\View;
use Query\Operator;
use Query\Product;
class SearchPreloadView extends View
{
protected $template = 'search/search.preload.tpl';
protected ProductList $productList;
protected SectionTree $sectionTree;
public function __construct(ProductList $productList, SectionTree $sectionTree)
{
$this->productList = $productList;
$this->sectionTree = $sectionTree;
}
public function getBodyVariables()
{
$vars = parent::getBodyVariables();
return array_merge($vars, $this->getPreloadData());
}
protected function getPreloadData()
{
$vars = [];
$dbcfg = \Settings::getDefault();
$config = $dbcfg->fulltext['preload'] ?? [];
foreach (['products', 'sections', 'producers'] as $type) {
$method = 'preload'.ucfirst($type);
if (method_exists($this, $method)) {
$vars[$type] = $this->{$method}($config[$type] ?? []);
}
}
return $vars;
}
protected function preparePreloadProductList(array $ids): ProductList
{
$this->productList->applyDefaultFilterParams();
$this->productList->andSpec(Product::productsIds($ids));
$this->productList->fetchImages(2);
return $this->productList;
}
protected function preloadProducts(array $ids): ProductCollection
{
return $this->preparePreloadProductList($ids)->getProducts();
}
protected function preloadSections(array $ids): array
{
$result = [];
foreach ($ids as $id) {
$result[$id] = $this->sectionTree->getSectionById($id);
}
return $result;
}
public function preloadProducers(array $ids): array
{
if (!findModule(\Modules::PRODUCERS)) {
return [];
}
$qb = sqlQueryBuilder()
->select('pr.id, pr.name')
->from('producers', 'pr')
->where(Operator::inIntArray($ids, 'pr.id'));
$result = [];
foreach ($qb->execute() as $item) {
$result[$item['id']] = [
'id' => (int) $item['id'],
'name' => $item['name'],
];
}
return $result;
}
}

View File

@@ -0,0 +1,680 @@
<?php
namespace KupShop\CatalogBundle\View;
use KupShop\CatalogBundle\Event\CatalogEvent;
use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\CatalogBundle\Query\Search;
use KupShop\CatalogBundle\Search\Exception\FulltextException;
use KupShop\CatalogBundle\Search\FulltextElastic;
use KupShop\CatalogBundle\Search\FulltextInterface;
use KupShop\ContentBundle\Util\ArticleList;
use KupShop\ContentBundle\Util\MenuUtil;
use KupShop\I18nBundle\Translations\MenuLinksTranslation;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Logging\SentryLogger;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use Query\Operator;
use Query\Product;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class SearchView extends View
{
use RequestTrait;
protected $template = 'search.tpl';
/** @var string String to search */
protected $searchTerm;
/** @var FulltextElastic */
protected $fulltextSearch;
protected $enabledTopics;
protected $topicsModules = [
'products' => [\Modules::SEARCH],
'articles' => [\Modules::ARTICLES],
'sections' => [\Modules::PRODUCTS_SECTIONS],
'producers' => [\Modules::PRODUCERS],
'pages' => [\Modules::MENU],
];
protected $multiSearchResult = [];
/** @var SentryLogger */
private $sentryLogger;
/** @var ProductList */
private $productList;
private EventDispatcherInterface $eventDispatcher;
public function __construct()
{
$this->proxyCacheEnabled = findModule(\Modules::PROXY_CACHE, 'search', findModule(\Modules::PROXY_CACHE, 'category'));
}
/**
* @required
*/
public function setSentryLogger(SentryLogger $sentryLogger): void
{
$this->sentryLogger = $sentryLogger;
}
/**
* @required
*/
public function setProductList(ProductList $productList): void
{
$this->productList = $productList;
}
/** @required */
public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void
{
$this->eventDispatcher = $eventDispatcher;
}
public function getTitle()
{
return $this->searchTerm ?? translate('title', 'search');
}
public function setSearchTerm(string $searchTerm): SearchView
{
$this->searchTerm = $searchTerm;
return $this;
}
public function getHeaderVariables()
{
return parent::getHeaderVariables() + ['searchString' => $this->searchTerm];
}
public function getBreadcrumbs()
{
return getReturnNavigation(-1, 'NO_TYPE', [translate('returnNav', 'search')]);
}
public function getBodyVariables()
{
$pageVars = array_merge(parent::getBodyVariables(), [
'title' => translate('h1_title', 'search'),
'search' => $this->searchTerm,
'searching' => 0,
'listShow' => $this->getListShowType(),
]);
// # VYHLEDAVANI V ESHOPU
if ($this->searchTerm) {
$pageVars['searching'] = 1;
$pageVars['results'] = $this->getSearchResults();
}
return $pageVars;
}
/** Search all enabled topics.
* @return array
*/
protected function getSearchResults()
{
$results = [];
// process multi-search
$enabledTopics = array_merge($this->fulltextSearch->getIndexTypes(), ['pages']);
if ($disabled_topics = Config::get()['Modules'][\Modules::SEARCH]['disabled_topics'] ?? null) {
$enabledTopics = array_diff($enabledTopics, $disabled_topics);
}
$this->setEnabledTopics($enabledTopics);
$enabledTypes = [];
foreach ($this->fulltextSearch->getIndexTypes() as $type) {
if ($this->isTopicEnabled($type)) {
$enabledTypes[] = $type;
}
}
$this->fulltextSearch->setDynamicFilters($this->request->get('dynamic_filter', []));
try {
$this->multiSearchResult = $this->fulltextSearch->search(
$this->searchTerm,
$this->getSearchConfig(),
$enabledTypes
);
} catch (FulltextException $e) {
$this->multiSearchResult = [];
$this->sentryLogger->captureException($e);
}
foreach ($enabledTypes as $type) {
switch ($type) {
case FulltextElastic::INDEX_PRODUCTS:
if ($this->fulltextSearch->supportsFilters()) {
$result = $this->searchProductsByIds();
} else {
$result = $this->searchProducts();
}
break;
case FulltextElastic::INDEX_ARTICLES:
$result = $this->searchArticles();
break;
default:
$result = $this->searchDefault($type);
}
$results[$type] = $result;
}
return $results;
}
protected function searchDefault($type)
{
return ['list' => $this->multiSearchResult[$type] ?? []];
}
protected function getSearchConfig(): array
{
$dbcfg = \Settings::getDefault();
$productsPage = (int) getVal('page', null, 1);
$productsNoOnPage = $dbcfg->cat_show_products_search ?: $dbcfg->cat_show_products;
$productsOffset = ceil(($productsPage - 1) * $productsNoOnPage);
$productsOrder = $this->getProductsOrder();
$dynamicFilters = $this->request->get('dynamic_filter', []);
if (!$this->fulltextSearch->supportsFilters() && (!empty($dynamicFilters) || findModule(\Modules::SEARCH, \Modules::SUB_FILTER))) {
$productsNoOnPage = 1000;
$productsOffset = 0;
$productsOrder = null;
}
$config = [];
foreach ($this->fulltextSearch->getIndexTypes() as $type) {
$config[$type] = [
'count' => 20,
'offset' => 0,
];
}
$config[FulltextElastic::INDEX_PRODUCTS] = [
'count' => (int) $productsNoOnPage,
'offset' => (int) $productsOffset,
'order' => $productsOrder,
'exact' => getVal('exact') ? true : false,
];
return $config;
}
protected function isTopicEnabled($topic): bool
{
if (!in_array($topic, $this->enabledTopics)) {
return false;
}
foreach ($this->topicsModules[$topic] ?? [] as $module) {
if (findModule($module)) {
return true;
}
}
return empty($this->topicsModules[$topic]);
}
protected function setEnabledTopics($topics)
{
$this->enabledTopics = $topics;
return $this;
}
protected function getProductList(): ProductList
{
$productList = clone $this->productList;
// TODO: Direct copy from class.Category - split class.Category to View and "FilteredProductList" and use FilteredProductList here
// start
$productList->fetchImages(2);
$productList->fetchProducers();
// Variations in product list
$variations = findModule('products_variations', 'category_variations');
if ($variations) {
$productList->fetchVariations($variations);
}
// Parameters in product list
$parameters = findModule('products_parameters', 'category_params');
if ($parameters) {
$productList->fetchParameters($parameters);
}
// Product sets in product list
if (findModule('products_sets')) {
$productList->fetchSets();
}
// Product sets in product list
if (findModule('reviews', 'show_in_category')) {
$productList->fetchReviews();
}
// end
return $productList;
}
protected function searchProductsByIds()
{
$productList = $this->getProductList();
$products = $this->multiSearchResult[FulltextElastic::INDEX_PRODUCTS] ?? [];
$productList
->andSpec(function (QueryBuilder $qb) use ($products) {
$qb->setParameter('products', array_keys($products), \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
->andWhere('p.id IN (:products)');
});
$noProducts = $this->fulltextSearch->getRowsCount();
return [
'list' => $productList->getProducts(),
'pager' => $this->getPager($noProducts),
];
}
protected function getPager($noProducts): \Pager
{
$dbcfg = \Settings::getDefault();
$noOnPage = $dbcfg->cat_show_products_search ?: $dbcfg->cat_show_products;
$page = getVal('page', null, 1);
$noPages = ceil($noProducts / $noOnPage);
$param = [
'URL' => 'launch.php',
's' => 'search',
'search' => $this->searchTerm,
'submit' => 'ok',
'so' => 'products',
'ESCAPE' => 'NO',
];
if (isset($_GET['show'])) {
$param['show'] = $_GET['show'];
}
$url = createScriptURL($param);
$dynamic_filter = $this->request->get('dynamic_filter', []);
if (!empty($dynamic_filter)) {
$url .= '&'.http_build_query(['dynamic_filter' => $dynamic_filter]);
}
$pager = new \Pager($noPages, $page);
$pager->setUrl($url);
$pager->setTotal($noProducts, $noOnPage);
if (!isAjax() && $noOnPage == 0 && $page != 1) {
throw new NotFoundHttpException('Page \''.$page.'\' is out of range.');
}
return $pager;
}
protected function searchProducts()
{
$noProducts = null;
$dbcfg = \Settings::getDefault();
$orderBy = getVal('orderby', null, getVal('order_by'));
$orderDir = getVal('orderdir', null, getVal('order_dir'));
$order = (int) getVal('order');
if ($order) {
$orderBy = abs($order);
$orderDir = $order >= 0 ? 1 : 2;
}
// ProductList
$page = getVal('page', null, 1);
$noOnPage = $dbcfg->cat_show_products_search ?: $dbcfg->cat_show_products;
$dynamic_filter = $this->request->get('dynamic_filter', []);
$productList = $this->getProductList();
$filterParams = $productList->applyDefaultFilterParams();
$this->eventDispatcher->dispatch(
new CatalogEvent($productList, $filterParams, CatalogEvent::TYPE_SEARCH)
);
// Show both hidden and not in store products to administrators
if ($dbcfg->prod_show_admin_hidden == 'Y' && getAdminUser()) {
$filterParams->setVisible(null);
$filterParams->setInStore(null);
}
// HACK: Když chce admin vidět ve vyhledávání i skrytý produkty, nepoužiju fulltext ale staré hledání
if (!($dbcfg->prod_show_admin_hidden == 'Y' && getAdminUser())) {
$products = $this->multiSearchResult[FulltextElastic::INDEX_PRODUCTS] ?? [];
if (!empty($dynamic_filter) || findModule(\Modules::SEARCH, \Modules::SUB_FILTER)) {
$filter = new \Filter($filterParams);
$filter->setFilterData($dynamic_filter);
if (!empty($dynamic_filter)) {
$this->setEnabledTopics(['products']);
}
$result['filter'] = $filter;
$filterParams->andSpec(function (QueryBuilder $qb) use ($products) {
$qb->andWhere(Product::productsIds(array_keys($products)));
});
if ($orderBy) {
// Sort by user defined sort
$sortParams = $this->getSortParams($orderBy, $orderDir, $productList);
$productList->orderBy($sortParams['orderby'], $sortParams['orderdir']);
} else {
// Sort by fulltext
$productList->orderBy($this->getOrderBy());
}
$productList
->limit($noOnPage, ceil(($page - 1) * $noOnPage));
$result['list'] = $productList->getProducts($noProducts);
} else {
$noProducts = $this->fulltextSearch->getRowsCount();
if (!$noProducts) {
$result['suggestion'] = $this->fulltextSearch->suggestTerm($this->searchTerm);
if ($result['suggestion']) {
$products = $this->fulltextSearch->searchProducts($result['suggestion'], $noOnPage, ceil(($page - 1) * $noOnPage), $this->getProductsOrder());
$noProducts = $this->fulltextSearch->getRowsCount();
}
}
$productList
->andSpec(function (QueryBuilder $qb) use ($products) {
$qb->setParameter('products', array_keys($products), \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
->andWhere('p.id IN (:products)');
})
->orderBy('FIELD(p.id, :products)')
->limit($noOnPage);
$result['list'] = $productList->getProducts($noProductsReal);
// Pokud mám vrácených položek z fulltextu jen na jednu stránku, můžu zobrazit reálný počet produktů
// (ponížených například o skryté produkty stále v indexu a podobně)
if ($noProducts < $noOnPage) {
$noProducts = $noProductsReal;
}
}
} else {
// HACK: Když chce admin vidět ve vyhledávání i skrytý produkty, nepoužiju fulltext ale staré hledání
$sortParams = $this->getSortParams($orderBy, $orderDir, $productList);
// Ordering by positions and in_store
if ($dbcfg->prod_subtract_from_store) {
$sortParams['order_start'] = 'IF(p.in_store > 0, COALESCE(p.position, '.POSITION_STANDARD.'), COALESCE(p.position, '.POSITION_STANDARD.') + 10000)';
} else {
$sortParams['order_start'] = 'COALESCE(p.position, '.POSITION_STANDARD.')';
}
$sortParams['orderby'] = "{$sortParams['order_start']}, {$sortParams['orderby']}";
// In store
if (getVal('filter_insupplier') || getVal('inSupplier', $dynamic_filter)) {
$filterParams->setInStore(\Filter::IN_STORE_SUPPLIER);
} elseif (getVal('filter_instore') || getVal('inStore', $dynamic_filter)) {
$filterParams->setInStore(\Filter::IN_STORE);
}
$fields = [
['field' => 'p.title', 'match' => 'both', 'order' => true],
['field' => 'p.short_descr', 'match' => 'both'],
['field' => 'p.code', 'match' => 'left', 'order' => true],
['field' => 'pr.name', 'match' => 'both'],
];
$productList->andSpec(function (QueryBuilder $qb) {
$qb->joinProducersOnProducts();
});
if (is_numeric($this->searchTerm)) {
$fields[] = ['field' => 'p.ean', 'match' => 'numeric', 'order' => true];
if (findModule(\Modules::PRODUCTS_VARIATIONS)) {
$fields[] = ['field' => 'pv.ean', 'match' => 'numeric', 'order' => true];
}
}
if (findModule(\Modules::PRODUCTS_VARIATIONS, 'variationCode')) {
$fields[] = ['field' => 'pv.code', 'match' => 'left', 'order' => true];
}
$productList->andSpec(function (QueryBuilder $qb) use ($sortParams, $dbcfg) {
$qb->addOrderBy($sortParams['orderby'], $sortParams['orderdir']);
if (!($dbcfg->prod_show_admin_hidden == 'Y' && getAdminUser())) {
return Operator::equals(['p.show_in_search' => 'Y']);
}
})->andSpec(Search::searchFields($this->searchTerm, $fields));
$productList->limit($noOnPage, ceil(($page - 1) * $noOnPage));
$result['list'] = $productList->getProducts($noProducts);
}
// #####################################################
if (!empty($dynamic_filter)) {
$result['dynamic_filter'] = $dynamic_filter;
}
$result['pager'] = $this->getPager($noProducts);
return $result;
}
public function getOrderBy(): string
{
return 'FIELD(p.id, :products)';
}
protected function searchPages()
{
$fields = [
['field' => 'ml.name', 'match' => 'both'],
['field' => 'b.content', 'match' => 'both'],
];
$search = get_search_query($this->searchTerm, $fields);
$qb = sqlQueryBuilder()
->select('ml.id')
->from('menu_links', 'ml')
->join('ml', 'blocks', 'b', 'b.id_root = ml.id_block')
->where($search['where'])
->andWhere(Operator::equals(['ml.type' => MenuUtil::TYPE_PAGE]))
->andWhere(Translation::coalesceTranslatedFields(
MenuLinksTranslation::class,
['name', 'url']
))
->andWhere(Operator::Not(Operator::equals(['ml.figure' => 'N'])))
->andWhere(Operator::Not(Operator::equals(['ml.show_in_search' => 'N'])))
->addParameters($search['data'])
->groupBy('ml.id')
->execute();
$result = sqlFetchAll($qb);
foreach ($result as &$page) {
$page['url'] = '/'.$page['url'];
}
return [
'list' => $result,
];
}
protected function searchArticles()
{
$result['list'] = [];
$result['pager'] = [];
$searchResult = $this->multiSearchResult[FulltextElastic::INDEX_ARTICLES] ?? [];
if (!empty($searchResult)) {
$articleIds = array_map(function ($x) {
return $x['id'];
}, $searchResult);
/** @var ArticleList $articleList */
$articleList = ServiceContainer::getService(ArticleList::class);
$result['list'] = $articleList->getArticles(function (\Query\QueryBuilder $qb) use ($articleIds) {
$qb->andWhere(Operator::inIntArray($articleIds, 'a.id'))
->setParameter('articles', $articleIds, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
->addOrderBy('FIELD(a.id, :articles)');
});
}
return $result;
}
protected function getListShowType()
{
if (!empty($_COOKIE['cat_show']) && empty($_GET['show'])) {
$_GET['show'] = $_COOKIE['cat_show'];
} else {
if (empty($_GET['show']) || !preg_match('/^[[:digit:]]{1}$/i', $_GET['show'])) {
$_GET['show'] = \Settings::getDefault()->cat_show_style;
} else {
SetCookies('cat_show', $_GET['show'], 86400);
}
}
return $_GET['show'];
}
protected function getProductsOrder(): ?string
{
$orderBy = getVal('orderby', null, getVal('order_by'));
$orderDir = getVal('orderdir', null, getVal('order_dir'));
$order = null;
switch ($orderBy) {
case 1:
$order = 'code';
break;
case 2:
$order = 'title';
break;
case 3:
$order = 'price';
break;
case 5:
$order = 'sold';
break;
}
if ($order && $orderDir == 2) {
$order = '-'.$order;
}
return $order;
}
/**
* @required
*/
public function setFulltextSearch(FulltextInterface $fulltextSearch): SearchView
{
$this->fulltextSearch = $fulltextSearch;
$this->fulltextSearch->setCurlTimeout(10);
return $this;
}
public function getSortParams($orderBy, $orderDir, ProductList $productList): array
{
switch ($orderBy) {
case 1:
$result['orderby'] = 'p.code';
break;
case 2:
$result['orderby'] = 'p.title';
break;
case 3:
$productList->andSpec(function (QueryBuilder $qb) {
$qb->joinVatsOnProducts();
});
$result['orderby'] = 'MIN(COALESCE(pv.price, p.price))*(1+v.vat/100)*(1-p.discount/100)';
break;
case 4:
$result['orderby'] = 'p.date_added';
break;
case 5:
$result['orderby'] = 'p.pieces_sold';
break;
case 6:
$result['orderby'] = 'p.updated';
break;
case 7:
$result['orderby'] = 'p.in_store > 0 DESC';
// if (findModule('products_suppliers'))
// $query['orderby'] .= ", in_store_suppliers DESC";
$result['orderby'] .= ', p.title';
break;
default:
$result['orderby'] = 'p.title';
break;
}
switch ($orderDir) {
case 1:
$result['orderdir'] = ' ASC ';
break;
case 2:
$result['orderdir'] = ' DESC ';
break;
default:
$result['orderdir'] = ' ASC ';
break;
}
return $result;
}
public function getFilters(): array
{
return $this->fulltextSearch->getFilters();
}
public function getCorrectUrl(): ?string
{
$urlCorrect = createScriptURL([
'URL' => 'launch.php',
's' => 'search',
'search' => $this->searchTerm,
]);
return $urlCorrect;
}
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace KupShop\CatalogBundle\View;
class SimpleProductListView extends CategoryView
{
protected $template = 'products.list.tpl';
public function getTitle()
{
return translate('title', 'category')['productsList'] ?? '';
}
public function getMetaTitle()
{
return translate('title', 'category')['productsList'] ?? '';
}
public function getBreadcrumbs()
{
return getReturnNavigation(-1, 'NO_TYPE', [translate('title', 'category')['productsList'] ?? '']);
}
public function getBodyVariables()
{
return array_merge_recursive(
parent::getBodyVariables(),
['category' => ['is_simple' => true]]
);
}
protected function getPagerOptions(): array
{
return [
'noOnPage' => 9999,
'page' => 1, 9,
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace KupShop\CatalogBundle\View\Wrapper;
use KupShop\KupShopBundle\Template\ObjectWrapper;
class FilterParamsWrapper extends ObjectWrapper
{
/** @var \FilterParams */
protected $object;
protected static $objectType = \FilterParams::class;
public function isSelectedSectionByLevel(
?int $ancestorID = null,
int $level,
?int $sectionIDToCheck = null,
) {
$sectionsByLevel = $this->object->getSectionsByLevel();
$sections = isset($sectionsByLevel[$ancestorID][$level]) ? $sectionsByLevel[$ancestorID][$level] : [];
return is_null($sectionIDToCheck) && count($sections) == 0 || in_array($sectionIDToCheck, $sections);
}
}