Files
kupshop/bundles/KupShop/ContentBundle/Util/ArticlesUtil.php
2025-08-02 16:30:27 +02:00

254 lines
9.2 KiB
PHP

<?php
namespace KupShop\ContentBundle\Util;
use KupShop\I18nBundle\Translations\ArticlesTagsTranslation;
use KupShop\I18nBundle\Translations\ArticlesTranslation;
use KupShop\KupShopBundle\Context\LanguageContext;
use Query\Operator;
use Query\QueryBuilder;
use Query\Translation;
use Symfony\Contracts\Service\Attribute\Required;
class ArticlesUtil
{
#[Required]
public LanguageContext $languageContext;
#[Required]
public ArticleList $articleList;
public function getArticleSections($topSection = null)
{
$sectionsCacheName = "article-sections-{$this->languageContext->getActiveId()}";
if (isset($topSection)) {
$sectionsCacheName .= '-'.$topSection;
}
if ($cache = getCache($sectionsCacheName)) {
$sections = $cache;
} else {
$sections = $this->articleList->getSectionsTree($topSection);
setCache($sectionsCacheName, $sections);
}
return $sections;
}
public function getArticleTags($idArticle, $onlyActive = null)
{
if (!findModule(\Modules::ARTICLES)) {
return null;
}
$qb = sqlQueryBuilder()
->select('at.*, COUNT(atr.id_article) as count')
->from('articles_tags', 'at')
->leftJoin('at', 'articles_tags_relation', 'atr', 'atr.id_tag = at.id')
->andWhere(Translation::coalesceTranslatedFields(ArticlesTagsTranslation::class))
->groupBy('at.id')
->orderBy('at.tag');
if ($idArticle) {
$qb->andWhere(Operator::equals(['atr.id_article' => $idArticle]));
}
if ($onlyActive) {
$qb->leftJoin('atr', 'articles', 'a', 'atr.id_article = a.id')
->andWhere('a.date <= NOW()');
$qb->andWhere(Translation::joinTranslatedFields(ArticlesTranslation::class,
function (QueryBuilder $qb, $columnName, $translatedField) {
$qb->andWhere(Operator::coalesce($translatedField, 'a.figure').' = "Y" ');
},
['figure']));
$qb->having('count > 0');
}
return $qb->execute()->fetchAll();
}
public function getArticles($params)
{
$defaults = [
'count' => null,
'section' => null,
'section_id' => null,
'product_id' => null,
'id' => null,
'section_id_exclude' => [],
'related' => [],
'related_symmetric' => false,
'tag' => null,
'assign' => null,
'order_by' => 'a.date',
'order' => 'DESC',
'require_tag' => null,
'image' => 1,
];
$params = array_merge($defaults, $params);
if (empty($params['section']) && empty($params['section_id']) && empty($params['product_id']) && empty($params['tag']) && empty($params['id']) && empty($params['related'])) {
echo "Použij parametr 'section' nebo 'section_id' nebo 'product_id' nebo 'tag' nebo 'id' nebo 'related'";
}
if ($params['tag'] && !is_array($params['tag'])) {
$params['tag'] = [$params['tag']];
}
$spec_section = null;
if ($params['section'] != 'all') {
$spec_section = function (QueryBuilder $qb) use ($params) {
$qb->andWhere('(ab.name=:section OR ab.id=:section_id)')
->setParameters(['section' => $params['section'], 'section_id' => $params['section_id']]);
};
}
return [
'section' => $this->articleList->getSection($spec_section),
'articles' => $this->getArticlesWithFallback($params, $defaults),
];
}
private function getArticlesWithFallback(array $params, array $defaultParams): array
{
if (!empty($params['section_id_exclude'])) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->andWhere(
Operator::not(
Operator::inIntArray($params['section_id_exclude'], 'ar.id_branch')
)
);
};
}
$specs[] = function (QueryBuilder $qb) use ($params) {
if (is_array($params['order_by'])) {
$qb->orderBy('FIELD(a.id, :orderByArticlesId)')
->setParameter('orderByArticlesId', $params['order_by'], \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
} else {
$qb->orderBy($params['order_by'], $params['order']);
}
};
if (isset($params['section_id']) && $params['section'] != 'all') {
$sectionIds = [$params['section_id']];
if ($filterSection = $this->articleList->getSectionById((int) $params['section_id'])) {
$this->getFilterSectionsIdsRecursively($filterSection, $sectionIds);
}
$specs[] = Operator::inIntArray($sectionIds, 'ar.id_branch');
}
if ($params['count'] > 0) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->setMaxResults($params['count']);
};
}
if ($params['product_id']) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->join('a', 'products_in_articles', 'pia', 'pia.id_article = a.id')
->andWhere('pia.id_product=:id_product')->setParameter('id_product', $params['product_id']);
};
}
if ($params['id']) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->andWhere(Operator::inIntArray((array) $params['id'], 'a.id'));
};
}
if ($params['tag']) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->leftJoin('a', 'articles_tags_relation', 'atr', 'a.id = atr.id_article')
->andWhere(Operator::inIntArray($params['tag'], 'atr.id_tag'));
};
}
if ($params['require_tag']) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->join('a', 'articles_tags_relation', 'atr2', 'a.id = atr2.id_article')
->andWhere(Operator::equals(['atr2.id_tag' => $params['require_tag']]));
};
}
if (!empty($params['exclude_articles'])) {
if (!is_array($params['exclude_articles'])) {
$params['exclude_articles'] = [$params['exclude_articles']];
}
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->andWhere(Operator::not(Operator::inIntArray($params['exclude_articles'], 'a.id')));
};
}
if (!empty($params['related'])) {
$specs[] = function (QueryBuilder $qb) use ($params) {
$qb->leftJoin('a', 'articles_related', 'arr', 'a.id = arr.id_article_related')
->orderBy('arr.position');
$orX = [Operator::inIntArray((array) $params['related'], 'arr.id_article')];
if ($params['related_symmetric'] ?? false) {
$qb->leftJoin('a', 'articles_related', 'arr2', 'a.id = arr2.id_article');
$orX[] = Operator::inIntArray((array) $params['related'], 'arr2.id_article_related');
}
$andX = [Operator::orX($orX)];
if (findModule(\Modules::ARTICLES_RELATED_TYPES) && !empty($params['related_type'])) {
$andX[] = Operator::inIntArray((array) $params['related_type'], 'arr.type');
if (!empty($params['related_symmetric'])) {
$andX[] = Operator::inIntArray((array) $params['related_type'], 'arr2.type');
}
}
$qb->andWhere(Operator::andX($andX));
};
}
if ($params['image']) {
$this->articleList->setImage($params['image']);
}
$articles = $this->articleList->getArticles(Operator::andX($specs));
$count = count($articles);
if (!empty($params['count']) && $count < $params['count'] && !empty($params['fallback'])) {
$fallback = $params['fallback'];
unset($params['fallback']);
foreach ($fallback as $fallbackParams) {
if ($count >= $params['count']) {
break;
}
$fallbackParams = array_merge($defaultParams, $fallbackParams, [
'count' => $params['count'] - $count,
]);
$fallbackArticles = $this->getArticlesWithFallback($fallbackParams, $defaultParams);
$count += count($fallbackArticles);
$articles = array_merge($articles, $fallbackArticles);
}
}
return $articles;
}
private function getFilterSectionsIdsRecursively(array $section, array &$filterIds): void
{
// pokud je nastaveno "Zobrazovat jen články v sekci", tak nenacitam IDcka podsekci
if (($section['behaviour'] ?? null) != 2) {
return;
}
// pokud je u sekce zaksrnuto "Zobrazovat články v této sekci a jejích podsekcích"
foreach ($section['children'] ?? [] as $child) {
$filterIds[] = $child['id'];
$this->getFilterSectionsIdsRecursively($child, $filterIds);
}
}
}