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