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

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