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