vendor/netzmacht/contao-toolkit/src/Component/AbstractComponent.php line 104

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Netzmacht\Contao\Toolkit\Component;
  4. use Contao\Database\Result;
  5. use Contao\Model;
  6. use Contao\Model\Collection;
  7. use Contao\StringUtil;
  8. use InvalidArgumentException;
  9. use Netzmacht\Contao\Toolkit\Assertion\Assertion;
  10. use Netzmacht\Contao\Toolkit\Routing\RequestScopeMatcher;
  11. use Netzmacht\Contao\Toolkit\View\Template\TemplateReference as ToolkitTemplateReference;
  12. use Symfony\Component\Templating\EngineInterface as TemplateEngine;
  13. use Symfony\Component\Templating\TemplateReferenceInterface as TemplateReference;
  14. use function array_key_exists;
  15. use function defined;
  16. use function implode;
  17. use function is_array;
  18. use function trigger_error;
  19. use function trim;
  20. use const E_USER_DEPRECATED;
  21. use const TL_MODE;
  22. /**
  23.  * Base element.
  24.  *
  25.  * @deprecated Since 3.5.0 and get removed in 4.0.0
  26.  *
  27.  * @psalm-suppress DeprecatedInterface
  28.  * @psalm-suppress DeprecatedClass
  29.  */
  30. abstract class AbstractComponent implements Component
  31. {
  32.     /**
  33.      * Assigned model.
  34.      *
  35.      * @var Model|null
  36.      */
  37.     private $model;
  38.     /**
  39.      * Column of the element.
  40.      *
  41.      * @var string
  42.      */
  43.     private $column;
  44.     /**
  45.      * Components parameter.
  46.      *
  47.      * @var array<string,mixed>
  48.      */
  49.     private $data;
  50.     /**
  51.      * The template name.
  52.      *
  53.      * @var string
  54.      */
  55.     protected $templateName '';
  56.     /**
  57.      * Template engine.
  58.      *
  59.      * @var TemplateEngine
  60.      */
  61.     private $templateEngine;
  62.     /**
  63.      * Request scope matcher.
  64.      *
  65.      * @var RequestScopeMatcher|null
  66.      */
  67.     protected $requestScopeMatcher;
  68.     /**
  69.      * @param Model|Collection|Result  $model               Object model or result.
  70.      * @param TemplateEngine           $templateEngine      Template engine.
  71.      * @param string                   $column              Column.
  72.      * @param RequestScopeMatcher|null $requestScopeMatcher Request scope matcher.
  73.      *
  74.      * @throws InvalidArgumentException When model does not have a row method.
  75.      */
  76.     public function __construct(
  77.         $model,
  78.         TemplateEngine $templateEngine,
  79.         $column 'main',
  80.         ?RequestScopeMatcher $requestScopeMatcher null
  81.     ) {
  82.         if ($model instanceof Collection) {
  83.             $model $model->current();
  84.         }
  85.         if ($model instanceof Model) {
  86.             $this->model $model;
  87.         }
  88.         if ($requestScopeMatcher === null) {
  89.             // @codingStandardsIgnoreStart
  90.             @trigger_error(
  91.                 'RequestScopeMatcher not passed as forth argument. RequestScopeMatcher will be required in version 4.0.0',
  92.                 E_USER_DEPRECATED
  93.             );
  94.             // @codingStandardsIgnoreEnd
  95.         }
  96.         Assertion::methodExists('row'$model);
  97.         $this->templateEngine      $templateEngine;
  98.         $this->column              $column;
  99.         $this->requestScopeMatcher $requestScopeMatcher;
  100.         $this->data                $this->deserializeData($model->row());
  101.         if ($this->get('customTpl') === '' || ! $this->isFrontendRequest()) {
  102.             return;
  103.         }
  104.         $this->setTemplateName((string) $this->get('customTpl'));
  105.     }
  106.     /**
  107.      * {@inheritDoc}
  108.      *
  109.      * @psalm-suppress DeprecatedClass
  110.      */
  111.     public function set(string $name$value): Component
  112.     {
  113.         $this->data[$name] = $value;
  114.         return $this;
  115.     }
  116.     /**
  117.      * {@inheritDoc}
  118.      */
  119.     public function get(string $name)
  120.     {
  121.         if ($this->has($name)) {
  122.             return $this->data[$name];
  123.         }
  124.         return null;
  125.     }
  126.     /**
  127.      * Check if parameter exists.
  128.      *
  129.      * @param string $name Name of the parameter.
  130.      */
  131.     public function has(string $name): bool
  132.     {
  133.         return array_key_exists($name$this->data);
  134.     }
  135.     /**
  136.      * Get templateName.
  137.      */
  138.     protected function getTemplateName(): string
  139.     {
  140.         return $this->templateName;
  141.     }
  142.     /**
  143.      * Set templateName.
  144.      *
  145.      * @param string $templateName Template name.
  146.      *
  147.      * @return $this
  148.      */
  149.     protected function setTemplateName(string $templateName): self
  150.     {
  151.         $this->templateName $templateName;
  152.         return $this;
  153.     }
  154.     /**
  155.      * {@inheritDoc}
  156.      */
  157.     public function getModel()
  158.     {
  159.         return $this->model;
  160.     }
  161.     public function generate(): string
  162.     {
  163.         $this->compile();
  164.         $data   $this->prepareTemplateData($this->getData());
  165.         $buffer $this->render($this->getTemplateReference(), $data);
  166.         $buffer $this->postGenerate($buffer);
  167.         return $buffer;
  168.     }
  169.     /**
  170.      * Render a template.
  171.      *
  172.      * @param TemplateReference|string $templateName Template name or reference.
  173.      * @param array<string,mixed>      $parameters   Additional parameters being passed to the template.
  174.      */
  175.     protected function render($templateName, array $parameters = []): string
  176.     {
  177.         return $this->templateEngine->render($templateName$parameters);
  178.     }
  179.     /**
  180.      * Pre template data.
  181.      *
  182.      * @param array<string,mixed> $data Given data.
  183.      *
  184.      * @return array<string,mixed>
  185.      */
  186.     protected function prepareTemplateData(array $data): array
  187.     {
  188.         $style = [];
  189.         $space $this->get('space');
  190.         if (! empty($space[0])) {
  191.             $style[] = 'margin-top:' $space[0] . 'px;';
  192.         }
  193.         if (! empty($space[1])) {
  194.             $style[] = 'margin-bottom:' $space[1] . 'px;';
  195.         }
  196.         $cssID    $this->get('cssID');
  197.         $cssClass $this->compileCssClass();
  198.         // Do not change this order (see #6191)
  199.         $data['style']    = implode(' '$style);
  200.         $data['class']    = $cssClass;
  201.         $data['cssID']    = $cssID[0] !== '' ' id="' $cssID[0] . '"' '';
  202.         $data['inColumn'] = $this->getColumn();
  203.         return $data;
  204.     }
  205.     /**
  206.      * Post generate the output.
  207.      *
  208.      * @param string $buffer Generated component.
  209.      */
  210.     private function postGenerate(string $buffer): string
  211.     {
  212.         return $buffer;
  213.     }
  214.     /**
  215.      * Compile the component.
  216.      *
  217.      * @return void
  218.      */
  219.     // phpcs:ignore SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint
  220.     protected function compile()
  221.     {
  222.     }
  223.     /**
  224.      * Get the template data.
  225.      *
  226.      * @return array<string,mixed>
  227.      */
  228.     protected function getData(): array
  229.     {
  230.         return $this->data;
  231.     }
  232.     /**
  233.      * Deserialize the model data.
  234.      *
  235.      * @param array<string,mixed> $row Model data.
  236.      *
  237.      * @return array<string,mixed>
  238.      */
  239.     protected function deserializeData(array $row): array
  240.     {
  241.         if (! empty($row['space'])) {
  242.             $row['space'] = StringUtil::deserialize($row['space']);
  243.         }
  244.         if (! empty($row['cssID'])) {
  245.             $row['cssID'] = StringUtil::deserialize($row['cssID'], true);
  246.         }
  247.         $headline StringUtil::deserialize($row['headline']);
  248.         if (is_array($headline)) {
  249.             $row['headline'] = $headline['value'];
  250.             $row['hl']       = $headline['unit'];
  251.         } else {
  252.             $row['headline'] = $headline;
  253.             $row['hl']       = 'h1';
  254.         }
  255.         return $row;
  256.     }
  257.     /**
  258.      * Compile the css class.
  259.      */
  260.     protected function compileCssClass(): string
  261.     {
  262.         $cssID    $this->get('cssID');
  263.         $cssClass '';
  264.         if (! empty($cssID[1])) {
  265.             $cssClass .= $cssID[1];
  266.         }
  267.         $model $this->getModel();
  268.         if ($model && $model->classes) {
  269.             $cssClass .= ' ' implode(' ', (array) $model->classes);
  270.         }
  271.         return trim($cssClass);
  272.     }
  273.     /**
  274.      * Get the column.
  275.      */
  276.     protected function getColumn(): string
  277.     {
  278.         return $this->column;
  279.     }
  280.     /**
  281.      * Get the template reference.
  282.      */
  283.     protected function getTemplateReference(): TemplateReference
  284.     {
  285.         return new ToolkitTemplateReference(
  286.             $this->getTemplateName(),
  287.             'html5',
  288.             ToolkitTemplateReference::SCOPE_FRONTEND
  289.         );
  290.     }
  291.     /**
  292.      * Check if current request is a Contao frontend request.
  293.      */
  294.     protected function isFrontendRequest(): bool
  295.     {
  296.         if ($this->requestScopeMatcher) {
  297.             return $this->requestScopeMatcher->isFrontendRequest();
  298.         }
  299.         return defined('TL_MODE') && TL_MODE === 'FE';
  300.     }
  301.     /**
  302.      * Check if current request is a Contao backend request.
  303.      */
  304.     protected function isBackendRequest(): bool
  305.     {
  306.         if ($this->requestScopeMatcher) {
  307.             return $this->requestScopeMatcher->isBackendRequest();
  308.         }
  309.         return defined('TL_MODE') && TL_MODE === 'BE';
  310.     }
  311. }