vendor/contao/core-bundle/src/Resources/contao/modules/ModuleArticle.php line 109

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag;
  11. use Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor;
  12. /**
  13.  * Provides methodes to handle articles.
  14.  *
  15.  * @property integer $tstamp
  16.  * @property string  $title
  17.  * @property string  $alias
  18.  * @property string  $inColumn
  19.  * @property boolean $showTeaser
  20.  * @property boolean $multiMode
  21.  * @property string  $teaser
  22.  * @property string  $teaserCssID
  23.  * @property string  $classes
  24.  * @property string  $keywords
  25.  * @property boolean $printable
  26.  * @property boolean $published
  27.  * @property integer $start
  28.  * @property integer $stop
  29.  *
  30.  * @author Leo Feyer <https://github.com/leofeyer>
  31.  */
  32. class ModuleArticle extends Module
  33. {
  34.     /**
  35.      * Template
  36.      * @var string
  37.      */
  38.     protected $strTemplate 'mod_article';
  39.     /**
  40.      * No markup
  41.      * @var boolean
  42.      */
  43.     protected $blnNoMarkup false;
  44.     /**
  45.      * Check whether the article is published
  46.      *
  47.      * @param boolean $blnNoMarkup
  48.      *
  49.      * @return string
  50.      */
  51.     public function generate($blnNoMarkup=false)
  52.     {
  53.         if ($this->isHidden())
  54.         {
  55.             return '';
  56.         }
  57.         $this->type 'article';
  58.         $this->blnNoMarkup $blnNoMarkup;
  59.         // Tag the article (see #2137)
  60.         if (System::getContainer()->has('fos_http_cache.http.symfony_response_tagger'))
  61.         {
  62.             $responseTagger System::getContainer()->get('fos_http_cache.http.symfony_response_tagger');
  63.             $responseTagger->addTags(array('contao.db.tl_article.' $this->id));
  64.         }
  65.         return parent::generate();
  66.     }
  67.     protected function isHidden()
  68.     {
  69.         $isUnpublished = !$this->published || ($this->start && $this->start time()) || ($this->stop && $this->stop <= time());
  70.         // The article is published, so show it
  71.         if (!$isUnpublished)
  72.         {
  73.             return false;
  74.         }
  75.         $tokenChecker System::getContainer()->get('contao.security.token_checker');
  76.         // Preview mode is enabled, so show the article
  77.         if ($tokenChecker->hasBackendUser() && $tokenChecker->isPreviewMode())
  78.         {
  79.             return false;
  80.         }
  81.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  82.         // We are in the back end, so show the article
  83.         if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
  84.         {
  85.             return false;
  86.         }
  87.         return true;
  88.     }
  89.     /**
  90.      * Generate the module
  91.      */
  92.     protected function compile()
  93.     {
  94.         /** @var PageModel $objPage */
  95.         global $objPage;
  96.         $id 'article-' $this->id;
  97.         // Generate the CSS ID if it is not set
  98.         if (empty($this->cssID[0]))
  99.         {
  100.             $this->cssID = array($id$this->cssID[1] ?? null);
  101.         }
  102.         $this->Template->column $this->inColumn;
  103.         $this->Template->noMarkup $this->blnNoMarkup;
  104.         // Add the modification date
  105.         $this->Template->timestamp $this->tstamp;
  106.         $this->Template->date Date::parse($objPage->datimFormat$this->tstamp);
  107.         // Clean the RTE output
  108.         $this->teaser StringUtil::toHtml5($this->teaser ?? '');
  109.         // Show the teaser only
  110.         if ($this->multiMode && $this->showTeaser)
  111.         {
  112.             $this->cssID = array($id'');
  113.             $arrCss StringUtil::deserialize($this->teaserCssID);
  114.             // Override the CSS ID and class
  115.             if (\is_array($arrCss) && \count($arrCss) == 2)
  116.             {
  117.                 if (!$arrCss[0])
  118.                 {
  119.                     $arrCss[0] = $id;
  120.                 }
  121.                 $this->cssID $arrCss;
  122.             }
  123.             $article $this->alias ?: $this->id;
  124.             $href '/articles/' . (($this->inColumn != 'main') ? $this->inColumn ':' '') . $article;
  125.             $this->Template->teaserOnly true;
  126.             $this->Template->headline $this->headline;
  127.             $this->Template->href $objPage->getFrontendUrl($href);
  128.             $this->Template->teaser $this->teaser;
  129.             $this->Template->readMore StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['readMore'], $this->headline), true);
  130.             $this->Template->more $GLOBALS['TL_LANG']['MSC']['more'];
  131.             return;
  132.         }
  133.         // Get section and article alias
  134.         $chunks explode(':'Input::get('articles') ?? '');
  135.         $strSection $chunks[0] ?? null;
  136.         $strArticle $chunks[1] ?? $strSection;
  137.         // Overwrite the page meta data (see #2853, #4955 and #87)
  138.         if (!$this->blnNoMarkup && $strArticle && ($strArticle == $this->id || $strArticle == $this->alias) && $this->title)
  139.         {
  140.             $responseContext System::getContainer()->get(ResponseContextAccessor::class)->getResponseContext();
  141.             if ($responseContext && $responseContext->has(HtmlHeadBag::class))
  142.             {
  143.                 /** @var HtmlHeadBag $htmlHeadBag */
  144.                 $htmlHeadBag $responseContext->get(HtmlHeadBag::class);
  145.                 $htmlHeadBag->setTitle(StringUtil::inputEncodedToPlainText($this->title ?? ''));
  146.                 if ($this->teaser)
  147.                 {
  148.                     $htmlHeadBag->setMetaDescription(StringUtil::htmlToPlainText($this->teaser));
  149.                 }
  150.             }
  151.         }
  152.         $this->Template->printable false;
  153.         $this->Template->backlink false;
  154.         // Back link
  155.         if (!$this->multiMode && $strArticle && ($strArticle == $this->id || $strArticle == $this->alias))
  156.         {
  157.             $this->Template->backlink 'javascript:history.go(-1)'// see #6955
  158.             $this->Template->back StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['goBack']);
  159.         }
  160.         $arrElements = array();
  161.         $objCte ContentModel::findPublishedByPidAndTable($this->id'tl_article');
  162.         if ($objCte !== null)
  163.         {
  164.             while ($objCte->next())
  165.             {
  166.                 $arrElements[] = $this->getContentElement($objCte->current(), $this->strColumn);
  167.             }
  168.         }
  169.         $this->Template->teaser $this->teaser;
  170.         $this->Template->elements $arrElements;
  171.         if ($this->keywords)
  172.         {
  173.             $GLOBALS['TL_KEYWORDS'] .= ($GLOBALS['TL_KEYWORDS'] ? ', ' '') . $this->keywords;
  174.         }
  175.         // Deprecated since Contao 4.0, to be removed in Contao 5.0
  176.         if ($this->printable == 1)
  177.         {
  178.             trigger_deprecation('contao/core-bundle''4.0''Setting tl_article.printable to "1" has been deprecated and will no longer work in Contao 5.0.');
  179.             $this->Template->printable = !empty($GLOBALS['TL_HOOKS']['printArticleAsPdf']);
  180.             $this->Template->pdfButton $this->Template->printable;
  181.         }
  182.         // New structure
  183.         elseif ($this->printable)
  184.         {
  185.             $options StringUtil::deserialize($this->printable);
  186.             if (!empty($options) && \is_array($options))
  187.             {
  188.                 // Remove the PDF option if there is no PDF handler (see #417)
  189.                 if (empty($GLOBALS['TL_HOOKS']['printArticleAsPdf']) && ($key array_search('pdf'$options)) !== false)
  190.                 {
  191.                     unset($options[$key]);
  192.                 }
  193.                 if (!empty($options))
  194.                 {
  195.                     $this->Template->printable true;
  196.                     $this->Template->printButton = \in_array('print'$options);
  197.                     $this->Template->pdfButton = \in_array('pdf'$options);
  198.                     $this->Template->facebookButton = \in_array('facebook'$options);
  199.                     $this->Template->twitterButton = \in_array('twitter'$options);
  200.                 }
  201.             }
  202.         }
  203.         // Add syndication variables
  204.         if ($this->Template->printable)
  205.         {
  206.             $request Environment::get('indexFreeRequest');
  207.             // URL encoding will be handled by the Symfony router, so do not apply rawurlencode() here anymore
  208.             $this->Template->print '#';
  209.             $this->Template->encUrl Environment::get('base') . Environment::get('request');
  210.             $this->Template->encTitle $objPage->pageTitle;
  211.             $this->Template->href $request . ((strpos($request'?') !== false) ? '&amp;' '?') . 'pdf=' $this->id;
  212.             $this->Template->printTitle StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['printPage']);
  213.             $this->Template->pdfTitle StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['printAsPdf']);
  214.             $this->Template->facebookTitle StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['facebookShare']);
  215.             $this->Template->twitterTitle StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['twitterShare']);
  216.         }
  217.         // HOOK: add custom logic
  218.         if (isset($GLOBALS['TL_HOOKS']['compileArticle']) && \is_array($GLOBALS['TL_HOOKS']['compileArticle']))
  219.         {
  220.             foreach ($GLOBALS['TL_HOOKS']['compileArticle'] as $callback)
  221.             {
  222.                 $this->import($callback[0]);
  223.                 $this->{$callback[0]}->{$callback[1]}($this->Template$this->arrData$this);
  224.             }
  225.         }
  226.     }
  227.     /**
  228.      * Print an article as PDF and stream it to the browser
  229.      */
  230.     public function generatePdf()
  231.     {
  232.         $this->headline $this->title;
  233.         $this->printable false;
  234.         // Generate article
  235.         $strArticle $this->replaceInsertTags($this->generate(), false);
  236.         $strArticle html_entity_decode($strArticleENT_QUOTESSystem::getContainer()->getParameter('kernel.charset'));
  237.         $strArticle $this->convertRelativeUrls($strArticle''true);
  238.         if (empty($GLOBALS['TL_HOOKS']['printArticleAsPdf']))
  239.         {
  240.             throw new \Exception('No PDF extension found. Did you forget to install contao/tcpdf-bundle?');
  241.         }
  242.         // HOOK: allow individual PDF routines
  243.         if (isset($GLOBALS['TL_HOOKS']['printArticleAsPdf']) && \is_array($GLOBALS['TL_HOOKS']['printArticleAsPdf']))
  244.         {
  245.             foreach ($GLOBALS['TL_HOOKS']['printArticleAsPdf'] as $callback)
  246.             {
  247.                 $this->import($callback[0]);
  248.                 $this->{$callback[0]}->{$callback[1]}($strArticle$this);
  249.             }
  250.         }
  251.     }
  252.     protected function getResponseCacheTags(): array
  253.     {
  254.         // Do not tag with 'contao.db.tl_module.<id>' when rendering articles (see #2814)
  255.         return array();
  256.     }
  257. }
  258. class_alias(ModuleArticle::class, 'ModuleArticle');