vendor/contao/calendar-bundle/src/Resources/contao/modules/ModuleEventlist.php line 48

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\PageNotFoundException;
  11. /**
  12.  * Front end module "event list".
  13.  *
  14.  * @property bool   $cal_noSpan
  15.  * @property string $cal_template
  16.  * @property int    $cal_limit
  17.  * @property string $cal_order
  18.  * @property array  $cal_calendar
  19.  * @property string $cal_format
  20.  * @property bool   $cal_ignoreDynamic
  21.  * @property int    $cal_readerModule
  22.  * @property bool   $cal_hideRunning
  23.  * @property string $cal_featured
  24.  */
  25. class ModuleEventlist extends Events
  26. {
  27.     /**
  28.      * Current date object
  29.      * @var Date
  30.      */
  31.     protected $Date;
  32.     /**
  33.      * Template
  34.      * @var string
  35.      */
  36.     protected $strTemplate 'mod_eventlist';
  37.     /**
  38.      * Display a wildcard in the back end
  39.      *
  40.      * @return string
  41.      */
  42.     public function generate()
  43.     {
  44.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  45.         if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
  46.         {
  47.             $objTemplate = new BackendTemplate('be_wildcard');
  48.             $objTemplate->wildcard '### ' $GLOBALS['TL_LANG']['FMD']['eventlist'][0] . ' ###';
  49.             $objTemplate->title $this->headline;
  50.             $objTemplate->id $this->id;
  51.             $objTemplate->link $this->name;
  52.             $objTemplate->href StringUtil::specialcharsUrl(System::getContainer()->get('router')->generate('contao_backend', array('do'=>'themes''table'=>'tl_module''act'=>'edit''id'=>$this->id)));
  53.             return $objTemplate->parse();
  54.         }
  55.         $this->cal_calendar $this->sortOutProtected(StringUtil::deserialize($this->cal_calendartrue));
  56.         // Return if there are no calendars
  57.         if (empty($this->cal_calendar) || !\is_array($this->cal_calendar))
  58.         {
  59.             return '';
  60.         }
  61.         // Show the event reader if an item has been selected
  62.         if ($this->cal_readerModule 0  && (isset($_GET['events']) || (Config::get('useAutoItem') && isset($_GET['auto_item']))))
  63.         {
  64.             return $this->getFrontendModule($this->cal_readerModule$this->strColumn);
  65.         }
  66.         // Tag the calendars (see #2137)
  67.         if (System::getContainer()->has('fos_http_cache.http.symfony_response_tagger'))
  68.         {
  69.             $responseTagger System::getContainer()->get('fos_http_cache.http.symfony_response_tagger');
  70.             $responseTagger->addTags(array_map(static function ($id) { return 'contao.db.tl_calendar.' $id; }, $this->cal_calendar));
  71.         }
  72.         return parent::generate();
  73.     }
  74.     /**
  75.      * Generate the module
  76.      */
  77.     protected function compile()
  78.     {
  79.         /** @var PageModel $objPage */
  80.         global $objPage;
  81.         $blnClearInput false;
  82.         $intYear = (int) Input::get('year');
  83.         $intMonth = (int) Input::get('month');
  84.         $intDay = (int) Input::get('day');
  85.         // Handle featured events
  86.         $blnFeatured null;
  87.         if ($this->cal_featured == 'featured')
  88.         {
  89.             $blnFeatured true;
  90.         }
  91.         elseif ($this->cal_featured == 'unfeatured')
  92.         {
  93.             $blnFeatured false;
  94.         }
  95.         // Jump to the current period
  96.         if (!isset($_GET['year']) && !isset($_GET['month']) && !isset($_GET['day']))
  97.         {
  98.             switch ($this->cal_format)
  99.             {
  100.                 case 'cal_year':
  101.                     $intYear date('Y');
  102.                     break;
  103.                 case 'cal_month':
  104.                     $intMonth date('Ym');
  105.                     break;
  106.                 case 'cal_day':
  107.                     $intDay date('Ymd');
  108.                     break;
  109.             }
  110.             $blnClearInput true;
  111.         }
  112.         $blnDynamicFormat = (!$this->cal_ignoreDynamic && \in_array($this->cal_format, array('cal_day''cal_month''cal_year')));
  113.         // Create the date object
  114.         try
  115.         {
  116.             if ($blnDynamicFormat && $intYear)
  117.             {
  118.                 $this->Date = new Date($intYear'Y');
  119.                 $this->cal_format 'cal_year';
  120.                 $this->headline .= ' ' date('Y'$this->Date->tstamp);
  121.             }
  122.             elseif ($blnDynamicFormat && $intMonth)
  123.             {
  124.                 $this->Date = new Date($intMonth'Ym');
  125.                 $this->cal_format 'cal_month';
  126.                 $this->headline .= ' ' Date::parse('F Y'$this->Date->tstamp);
  127.             }
  128.             elseif ($blnDynamicFormat && $intDay)
  129.             {
  130.                 $this->Date = new Date($intDay'Ymd');
  131.                 $this->cal_format 'cal_day';
  132.                 $this->headline .= ' ' Date::parse($objPage->dateFormat$this->Date->tstamp);
  133.             }
  134.             else
  135.             {
  136.                 $this->Date = new Date();
  137.             }
  138.         }
  139.         catch (\OutOfBoundsException $e)
  140.         {
  141.             throw new PageNotFoundException('Page not found: ' Environment::get('uri'));
  142.         }
  143.         list($intStart$intEnd$strEmpty) = $this->getDatesFromFormat($this->Date$this->cal_format);
  144.         // Get all events
  145.         $arrAllEvents $this->getAllEvents($this->cal_calendar$intStart$intEnd$blnFeatured);
  146.         $sort = ($this->cal_order == 'descending') ? 'krsort' 'ksort';
  147.         // Sort the days
  148.         $sort($arrAllEvents);
  149.         // Sort the events
  150.         foreach (array_keys($arrAllEvents) as $key)
  151.         {
  152.             $sort($arrAllEvents[$key]);
  153.         }
  154.         $intCount 0;
  155.         $arrEvents = array();
  156.         // Remove events outside the scope
  157.         foreach ($arrAllEvents as $days)
  158.         {
  159.             foreach ($days as $day=>$events)
  160.             {
  161.                 // Skip events before the start day if the "shortened view" option is not set.
  162.                 // Events after the end day are filtered in the Events::addEvent() method (see #8782).
  163.                 if (!$this->cal_noSpan && $day $intStart)
  164.                 {
  165.                     continue;
  166.                 }
  167.                 foreach ($events as $event)
  168.                 {
  169.                     // Use repeatEnd if > 0 (see #8447)
  170.                     if ($event['startTime'] > $intEnd || ($event['repeatEnd'] ?: $event['endTime']) < $intStart)
  171.                     {
  172.                         continue;
  173.                     }
  174.                     // Hide running events
  175.                     if ($this->cal_hideRunning && $event['begin'] < $intStart)
  176.                     {
  177.                         continue;
  178.                     }
  179.                     // Skip occurrences in the past
  180.                     if ($event['repeatEnd'] && $event['end'] < $intStart)
  181.                     {
  182.                         continue;
  183.                     }
  184.                     // Hide running non-recurring events (see #30)
  185.                     if ($this->cal_hideRunning && !$event['recurring'] && $event['startTime'] < time())
  186.                     {
  187.                         continue;
  188.                     }
  189.                     $event['firstDay'] = $GLOBALS['TL_LANG']['DAYS'][date('w', (int) $day)];
  190.                     $event['firstDate'] = Date::parse($objPage->dateFormat$day);
  191.                     $event['count'] = ++$intCount// see #74
  192.                     $arrEvents[] = $event;
  193.                 }
  194.             }
  195.         }
  196.         unset($arrAllEvents);
  197.         $total \count($arrEvents);
  198.         $limit $total;
  199.         $offset 0;
  200.         // Overall limit
  201.         if ($this->cal_limit 0)
  202.         {
  203.             $total min($this->cal_limit$total);
  204.             $limit $total;
  205.         }
  206.         // Pagination
  207.         if ($this->perPage 0)
  208.         {
  209.             $id 'page_e' $this->id;
  210.             $page Input::get($id) ?? 1;
  211.             // Do not index or cache the page if the page number is outside the range
  212.             if ($page || $page max(ceil($total/$this->perPage), 1))
  213.             {
  214.                 throw new PageNotFoundException('Page not found: ' Environment::get('uri'));
  215.             }
  216.             $offset = ($page 1) * $this->perPage;
  217.             $limit min($this->perPage $offset$total);
  218.             $objPagination = new Pagination($total$this->perPageConfig::get('maxPaginationLinks'), $id);
  219.             $this->Template->pagination $objPagination->generate("\n  ");
  220.         }
  221.         $strMonth '';
  222.         $strDate '';
  223.         $strEvents '';
  224.         $dayCount 0;
  225.         $eventCount 0;
  226.         $headerCount 0;
  227.         $uuids = array();
  228.         for ($i=$offset$i<$limit$i++)
  229.         {
  230.             if ($arrEvents[$i]['addImage'] && $arrEvents[$i]['singleSRC'])
  231.             {
  232.                 $uuids[] = $arrEvents[$i]['singleSRC'];
  233.             }
  234.         }
  235.         // Preload all images in one query, so they are loaded into the model registry
  236.         FilesModel::findMultipleByUuids($uuids);
  237.         // Parse events
  238.         for ($i=$offset$i<$limit$i++)
  239.         {
  240.             $event $arrEvents[$i];
  241.             $blnIsLastEvent false;
  242.             // Last event on the current day
  243.             if (($i+1) == $limit || !isset($arrEvents[($i+1)]['firstDate']) || $event['firstDate'] != $arrEvents[($i+1)]['firstDate'])
  244.             {
  245.                 $blnIsLastEvent true;
  246.             }
  247.             $objTemplate = new FrontendTemplate($this->cal_template ?: 'event_list');
  248.             $objTemplate->setData($event);
  249.             // Month header
  250.             if ($strMonth != $event['month'])
  251.             {
  252.                 $objTemplate->newMonth true;
  253.                 $strMonth $event['month'];
  254.             }
  255.             // Day header
  256.             if ($strDate != $event['firstDate'])
  257.             {
  258.                 $headerCount 0;
  259.                 $objTemplate->header true;
  260.                 $objTemplate->classHeader = ((($dayCount 2) == 0) ? ' even' ' odd') . (($dayCount == 0) ? ' first' '') . (($event['firstDate'] == $arrEvents[($limit-1)]['firstDate']) ? ' last' '');
  261.                 $strDate $event['firstDate'];
  262.                 ++$dayCount;
  263.             }
  264.             // Show the teaser text of redirect events (see #6315)
  265.             if (\is_bool($event['details']) && $event['source'] == 'default')
  266.             {
  267.                 $objTemplate->hasDetails false;
  268.             }
  269.             $objTemplate->hasReader $event['source'] == 'default';
  270.             // Add the template variables
  271.             $objTemplate->classList $event['class'] . ((($headerCount 2) == 0) ? ' even' ' odd') . (($headerCount == 0) ? ' first' '') . ($blnIsLastEvent ' last' '') . ' cal_' $event['parent'];
  272.             $objTemplate->classUpcoming $event['class'] . ((($eventCount 2) == 0) ? ' even' ' odd') . (($eventCount == 0) ? ' first' '') . ((($offset $eventCount 1) >= $limit) ? ' last' '') . ' cal_' $event['parent'];
  273.             $objTemplate->readMore StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['readMore'], $event['title']));
  274.             $objTemplate->more $GLOBALS['TL_LANG']['MSC']['more'];
  275.             $objTemplate->locationLabel $GLOBALS['TL_LANG']['MSC']['location'];
  276.             // Short view
  277.             if ($this->cal_noSpan)
  278.             {
  279.                 $objTemplate->day $event['day'];
  280.                 $objTemplate->date $event['date'];
  281.             }
  282.             else
  283.             {
  284.                 $objTemplate->day $event['firstDay'];
  285.                 $objTemplate->date $event['firstDate'];
  286.             }
  287.             $objTemplate->addImage false;
  288.             $objTemplate->addBefore false;
  289.             // Add an image
  290.             if ($event['addImage'])
  291.             {
  292.                 /** @var CalendarEventsModel $eventModel */
  293.                 $eventModel CalendarEventsModel::findByPk($event['id']);
  294.                 $imgSize $eventModel->size ?: null;
  295.                 // Override the default image size
  296.                 if ($this->imgSize)
  297.                 {
  298.                     $size StringUtil::deserialize($this->imgSize);
  299.                     if ($size[0] > || $size[1] > || is_numeric($size[2]) || ($size[2][0] ?? null) === '_')
  300.                     {
  301.                         $imgSize $this->imgSize;
  302.                     }
  303.                 }
  304.                 $figureBuilder System::getContainer()->get('contao.image.studio')->createFigureBuilder();
  305.                 $figure $figureBuilder
  306.                     ->from($event['singleSRC'])
  307.                     ->setSize($imgSize)
  308.                     ->setMetadata($eventModel->getOverwriteMetadata())
  309.                     ->enableLightbox((bool) $eventModel->fullsize)
  310.                     ->buildIfResourceExists();
  311.                 if (null !== $figure)
  312.                 {
  313.                     // Rebuild with link to event if none is set
  314.                     if (!$figure->getLinkHref())
  315.                     {
  316.                         $figure $figureBuilder
  317.                             ->setLinkHref($event['href'])
  318.                             ->setLinkAttribute('title'$objTemplate->readMore)
  319.                             ->build();
  320.                     }
  321.                     $figure->applyLegacyTemplateData($objTemplate$eventModel->imagemargin$eventModel->floating);
  322.                 }
  323.             }
  324.             $objTemplate->enclosure = array();
  325.             // Add enclosure
  326.             if ($event['addEnclosure'])
  327.             {
  328.                 $this->addEnclosuresToTemplate($objTemplate$event);
  329.             }
  330.             // schema.org information
  331.             $objTemplate->getSchemaOrgData = static function () use ($objTemplate$event): array
  332.             {
  333.                 $jsonLd Events::getSchemaOrgData((new CalendarEventsModel())->setRow($event));
  334.                 if ($objTemplate->addImage && $objTemplate->figure)
  335.                 {
  336.                     $jsonLd['image'] = $objTemplate->figure->getSchemaOrgData();
  337.                 }
  338.                 return $jsonLd;
  339.             };
  340.             $strEvents .= $objTemplate->parse();
  341.             ++$eventCount;
  342.             ++$headerCount;
  343.         }
  344.         // No events found
  345.         if (!$strEvents)
  346.         {
  347.             $strEvents "\n" '<div class="empty">' $strEmpty '</div>' "\n";
  348.         }
  349.         // See #3672
  350.         $this->Template->headline $this->headline;
  351.         $this->Template->events $strEvents;
  352.         $this->Template->eventCount $eventCount;
  353.         // Clear the $_GET array (see #2445)
  354.         if ($blnClearInput)
  355.         {
  356.             Input::setGet('year'null);
  357.             Input::setGet('month'null);
  358.             Input::setGet('day'null);
  359.         }
  360.     }
  361. }
  362. class_alias(ModuleEventlist::class, 'ModuleEventlist');