vendor/pimcore/pimcore/models/Document/Editable/Link.php line 26

  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\Logger;
  17. use Pimcore\Model;
  18. use Pimcore\Model\Asset;
  19. use Pimcore\Model\DataObject;
  20. use Pimcore\Model\Document;
  21. use Pimcore\Tool\Serialize;
  22. /**
  23.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  24.  */
  25. class Link extends Model\Document\Editable implements IdRewriterInterfaceEditmodeDataInterface
  26. {
  27.     /**
  28.      * Contains the data for the link
  29.      *
  30.      * @internal
  31.      *
  32.      */
  33.     protected ?array $data null;
  34.     public function getType(): string
  35.     {
  36.         return 'link';
  37.     }
  38.     public function getData(): mixed
  39.     {
  40.         // update path if internal link
  41.         $this->updatePathFromInternal(true);
  42.         return $this->data;
  43.     }
  44.     public function getDataEditmode(): ?array
  45.     {
  46.         // update path if internal link
  47.         $this->updatePathFromInternal(truetrue);
  48.         return $this->data;
  49.     }
  50.     protected function getEditmodeElementClasses(array $options = []): array
  51.     {
  52.         // we don't want the class attribute being applied to the editable container element (<div>, only to the <a> tag inside
  53.         // the default behavior of the parent method is to include the "class" attribute
  54.         $classes = [
  55.             'pimcore_editable',
  56.             'pimcore_editable_' $this->getType(),
  57.         ];
  58.         return $classes;
  59.     }
  60.     public function frontend()
  61.     {
  62.         $url $this->getHref();
  63.         if (strlen($url) > 0) {
  64.             $prefix '';
  65.             $suffix '';
  66.             $noText false;
  67.             $disabledText false;
  68.             if (array_key_exists('textPrefix'$this->config)) {
  69.                 $prefix $this->config['textPrefix'];
  70.                 unset($this->config['textPrefix']);
  71.             }
  72.             if (array_key_exists('textSuffix'$this->config)) {
  73.                 $suffix $this->config['textSuffix'];
  74.                 unset($this->config['textSuffix']);
  75.             }
  76.             if (isset($this->config['noText']) && $this->config['noText'] == true) {
  77.                 $noText true;
  78.                 unset($this->config['noText']);
  79.             }
  80.             if (array_key_exists('disabledFields'$this->config) && is_array($this->config['disabledFields'])) {
  81.                 $disabledText in_array('text'$this->config['disabledFields'], true);
  82.                 unset($this->config['disabledFields']);
  83.             }
  84.             $this->data is_array($this->data) ? $this->data : [];
  85.             $availableAttribs array_merge($this->data$this->config);
  86.             // add attributes to link
  87.             $attribs = [];
  88.             foreach ($availableAttribs as $key => $value) {
  89.                 if (is_string($value) || is_numeric($value)) {
  90.                     if (!empty($this->data[$key]) && !empty($this->config[$key])) {
  91.                         $attribs[] = $key.'="'htmlspecialchars($this->data[$key]) .' 'htmlspecialchars($this->config[$key]) .'"';
  92.                     } elseif ($value) {
  93.                         $attribs[] = (is_string($value)) ?
  94.                             $key '="' htmlspecialchars($value) . '"' :
  95.                             $key '="' $value '"';
  96.                     }
  97.                 }
  98.             }
  99.             $attribs array_unique($attribs);
  100.             $text '';
  101.             if (!$noText) {
  102.                 $text htmlspecialchars($disabledText $url : ($this->data['text'] ?? $url));
  103.             }
  104.             return '<a href="'.$url.'" '.implode(' '$attribs).'>' $prefix $text $suffix '</a>';
  105.         }
  106.         return '';
  107.     }
  108.     public function checkValidity(): bool
  109.     {
  110.         $sane true;
  111.         if (is_array($this->data) && isset($this->data['internal']) && $this->data['internal']) {
  112.             if ($this->data['internalType'] == 'document') {
  113.                 $doc Document::getById($this->data['internalId']);
  114.                 if (!$doc) {
  115.                     $sane false;
  116.                     Logger::notice(
  117.                         'Detected insane relation, removing reference to non existent document with id ['.$this->getDocumentId(
  118.                         ).']'
  119.                     );
  120.                     $this->data null;
  121.                 }
  122.             } elseif ($this->data['internalType'] == 'asset') {
  123.                 $asset Asset::getById($this->data['internalId']);
  124.                 if (!$asset) {
  125.                     $sane false;
  126.                     Logger::notice(
  127.                         'Detected insane relation, removing reference to non existent asset with id ['.$this->getDocumentId(
  128.                         ).']'
  129.                     );
  130.                     $this->data null;
  131.                 }
  132.             } elseif ($this->data['internalType'] == 'object') {
  133.                 $object Model\DataObject\Concrete::getById($this->data['internalId']);
  134.                 if (!$object) {
  135.                     $sane false;
  136.                     Logger::notice(
  137.                         'Detected insane relation, removing reference to non existent object with id ['.$this->getDocumentId(
  138.                         ).']'
  139.                     );
  140.                     $this->data null;
  141.                 }
  142.             }
  143.         }
  144.         return $sane;
  145.     }
  146.     public function getHref(): string
  147.     {
  148.         $this->updatePathFromInternal();
  149.         $url $this->data['path'] ?? '';
  150.         if (strlen($this->data['parameters'] ?? '') > 0) {
  151.             $url .= (str_contains($url'?') ? '&' '?') . htmlspecialchars(str_replace('?'''$this->getParameters()));
  152.         }
  153.         if (strlen($this->data['anchor'] ?? '') > 0) {
  154.             $anchor str_replace('"'urlencode('"'), htmlspecialchars($this->getAnchor()));
  155.             $url .= '#' str_replace('#'''$anchor);
  156.         }
  157.         return $url;
  158.     }
  159.     private function updatePathFromInternal(bool $realPath falsebool $editmode false): void
  160.     {
  161.         $method 'getFullPath';
  162.         if ($realPath) {
  163.             $method 'getRealFullPath';
  164.         }
  165.         if (isset($this->data['internal']) && $this->data['internal']) {
  166.             if ($this->data['internalType'] == 'document') {
  167.                 if ($doc Document::getById($this->data['internalId'])) {
  168.                     if ($editmode || (!Document::doHideUnpublished() || $doc->isPublished())) {
  169.                         $this->data['path'] = $doc->$method();
  170.                     } else {
  171.                         $this->data['path'] = '';
  172.                     }
  173.                 }
  174.             } elseif ($this->data['internalType'] == 'asset') {
  175.                 if ($asset Asset::getById($this->data['internalId'])) {
  176.                     $this->data['path'] = $asset->$method();
  177.                 }
  178.             } elseif ($this->data['internalType'] == 'object') {
  179.                 if ($object Model\DataObject::getById($this->data['internalId'])) {
  180.                     if ($editmode) {
  181.                         $this->data['path'] = $object->getFullPath();
  182.                     } else {
  183.                         if ($object instanceof Model\DataObject\Concrete) {
  184.                             if ($linkGenerator $object->getClass()->getLinkGenerator()) {
  185.                                 if ($realPath) {
  186.                                     $this->data['path'] = $object->getFullPath();
  187.                                 } else {
  188.                                     $this->data['path'] = $linkGenerator->generate(
  189.                                         $object,
  190.                                         [
  191.                                             'document' => $this->getDocument(),
  192.                                             'context' => $this,
  193.                                         ]
  194.                                     );
  195.                                 }
  196.                             }
  197.                         }
  198.                     }
  199.                 }
  200.             }
  201.         }
  202.         // deletes unnecessary attribute, which was set by mistake in earlier versions, see also
  203.         // https://github.com/pimcore/pimcore/issues/7394
  204.         if (isset($this->data['type'])) {
  205.             unset($this->data['type']);
  206.         }
  207.     }
  208.     public function getText(): string
  209.     {
  210.         return $this->data['text'] ?? '';
  211.     }
  212.     public function setText(string $text): void
  213.     {
  214.         $this->data['text'] = $text;
  215.     }
  216.     public function getTarget(): string
  217.     {
  218.         return $this->data['target'] ?? '';
  219.     }
  220.     public function getParameters(): string
  221.     {
  222.         return $this->data['parameters'] ?? '';
  223.     }
  224.     public function getAnchor(): string
  225.     {
  226.         return $this->data['anchor'] ?? '';
  227.     }
  228.     public function getTitle(): string
  229.     {
  230.         return $this->data['title'] ?? '';
  231.     }
  232.     public function getRel(): string
  233.     {
  234.         return $this->data['rel'] ?? '';
  235.     }
  236.     public function getTabindex(): string
  237.     {
  238.         return $this->data['tabindex'] ?? '';
  239.     }
  240.     public function getAccesskey(): string
  241.     {
  242.         return $this->data['accesskey'] ?? '';
  243.     }
  244.     public function getClass(): mixed
  245.     {
  246.         return $this->data['class'] ?? '';
  247.     }
  248.     public function setDataFromResource(mixed $data): static
  249.     {
  250.         if (is_string($data)) {
  251.             $data Serialize::unserialize($data);
  252.         }
  253.         if (is_array($data) || is_null($data)) {
  254.             $this->data $data;
  255.         }
  256.         return $this;
  257.     }
  258.     public function setDataFromEditmode(mixed $data): static
  259.     {
  260.         if (!is_array($data)) {
  261.             $data = [];
  262.         }
  263.         $path $data['path'] ?? null;
  264.         if (!empty($path)) {
  265.             $target null;
  266.             if ($data['linktype'] == 'internal' && $data['internalType']) {
  267.                 $target Model\Element\Service::getElementByPath($data['internalType'], $path);
  268.                 if ($target) {
  269.                     $data['internal'] = true;
  270.                     $data['internalId'] = $target->getId();
  271.                 }
  272.             }
  273.             if (!$target) {
  274.                 if ($target Document::getByPath($path)) {
  275.                     $data['internal'] = true;
  276.                     $data['internalId'] = $target->getId();
  277.                     $data['internalType'] = 'document';
  278.                 } elseif ($target Asset::getByPath($path)) {
  279.                     $data['internal'] = true;
  280.                     $data['internalId'] = $target->getId();
  281.                     $data['internalType'] = 'asset';
  282.                 } elseif ($target Model\DataObject\Concrete::getByPath($path)) {
  283.                     $data['internal'] = true;
  284.                     $data['internalId'] = $target->getId();
  285.                     $data['internalType'] = 'object';
  286.                 } else {
  287.                     $data['internal'] = false;
  288.                     $data['internalId'] = null;
  289.                     $data['internalType'] = null;
  290.                     $data['linktype'] = 'direct';
  291.                 }
  292.                 if ($target) {
  293.                     $data['linktype'] = 'internal';
  294.                 }
  295.             }
  296.         }
  297.         $this->data $data;
  298.         return $this;
  299.     }
  300.     public function isEmpty(): bool
  301.     {
  302.         return strlen($this->getHref()) < 1;
  303.     }
  304.     public function resolveDependencies(): array
  305.     {
  306.         $dependencies = [];
  307.         $isInternal $this->data['internal'] ?? false;
  308.         if (is_array($this->data) && $isInternal) {
  309.             if ((int)$this->data['internalId'] > 0) {
  310.                 if ($this->data['internalType'] == 'document') {
  311.                     if ($doc Document::getById($this->data['internalId'])) {
  312.                         $key 'document_'.$doc->getId();
  313.                         $dependencies[$key] = [
  314.                             'id' => $doc->getId(),
  315.                             'type' => 'document',
  316.                         ];
  317.                     }
  318.                 } elseif ($this->data['internalType'] == 'asset') {
  319.                     if ($asset Asset::getById($this->data['internalId'])) {
  320.                         $key 'asset_' $asset->getId();
  321.                         $dependencies[$key] = [
  322.                             'id' => $asset->getId(),
  323.                             'type' => 'asset',
  324.                         ];
  325.                     }
  326.                 } elseif ($this->data['internalType'] == 'object') {
  327.                     if ($object DataObject\Concrete::getById($this->data['internalId'])) {
  328.                         $key 'object_' $object->getId();
  329.                         $dependencies[$key] = [
  330.                             'id' => $object->getId(),
  331.                             'type' => 'object',
  332.                         ];
  333.                     }
  334.                 }
  335.             }
  336.         }
  337.         return $dependencies;
  338.     }
  339.     public function rewriteIds(array $idMapping): void
  340.     {
  341.         if (isset($this->data['internal']) && $this->data['internal']) {
  342.             $type $this->data['internalType'];
  343.             $id = (int)$this->data['internalId'];
  344.             if (array_key_exists($type$idMapping)) {
  345.                 if (array_key_exists($id$idMapping[$type])) {
  346.                     $this->data['internalId'] = $idMapping[$type][$id];
  347.                     $this->getHref();
  348.                 }
  349.             }
  350.         }
  351.     }
  352. }