<?php/* * This file is part of Contao. * * (c) Leo Feyer * * @license LGPL-3.0-or-later */namespace Contao;use Contao\Model\Collection;/** * Parent class for objects that can be modules or content elements. * * @property string $headline * @property string $cssID * @property string $space * @property string $typePrefix * @property string $hl * @property string $attributes * * @author Leo Feyer <https://github.com/leofeyer> */abstract class Hybrid extends Frontend{ /** * Key * @var string */ protected $strKey; /** * Table * @var string */ protected $strTable; /** * Template * @var string */ protected $strTemplate; /** * Column * @var string */ protected $strColumn; /** * Model * @var Model */ protected $objModel; /** * Parent element * @var Model */ protected $objParent; /** * Current record * @var array */ protected $arrData = array(); /** * Style array * @var array */ protected $arrStyle = array(); /** * Initialize the object * * @param ContentModel|ModuleModel $objElement * @param string $strColumn */ public function __construct($objElement, $strColumn='main') { parent::__construct(); // Store the parent element (see #4556) if ($objElement instanceof Model || $objElement instanceof Collection) { /** @var ContentModel|ModuleModel $objModel */ $objModel = $objElement; if ($objModel instanceof Collection) { $objModel = $objModel->current(); } $this->objParent = $objModel; } if (!$this->strKey || !$this->strTable) { return; } $strModelClass = Model::getClassFromTable($this->strTable); // Load the model if (class_exists($strModelClass)) { /** @var Model|null $objHybrid */ $objHybrid = $strModelClass::findByPk($objElement->{$this->strKey}); if ($objHybrid === null) { return; } $this->objModel = $objHybrid; } // Directly query the database if there is no model class else { $objHybrid = $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE id=?") ->limit(1) ->execute($objElement->{$this->strKey}); if ($objHybrid->numRows < 1) { return; } } $cssID = array(); $this->arrData = $objHybrid->row(); // Get the CSS ID from the parent element (!) $this->cssID = StringUtil::deserialize($objElement->cssID, true); // Override the CSS ID (see #305) if (!empty($this->cssID[0])) { $cssID[0] = $this->cssID[0]; } // Merge the CSS classes (see #6011) if (!empty($this->cssID[1])) { $cssID[1] = trim(($cssID[1] ?? '') . ' ' . $this->cssID[1]); } $this->cssID = $cssID; $this->typePrefix = $objElement->typePrefix; $arrHeadline = StringUtil::deserialize($objElement->headline); $this->headline = \is_array($arrHeadline) ? $arrHeadline['value'] : $arrHeadline; $this->hl = \is_array($arrHeadline) ? $arrHeadline['unit'] : 'h1'; $this->strColumn = $strColumn; } /** * Set an object property * * @param string $strKey * @param mixed $varValue */ public function __set($strKey, $varValue) { $this->arrData[$strKey] = $varValue; } /** * Return an object property * * @param string $strKey * * @return mixed */ public function __get($strKey) { return $this->arrData[$strKey] ?? parent::__get($strKey); } /** * Check whether a property is set * * @param string $strKey * * @return boolean */ public function __isset($strKey) { return isset($this->arrData[$strKey]); } /** * Return the model * * @return Model */ public function getModel() { return $this->objModel; } /** * Return the parent object * * @return object */ public function getParent() { return $this->objParent; } /** * Parse the template * * @return string */ public function generate() { if ($this->isHidden()) { return ''; } $this->Template = new FrontendTemplate($this->strTemplate); $this->Template->setData($this->arrData); $this->compile(); $this->Template->style = !empty($this->arrStyle) ? implode(' ', $this->arrStyle) : ''; $this->Template->class = trim($this->typePrefix . $this->strKey . ' ' . ($this->cssID[1] ?? '')); $this->Template->cssID = !empty($this->cssID[0]) ? ' id="' . $this->cssID[0] . '"' : ''; $this->Template->inColumn = $this->strColumn; if (!$this->Template->headline) { $this->Template->headline = $this->headline; } if (!$this->Template->hl) { $this->Template->hl = $this->hl; } if (!empty($this->objParent->classes) && \is_array($this->objParent->classes)) { $this->Template->class .= ' ' . implode(' ', $this->objParent->classes); } return $this->Template->parse(); } protected function isHidden() { // Only content models can be invisible if (!$this->objParent instanceof ContentModel) { return false; } // Skip unsaved elements (see #2708) if (isset($this->objParent->tstamp) && !$this->objParent->tstamp) { return true; } $isInvisible = $this->objParent->invisible || ($this->objParent->start && $this->objParent->start > time()) || ($this->objParent->stop && $this->objParent->stop <= time()); // The element is visible, so show it if (!$isInvisible) { return false; } $tokenChecker = System::getContainer()->get('contao.security.token_checker'); // Preview mode is enabled, so show the element if ($tokenChecker->hasBackendUser() && $tokenChecker->isPreviewMode()) { return false; } $request = System::getContainer()->get('request_stack')->getCurrentRequest(); // We are in the back end, so show the element if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request)) { return false; } return true; } /** * Compile the current element */ abstract protected function compile();}class_alias(Hybrid::class, 'Hybrid');