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

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