vendor/pimcore/pimcore/models/Document/Editable/Block.php line 25

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * Pimcore
  5.  *
  6.  * This source file is available under two different licenses:
  7.  * - GNU General Public License version 3 (GPLv3)
  8.  * - Pimcore Commercial License (PCL)
  9.  * Full copyright and license information is available in
  10.  * LICENSE.md which is distributed with this source code.
  11.  *
  12.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  13.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  14.  */
  15. namespace Pimcore\Model\Document\Editable;
  16. use Pimcore\Document\Editable\Block\BlockName;
  17. use Pimcore\Model;
  18. use Pimcore\Tool\HtmlUtils;
  19. /**
  20.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  21.  */
  22. class Block extends Model\Document\Editable implements BlockInterface
  23. {
  24.     /**
  25.      * @internal
  26.      */
  27.     const ATTRIBUTE_IGNORE_EDITMODE_INDICES '_block_ignore_extra_editmode_indices';
  28.     /**
  29.      * Contains an array of indices, which represent the order of the elements in the block
  30.      *
  31.      * @internal
  32.      *
  33.      */
  34.     protected array $indices = [];
  35.     /**
  36.      * Current step of the block while iteration
  37.      *
  38.      * @internal
  39.      *
  40.      */
  41.     protected int $current 0;
  42.     public function getType(): string
  43.     {
  44.         return 'block';
  45.     }
  46.     public function getData(): mixed
  47.     {
  48.         return $this->indices;
  49.     }
  50.     public function admin()
  51.     {
  52.         // nothing to do
  53.         return '';
  54.     }
  55.     public function frontend()
  56.     {
  57.         // nothing to do
  58.         return '';
  59.     }
  60.     public function setDataFromResource(mixed $data): static
  61.     {
  62.         $this->indices \Pimcore\Tool\Serialize::unserialize($data);
  63.         return $this;
  64.     }
  65.     public function setDataFromEditmode(mixed $data): static
  66.     {
  67.         $this->indices $data;
  68.         return $this;
  69.     }
  70.     /**
  71.      * @internal
  72.      *
  73.      * @return $this
  74.      */
  75.     protected function setDefault(): static
  76.     {
  77.         if (empty($this->indices) && isset($this->config['default']) && $this->config['default']) {
  78.             for ($i 0$i < (int)$this->config['default']; $i++) {
  79.                 $this->indices[$i] = $i 1;
  80.             }
  81.         }
  82.         return $this;
  83.     }
  84.     public function getIterator(): \Generator
  85.     {
  86.         while ($this->loop()) {
  87.             yield $this->getCurrentIndex();
  88.         }
  89.         if ($this->getEditmode() && !$this->isIgnoreEditmodeIndices()) {
  90.             // yeah, I know the following is f******* crazy :D
  91.             $this->current 0;
  92.             $indicesBackup $this->indices;
  93.             $this->indices[0] = 1000000;
  94.             $this->getBlockState()->pushBlock(BlockName::createFromEditable($this));
  95.             $this->blockConstruct();
  96.             $blockStartHtml $this->blockStart(truetrue);
  97.             ob_start();
  98.             $editableDefCollector $this->getEditableDefinitionCollector();
  99.             $editableDefCollector->stashPush();
  100.             yield $this->getCurrentIndex() + 1;
  101.             $blockEndHtml $this->blockEnd(true);
  102.             $this->blockDestruct();
  103.             $blockState $this->getBlockState();
  104.             if ($blockState->hasBlocks()) {
  105.                 $blockState->popBlock();
  106.             }
  107.             $templateEditableDefinitions $editableDefCollector->getDefinitions();
  108.             $editableDefCollector->stashPull();
  109.             $this->config['template'] = [
  110.                 'html' => $blockStartHtml ob_get_clean() . $blockEndHtml,
  111.                 'editables' => $templateEditableDefinitions,
  112.             ];
  113.             $editableDefCollector->add($this);
  114.             $this->indices $indicesBackup;
  115.         }
  116.     }
  117.     /**
  118.      * @internal
  119.      *
  120.      */
  121.     public function loop(): bool
  122.     {
  123.         $manual false;
  124.         if (($this->config['manual'] ?? false) == true) {
  125.             $manual true;
  126.         }
  127.         $this->setDefault();
  128.         if ($this->current 0) {
  129.             if (!$manual) {
  130.                 $this->blockDestruct();
  131.                 $this->blockEnd();
  132.             }
  133.         } else {
  134.             if (!$manual) {
  135.                 $this->start();
  136.             }
  137.         }
  138.         if ($this->current count($this->indices) && $this->current $this->config['limit']) {
  139.             if (!$manual) {
  140.                 $this->blockConstruct();
  141.                 $this->blockStart();
  142.             }
  143.             return true;
  144.         } else {
  145.             if (!$manual) {
  146.                 $this->end();
  147.             }
  148.             return false;
  149.         }
  150.     }
  151.     protected function getEditmodeElementAttributes(): array
  152.     {
  153.         $attributes parent::getEditmodeElementAttributes();
  154.         $attributes array_merge($attributes, [
  155.             'name' => $this->getName(),
  156.             'type' => $this->getType(),
  157.         ]);
  158.         return $attributes;
  159.     }
  160.     public function start()
  161.     {
  162.         // set name suffix for the whole block element, this will be added to all child elements of the block
  163.         $this->getBlockState()->pushBlock(BlockName::createFromEditable($this));
  164.         $attributes $this->getEditmodeElementAttributes();
  165.         $attributeString HtmlUtils::assembleAttributeString($attributes);
  166.         $this->outputEditmode('<div ' $attributeString '>');
  167.         return $this;
  168.     }
  169.     public function end(bool $return false): void
  170.     {
  171.         $this->current 0;
  172.         // remove the current block which was set by $this->start()
  173.         $blockState $this->getBlockState();
  174.         if ($blockState->hasBlocks()) {
  175.             $blockState->popBlock();
  176.         }
  177.         $this->outputEditmode('</div>');
  178.     }
  179.     public function blockConstruct(): void
  180.     {
  181.         // set the current block suffix for the child elements (0, 1, 3, ...)
  182.         // this will be removed in blockDestruct
  183.         $this->getBlockState()->pushIndex((int) ($this->indices[$this->current] ?? 0));
  184.     }
  185.     public function blockDestruct(): void
  186.     {
  187.         $blockState $this->getBlockState();
  188.         if ($blockState->hasIndexes()) {
  189.             $blockState->popIndex();
  190.         }
  191.     }
  192.     public function blockStart(bool $showControls truebool $return falsestring $additionalClass '')
  193.     {
  194.         $attr $this->getBlockAttributes();
  195.         $outerAttributes = [
  196.             'key' => $this->indices[$this->current] ?? null,
  197.         ];
  198.         $oAttr HtmlUtils::assembleAttributeString($outerAttributes);
  199.         $class 'pimcore_block_entry';
  200.         if (!empty($additionalClass)) {
  201.             $class sprintf('%s %s'$class$additionalClass);
  202.         }
  203.         $html '<div class="' $class '" ' $oAttr ' ' $attr '>';
  204.         if ($showControls) {
  205.             $html .= $this->blockControls(true);
  206.         }
  207.         if ($return) {
  208.             return $html;
  209.         }
  210.         $this->outputEditmode($html);
  211.     }
  212.     /**
  213.      * Custom position of button controls between blockStart -> blockEnd
  214.      *
  215.      * @return ($return is true ? string : void)
  216.      */
  217.     public function blockControls(bool $return false)
  218.     {
  219.         $attr $this->getBlockAttributes();
  220.         $html = <<<EOT
  221. <div class="pimcore_block_buttons" $attr>
  222.     <div class="pimcore_block_amount" $attr></div>
  223.     <div class="pimcore_block_plus" $attr></div>
  224.     <div class="pimcore_block_minus" $attr></div>
  225.     <div class="pimcore_block_up" $attr></div>
  226.     <div class="pimcore_block_down" $attr></div>
  227.     <div class="pimcore_block_clear" $attr></div>
  228. </div>
  229. EOT;
  230.         $this->current++;
  231.         if ($return) {
  232.             return $html;
  233.         }
  234.         $this->outputEditmode($html);
  235.     }
  236.     public function blockEnd(bool $return false)
  237.     {
  238.         // close outer element
  239.         $html '</div>';
  240.         if ($return) {
  241.             return $html;
  242.         }
  243.         $this->outputEditmode($html);
  244.     }
  245.     public function setConfig(array $config): static
  246.     {
  247.         if (empty($config['limit'])) {
  248.             $config['limit'] = 1000000;
  249.         }
  250.         $this->config $config;
  251.         if (($this->config['manual'] ?? false) === true) {
  252.             $this->config['reload'] = true;
  253.         }
  254.         return $this;
  255.     }
  256.     public function getCount(): int
  257.     {
  258.         return count($this->indices);
  259.     }
  260.     public function getCurrent(): int
  261.     {
  262.         return $this->current 1;
  263.     }
  264.     public function getCurrentIndex(): int
  265.     {
  266.         return (int) ($this->indices[$this->getCurrent()] ?? 0);
  267.     }
  268.     public function getIndices(): array
  269.     {
  270.         return $this->indices;
  271.     }
  272.     /**
  273.      * If object was serialized, set the counter back to 0
  274.      */
  275.     public function __wakeup(): void
  276.     {
  277.         $this->current 0;
  278.     }
  279.     public function isEmpty(): bool
  280.     {
  281.         return !(bool) count($this->indices);
  282.     }
  283.     /**
  284.      * @return Block\Item[]
  285.      */
  286.     public function getElements(): array
  287.     {
  288.         $document $this->getDocument();
  289.         // https://github.com/pimcore/pimcore/issues/6629
  290.         if (!$document instanceof Model\Document\PageSnippet) {
  291.             return [];
  292.         }
  293.         $parentBlockNames $this->getParentBlockNames();
  294.         $parentBlockNames[] = $this->getName();
  295.         $list = [];
  296.         foreach ($this->getData() as $index) {
  297.             $list[] = new Block\Item($document$parentBlockNames, (int)$index);
  298.         }
  299.         return $list;
  300.     }
  301.     private function getBlockAttributes(): string
  302.     {
  303.         $attributes = [
  304.             'data-name' => $this->getName(),
  305.             'data-real-name' => $this->getRealName(),
  306.         ];
  307.         return HtmlUtils::assembleAttributeString($attributes);
  308.     }
  309.     private function isIgnoreEditmodeIndices(): bool
  310.     {
  311.         $requestStack \Pimcore::getContainer()->get('request_stack');
  312.         $request $requestStack->getCurrentRequest();
  313.         if ($request === null) {
  314.             return false;
  315.         }
  316.         return $request->attributes->getBoolean(self::ATTRIBUTE_IGNORE_EDITMODE_INDICES);
  317.     }
  318. }