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

397 lines
12 KiB
PHP

<?php
namespace KupShop\ContentBundle\View;
use KupShop\ComponentsBundle\View\ComponentsViewInterface;
use KupShop\ComponentsBundle\View\ComponentsViewTrait;
use KupShop\ContentBundle\Util\Block;
use KupShop\ContentBundle\Util\InlineEdit;
use KupShop\ContentBundle\Util\RecursiveTemplateFinderTrait;
use KupShop\I18nBundle\Translations\ArticlesAuthorsTranslation;
use KupShop\I18nBundle\Translations\ArticlesTagsTranslation;
use KupShop\KupShopBundle\Util;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use Query\Operator;
use Query\Translation;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ArticleView extends View implements ComponentsViewInterface
{
use RequestTrait;
use ComponentsViewTrait;
use RecursiveTemplateFinderTrait;
protected $template = 'article.tpl';
protected string $entrypoint = 'article';
protected $IDa;
private $articleBlocks;
private $article;
public function __construct(protected Block $block, private InlineEdit $inlineEdit, protected Util\RequestUtil $requestUtil)
{
$this->proxyCacheEnabled = findModule(\Modules::PROXY_CACHE, 'content');
}
public function getResponse(?Request $request = null)
{
if (!findModule('articles')) {
redirection('MODUL_NOT_FOUND');
}
return parent::getResponse($request);
}
public function getBodyVariables()
{
$vars = parent::getBodyVariables();
$article = $this->getArticle();
$vars['article'] = [
'id' => $this->IDa,
'title' => $article['title'],
'image' => leadImage($this->IDa, 1, 'ARTICLE'),
'lead' => $article['lead_in'],
'source' => $article['source'],
'date' => $article['datef'],
'body' => $this->getArticleBody(),
'seen' => $article['seen'],
'parts' => [],
'authors' => [],
'blocks' => $this->getArticleBlocks(),
'data' => $article['data'],
'id_branch' => $article['id_branch'],
'section' => ['name' => $article['section_name'] ?? '', 'id' => $article['id_branch'] ?? 0],
'id_block' => $article['id_block'],
];
$this->title = $article['title'];
$vars['returnNav'] = $this->getReturnNav($article['title']);
$vars['printPreview'] = $this->handlePrint();
$vars['article']['authors'] = $this->getArticleAuthors();
$vars['article']['photos'] = $this->getArticleImages();
$vars['article']['tags'] = $this->getArticleTags();
return $vars;
}
public function getShowInSearch(): bool
{
return ($this->getArticle()['show_in_search'] ?? false) === 'Y';
}
public function getWpjToolbar()
{
if ($this->IDa > 0) {
$url = getAdminUrl('articles', ['ID' => $this->IDa]);
$arr = [
'url' => $url,
'title' => 'Upravit článek',
];
return array_merge(parent::getWpjToolbar(), $arr);
}
return [];
}
protected function getObjectInfo()
{
$object_info = [
'type' => 'articles',
'id' => $this->IDa,
'name' => (translate('objects', 'blocks', true, true)['article'] ?? 'article').': '.$this->getArticle()['title'] ?? '',
];
return json_encode($object_info);
}
public function getArticleBody()
{
$body = ['title' => '', 'body' => ''];
foreach ($this->getArticleBlocks() as $block) {
$wrapped = $this->inlineEdit->wrapBlock($block);
$body['body'] .= $wrapped['content'];
}
return $body;
}
public function getArticleBlocks()
{
if ($this->articleBlocks) {
return $this->articleBlocks;
}
$article = $this->getArticle();
if ($id_block = $article['id_block'] ?? null) {
$blocks = $this->block->getBlocks($id_block);
$object_info = $this->getObjectInfo();
$this->articleBlocks = array_map(function ($block) use ($object_info) {
$block['object_info'] = $object_info;
return $block;
}, $blocks);
} else {
$this->articleBlocks = [
[
'id_object' => $this->IDa,
'type' => 'articles',
],
];
}
return $this->articleBlocks;
}
public function getArticle()
{
global $cfg;
if ($this->article) {
return $this->article;
}
$dbcfg = \Settings::getDefault();
$article = false;
$qb = sqlQueryBuilder()
->select('a.show_in_search, a.id', 'a.title', 'a.id_block', 'a.source', 'DATE_FORMAT(a.date, "'.$dbcfg['date_format'].' '.$dbcfg['time_format'].'") AS datef',
'a.lead_in', 'a.seen', 'a.comments', 'a.comment_question', 'a.rating_value', 'a.rating_voted', 'a.type, a.link', 'a.figure', 'a.data',
'ab.template AS branch_template, a.url, a.meta_title, a.meta_description, ar.id_branch, ab.name as section_name', 'a.date > NOW() AS dateunactive')
->from('articles', 'a')
->leftJoin('a', 'articles_relation', 'ar', 'ar.id_art=a.id')
->leftJoin('ar', 'articles_branches', 'ab', 'ab.id=ar.id_branch')
->where('a.id=:IDa')
->setMaxResults(1)
->setParameter('IDa', $this->IDa)
->groupBy('a.id');
// join translations
$qb->andWhere(
Translation::adminAlwaysVisible(
\Query\Translation::coalesceTranslatedFields(
\KupShop\I18nBundle\Translations\ArticlesTranslation::class
)
)
);
if (!($article = $qb->execute()->fetchAssociative())) {
throw new NotFoundHttpException('Article not found');
}
if (($article['dateunactive'] or ($article['figure'] != 'Y')) and !getAdminUser()) {
throw new NotFoundHttpException('Invisible article');
}
$article['seo_url'] = !empty($article['url']) ? $article['url'] : StringUtil::slugify($article['title']);
// pokud clanek slouzi jen jako presmerovani
if ($article['type'] == 'L' && $article['link'] != '') {
if (strpos($article['link'], $cfg['Addr']['full']) !== false || $article['link'][0] == '/') {
$url = $article['link'];
} else {
$url = createScriptURL([
'URL' => 'launch.php',
's' => 'redir',
'link' => urlencode($article['link']),
'ESCAPE' => 'NO',
]);
}
redirection($url);
}
if (!empty($article['branch_template'])) {
if (findModule(\Modules::COMPONENTS)) {
$this->template = "articles/{$article['branch_template']}/article.html.twig";
} else {
$this->template = 'fallback:article.'.$article['branch_template'].'.tpl:'.$this->template;
}
}
// zobrazeni
if (!isset($_GET['comment']) && !isset($_GET['part'])) {
$this->updateArticleSeen();
$article['seen']++;
}
$article['data'] = json_decode($article['data'], true);
return $this->article = $article;
}
public function getArticleImages()
{
$data = [];
$qb = sqlQueryBuilder()
->select('ph.id', 'ph.date', 'ph.descr', 'ph.source', 'ph.image_2', 'pha.show_in_lead', 'ph.date_update', 'ph.descr')
->from('photos', 'ph')
->from('photos_articles_relation', 'pha')
->where('ph.id=pha.id_photo AND pha.id_art=:IDa')
->orderBy('pha.position', 'ASC')
->addOrderBy('pha.date_added', 'ASC')
->setParameter('IDa', $this->IDa)
->execute();
foreach ($qb as $row) {
$row['IDph'] = $row['id'];
$row['img'] = getImage($row['id'], $row['image_2'], $row['source'], 4, $row['descr'], strtotime($row['date_update']));
$row['width'] = ($row['img']['width'] <= 200) ? $row['img']['width'] : 200;
$data[] = $row;
}
return $data;
}
public function getArticleAuthors(): array
{
if (!findModule(\Modules::ARTICLES_AUTHORS)) {
return [];
}
$qb = sqlFetchAll(sqlQueryBuilder()
->select('au.*')
->from('articles_authors', 'au')
->from('articles_authors_relation', 'aar')
->andWhere(
Operator::andX(
Operator::equals(['aar.id_art' => $this->IDa]),
'aar.id_auth=au.id'
)
)
->andWhere(Translation::coalesceTranslatedFields(ArticlesAuthorsTranslation::class))
->execute(), 'id');
foreach ($qb as $row) {
$row['photo'] = getImage($row['id'], $row['photo'], '../articles_authors/', 'articles_authors', dateUpdate: strtotime($row['date_update']));
$data[] = $row;
}
return $data ?? $qb;
}
public function getArticleTags()
{
$tags = sqlQueryBuilder()
->select('at.id, at.tag')
->from('articles_tags_relation', 'atr')
->leftJoin('atr', 'articles_tags', 'at', 'at.id = atr.id_tag')
->where(\Query\Operator::equals(['atr.id_article' => $this->IDa]))
->andWhere(Translation::coalesceTranslatedFields(ArticlesTagsTranslation::class))
->execute()->fetchAll();
$tags = array_combine(array_column($tags, 'id'), $tags);
return $tags;
}
public function getReturnNav($articleTitle)
{
$returnNav = [];
$qb = sqlQueryBuilder()
->select('id_branch')
->from(getTableName('articles_relation'))
->where('id_art=:IDa')
->setParameter('IDa', $this->IDa)
->execute();
foreach ($qb as $row) {
$returnNav = array_merge($returnNav, getReturnNavigation($row['id_branch'], 'ARTICLE', [$articleTitle]));
}
return $returnNav;
}
public function updateArticleSeen(): bool
{
if (!$this->requestUtil->isRobot($this->request)) {
$qb = sqlQueryBuilder()
->update('articles')
->set('seen', 'seen+1')
->where('id=:IDa')
->setParameter('IDa', $this->IDa);
if ($qb->execute()) {
return true;
}
return false;
}
return false;
}
public function setIDa($IDa)
{
$this->IDa = $IDa;
}
public function handlePrint()
{
return $this->request->get('print');
}
/**
* Returns correct url of category.
*/
public function getCorrectUrl(): ?string
{
if (!$this->getArticle()) {
return null;
}
return createScriptURL([
'URL' => 'launch.php',
's' => 'article',
'IDa' => $this->IDa,
'TITLE' => $this->article['seo_url'],
]);
}
public function getMetaTitle()
{
if (!empty($this->getArticle()['meta_title'])) {
return $this->getArticle()['meta_title'];
}
return parent::getMetaTitle();
}
public function getMetaDescription()
{
if (!empty($this->getArticle()['meta_description'])) {
return $this->getArticle()['meta_description'];
}
return parent::getMetaDescription();
}
public function getBreadcrumbsNew(): array
{
if (findModule(\Modules::COMPONENTS)) {
$breadcrumbs = getReturnNavigation($this->article['id_branch'], 'ARTICLE', [$this->article['title']]);
return reset($breadcrumbs);
}
return parent::getBreadcrumbsNew();
}
public function getTemplates(): iterable
{
yield from $this->getTemplatesFromPath(__DIR__.'/../../../../../shop/twig/articles', 'article.html.twig', 'articles');
// default template
yield $this->getTemplate();
}
}