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

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\Editable;
  18. use Pimcore\Logger;
  19. use Pimcore\Model;
  20. use Pimcore\Model\Asset;
  21. use Pimcore\Model\Document;
  22. /**
  23.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  24.  */
  25. class Link extends Model\Document\Editable
  26. {
  27.     /**
  28.      * Contains the data for the link
  29.      *
  30.      * @var array
  31.      */
  32.     public $data;
  33.     /**
  34.      * @see Pimcore\Model\Document\Editable;::getType
  35.      *
  36.      * @return string
  37.      */
  38.     public function getType()
  39.     {
  40.         return 'link';
  41.     }
  42.     /**
  43.      * @see EditableInterface::getData
  44.      *
  45.      * @return mixed
  46.      */
  47.     public function getData()
  48.     {
  49.         // update path if internal link
  50.         $this->updatePathFromInternal(true);
  51.         return $this->data;
  52.     }
  53.     /**
  54.      * @see EditableInterface::getDataEditmode
  55.      *
  56.      * @return mixed
  57.      */
  58.     public function getDataEditmode()
  59.     {
  60.         // update path if internal link
  61.         $this->updatePathFromInternal(truetrue);
  62.         return $this->data;
  63.     }
  64.     /**
  65.      * @inheritDoc
  66.      */
  67.     protected function getEditmodeElementClasses($options = []): array
  68.     {
  69.         // we don't want the class attribute being applied to the editable container element (<div>, only to the <a> tag inside
  70.         // the default behavior of the parent method is to include the "class" attribute
  71.         $classes = [
  72.             'pimcore_editable',
  73.             'pimcore_tag_' $this->getType(),
  74.             'pimcore_editable_' $this->getType(),
  75.         ];
  76.         return $classes;
  77.     }
  78.     /**
  79.      * @see EditableInterface::frontend
  80.      *
  81.      * @return string
  82.      */
  83.     public function frontend()
  84.     {
  85.         $url $this->getHref();
  86.         if (strlen($url) > 0) {
  87.             if (!is_array($this->config)) {
  88.                 $this->config = [];
  89.             }
  90.             $prefix '';
  91.             $suffix '';
  92.             $noText false;
  93.             if (array_key_exists('textPrefix'$this->config)) {
  94.                 $prefix $this->config['textPrefix'];
  95.                 unset($this->config['textPrefix']);
  96.             }
  97.             if (array_key_exists('textSuffix'$this->config)) {
  98.                 $suffix $this->config['textSuffix'];
  99.                 unset($this->config['textSuffix']);
  100.             }
  101.             if (isset($this->config['noText']) && $this->config['noText'] == true) {
  102.                 $noText true;
  103.                 unset($this->config['noText']);
  104.             }
  105.             // add attributes to link
  106.             $allowedAttributes = [
  107.                 'charset',
  108.                 'coords',
  109.                 'hreflang',
  110.                 'name',
  111.                 'rel',
  112.                 'rev',
  113.                 'shape',
  114.                 'target',
  115.                 'accesskey',
  116.                 'class',
  117.                 'dir',
  118.                 'draggable',
  119.                 'dropzone',
  120.                 'contextmenu',
  121.                 'id',
  122.                 'lang',
  123.                 'style',
  124.                 'tabindex',
  125.                 'title',
  126.                 'media',
  127.                 'download',
  128.                 'ping',
  129.                 'type',
  130.                 'referrerpolicy',
  131.                 'xml:lang',
  132.                 'onblur',
  133.                 'onclick',
  134.                 'ondblclick',
  135.                 'onfocus',
  136.                 'onmousedown',
  137.                 'onmousemove',
  138.                 'onmouseout',
  139.                 'onmouseover',
  140.                 'onmouseup',
  141.                 'onkeydown',
  142.                 'onkeypress',
  143.                 'onkeyup',
  144.             ];
  145.             $defaultAttributes = [];
  146.             if (!is_array($this->data)) {
  147.                 $this->data = [];
  148.             }
  149.             $availableAttribs array_merge($defaultAttributes$this->data$this->config);
  150.             // add attributes to link
  151.             $attribs = [];
  152.             foreach ($availableAttribs as $key => $value) {
  153.                 if ((is_string($value) || is_numeric($value))
  154.                     && (strpos($key'data-') === ||
  155.                         strpos($key'aria-') === ||
  156.                         in_array($key$allowedAttributes))) {
  157.                     if (!empty($this->data[$key]) && !empty($this->config[$key])) {
  158.                         $attribs[] = $key.'="'$this->data[$key] .' '$this->config[$key] .'"';
  159.                     } elseif (!empty($value)) {
  160.                         $attribs[] = $key.'="'.$value.'"';
  161.                     }
  162.                 }
  163.             }
  164.             $attribs array_unique($attribs);
  165.             if (array_key_exists('attributes'$this->data) && !empty($this->data['attributes'])) {
  166.                 $attribs[] = $this->data['attributes'];
  167.             }
  168.             return '<a href="'.$url.'" '.implode(' '$attribs).'>' $prefix . ($noText '' htmlspecialchars($this->data['text'])) . $suffix '</a>';
  169.         }
  170.         return '';
  171.     }
  172.     /**
  173.      * @return bool
  174.      */
  175.     public function checkValidity()
  176.     {
  177.         $sane true;
  178.         if (is_array($this->data) && isset($this->data['internal']) && $this->data['internal']) {
  179.             if ($this->data['internalType'] == 'document') {
  180.                 $doc Document::getById($this->data['internalId']);
  181.                 if (!$doc) {
  182.                     $sane false;
  183.                     Logger::notice(
  184.                         'Detected insane relation, removing reference to non existent document with id ['.$this->getDocumentId(
  185.                         ).']'
  186.                     );
  187.                     $new Document\Editable::factory($this->getType(), $this->getName(), $this->getDocumentId());
  188.                     $this->data $new->getData();
  189.                 }
  190.             } elseif ($this->data['internalType'] == 'asset') {
  191.                 $asset Asset::getById($this->data['internalId']);
  192.                 if (!$asset) {
  193.                     $sane false;
  194.                     Logger::notice(
  195.                         'Detected insane relation, removing reference to non existent asset with id ['.$this->getDocumentId(
  196.                         ).']'
  197.                     );
  198.                     $new Document\Editable::factory($this->getType(), $this->getName(), $this->getDocumentId());
  199.                     $this->data $new->getData();
  200.                 }
  201.             } elseif ($this->data['internalType'] == 'object') {
  202.                 $object Model\DataObject\Concrete::getById($this->data['internalId']);
  203.                 if (!$object) {
  204.                     $sane false;
  205.                     Logger::notice(
  206.                         'Detected insane relation, removing reference to non existent object with id ['.$this->getDocumentId(
  207.                         ).']'
  208.                     );
  209.                     $new Document\Editable::factory($this->getType(), $this->getName(), $this->getDocumentId());
  210.                     $this->data $new->getData();
  211.                 }
  212.             }
  213.         }
  214.         return $sane;
  215.     }
  216.     /**
  217.      * @return string
  218.      */
  219.     public function getHref()
  220.     {
  221.         $this->updatePathFromInternal();
  222.         $url $this->data['path'] ?? '';
  223.         if (strlen($this->data['parameters'] ?? '') > 0) {
  224.             $url .= '?'.str_replace('?'''$this->getParameters());
  225.         }
  226.         if (strlen($this->data['anchor'] ?? '') > 0) {
  227.             $anchor $this->getAnchor();
  228.             $anchor str_replace('"'urlencode('"'), $anchor);
  229.             $url .= '#' str_replace('#'''$anchor);
  230.         }
  231.         return $url;
  232.     }
  233.     /**
  234.      * @param bool $realPath
  235.      * @param bool $editmode
  236.      */
  237.     protected function updatePathFromInternal($realPath false$editmode false)
  238.     {
  239.         $method 'getFullPath';
  240.         if ($realPath) {
  241.             $method 'getRealFullPath';
  242.         }
  243.         if (isset($this->data['internal']) && $this->data['internal']) {
  244.             if ($this->data['internalType'] == 'document') {
  245.                 if ($doc Document::getById($this->data['internalId'])) {
  246.                     if ($editmode || (!Document::doHideUnpublished() || $doc->isPublished())) {
  247.                         $this->data['path'] = $doc->$method();
  248.                     } else {
  249.                         $this->data['path'] = '';
  250.                     }
  251.                 }
  252.             } elseif ($this->data['internalType'] == 'asset') {
  253.                 if ($asset Asset::getById($this->data['internalId'])) {
  254.                     $this->data['path'] = $asset->$method();
  255.                 }
  256.             } elseif ($this->data['internalType'] == 'object') {
  257.                 if ($object Model\DataObject::getById($this->data['internalId'])) {
  258.                     if ($editmode) {
  259.                         $this->data['path'] = $object->getFullPath();
  260.                     } else {
  261.                         if ($object instanceof Model\DataObject\Concrete) {
  262.                             if ($linkGenerator $object->getClass()->getLinkGenerator()) {
  263.                                 if ($realPath) {
  264.                                     $this->data['path'] = $object->getFullPath();
  265.                                 } else {
  266.                                     $this->data['path'] = $linkGenerator->generate(
  267.                                         $object,
  268.                                         [
  269.                                             'document' => $this->getDocument(),
  270.                                             'context' => $this,
  271.                                         ]
  272.                                     );
  273.                                 }
  274.                             }
  275.                         }
  276.                     }
  277.                 }
  278.             }
  279.         }
  280.     }
  281.     /**
  282.      * @return string
  283.      */
  284.     public function getText()
  285.     {
  286.         return $this->data['text'] ?? '';
  287.     }
  288.     /**
  289.      * @param string $text
  290.      */
  291.     public function setText($text)
  292.     {
  293.         $this->data['text'] = $text;
  294.     }
  295.     /**
  296.      * @return string
  297.      */
  298.     public function getTarget()
  299.     {
  300.         return $this->data['target'] ?? '';
  301.     }
  302.     /**
  303.      * @return string
  304.      */
  305.     public function getParameters()
  306.     {
  307.         return $this->data['parameters'] ?? '';
  308.     }
  309.     /**
  310.      * @return string
  311.      */
  312.     public function getAnchor()
  313.     {
  314.         return $this->data['anchor'] ?? '';
  315.     }
  316.     /**
  317.      * @return string
  318.      */
  319.     public function getTitle()
  320.     {
  321.         return $this->data['title'] ?? '';
  322.     }
  323.     /**
  324.      * @return string
  325.      */
  326.     public function getRel()
  327.     {
  328.         return $this->data['rel'] ?? '';
  329.     }
  330.     /**
  331.      * @return string
  332.      */
  333.     public function getTabindex()
  334.     {
  335.         return $this->data['tabindex'] ?? '';
  336.     }
  337.     /**
  338.      * @return string
  339.      */
  340.     public function getAccesskey()
  341.     {
  342.         return $this->data['accesskey'] ?? '';
  343.     }
  344.     /**
  345.      * @return mixed
  346.      */
  347.     public function getClass()
  348.     {
  349.         return $this->data['class'] ?? '';
  350.     }
  351.     /**
  352.      * @return mixed
  353.      */
  354.     public function getAttributes()
  355.     {
  356.         return $this->data['attributes'] ?? '';
  357.     }
  358.     /**
  359.      * @see EditableInterface::setDataFromResource
  360.      *
  361.      * @param mixed $data
  362.      *
  363.      * @return $this
  364.      */
  365.     public function setDataFromResource($data)
  366.     {
  367.         $this->data = \Pimcore\Tool\Serialize::unserialize($data);
  368.         if (!is_array($this->data)) {
  369.             $this->data = [];
  370.         }
  371.         return $this;
  372.     }
  373.     /**
  374.      * @see EditableInterface::setDataFromEditmode
  375.      *
  376.      * @param mixed $data
  377.      *
  378.      * @return $this
  379.      */
  380.     public function setDataFromEditmode($data)
  381.     {
  382.         if (!is_array($data)) {
  383.             $data = [];
  384.         }
  385.         $path $data['path'];
  386.         if (!empty($path)) {
  387.             $target null;
  388.             if ($data['linktype'] == 'internal' && $data['internalType']) {
  389.                 $target Model\Element\Service::getElementByPath($data['internalType'], $path);
  390.                 if ($target) {
  391.                     $data['internal'] = true;
  392.                     $data['internalId'] = $target->getId();
  393.                 }
  394.             }
  395.             if (!$target) {
  396.                 if ($target Document::getByPath($path)) {
  397.                     $data['internal'] = true;
  398.                     $data['internalId'] = $target->getId();
  399.                     $data['internalType'] = 'document';
  400.                 } elseif ($target Asset::getByPath($path)) {
  401.                     $data['internal'] = true;
  402.                     $data['internalId'] = $target->getId();
  403.                     $data['internalType'] = 'asset';
  404.                 } elseif ($target Model\DataObject\Concrete::getByPath($path)) {
  405.                     $data['internal'] = true;
  406.                     $data['internalId'] = $target->getId();
  407.                     $data['internalType'] = 'object';
  408.                 } else {
  409.                     $data['internal'] = false;
  410.                     $data['internalId'] = null;
  411.                     $data['internalType'] = null;
  412.                     $data['linktype'] = 'direct';
  413.                 }
  414.                 if ($target) {
  415.                     $data['linktype'] = 'internal';
  416.                 }
  417.             }
  418.         }
  419.         $this->data $data;
  420.         return $this;
  421.     }
  422.     /**
  423.      * @return bool
  424.      */
  425.     public function isEmpty()
  426.     {
  427.         return strlen($this->getHref()) < 1;
  428.     }
  429.     /**
  430.      * @return array
  431.      */
  432.     public function resolveDependencies()
  433.     {
  434.         $dependencies = [];
  435.         $isInternal $this->data['internal'] ?? false;
  436.         if (is_array($this->data) && $isInternal) {
  437.             if (intval($this->data['internalId']) > 0) {
  438.                 if ($this->data['internalType'] == 'document') {
  439.                     if ($doc Document::getById($this->data['internalId'])) {
  440.                         $key 'document_'.$doc->getId();
  441.                         $dependencies[$key] = [
  442.                             'id' => $doc->getId(),
  443.                             'type' => 'document',
  444.                         ];
  445.                     }
  446.                 } elseif ($this->data['internalType'] == 'asset') {
  447.                     if ($asset Asset::getById($this->data['internalId'])) {
  448.                         $key 'asset_'.$asset->getId();
  449.                         $dependencies[$key] = [
  450.                             'id' => $asset->getId(),
  451.                             'type' => 'asset',
  452.                         ];
  453.                     }
  454.                 }
  455.             }
  456.         }
  457.         return $dependencies;
  458.     }
  459.     /**
  460.      * @deprecated
  461.      *
  462.      * @param Model\Webservice\Data\Document\Element $wsElement
  463.      * @param Model\Document\PageSnippet $document
  464.      * @param array $params
  465.      * @param Model\Webservice\IdMapperInterface|null $idMapper
  466.      *
  467.      * @throws \Exception
  468.      */
  469.     public function getFromWebserviceImport($wsElement$document null$params = [], $idMapper null)
  470.     {
  471.         $data $this->sanitizeWebserviceData($wsElement->value);
  472.         if (empty($data->data) or $data->data instanceof \stdClass) {
  473.             $this->data $data->data instanceof \stdClass get_object_vars($data->data) : null;
  474.             if ($this->data['internal']) {
  475.                 if (intval($this->data['internalId']) > 0) {
  476.                     $id $this->data['internalId'];
  477.                     if ($this->data['internalType'] == 'document') {
  478.                         if ($idMapper) {
  479.                             $id $idMapper->getMappedId('document'$id);
  480.                         }
  481.                         $referencedDocument Document::getById($id);
  482.                         if (!$referencedDocument instanceof Document) {
  483.                             if ($idMapper && $idMapper->ignoreMappingFailures()) {
  484.                                 $idMapper->recordMappingFailure(
  485.                                     'document',
  486.                                     $this->getDocumentId(),
  487.                                     $this->data['internalType'],
  488.                                     $this->data['internalId']
  489.                                 );
  490.                             } else {
  491.                                 throw new \Exception(
  492.                                     'cannot get values from web service import - link references unknown document with id [ '.$this->data['internalId'].' ] '
  493.                                 );
  494.                             }
  495.                         }
  496.                     } elseif ($this->data['internalType'] == 'asset') {
  497.                         if ($idMapper) {
  498.                             $id $idMapper->getMappedId('document'$id);
  499.                         }
  500.                         $referencedAsset Asset::getById($id);
  501.                         if (!$referencedAsset instanceof Asset) {
  502.                             if ($idMapper && $idMapper->ignoreMappingFailures()) {
  503.                                 $idMapper->recordMappingFailure(
  504.                                     'document',
  505.                                     $this->getDocumentId(),
  506.                                     $this->data['internalType'],
  507.                                     $this->data['internalId']
  508.                                 );
  509.                             } else {
  510.                                 throw new \Exception(
  511.                                     'cannot get values from web service import - link references unknown asset with id [ '.$this->data['internalId'].' ] '
  512.                                 );
  513.                             }
  514.                         }
  515.                     }
  516.                     if ($id) {
  517.                         $this->data['internalId'] = $id;
  518.                     }
  519.                 }
  520.             }
  521.         } else {
  522.             throw new \Exception('cannot get values from web service import - invalid data');
  523.         }
  524.     }
  525.     /**
  526.      * Returns the current tag's data for web service export
  527.      *
  528.      * @deprecated
  529.      *
  530.      * @param Model\Document\PageSnippet|null $document
  531.      * @param array $params
  532.      *
  533.      * @return \stdClass
  534.      */
  535.     public function getForWebserviceExport($document null$params = [])
  536.     {
  537.         $el parent::getForWebserviceExport($document$params);
  538.         if ($this->data['internal']) {
  539.             if (intval($this->data['internalId']) > 0) {
  540.                 if ($this->data['internalType'] == 'document') {
  541.                     $referencedDocument Document::getById($this->data['internalId']);
  542.                     if (!$referencedDocument instanceof Document) {
  543.                         //detected broken link
  544.                         $document $this->getDocument();
  545.                     }
  546.                 } elseif ($this->data['internalType'] == 'asset') {
  547.                     $referencedAsset Asset::getById($this->data['internalId']);
  548.                     if (!$referencedAsset instanceof Asset) {
  549.                         //detected broken link
  550.                         $document $this->getDocument();
  551.                     }
  552.                 }
  553.             }
  554.         }
  555.         $el->data $this->data;
  556.         return $el;
  557.     }
  558.     /**
  559.      * Rewrites id from source to target, $idMapping contains
  560.      * array(
  561.      *  "document" => array(
  562.      *      SOURCE_ID => TARGET_ID,
  563.      *      SOURCE_ID => TARGET_ID
  564.      *  ),
  565.      *  "object" => array(...),
  566.      *  "asset" => array(...)
  567.      * )
  568.      *
  569.      * @param array $idMapping
  570.      */
  571.     public function rewriteIds($idMapping)
  572.     {
  573.         if (isset($this->data['internal']) && $this->data['internal']) {
  574.             $type $this->data['internalType'];
  575.             $id = (int)$this->data['internalId'];
  576.             if (array_key_exists($type$idMapping)) {
  577.                 if (array_key_exists($id$idMapping[$type])) {
  578.                     $this->data['internalId'] = $idMapping[$type][$id];
  579.                     $this->getHref();
  580.                 }
  581.             }
  582.         }
  583.     }
  584. }
  585. class_alias(Link::class, 'Pimcore\Model\Document\Tag\Link');