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

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 Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\Document\Editable;
  15. use Pimcore\Logger;
  16. use Pimcore\Model;
  17. use Pimcore\Model\Asset;
  18. use Pimcore\Model\DataObject;
  19. use Pimcore\Model\Document;
  20. /**
  21.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  22.  */
  23. class Link extends Model\Document\Editable implements IdRewriterInterfaceEditmodeDataInterface
  24. {
  25.     /**
  26.      * Contains the data for the link
  27.      *
  28.      * @internal
  29.      *
  30.      * @var array|null
  31.      */
  32.     protected $data;
  33.     /**
  34.      * {@inheritdoc}
  35.      */
  36.     public function getType()
  37.     {
  38.         return 'link';
  39.     }
  40.     /**
  41.      * {@inheritdoc}
  42.      */
  43.     public function getData()
  44.     {
  45.         // update path if internal link
  46.         $this->updatePathFromInternal(true);
  47.         return $this->data;
  48.     }
  49.     /**
  50.      * {@inheritdoc}
  51.      */
  52.     public function getDataEditmode() /** : mixed */
  53.     {
  54.         // update path if internal link
  55.         $this->updatePathFromInternal(truetrue);
  56.         return $this->data;
  57.     }
  58.     /**
  59.      * {@inheritdoc}
  60.      */
  61.     protected function getEditmodeElementClasses($options = []): array
  62.     {
  63.         // we don't want the class attribute being applied to the editable container element (<div>, only to the <a> tag inside
  64.         // the default behavior of the parent method is to include the "class" attribute
  65.         $classes = [
  66.             'pimcore_editable',
  67.             'pimcore_editable_' $this->getType(),
  68.         ];
  69.         return $classes;
  70.     }
  71.     /**
  72.      * {@inheritdoc}
  73.      */
  74.     public function frontend()
  75.     {
  76.         $url $this->getHref();
  77.         if (strlen($url) > 0) {
  78.             if (!is_array($this->config)) {
  79.                 $this->config = [];
  80.             }
  81.             $prefix '';
  82.             $suffix '';
  83.             $noText false;
  84.             if (array_key_exists('textPrefix'$this->config)) {
  85.                 $prefix $this->config['textPrefix'];
  86.                 unset($this->config['textPrefix']);
  87.             }
  88.             if (array_key_exists('textSuffix'$this->config)) {
  89.                 $suffix $this->config['textSuffix'];
  90.                 unset($this->config['textSuffix']);
  91.             }
  92.             if (isset($this->config['noText']) && $this->config['noText'] == true) {
  93.                 $noText true;
  94.                 unset($this->config['noText']);
  95.             }
  96.             // add attributes to link
  97.             $allowedAttributes = [
  98.                 'charset',
  99.                 'coords',
  100.                 'hreflang',
  101.                 'name',
  102.                 'rel',
  103.                 'rev',
  104.                 'shape',
  105.                 'target',
  106.                 'accesskey',
  107.                 'class',
  108.                 'dir',
  109.                 'draggable',
  110.                 'dropzone',
  111.                 'contextmenu',
  112.                 'id',
  113.                 'lang',
  114.                 'style',
  115.                 'tabindex',
  116.                 'title',
  117.                 'media',
  118.                 'download',
  119.                 'ping',
  120.                 'type',
  121.                 'referrerpolicy',
  122.                 'xml:lang',
  123.             ];
  124.             $defaultAttributes = [];
  125.             if (!is_array($this->data)) {
  126.                 $this->data = [];
  127.             }
  128.             $availableAttribs array_merge($defaultAttributes$this->data$this->config);
  129.             // add attributes to link
  130.             $attribs = [];
  131.             foreach ($availableAttribs as $key => $value) {
  132.                 if ((is_string($value) || is_numeric($value))
  133.                     && (strpos($key'data-') === ||
  134.                         strpos($key'aria-') === ||
  135.                         in_array($key$allowedAttributes))) {
  136.                     if (!empty($this->data[$key]) && !empty($this->config[$key])) {
  137.                         $attribs[] = $key.'="'htmlspecialchars($this->data[$key]) .' 'htmlspecialchars($this->config[$key]) .'"';
  138.                     } elseif (!empty($value)) {
  139.                         $attribs[] = $key.'="'.htmlspecialchars($value).'"';
  140.                     }
  141.                 }
  142.             }
  143.             $attribs array_unique($attribs);
  144.             if (array_key_exists('attributes'$this->data) && !empty($this->data['attributes'])) {
  145.                 $attribs[] = $this->data['attributes'];
  146.             }
  147.             return '<a href="'.$url.'" '.implode(' '$attribs).'>' $prefix . ($noText '' htmlspecialchars($this->data['text'])) . $suffix '</a>';
  148.         }
  149.         return '';
  150.     }
  151.     /**
  152.      * {@inheritdoc}
  153.      */
  154.     public function checkValidity()
  155.     {
  156.         $sane true;
  157.         if (is_array($this->data) && isset($this->data['internal']) && $this->data['internal']) {
  158.             if ($this->data['internalType'] == 'document') {
  159.                 $doc Document::getById($this->data['internalId']);
  160.                 if (!$doc) {
  161.                     $sane false;
  162.                     Logger::notice(
  163.                         'Detected insane relation, removing reference to non existent document with id ['.$this->getDocumentId(
  164.                         ).']'
  165.                     );
  166.                     $this->data null;
  167.                 }
  168.             } elseif ($this->data['internalType'] == 'asset') {
  169.                 $asset Asset::getById($this->data['internalId']);
  170.                 if (!$asset) {
  171.                     $sane false;
  172.                     Logger::notice(
  173.                         'Detected insane relation, removing reference to non existent asset with id ['.$this->getDocumentId(
  174.                         ).']'
  175.                     );
  176.                     $this->data null;
  177.                 }
  178.             } elseif ($this->data['internalType'] == 'object') {
  179.                 $object Model\DataObject\Concrete::getById($this->data['internalId']);
  180.                 if (!$object) {
  181.                     $sane false;
  182.                     Logger::notice(
  183.                         'Detected insane relation, removing reference to non existent object with id ['.$this->getDocumentId(
  184.                         ).']'
  185.                     );
  186.                     $this->data null;
  187.                 }
  188.             }
  189.         }
  190.         return $sane;
  191.     }
  192.     /**
  193.      * @return string
  194.      */
  195.     public function getHref()
  196.     {
  197.         $this->updatePathFromInternal();
  198.         $url $this->data['path'] ?? '';
  199.         if (strlen($this->data['parameters'] ?? '') > 0) {
  200.             $url .= (strpos($url'?') !== false '&' '?') . htmlspecialchars(str_replace('?'''$this->getParameters()));
  201.         }
  202.         if (strlen($this->data['anchor'] ?? '') > 0) {
  203.             $anchor str_replace('"'urlencode('"'), htmlspecialchars($this->getAnchor()));
  204.             $url .= '#' str_replace('#'''$anchor);
  205.         }
  206.         return $url;
  207.     }
  208.     /**
  209.      * @param bool $realPath
  210.      * @param bool $editmode
  211.      */
  212.     private function updatePathFromInternal($realPath false$editmode false)
  213.     {
  214.         $method 'getFullPath';
  215.         if ($realPath) {
  216.             $method 'getRealFullPath';
  217.         }
  218.         if (isset($this->data['internal']) && $this->data['internal']) {
  219.             if ($this->data['internalType'] == 'document') {
  220.                 if ($doc Document::getById($this->data['internalId'])) {
  221.                     if ($editmode || (!Document::doHideUnpublished() || $doc->isPublished())) {
  222.                         $this->data['path'] = $doc->$method();
  223.                     } else {
  224.                         $this->data['path'] = '';
  225.                     }
  226.                 }
  227.             } elseif ($this->data['internalType'] == 'asset') {
  228.                 if ($asset Asset::getById($this->data['internalId'])) {
  229.                     $this->data['path'] = $asset->$method();
  230.                 }
  231.             } elseif ($this->data['internalType'] == 'object') {
  232.                 if ($object Model\DataObject::getById($this->data['internalId'])) {
  233.                     if ($editmode) {
  234.                         $this->data['path'] = $object->getFullPath();
  235.                     } else {
  236.                         if ($object instanceof Model\DataObject\Concrete) {
  237.                             if ($linkGenerator $object->getClass()->getLinkGenerator()) {
  238.                                 if ($realPath) {
  239.                                     $this->data['path'] = $object->getFullPath();
  240.                                 } else {
  241.                                     $this->data['path'] = $linkGenerator->generate(
  242.                                         $object,
  243.                                         [
  244.                                             'document' => $this->getDocument(),
  245.                                             'context' => $this,
  246.                                         ]
  247.                                     );
  248.                                 }
  249.                             }
  250.                         }
  251.                     }
  252.                 }
  253.             }
  254.         }
  255.         // sanitize attributes
  256.         if ($this->getEditmode() === false && isset($this->data['attributes'])) {
  257.             $this->data['attributes'] = htmlspecialchars($this->data['attributes'], HTML_ENTITIES);
  258.         }
  259.         // deletes unnecessary attribute, which was set by mistake in earlier versions, see also
  260.         // https://github.com/pimcore/pimcore/issues/7394
  261.         if (isset($this->data['type'])) {
  262.             unset($this->data['type']);
  263.         }
  264.     }
  265.     /**
  266.      * @return string
  267.      */
  268.     public function getText()
  269.     {
  270.         return $this->data['text'] ?? '';
  271.     }
  272.     /**
  273.      * @param string $text
  274.      */
  275.     public function setText($text)
  276.     {
  277.         $this->data['text'] = $text;
  278.     }
  279.     /**
  280.      * @return string
  281.      */
  282.     public function getTarget()
  283.     {
  284.         return $this->data['target'] ?? '';
  285.     }
  286.     /**
  287.      * @return string
  288.      */
  289.     public function getParameters()
  290.     {
  291.         return $this->data['parameters'] ?? '';
  292.     }
  293.     /**
  294.      * @return string
  295.      */
  296.     public function getAnchor()
  297.     {
  298.         return $this->data['anchor'] ?? '';
  299.     }
  300.     /**
  301.      * @return string
  302.      */
  303.     public function getTitle()
  304.     {
  305.         return $this->data['title'] ?? '';
  306.     }
  307.     /**
  308.      * @return string
  309.      */
  310.     public function getRel()
  311.     {
  312.         return $this->data['rel'] ?? '';
  313.     }
  314.     /**
  315.      * @return string
  316.      */
  317.     public function getTabindex()
  318.     {
  319.         return $this->data['tabindex'] ?? '';
  320.     }
  321.     /**
  322.      * @return string
  323.      */
  324.     public function getAccesskey()
  325.     {
  326.         return $this->data['accesskey'] ?? '';
  327.     }
  328.     /**
  329.      * @return mixed
  330.      */
  331.     public function getClass()
  332.     {
  333.         return $this->data['class'] ?? '';
  334.     }
  335.     /**
  336.      * @return mixed
  337.      */
  338.     public function getAttributes()
  339.     {
  340.         return $this->data['attributes'] ?? '';
  341.     }
  342.     /**
  343.      * {@inheritdoc}
  344.      */
  345.     public function setDataFromResource($data)
  346.     {
  347.         $this->data \Pimcore\Tool\Serialize::unserialize($data);
  348.         if (!is_array($this->data)) {
  349.             $this->data = [];
  350.         }
  351.         return $this;
  352.     }
  353.     /**
  354.      * {@inheritdoc}
  355.      */
  356.     public function setDataFromEditmode($data)
  357.     {
  358.         if (!is_array($data)) {
  359.             $data = [];
  360.         }
  361.         $path $data['path'] ?? null;
  362.         if (!empty($path)) {
  363.             $target null;
  364.             if ($data['linktype'] == 'internal' && $data['internalType']) {
  365.                 $target Model\Element\Service::getElementByPath($data['internalType'], $path);
  366.                 if ($target) {
  367.                     $data['internal'] = true;
  368.                     $data['internalId'] = $target->getId();
  369.                 }
  370.             }
  371.             if (!$target) {
  372.                 if ($target Document::getByPath($path)) {
  373.                     $data['internal'] = true;
  374.                     $data['internalId'] = $target->getId();
  375.                     $data['internalType'] = 'document';
  376.                 } elseif ($target Asset::getByPath($path)) {
  377.                     $data['internal'] = true;
  378.                     $data['internalId'] = $target->getId();
  379.                     $data['internalType'] = 'asset';
  380.                 } elseif ($target Model\DataObject\Concrete::getByPath($path)) {
  381.                     $data['internal'] = true;
  382.                     $data['internalId'] = $target->getId();
  383.                     $data['internalType'] = 'object';
  384.                 } else {
  385.                     $data['internal'] = false;
  386.                     $data['internalId'] = null;
  387.                     $data['internalType'] = null;
  388.                     $data['linktype'] = 'direct';
  389.                 }
  390.                 if ($target) {
  391.                     $data['linktype'] = 'internal';
  392.                 }
  393.             }
  394.         }
  395.         $this->data $data;
  396.         return $this;
  397.     }
  398.     /**
  399.      * {@inheritdoc}
  400.      */
  401.     public function isEmpty()
  402.     {
  403.         return strlen($this->getHref()) < 1;
  404.     }
  405.     /**
  406.      * {@inheritdoc}
  407.      */
  408.     public function resolveDependencies()
  409.     {
  410.         $dependencies = [];
  411.         $isInternal $this->data['internal'] ?? false;
  412.         if (is_array($this->data) && $isInternal) {
  413.             if ((int)$this->data['internalId'] > 0) {
  414.                 if ($this->data['internalType'] == 'document') {
  415.                     if ($doc Document::getById($this->data['internalId'])) {
  416.                         $key 'document_'.$doc->getId();
  417.                         $dependencies[$key] = [
  418.                             'id' => $doc->getId(),
  419.                             'type' => 'document',
  420.                         ];
  421.                     }
  422.                 } elseif ($this->data['internalType'] == 'asset') {
  423.                     if ($asset Asset::getById($this->data['internalId'])) {
  424.                         $key 'asset_' $asset->getId();
  425.                         $dependencies[$key] = [
  426.                             'id' => $asset->getId(),
  427.                             'type' => 'asset',
  428.                         ];
  429.                     }
  430.                 } elseif ($this->data['internalType'] == 'object') {
  431.                     if ($object DataObject\Concrete::getById($this->data['internalId'])) {
  432.                         $key 'object_' $object->getId();
  433.                         $dependencies[$key] = [
  434.                             'id' => $object->getId(),
  435.                             'type' => 'object',
  436.                         ];
  437.                     }
  438.                 }
  439.             }
  440.         }
  441.         return $dependencies;
  442.     }
  443.     /**
  444.      * { @inheritdoc }
  445.      */
  446.     public function rewriteIds($idMapping/** : void */
  447.     {
  448.         if (isset($this->data['internal']) && $this->data['internal']) {
  449.             $type $this->data['internalType'];
  450.             $id = (int)$this->data['internalId'];
  451.             if (array_key_exists($type$idMapping)) {
  452.                 if (array_key_exists($id$idMapping[$type])) {
  453.                     $this->data['internalId'] = $idMapping[$type][$id];
  454.                     $this->getHref();
  455.                 }
  456.             }
  457.         }
  458.     }
  459. }