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

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