vendor/pimcore/pimcore/models/Document/Tag/Areablock.php line 31

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @category   Pimcore
  12.  * @package    Document
  13.  *
  14.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  15.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  16.  */
  17. namespace Pimcore\Model\Document\Tag;
  18. use Pimcore\Document\Tag\Block\BlockName;
  19. use Pimcore\Document\Tag\TagHandlerInterface;
  20. use Pimcore\Logger;
  21. use Pimcore\Model;
  22. use Pimcore\Model\Document;
  23. use Pimcore\Tool;
  24. use Pimcore\Tool\HtmlUtils;
  25. /**
  26.  * @method \Pimcore\Model\Document\Tag\Dao getDao()
  27.  */
  28. class Areablock extends Model\Document\Tag implements BlockInterface
  29. {
  30.     /**
  31.      * Contains an array of indices, which represent the order of the elements in the block
  32.      *
  33.      * @var array
  34.      */
  35.     public $indices = [];
  36.     /**
  37.      * Current step of the block while iteration
  38.      *
  39.      * @var int
  40.      */
  41.     public $current 0;
  42.     /**
  43.      * @var array
  44.      */
  45.     public $currentIndex;
  46.     /**
  47.      * @var bool
  48.      */
  49.     protected $blockStarted;
  50.     /**
  51.      * @var array
  52.      */
  53.     private $brickTypeUsageCounter = [];
  54.     /**
  55.      * @see Document\Tag\TagInterface::getType
  56.      *
  57.      * @return string
  58.      */
  59.     public function getType()
  60.     {
  61.         return 'areablock';
  62.     }
  63.     /**
  64.      * @see Document\Tag\TagInterface::getData
  65.      *
  66.      * @return mixed
  67.      */
  68.     public function getData()
  69.     {
  70.         return $this->indices;
  71.     }
  72.     /**
  73.      * @see Document\Tag\TagInterface::admin
  74.      *
  75.      * @return void
  76.      */
  77.     public function admin()
  78.     {
  79.         $this->frontend();
  80.     }
  81.     /**
  82.      * @see Document\Tag\TagInterface::frontend
  83.      *
  84.      * @return void
  85.      */
  86.     public function frontend()
  87.     {
  88.         if (!is_array($this->indices)) {
  89.             $this->indices = [];
  90.         }
  91.         reset($this->indices);
  92.         while ($this->loop());
  93.     }
  94.     /**
  95.      * @param int $index
  96.      */
  97.     public function renderIndex($index)
  98.     {
  99.         $this->start();
  100.         $this->currentIndex $this->indices[$index];
  101.         $this->current $index;
  102.         $this->blockConstruct();
  103.         $this->blockStart();
  104.         $this->content();
  105.         $this->blockDestruct();
  106.         $this->blockEnd();
  107.         $this->end();
  108.     }
  109.     public function loop()
  110.     {
  111.         $disabled false;
  112.         $options $this->getOptions();
  113.         $manual false;
  114.         if (is_array($options) && array_key_exists('manual'$options) && $options['manual'] == true) {
  115.             $manual true;
  116.         }
  117.         if ($this->current 0) {
  118.             if (!$manual && $this->blockStarted) {
  119.                 $this->blockDestruct();
  120.                 $this->blockEnd();
  121.                 $this->blockStarted false;
  122.             }
  123.         } else {
  124.             if (!$manual) {
  125.                 $this->start();
  126.             }
  127.         }
  128.         if ($this->current count($this->indices) && $this->current $this->options['limit']) {
  129.             $index current($this->indices);
  130.             next($this->indices);
  131.             $this->currentIndex $index;
  132.             if (!empty($options['allowed']) && !in_array($index['type'], $options['allowed'])) {
  133.                 $disabled true;
  134.             }
  135.             $brickTypeLimit $this->options['limits'][$this->currentIndex['type']] ?? 100000;
  136.             $brickTypeUsageCounter $this->brickTypeUsageCounter[$this->currentIndex['type']] ?? 0;
  137.             if ($brickTypeUsageCounter >= $brickTypeLimit) {
  138.                 $disabled true;
  139.             }
  140.             if (!$this->getTagHandler()->isBrickEnabled($this$index['type']) && $options['dontCheckEnabled'] != true) {
  141.                 $disabled true;
  142.             }
  143.             $this->blockStarted false;
  144.             if (!$manual && !$disabled) {
  145.                 $this->blockConstruct();
  146.                 $this->blockStart();
  147.                 $this->blockStarted true;
  148.                 $this->content();
  149.             } elseif (!$manual) {
  150.                 $this->current++;
  151.             }
  152.             return true;
  153.         } else {
  154.             if (!$manual) {
  155.                 $this->end();
  156.             }
  157.             return false;
  158.         }
  159.     }
  160.     public function content()
  161.     {
  162.         // create info object and assign it to the view
  163.         $info = new Area\Info();
  164.         try {
  165.             $info->setId($this->currentIndex['type']);
  166.             $info->setTag($this);
  167.             $info->setIndex($this->current);
  168.         } catch (\Exception $e) {
  169.             Logger::err($e);
  170.         }
  171.         $params = [];
  172.         $options $this->getOptions();
  173.         if (isset($options['params']) && is_array($options['params']) && array_key_exists($this->currentIndex['type'], $options['params'])) {
  174.             if (is_array($options['params'][$this->currentIndex['type']])) {
  175.                 $params $options['params'][$this->currentIndex['type']];
  176.             }
  177.         }
  178.         if (isset($options['globalParams'])) {
  179.             $params array_merge($options['globalParams'], (array)$params);
  180.         }
  181.         $info->setParams($params);
  182.         if ($this->editmode || !isset($this->currentIndex['hidden']) || !$this->currentIndex['hidden']) {
  183.             $this->getTagHandler()->renderAreaFrontend($info);
  184.             $this->brickTypeUsageCounter += [$this->currentIndex['type'] => 0];
  185.             $this->brickTypeUsageCounter[$this->currentIndex['type']]++;
  186.         }
  187.         $this->current++;
  188.     }
  189.     /**
  190.      * @return TagHandlerInterface
  191.      */
  192.     private function getTagHandler()
  193.     {
  194.         // TODO inject area handler via DI when tags are built through container
  195.         return \Pimcore::getContainer()->get('pimcore.document.tag.handler');
  196.     }
  197.     /**
  198.      * @see Document\Tag\TagInterface::setDataFromResource
  199.      *
  200.      * @param mixed $data
  201.      *
  202.      * @return $this
  203.      */
  204.     public function setDataFromResource($data)
  205.     {
  206.         $this->indices Tool\Serialize::unserialize($data);
  207.         if (!is_array($this->indices)) {
  208.             $this->indices = [];
  209.         }
  210.         return $this;
  211.     }
  212.     /**
  213.      * @see Document\Tag\TagInterface::setDataFromEditmode
  214.      *
  215.      * @param mixed $data
  216.      *
  217.      * @return $this
  218.      */
  219.     public function setDataFromEditmode($data)
  220.     {
  221.         $this->indices $data;
  222.         return $this;
  223.     }
  224.     /**
  225.      * Called before the block is rendered
  226.      */
  227.     public function blockConstruct()
  228.     {
  229.         // set the current block suffix for the child elements (0, 1, 3, ...)
  230.         // this will be removed in blockDestruct
  231.         $this->getBlockState()->pushIndex($this->indices[$this->current]['key']);
  232.     }
  233.     /**
  234.      * Called when the block was rendered
  235.      */
  236.     public function blockDestruct()
  237.     {
  238.         $this->getBlockState()->popIndex();
  239.     }
  240.     /**
  241.      * @return array
  242.      */
  243.     protected function getToolBarDefaultConfig()
  244.     {
  245.         return [
  246.             'areablock_toolbar' => [
  247.                 'width' => 172,
  248.                 'buttonWidth' => 168,
  249.                 'buttonMaxCharacters' => 20,
  250.             ],
  251.         ];
  252.     }
  253.     /**
  254.      * @inheritDoc
  255.      */
  256.     protected function getEditmodeOptions(): array
  257.     {
  258.         $configOptions array_merge($this->getToolBarDefaultConfig(), $this->getOptions());
  259.         $options parent::getEditmodeOptions();
  260.         $options array_merge($options, [
  261.             'options' => $configOptions,
  262.         ]);
  263.         return $options;
  264.     }
  265.     /**
  266.      * @inheritDoc
  267.      */
  268.     protected function getEditmodeElementAttributes(array $options): array
  269.     {
  270.         $attributes parent::getEditmodeElementAttributes($options);
  271.         $attributes array_merge($attributes, [
  272.             'name' => $this->getName(),
  273.             'type' => $this->getType(),
  274.         ]);
  275.         return $attributes;
  276.     }
  277.     /**
  278.      * Is executed at the beginning of the loop and setup some general settings
  279.      *
  280.      * @return $this
  281.      */
  282.     public function start()
  283.     {
  284.         reset($this->indices);
  285.         $options $this->getEditmodeOptions();
  286.         $this->outputEditmodeOptions($options);
  287.         // set name suffix for the whole block element, this will be added to all child elements of the block
  288.         $this->getBlockState()->pushBlock(BlockName::createFromTag($this));
  289.         $attributes $this->getEditmodeElementAttributes($options);
  290.         $attributeString HtmlUtils::assembleAttributeString($attributes);
  291.         $this->outputEditmode('<div ' $attributeString '>');
  292.         return $this;
  293.     }
  294.     /**
  295.      * Is executed at the end of the loop and removes the settings set in start()
  296.      */
  297.     public function end()
  298.     {
  299.         $this->current 0;
  300.         // remove the current block which was set by $this->start()
  301.         $this->getBlockState()->popBlock();
  302.         $this->outputEditmode('</div>');
  303.     }
  304.     /**
  305.      * Is called evertime a new iteration starts (new entry of the block while looping)
  306.      */
  307.     public function blockStart()
  308.     {
  309.         $attributes = [
  310.             'data-name' => $this->getName(),
  311.             'data-real-name' => $this->getRealName(),
  312.         ];
  313.         $hidden 'false';
  314.         if (isset($this->indices[$this->current]['hidden']) && $this->indices[$this->current]['hidden']) {
  315.             $hidden 'true';
  316.         }
  317.         $outerAttributes = [
  318.             'key' => $this->indices[$this->current]['key'],
  319.             'type' => $this->indices[$this->current]['type'],
  320.             'data-hidden' => $hidden,
  321.         ];
  322.         $attr HtmlUtils::assembleAttributeString($attributes);
  323.         $oAttr HtmlUtils::assembleAttributeString($outerAttributes);
  324.         // outer element
  325.         $this->outputEditmode('<div class="pimcore_area_entry pimcore_block_entry" ' $oAttr ' ' $attr '>');
  326.         $this->outputEditmode('<div class="pimcore_area_buttons" ' $attr '>');
  327.         $this->outputEditmode('<div class="pimcore_area_buttons_inner">');
  328.         $this->outputEditmode('<div class="pimcore_block_plus_up" ' $attr '></div>');
  329.         $this->outputEditmode('<div class="pimcore_block_plus" ' $attr '></div>');
  330.         $this->outputEditmode('<div class="pimcore_block_minus" ' $attr '></div>');
  331.         $this->outputEditmode('<div class="pimcore_block_up" ' $attr '></div>');
  332.         $this->outputEditmode('<div class="pimcore_block_down" ' $attr '></div>');
  333.         $this->outputEditmode('<div class="pimcore_block_type" ' $attr '></div>');
  334.         $this->outputEditmode('<div class="pimcore_block_options" ' $attr '></div>');
  335.         $this->outputEditmode('<div class="pimcore_block_visibility" ' $attr '></div>');
  336.         $this->outputEditmode('<div class="pimcore_block_label" ' $attr '></div>');
  337.         $this->outputEditmode('<div class="pimcore_block_clear" ' $attr '></div>');
  338.         $this->outputEditmode('</div>'); // .pimcore_area_buttons_inner
  339.         $this->outputEditmode('</div>'); // .pimcore_area_buttons
  340.     }
  341.     /**
  342.      * Is called evertime a new iteration ends (new entry of the block while looping)
  343.      */
  344.     public function blockEnd()
  345.     {
  346.         // close outer element
  347.         $this->outputEditmode('</div>');
  348.     }
  349.     /**
  350.      * @param array $options
  351.      *
  352.      * @return $this
  353.      */
  354.     public function setOptions($options)
  355.     {
  356.         // we need to set this here otherwise custom areaDir's won't work
  357.         $this->options $options;
  358.         if ($this->getView()) {
  359.             $translator = \Pimcore::getContainer()->get('translator');
  360.             if (!isset($options['allowed']) || !is_array($options['allowed'])) {
  361.                 $options['allowed'] = [];
  362.             }
  363.             $availableAreas $this->getTagHandler()->getAvailableAreablockAreas($this$options);
  364.             $availableAreas $this->sortAvailableAreas($availableAreas$options);
  365.             $options['types'] = $availableAreas;
  366.             if (isset($options['group']) && is_array($options['group'])) {
  367.                 $groupingareas = [];
  368.                 foreach ($availableAreas as $area) {
  369.                     $groupingareas[$area['type']] = $area['type'];
  370.                 }
  371.                 $groups = [];
  372.                 foreach ($options['group'] as $name => $areas) {
  373.                     $n $name;
  374.                     if ($this->editmode) {
  375.                         $n $translator->trans($name, [], 'admin');
  376.                     }
  377.                     $groups[$n] = $areas;
  378.                     foreach ($areas as $area) {
  379.                         unset($groupingareas[$area]);
  380.                     }
  381.                 }
  382.                 if (count($groupingareas) > 0) {
  383.                     $uncatAreas = [];
  384.                     foreach ($groupingareas as $area) {
  385.                         $uncatAreas[] = $area;
  386.                     }
  387.                     $n 'Uncategorized';
  388.                     if ($this->editmode) {
  389.                         $n $translator->trans($n, [], 'admin');
  390.                     }
  391.                     $groups[$n] = $uncatAreas;
  392.                 }
  393.                 $options['group'] = $groups;
  394.             }
  395.             if (empty($options['limit'])) {
  396.                 $options['limit'] = 1000000;
  397.             }
  398.             $this->options $options;
  399.         }
  400.         return $this;
  401.     }
  402.     /**
  403.      * Sorts areas by index (sorting option) first, then by name
  404.      *
  405.      * @param array $areas
  406.      * @param array $options
  407.      *
  408.      * @return array
  409.      */
  410.     protected function sortAvailableAreas(array $areas, array $options)
  411.     {
  412.         if (isset($options['sorting']) && is_array($options['sorting']) && count($options['sorting'])) {
  413.             $sorting $options['sorting'];
  414.         } else {
  415.             if (isset($options['allowed']) && is_array($options['allowed']) && count($options['allowed'])) {
  416.                 $sorting $options['allowed'];
  417.             } else {
  418.                 $sorting = [];
  419.             }
  420.         }
  421.         $result = [
  422.             'name' => [],
  423.             'index' => [],
  424.         ];
  425.         foreach ($areas as $area) {
  426.             $sortIndex false;
  427.             if (!empty($sorting)) {
  428.                 $sortIndex array_search($area['type'], $sorting);
  429.             }
  430.             $sortKey 'name'// allowed and sorting is not set || areaName is not in allowed
  431.             if (false !== $sortIndex) {
  432.                 $sortKey 'index';
  433.                 $area['sortIndex'] = $sortIndex;
  434.             }
  435.             $result[$sortKey][] = $area;
  436.         }
  437.         // sort with translated names
  438.         if (count($result['name'])) {
  439.             usort($result['name'], function ($a$b) {
  440.                 if ($a['name'] == $b['name']) {
  441.                     return 0;
  442.                 }
  443.                 return ($a['name'] < $b['name']) ? -1;
  444.             });
  445.         }
  446.         // sort by allowed brick config order
  447.         if (count($result['index'])) {
  448.             usort($result['index'], function ($a$b) {
  449.                 return $a['sortIndex'] - $b['sortIndex'];
  450.             });
  451.         }
  452.         $result array_merge($result['index'], $result['name']);
  453.         return $result;
  454.     }
  455.     /**
  456.      * Return the amount of block elements
  457.      *
  458.      * @return int
  459.      */
  460.     public function getCount()
  461.     {
  462.         return count($this->indices);
  463.     }
  464.     /**
  465.      * Return current iteration step
  466.      *
  467.      * @return int
  468.      */
  469.     public function getCurrent()
  470.     {
  471.         return $this->current 1;
  472.     }
  473.     /**
  474.      * Return current index
  475.      *
  476.      * @return int
  477.      */
  478.     public function getCurrentIndex()
  479.     {
  480.         return $this->indices[$this->getCurrent()]['key'];
  481.     }
  482.     /**
  483.      * If object was serialized, set the counter back to 0
  484.      */
  485.     public function __wakeup()
  486.     {
  487.         $this->current 0;
  488.         reset($this->indices);
  489.     }
  490.     /**
  491.      * @return bool
  492.      */
  493.     public function isEmpty()
  494.     {
  495.         return !(bool) count($this->indices);
  496.     }
  497.     /**
  498.      * @deprecated
  499.      *
  500.      * @param Model\Webservice\Data\Document\Element $wsElement
  501.      * @param Model\Document\PageSnippet $document
  502.      * @param array $params
  503.      * @param Model\Webservice\IdMapperInterface|null $idMapper
  504.      *
  505.      * @throws \Exception
  506.      */
  507.     public function getFromWebserviceImport($wsElement$document null$params = [], $idMapper null)
  508.     {
  509.         $data $this->sanitizeWebserviceData($wsElement->value);
  510.         if (($data->indices === null || is_array($data->indices)) && ($data->current == null || is_numeric($data->current))
  511.             && ($data->currentIndex == null || is_numeric($data->currentIndex))) {
  512.             $indices $data->indices;
  513.             $indices json_decode(json_encode($indices), true);
  514.             $this->indices $indices;
  515.             $this->current $data->current;
  516.             $this->currentIndex $data->currentIndex;
  517.         } else {
  518.             throw new \Exception('cannot get  values from web service import - invalid data');
  519.         }
  520.     }
  521.     /**
  522.      * @param string $name
  523.      *
  524.      * @return Areablock\Item[]
  525.      */
  526.     public function getElement(string $name)
  527.     {
  528.         $document $this->getDocument();
  529.         $parentBlockNames $this->getParentBlockNames();
  530.         $parentBlockNames[] = $this->getName();
  531.         $list = [];
  532.         foreach ($this->getData() as $index => $item) {
  533.             if ($item['type'] === $name) {
  534.                 $list[$index] = new Areablock\Item($document$parentBlockNames, (int)$item['key']);
  535.             }
  536.         }
  537.         return $list;
  538.     }
  539. }