vendor/contao/calendar-bundle/src/Resources/contao/modules/ModuleEventReader.php line 41

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\Exception\InternalServerErrorException;
  11. use Contao\CoreBundle\Exception\PageNotFoundException;
  12. use Contao\CoreBundle\Exception\RedirectResponseException;
  13. use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag;
  14. /**
  15.  * Front end module "event reader".
  16.  *
  17.  * @property Comments $Comments
  18.  * @property string   $com_template
  19.  * @property string   $cal_template
  20.  * @property array    $cal_calendar
  21.  */
  22. class ModuleEventReader extends Events
  23. {
  24.     /**
  25.      * Template
  26.      * @var string
  27.      */
  28.     protected $strTemplate 'mod_eventreader';
  29.     /**
  30.      * Display a wildcard in the back end
  31.      *
  32.      * @throws InternalServerErrorException
  33.      *
  34.      * @return string
  35.      */
  36.     public function generate()
  37.     {
  38.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  39.         if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
  40.         {
  41.             $objTemplate = new BackendTemplate('be_wildcard');
  42.             $objTemplate->wildcard '### ' $GLOBALS['TL_LANG']['FMD']['eventreader'][0] . ' ###';
  43.             $objTemplate->title $this->headline;
  44.             $objTemplate->id $this->id;
  45.             $objTemplate->link $this->name;
  46.             $objTemplate->href StringUtil::specialcharsUrl(System::getContainer()->get('router')->generate('contao_backend', array('do'=>'themes''table'=>'tl_module''act'=>'edit''id'=>$this->id)));
  47.             return $objTemplate->parse();
  48.         }
  49.         // Set the item from the auto_item parameter
  50.         if (!isset($_GET['events']) && isset($_GET['auto_item']) && Config::get('useAutoItem'))
  51.         {
  52.             Input::setGet('events'Input::get('auto_item'));
  53.         }
  54.         // Return an empty string if "events" is not set (to combine list and reader on same page)
  55.         if (!Input::get('events'))
  56.         {
  57.             return '';
  58.         }
  59.         $this->cal_calendar $this->sortOutProtected(StringUtil::deserialize($this->cal_calendar));
  60.         if (empty($this->cal_calendar) || !\is_array($this->cal_calendar))
  61.         {
  62.             throw new InternalServerErrorException('The event reader ID ' $this->id ' has no calendars specified.');
  63.         }
  64.         return parent::generate();
  65.     }
  66.     /**
  67.      * Generate the module
  68.      */
  69.     protected function compile()
  70.     {
  71.         /** @var PageModel $objPage */
  72.         global $objPage;
  73.         $this->Template->event '';
  74.         if ($this->overviewPage)
  75.         {
  76.             $this->Template->referer PageModel::findById($this->overviewPage)->getFrontendUrl();
  77.             $this->Template->back $this->customLabel ?: $GLOBALS['TL_LANG']['MSC']['eventOverview'];
  78.         }
  79.         else
  80.         {
  81.             trigger_deprecation('contao/calendar-bundle''4.13''If you do not select an overview page in the event reader module, the "go back" link will no longer be shown in Contao 5.0.');
  82.             $this->Template->referer 'javascript:history.go(-1)';
  83.             $this->Template->back $GLOBALS['TL_LANG']['MSC']['goBack'];
  84.         }
  85.         // Get the current event
  86.         $objEvent CalendarEventsModel::findPublishedByParentAndIdOrAlias(Input::get('events'), $this->cal_calendar);
  87.         // The event does not exist (see #33)
  88.         if ($objEvent === null)
  89.         {
  90.             throw new PageNotFoundException('Page not found: ' Environment::get('uri'));
  91.         }
  92.         // Redirect if the event has a target URL (see #1498)
  93.         switch ($objEvent->source) {
  94.             case 'internal':
  95.                 if ($page PageModel::findPublishedById($objEvent->jumpTo))
  96.                 {
  97.                     throw new RedirectResponseException($page->getAbsoluteUrl(), 301);
  98.                 }
  99.                 throw new InternalServerErrorException('Invalid "jumpTo" value or target page not public');
  100.             case 'article':
  101.                 if (($article ArticleModel::findByPk($objEvent->articleId)) && ($page PageModel::findPublishedById($article->pid)))
  102.                 {
  103.                     throw new RedirectResponseException($page->getAbsoluteUrl('/articles/' . ($article->alias ?: $article->id)), 301);
  104.                 }
  105.                 throw new InternalServerErrorException('Invalid "articleId" value or target page not public');
  106.             case 'external':
  107.                 if ($objEvent->url)
  108.                 {
  109.                     throw new RedirectResponseException($objEvent->url301);
  110.                 }
  111.                 throw new InternalServerErrorException('Empty target URL');
  112.         }
  113.         // Overwrite the page metadata (see #2853, #4955 and #87)
  114.         $responseContext System::getContainer()->get('contao.routing.response_context_accessor')->getResponseContext();
  115.         if ($responseContext && $responseContext->has(HtmlHeadBag::class))
  116.         {
  117.             /** @var HtmlHeadBag $htmlHeadBag */
  118.             $htmlHeadBag $responseContext->get(HtmlHeadBag::class);
  119.             $htmlDecoder System::getContainer()->get('contao.string.html_decoder');
  120.             if ($objEvent->pageTitle)
  121.             {
  122.                 $htmlHeadBag->setTitle($objEvent->pageTitle); // Already stored decoded
  123.             }
  124.             elseif ($objEvent->title)
  125.             {
  126.                 $htmlHeadBag->setTitle($htmlDecoder->inputEncodedToPlainText($objEvent->title));
  127.             }
  128.             if ($objEvent->description)
  129.             {
  130.                 $htmlHeadBag->setMetaDescription($htmlDecoder->inputEncodedToPlainText($objEvent->description));
  131.             }
  132.             elseif ($objEvent->teaser)
  133.             {
  134.                 $htmlHeadBag->setMetaDescription($htmlDecoder->htmlToPlainText($objEvent->teaser));
  135.             }
  136.             if ($objEvent->robots)
  137.             {
  138.                 $htmlHeadBag->setMetaRobots($objEvent->robots);
  139.             }
  140.         }
  141.         $intStartTime $objEvent->startTime;
  142.         $intEndTime $objEvent->endTime;
  143.         $span Calendar::calculateSpan($intStartTime$intEndTime);
  144.         // Do not show dates in the past if the event is recurring (see #923)
  145.         if ($objEvent->recurring)
  146.         {
  147.             $arrRange StringUtil::deserialize($objEvent->repeatEach);
  148.             if (isset($arrRange['unit'], $arrRange['value']))
  149.             {
  150.                 while (($this->cal_hideRunning $intStartTime $intEndTime) < time() && $intEndTime $objEvent->repeatEnd)
  151.                 {
  152.                     $intStartTime strtotime('+' $arrRange['value'] . ' ' $arrRange['unit'], $intStartTime);
  153.                     $intEndTime strtotime('+' $arrRange['value'] . ' ' $arrRange['unit'], $intEndTime);
  154.                 }
  155.             }
  156.         }
  157.         // Mark past and upcoming events (see #187)
  158.         if ($intEndTime strtotime('00:00:00'))
  159.         {
  160.             $objEvent->cssClass .= ' bygone';
  161.         }
  162.         elseif ($intStartTime strtotime('23:59:59'))
  163.         {
  164.             $objEvent->cssClass .= ' upcoming';
  165.         }
  166.         else
  167.         {
  168.             $objEvent->cssClass .= ' current';
  169.         }
  170.         list($strDate$strTime) = $this->getDateAndTime($objEvent$objPage$intStartTime$intEndTime$span);
  171.         $until '';
  172.         $recurring '';
  173.         $arrRange = array();
  174.         // Recurring event
  175.         if ($objEvent->recurring)
  176.         {
  177.             $arrRange StringUtil::deserialize($objEvent->repeatEach);
  178.             if (isset($arrRange['unit'], $arrRange['value']))
  179.             {
  180.                 if ($arrRange['value'] == 1)
  181.                 {
  182.                     $repeat $GLOBALS['TL_LANG']['MSC']['cal_single_' $arrRange['unit']];
  183.                 }
  184.                 else
  185.                 {
  186.                     $repeat sprintf($GLOBALS['TL_LANG']['MSC']['cal_multiple_' $arrRange['unit']], $arrRange['value']);
  187.                 }
  188.                 if ($objEvent->recurrences 0)
  189.                 {
  190.                     $until ' ' sprintf($GLOBALS['TL_LANG']['MSC']['cal_until'], Date::parse($objPage->dateFormat$objEvent->repeatEnd));
  191.                 }
  192.                 if ($objEvent->recurrences && $intEndTime <= time())
  193.                 {
  194.                     $recurring sprintf($GLOBALS['TL_LANG']['MSC']['cal_repeat_ended'], $repeat$until);
  195.                 }
  196.                 elseif ($objEvent->addTime)
  197.                 {
  198.                     $recurring sprintf($GLOBALS['TL_LANG']['MSC']['cal_repeat'], $repeat$untildate('Y-m-d\TH:i:sP'$intStartTime), $strDate . ($strTime ' ' $strTime ''));
  199.                 }
  200.                 else
  201.                 {
  202.                     $recurring sprintf($GLOBALS['TL_LANG']['MSC']['cal_repeat'], $repeat$untildate('Y-m-d'$intStartTime), $strDate);
  203.                 }
  204.             }
  205.         }
  206.         $objTemplate = new FrontendTemplate($this->cal_template ?: 'event_full');
  207.         $objTemplate->setData($objEvent->row());
  208.         $objTemplate->date $strDate;
  209.         $objTemplate->time $strTime;
  210.         $objTemplate->datetime $objEvent->addTime date('Y-m-d\TH:i:sP'$intStartTime) : date('Y-m-d'$intStartTime);
  211.         $objTemplate->begin $intStartTime;
  212.         $objTemplate->end $intEndTime;
  213.         $objTemplate->class $objEvent->cssClass ' ' trim($objEvent->cssClass) : '';
  214.         $objTemplate->recurring $recurring;
  215.         $objTemplate->until $until;
  216.         $objTemplate->locationLabel $GLOBALS['TL_LANG']['MSC']['location'];
  217.         $objTemplate->calendar $objEvent->getRelated('pid');
  218.         $objTemplate->count 0// see #74
  219.         $objTemplate->details '';
  220.         $objTemplate->hasDetails false;
  221.         $objTemplate->hasTeaser false;
  222.         $objTemplate->hasReader true;
  223.         // Clean the RTE output
  224.         if ($objEvent->teaser)
  225.         {
  226.             $objTemplate->hasTeaser true;
  227.             $objTemplate->teaser StringUtil::encodeEmail($objEvent->teaser);
  228.         }
  229.         // Display the "read more" button for external/article links
  230.         if ($objEvent->source != 'default')
  231.         {
  232.             $objTemplate->hasDetails true;
  233.             $objTemplate->hasReader false;
  234.         }
  235.         // Compile the event text
  236.         else
  237.         {
  238.             $id $objEvent->id;
  239.             $objTemplate->details = function () use ($id)
  240.             {
  241.                 $strDetails '';
  242.                 $objElement ContentModel::findPublishedByPidAndTable($id'tl_calendar_events');
  243.                 if ($objElement !== null)
  244.                 {
  245.                     while ($objElement->next())
  246.                     {
  247.                         $strDetails .= $this->getContentElement($objElement->current());
  248.                     }
  249.                 }
  250.                 return $strDetails;
  251.             };
  252.             $objTemplate->hasDetails = static function () use ($id)
  253.             {
  254.                 return ContentModel::countPublishedByPidAndTable($id'tl_calendar_events') > 0;
  255.             };
  256.         }
  257.         $objTemplate->addImage false;
  258.         $objTemplate->addBefore false;
  259.         // Add an image
  260.         if ($objEvent->addImage)
  261.         {
  262.             $imgSize $objEvent->size ?: null;
  263.             // Override the default image size
  264.             if ($this->imgSize)
  265.             {
  266.                 $size StringUtil::deserialize($this->imgSize);
  267.                 if ($size[0] > || $size[1] > || is_numeric($size[2]) || ($size[2][0] ?? null) === '_')
  268.                 {
  269.                     $imgSize $this->imgSize;
  270.                 }
  271.             }
  272.             $figure System::getContainer()
  273.                 ->get('contao.image.studio')
  274.                 ->createFigureBuilder()
  275.                 ->from($objEvent->singleSRC)
  276.                 ->setSize($imgSize)
  277.                 ->setMetadata($objEvent->getOverwriteMetadata())
  278.                 ->enableLightbox((bool) $objEvent->fullsize)
  279.                 ->buildIfResourceExists();
  280.             if (null !== $figure)
  281.             {
  282.                 $figure->applyLegacyTemplateData($objTemplate$objEvent->imagemargin$objEvent->floating);
  283.             }
  284.         }
  285.         $objTemplate->enclosure = array();
  286.         // Add enclosures
  287.         if ($objEvent->addEnclosure)
  288.         {
  289.             $this->addEnclosuresToTemplate($objTemplate$objEvent->row());
  290.         }
  291.         // Add a function to retrieve upcoming dates (see #175)
  292.         $objTemplate->getUpcomingDates = function ($recurrences) use ($objEvent$objPage$intStartTime$intEndTime$arrRange$span)
  293.         {
  294.             if (!$objEvent->recurring || !isset($arrRange['unit'], $arrRange['value']))
  295.             {
  296.                 return array();
  297.             }
  298.             $dates = array();
  299.             $startTime $intStartTime;
  300.             $endTime $intEndTime;
  301.             $strtotime '+ ' $arrRange['value'] . ' ' $arrRange['unit'];
  302.             for ($i=0$i<$recurrences$i++)
  303.             {
  304.                 $startTime strtotime($strtotime$startTime);
  305.                 $endTime strtotime($strtotime$endTime);
  306.                 if ($endTime $objEvent->repeatEnd)
  307.                 {
  308.                     break;
  309.                 }
  310.                 list($strDate$strTime) = $this->getDateAndTime($objEvent$objPage$startTime$endTime$span);
  311.                 $dates[] = array
  312.                 (
  313.                     'date' => $strDate,
  314.                     'time' => $strTime,
  315.                     'datetime' => $objEvent->addTime date('Y-m-d\TH:i:sP'$startTime) : date('Y-m-d'$endTime),
  316.                     'begin' => $startTime,
  317.                     'end' => $endTime
  318.                 );
  319.             }
  320.             return $dates;
  321.         };
  322.         // Add a function to retrieve past dates (see #175)
  323.         $objTemplate->getPastDates = function ($recurrences) use ($objEvent$objPage$intStartTime$intEndTime$arrRange$span)
  324.         {
  325.             if (!$objEvent->recurring || !isset($arrRange['unit'], $arrRange['value']))
  326.             {
  327.                 return array();
  328.             }
  329.             $dates = array();
  330.             $startTime $intStartTime;
  331.             $endTime $intEndTime;
  332.             $strtotime '- ' $arrRange['value'] . ' ' $arrRange['unit'];
  333.             for ($i=0$i<$recurrences$i++)
  334.             {
  335.                 $startTime strtotime($strtotime$startTime);
  336.                 $endTime strtotime($strtotime$endTime);
  337.                 if ($startTime $objEvent->startDate)
  338.                 {
  339.                     break;
  340.                 }
  341.                 list($strDate$strTime) = $this->getDateAndTime($objEvent$objPage$startTime$endTime$span);
  342.                 $dates[] = array
  343.                 (
  344.                     'date' => $strDate,
  345.                     'time' => $strTime,
  346.                     'datetime' => $objEvent->addTime date('Y-m-d\TH:i:sP'$startTime) : date('Y-m-d'$endTime),
  347.                     'begin' => $startTime,
  348.                     'end' => $endTime
  349.                 );
  350.             }
  351.             return $dates;
  352.         };
  353.         // schema.org information
  354.         $objTemplate->getSchemaOrgData = static function () use ($objTemplate$objEvent): array
  355.         {
  356.             $jsonLd Events::getSchemaOrgData($objEvent);
  357.             if ($objTemplate->addImage && $objTemplate->figure)
  358.             {
  359.                 $jsonLd['image'] = $objTemplate->figure->getSchemaOrgData();
  360.             }
  361.             return $jsonLd;
  362.         };
  363.         $this->Template->event $objTemplate->parse();
  364.         // Tag the event (see #2137)
  365.         if (System::getContainer()->has('fos_http_cache.http.symfony_response_tagger'))
  366.         {
  367.             $responseTagger System::getContainer()->get('fos_http_cache.http.symfony_response_tagger');
  368.             $responseTagger->addTags(array('contao.db.tl_calendar_events.' $objEvent->id));
  369.         }
  370.         $bundles System::getContainer()->getParameter('kernel.bundles');
  371.         // HOOK: comments extension required
  372.         if ($objEvent->noComments || !isset($bundles['ContaoCommentsBundle']))
  373.         {
  374.             $this->Template->allowComments false;
  375.             return;
  376.         }
  377.         /** @var CalendarModel $objCalendar */
  378.         $objCalendar $objEvent->getRelated('pid');
  379.         $this->Template->allowComments $objCalendar->allowComments;
  380.         // Comments are not allowed
  381.         if (!$objCalendar->allowComments)
  382.         {
  383.             return;
  384.         }
  385.         // Adjust the comments headline level
  386.         $intHl min((int) str_replace('h'''$this->hl), 5);
  387.         $this->Template->hlc 'h' . ($intHl 1);
  388.         $this->import(Comments::class, 'Comments');
  389.         $arrNotifies = array();
  390.         // Notify the system administrator
  391.         if ($objCalendar->notify != 'notify_author')
  392.         {
  393.             $arrNotifies[] = $GLOBALS['TL_ADMIN_EMAIL'];
  394.         }
  395.         /** @var UserModel $objAuthor */
  396.         if ($objCalendar->notify != 'notify_admin' && ($objAuthor $objEvent->getRelated('author')) instanceof UserModel && $objAuthor->email)
  397.         {
  398.             $arrNotifies[] = $objAuthor->email;
  399.         }
  400.         $objConfig = new \stdClass();
  401.         $objConfig->perPage $objCalendar->perPage;
  402.         $objConfig->order $objCalendar->sortOrder;
  403.         $objConfig->template $this->com_template;
  404.         $objConfig->requireLogin $objCalendar->requireLogin;
  405.         $objConfig->disableCaptcha $objCalendar->disableCaptcha;
  406.         $objConfig->bbcode $objCalendar->bbcode;
  407.         $objConfig->moderate $objCalendar->moderate;
  408.         $this->Comments->addCommentsToTemplate($this->Template$objConfig'tl_calendar_events'$objEvent->id$arrNotifies);
  409.     }
  410.     /**
  411.      * Return the date and time strings
  412.      *
  413.      * @param CalendarEventsModel $objEvent
  414.      * @param PageModel           $objPage
  415.      * @param integer             $intStartTime
  416.      * @param integer             $intEndTime
  417.      * @param integer             $span
  418.      *
  419.      * @return array
  420.      */
  421.     private function getDateAndTime(CalendarEventsModel $objEventPageModel $objPage$intStartTime$intEndTime$span)
  422.     {
  423.         $strDate Date::parse($objPage->dateFormat$intStartTime);
  424.         if ($span 0)
  425.         {
  426.             $strDate Date::parse($objPage->dateFormat$intStartTime) . $GLOBALS['TL_LANG']['MSC']['cal_timeSeparator'] . Date::parse($objPage->dateFormat$intEndTime);
  427.         }
  428.         $strTime '';
  429.         if ($objEvent->addTime)
  430.         {
  431.             if ($span 0)
  432.             {
  433.                 $strDate Date::parse($objPage->datimFormat$intStartTime) . $GLOBALS['TL_LANG']['MSC']['cal_timeSeparator'] . Date::parse($objPage->datimFormat$intEndTime);
  434.             }
  435.             elseif ($intStartTime == $intEndTime)
  436.             {
  437.                 $strTime Date::parse($objPage->timeFormat$intStartTime);
  438.             }
  439.             else
  440.             {
  441.                 $strTime Date::parse($objPage->timeFormat$intStartTime) . $GLOBALS['TL_LANG']['MSC']['cal_timeSeparator'] . Date::parse($objPage->timeFormat$intEndTime);
  442.             }
  443.         }
  444.         return array($strDate$strTime);
  445.     }
  446. }
  447. class_alias(ModuleEventReader::class, 'ModuleEventReader');