444 lines
17 KiB
PHP
444 lines
17 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KupShop\CatalogBundle\Util;
|
|
|
|
use KupShop\CatalogBundle\Entity\Category;
|
|
use KupShop\CatalogBundle\Entity\Producer;
|
|
use KupShop\CatalogBundle\Entity\Section;
|
|
use KupShop\CatalogBundle\ProductList\DynamicFilterAttributes;
|
|
use KupShop\CatalogBundle\Repository\SectionsRepository;
|
|
use KupShop\I18nBundle\Translations\BlocksTranslation;
|
|
use KupShop\I18nBundle\Translations\ParametersListTranslation;
|
|
use KupShop\I18nBundle\Translations\ProducersTranslation;
|
|
use KupShop\I18nBundle\Translations\VariationsValuesTranslation;
|
|
use KupShop\KupShopBundle\Config;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use Query\Operator;
|
|
use Query\QueryBuilder;
|
|
use Query\Translation;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
|
|
class SectionViewUtil
|
|
{
|
|
public function __construct(
|
|
protected readonly ActiveCategory $activeCategory,
|
|
protected readonly IndexedFilterUtil $indexedFilterUtil,
|
|
protected readonly FilterUtil $filterUtil,
|
|
) {
|
|
}
|
|
|
|
public function getListShowType(): mixed
|
|
{
|
|
$show = \Settings::getDefault()->cat_show_style;
|
|
|
|
if (!empty($_COOKIE['cat_show'])) {
|
|
$show = $_COOKIE['cat_show'];
|
|
}
|
|
|
|
if (!empty($_GET['show']) && preg_match('/^[[:digit:]]{1}$/i', $_GET['show'])) {
|
|
$show = $_GET['show'];
|
|
SetCookies('cat_show', $show);
|
|
}
|
|
|
|
return $show;
|
|
}
|
|
|
|
/**
|
|
* @return array{noOnPage: int, page: int}
|
|
*/
|
|
public function getPagerOptions(Request $request): array
|
|
{
|
|
$dbcfg = \Settings::getDefault();
|
|
|
|
$noOnPage = $dbcfg['cat_show_products'];
|
|
|
|
if (is_numeric(getVal('filter_onpage'))) {
|
|
$noOnPage = getVal('filter_onpage');
|
|
SetCookies('filter_onpage', $noOnPage);
|
|
} elseif (!empty($_COOKIE['filter_onpage'])) {
|
|
$noOnPage = intval($_COOKIE['filter_onpage']);
|
|
}
|
|
|
|
$page = (int) max(intval($request->get('page', default: 1)), 1);
|
|
$noOnPage = (int) $noOnPage;
|
|
|
|
return compact('noOnPage', 'page');
|
|
}
|
|
|
|
/**
|
|
* @deprecated use {@see SectionsRepository}
|
|
*/
|
|
public function getCategory(int|array $categoryId, ?int $campaign = null): Category
|
|
{
|
|
$cfg = Config::get();
|
|
global $catPath;
|
|
|
|
$catPath = [];
|
|
|
|
if (is_array($categoryId)) {
|
|
$catPath = array_unique($categoryId);
|
|
$categoryId = $catPath[0];
|
|
$catPath = array_reverse($catPath);
|
|
}
|
|
|
|
$categoryId = (string) $categoryId;
|
|
|
|
if (!empty($categoryId)) {
|
|
$cat = $this->activeCategory->getSectionById($categoryId);
|
|
if (!$cat) {
|
|
throw new NotFoundHttpException('Section not found!');
|
|
}
|
|
if (($cat->getFigure() == 'N') && !getAdminUser()) {
|
|
// skryta sekce - 404 (pro admina nezobrazovat 404, pokud je sekce skryta)
|
|
throw new NotFoundHttpException('Section not found!');
|
|
}
|
|
}
|
|
|
|
$this->activeCategory->setCategoryId($categoryId);
|
|
|
|
if (!is_array($categoryId) && empty($catPath)) {
|
|
$catPath = $this->activeCategory->getOpenedTreePath();
|
|
}
|
|
|
|
$this->activeCategory->validate([$categoryId]);
|
|
$category = null;
|
|
|
|
if (preg_match("/^-?[[:digit:]]+({$cfg['Products']['UrlFlags']})?$/i", $categoryId)) {
|
|
if (!is_numeric($categoryId)) {
|
|
$campaign = substr($categoryId, -1);
|
|
$categoryId = substr($categoryId, 0, -1);
|
|
}
|
|
|
|
if ($categoryId >= 0) {
|
|
// Tohle je demence, ale Honza tvrdí, že to je třeba kvůli Seznam remarketingu, bohužel :-(
|
|
$cqb = sqlQueryBuilder()
|
|
->select('s.*, fs.category_text as feed_seznam_category')
|
|
->from('sections', 's')
|
|
->leftJoin('s', 'kupshop_shared.feed_seznam', 'fs', 's.feed_seznam = fs.id')
|
|
->where(Operator::equals(['s.id' => $categoryId]));
|
|
$cqb->andWhere(
|
|
Translation::coalesceTranslatedFields(
|
|
\KupShop\I18nBundle\Translations\SectionsTranslation::class,
|
|
function ($columns) {
|
|
$columns['data'] = 'data_translated';
|
|
|
|
return $columns;
|
|
}
|
|
)
|
|
);
|
|
|
|
$category = $cqb->execute()
|
|
->fetch();
|
|
if ($category) {
|
|
$category['param'] = '';
|
|
$category['parents'] = $catPath;
|
|
$sectionData = array_replace_recursive(json_decode($category['data'] ?? '{}', true) ?: [], json_decode($category['data_translated'] ?? '{}', true) ?: []);
|
|
$category['data'] = $sectionData;
|
|
$category['date_updated'] = $category['date_updated'] ? new \DateTime($category['date_updated']) : null;
|
|
} else {
|
|
throw new NotFoundHttpException('Section not found!');
|
|
}
|
|
} else {
|
|
$category = [
|
|
'id' => 0,
|
|
'name' => '',
|
|
'descr' => '',
|
|
'behaviour' => 0,
|
|
'param' => '',
|
|
'lead_figure' => false,
|
|
'lead_text' => '',
|
|
'lead_products' => '',
|
|
'orderby' => 'title',
|
|
'orderdir' => 'ASC',
|
|
'producers_filter' => true,
|
|
'producers_to_title' => true,
|
|
'producers_indexing' => false,
|
|
];
|
|
}
|
|
$category['name_orig'] = $category['name'];
|
|
|
|
$category['campaign'] = $campaign;
|
|
|
|
$category = new Category($category);
|
|
} else {
|
|
redirection('REFERER');
|
|
}
|
|
|
|
return $category;
|
|
}
|
|
|
|
public function getDynamicFilterConfiguration(Section $section, ?int $producerId): DynamicFilterAttributes
|
|
{
|
|
if (FilterUtil::useOrderableFilters()) {
|
|
$sectionFilters = $this->filterUtil->getSectionFilters(
|
|
$section,
|
|
$producerId,
|
|
);
|
|
|
|
return DynamicFilterAttributes::fromOrderedFilters($sectionFilters);
|
|
}
|
|
|
|
$parameters = [];
|
|
if (findModule('producers') || findModule('products_sections')) {
|
|
$qb = sqlQueryBuilder()
|
|
->select('pa.*')
|
|
->from('parameters', 'pa')
|
|
->leftJoin('pa', 'parameters_sections', 'ps', 'ps.id_section=:id_section AND ps.id_parameter=pa.id')
|
|
->setParameter('id_section', $section->getId())
|
|
->where(Operator::orX(
|
|
findModule('products_sections') ? Operator::andX(\Query\Parameter::inSections([$section->getId()]), Operator::equals(['ps.filter' => 'Y'])) : null,
|
|
findModule('producers') ? \Query\Parameter::inProducers([$producerId]) : null))
|
|
->groupBy('pa.id')
|
|
->orderBy('ps.weight')
|
|
->addOrderBy('pa.position');
|
|
|
|
if (findModule(\Modules::INDEXED_FILTER)) {
|
|
$qb->addSelect('ps.to_title, ps.indexing');
|
|
}
|
|
|
|
$qb->andWhere(Translation::coalesceTranslatedFields(\KupShop\I18nBundle\Translations\ParametersTranslation::class, ['name', 'descr']));
|
|
$parameters = sqlFetchAll($qb->execute(), 'id');
|
|
}
|
|
|
|
$variations = [];
|
|
if (findModule('products_variations')) {
|
|
$qb = sqlQueryBuilder()
|
|
->select('pvcl.id, pvcl.label as name')
|
|
->from('products_variations_choices_labels', 'pvcl')
|
|
->where(\Query\Variation::labelsInSections([$section->getId()]))
|
|
->orderBy('pvs.weight');
|
|
|
|
if (findModule(\Modules::INDEXED_FILTER)) {
|
|
$qb->addSelect('to_title, indexing');
|
|
}
|
|
|
|
if (findModule(\Modules::CONVERTORS)) {
|
|
$qb->addSelect('convertor');
|
|
}
|
|
|
|
$qb->andWhere(Translation::coalesceTranslatedFields(\KupShop\I18nBundle\Translations\VariationsLabelsTranslation::class, ['label' => 'name']));
|
|
|
|
$variations = sqlFetchAll($qb->execute(), 'id');
|
|
}
|
|
$producers = true;
|
|
if (findModule(\Modules::PRODUCERS)) {
|
|
$producers = $section->getProducersFilter() == 'Y';
|
|
if ($producers && findModule(\Modules::INDEXED_FILTER)) {
|
|
$producers = [
|
|
'to_title' => $section->getProducersToTitle() === 'Y',
|
|
'indexing' => $section->getProducersIndexing() === 'Y',
|
|
];
|
|
}
|
|
}
|
|
|
|
$labels = findModule(\Modules::LABELS) && $section->getLabelsFilter() === 'Y';
|
|
|
|
return new DynamicFilterAttributes(
|
|
parameters: $parameters,
|
|
variations: $variations,
|
|
producers: $producers,
|
|
labels: $labels,
|
|
);
|
|
}
|
|
|
|
public function getTitleParts(?Section $section, ?Producer $producer, bool $useSeo = true): array
|
|
{
|
|
$parts = [];
|
|
|
|
if ($producer) {
|
|
if ($useSeo && $producerMeta = $producer->getMetaTitle()) {
|
|
$parts['producer'] = $producerMeta;
|
|
} elseif ($producerName = $producer->getName()) {
|
|
$parts['producer'] = $producerName;
|
|
}
|
|
}
|
|
|
|
if ($section) {
|
|
if ($section->getId() !== 0 || empty($parts['producer'])) {
|
|
if ($useSeo && $categoryMetaTitle = $section->getMetaTitle()) {
|
|
$parts = array_merge(['category' => $categoryMetaTitle], $parts);
|
|
} elseif ($categoryName = $section->getName()) {
|
|
$parts = array_merge(['category' => $categoryName], $parts);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $parts;
|
|
}
|
|
|
|
public function getTitle(?Section $section, ?Producer $producer, string $separator = ' - ', bool $useSeo = true): string
|
|
{
|
|
$parts = $this->getTitleParts($section, $producer, $useSeo);
|
|
|
|
return join($separator, array_filter($parts));
|
|
}
|
|
|
|
protected function getBlockContent(int $rootId): ?string
|
|
{
|
|
$block = sqlQueryBuilder()->from('blocks', 'b')
|
|
->where(Operator::equals(['id_root' => $rootId]))
|
|
->andWhere(Translation::coalesceTranslatedFields(BlocksTranslation::class, ['content']))
|
|
->execute()->fetchOne();
|
|
|
|
if ($block) {
|
|
return strip_tags($block);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getMetaDescriptionParts(?Section $section, ?Producer $producer): array
|
|
{
|
|
$parts = [];
|
|
|
|
if ($categoryMeta = $section?->getMetaDescription()) {
|
|
$parts['category'] = $categoryMeta;
|
|
}
|
|
|
|
if ($producerMeta = $producer?->getMetaDescription()) {
|
|
$parts['producer'] = $producerMeta;
|
|
}
|
|
|
|
if (!isset($parts['category']) && ($sectionBlock = $section?->getIdBlock())) {
|
|
if ($block = $this->getBlockContent($sectionBlock)) {
|
|
$parts['category_block'] = $block;
|
|
}
|
|
}
|
|
|
|
if (!isset($parts['producer']) && ($idProducerBlock = $producer?->getIdBlock())) {
|
|
if ($block = $this->getBlockContent($idProducerBlock)) {
|
|
$parts['producer_block'] = $block;
|
|
}
|
|
}
|
|
|
|
return $parts;
|
|
}
|
|
|
|
public function createMetaDescription(?Section $section, ?Producer $producer, string $separator = ', '): string
|
|
{
|
|
if ($parts = $this->getMetaDescriptionParts($section, $producer)) {
|
|
return StringUtil::cutToWords(join($separator, $parts), 160);
|
|
}
|
|
|
|
return $this->getTitle($section, $producer).' - '.\Settings::getDefault()->shop_description;
|
|
}
|
|
|
|
public function getDynamicTitleParts(DynamicFilterAttributes $dynamicFilter, \FilterParams $params, bool $includeProducer = true): array
|
|
{
|
|
if (!findModule(\Modules::INDEXED_FILTER)) {
|
|
return [];
|
|
}
|
|
|
|
$variationNames = [];
|
|
$parameterNames = [];
|
|
$producerNames = [];
|
|
|
|
// Variation names
|
|
foreach ($params->getVariations() as $labelId => $values) {
|
|
if (isset($dynamicFilter['variations'][$labelId])
|
|
&& $dynamicFilter['variations'][$labelId]['to_title'] == 'Y') {
|
|
foreach ($values as $value) {
|
|
$data = sqlQueryBuilder()->select('pvcv.id')
|
|
->from('products_variations_choices_values', 'pvcv')
|
|
->where(Operator::equals(['pvcv.id' => $value]))
|
|
->andWhere(Translation::coalesceTranslatedFields(VariationsValuesTranslation::class, ['value', 'title']))
|
|
->execute()->fetch();
|
|
if ($data) {
|
|
$variationNames[] = (!empty($data['title']) ? $data['title'] : $data['value']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parameter names
|
|
foreach ($params->getParameters() as $id => $parameter) {
|
|
if (isset($dynamicFilter['parameters'][$id])
|
|
&& $dynamicFilter['parameters'][$id]['to_title'] == 'Y') {
|
|
if ($parameter['type'] == \Filter::PARAM_LIST) {
|
|
foreach ($parameter['values'] as $parameterListId) {
|
|
$data = sqlQueryBuilder()->select('pl.id')
|
|
->from('parameters_list', 'pl')->where(Operator::equals(['pl.id' => $parameterListId]))
|
|
->andWhere(Translation::coalesceTranslatedFields(ParametersListTranslation::class, ['value', 'title']))
|
|
->execute()->fetch();
|
|
if ($data) {
|
|
$parameterNames[$id][] = (!empty($data['title']) ? $data['title'] : $data['value']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($includeProducer
|
|
&& ($dynamicFilter['producers'] ?? false)
|
|
&& ($dynamicFilter['producers']['to_title'] ?? false) == 'Y'
|
|
) {
|
|
foreach ($params->getProducers() as $producer) {
|
|
$data = sqlQueryBuilder()->select('pr.id')
|
|
->from('producers', 'pr')->where(Operator::equals(['pr.id' => $producer]))
|
|
->andWhere(Translation::joinTranslatedFields(ProducersTranslation::class, function (QueryBuilder $qb, $columnName, $translatedField) {}, ['name', 'title']))
|
|
->execute()->fetch();
|
|
if ($data) {
|
|
$producerNames[] = (!empty($data['title']) ? $data['title'] : $data['name']);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($params->getVariationsSizeConvertion() as $labelId => $convertor) {
|
|
if (($dynamicFilter['variations'][$labelId]['to_title'] ?? false) == 'Y') {
|
|
foreach ($convertor['value'] as $paramId) {
|
|
$data = sqlQueryBuilder()->select('pl.id')
|
|
->from('parameters_list', 'pl')->where(Operator::equals(['pl.id' => $paramId]))
|
|
->andWhere(Translation::coalesceTranslatedFields(ParametersListTranslation::class, ['value', 'title']))
|
|
->execute()->fetch();
|
|
if ($data) {
|
|
$variationNames[] = (!empty($data['title']) ? $data['title'] : $data['value']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return compact('variationNames', 'parameterNames', 'producerNames');
|
|
}
|
|
|
|
public function createDynamicTitle(DynamicFilterAttributes $dynamicFilter, \FilterParams $params, bool $includeProducer = true): string
|
|
{
|
|
list(
|
|
'variationNames' => $variationNames,
|
|
'parameterNames' => $parameterNames,
|
|
'producerNames' => $producerNames,
|
|
) = $this->getDynamicTitleParts($dynamicFilter, $params, $includeProducer);
|
|
|
|
$parametersTitle = '';
|
|
foreach ($parameterNames as $values) {
|
|
$parametersTitle .= ' '.join(', ', $values);
|
|
}
|
|
|
|
$title = '';
|
|
$title .= !empty($producerNames) ? ' '.join(', ', $producerNames) : '';
|
|
$title .= $parametersTitle;
|
|
$title .= !empty($variationNames) ? ' '.join(', ', $variationNames) : '';
|
|
|
|
return $title;
|
|
}
|
|
|
|
public function createTitle(
|
|
?Section $section,
|
|
?Producer $producer,
|
|
\FilterParams $filterParams,
|
|
DynamicFilterAttributes $filterConfig,
|
|
bool $useSeo = true,
|
|
): string {
|
|
$categoryMeta = $this->getTitle($section, $producer, useSeo: $useSeo);
|
|
$categoryDynamic = $this->createDynamicTitle(
|
|
dynamicFilter: $filterConfig,
|
|
params: $filterParams,
|
|
includeProducer: $producer !== null,
|
|
);
|
|
|
|
return $categoryMeta.$categoryDynamic;
|
|
}
|
|
}
|