vendor/pimcore/pimcore/models/Document/Editable/Image.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\Model;
  16. use Pimcore\Model\Asset;
  17. use Pimcore\Model\Element;
  18. use Pimcore\Model\Element\ElementDescriptor;
  19. use Pimcore\Model\Element\ElementInterface;
  20. use Pimcore\Tool\Serialize;
  21. /**
  22.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  23.  */
  24. class Image extends Model\Document\Editable implements IdRewriterInterfaceEditmodeDataInterface
  25. {
  26.     /**
  27.      * ID of the referenced image
  28.      *
  29.      * @internal
  30.      *
  31.      * @var int|null
  32.      */
  33.     protected $id;
  34.     /**
  35.      * The ALT text of the image
  36.      *
  37.      * @internal
  38.      *
  39.      * @var string|null
  40.      */
  41.     protected $alt;
  42.     /**
  43.      * Contains the imageobject itself
  44.      *
  45.      * @internal
  46.      *
  47.      * @var Asset\Image|ElementDescriptor|ElementInterface|null
  48.      */
  49.     protected $image;
  50.     /**
  51.      * @internal
  52.      *
  53.      * @var bool
  54.      */
  55.     protected $cropPercent false;
  56.     /**
  57.      * @internal
  58.      *
  59.      * @var float
  60.      */
  61.     protected $cropWidth;
  62.     /**
  63.      * @internal
  64.      *
  65.      * @var float
  66.      */
  67.     protected $cropHeight;
  68.     /**
  69.      * @internal
  70.      *
  71.      * @var float
  72.      */
  73.     protected $cropTop;
  74.     /**
  75.      * @internal
  76.      *
  77.      * @var float
  78.      */
  79.     protected $cropLeft;
  80.     /**
  81.      * @internal
  82.      *
  83.      * @var array
  84.      */
  85.     protected $hotspots = [];
  86.     /**
  87.      * @internal
  88.      *
  89.      * @var array
  90.      */
  91.     protected $marker = [];
  92.     /**
  93.      * The Thumbnail config of the image
  94.      *
  95.      * @internal
  96.      *
  97.      * @var string|null
  98.      */
  99.     protected $thumbnail;
  100.     /**
  101.      * {@inheritdoc}
  102.      */
  103.     public function getType()
  104.     {
  105.         return 'image';
  106.     }
  107.     /**
  108.      * {@inheritdoc}
  109.      *
  110.      * @return mixed
  111.      */
  112.     public function getData()
  113.     {
  114.         return [
  115.             'id' => $this->id,
  116.             'alt' => $this->alt,
  117.             'cropPercent' => $this->cropPercent,
  118.             'cropWidth' => $this->cropWidth,
  119.             'cropHeight' => $this->cropHeight,
  120.             'cropTop' => $this->cropTop,
  121.             'cropLeft' => $this->cropLeft,
  122.             'hotspots' => $this->hotspots,
  123.             'marker' => $this->marker,
  124.             'thumbnail' => $this->thumbnail,
  125.         ];
  126.     }
  127.     /**
  128.      * {@inheritdoc}
  129.      *
  130.      * @return array
  131.      */
  132.     public function getDataForResource()
  133.     {
  134.         return [
  135.             'id' => $this->id,
  136.             'alt' => $this->alt,
  137.             'cropPercent' => $this->cropPercent,
  138.             'cropWidth' => $this->cropWidth,
  139.             'cropHeight' => $this->cropHeight,
  140.             'cropTop' => $this->cropTop,
  141.             'cropLeft' => $this->cropLeft,
  142.             'hotspots' => $this->hotspots,
  143.             'marker' => $this->marker,
  144.             'thumbnail' => $this->thumbnail,
  145.         ];
  146.     }
  147.     /**
  148.      * {@inheritdoc}
  149.      */
  150.     public function getDataEditmode() /** : mixed */
  151.     {
  152.         $image $this->getImage();
  153.         if ($image instanceof Asset\Image) {
  154.             $rewritePath = function ($data) {
  155.                 if (!is_array($data)) {
  156.                     return [];
  157.                 }
  158.                 foreach ($data as &$element) {
  159.                     if (array_key_exists('data'$element) && is_array($element['data']) && count($element['data']) > 0) {
  160.                         foreach ($element['data'] as &$metaData) {
  161.                             if ($metaData instanceof Element\Data\MarkerHotspotItem) {
  162.                                 $metaData get_object_vars($metaData);
  163.                             }
  164.                             if (in_array($metaData['type'], ['object''asset''document'])
  165.                             && $el Element\Service::getElementById($metaData['type'], $metaData['value'])) {
  166.                                 $metaData['value'] = $el;
  167.                             }
  168.                             if ($metaData['value'] instanceof Element\ElementInterface) {
  169.                                 $metaData['value'] = $metaData['value']->getRealFullPath();
  170.                             }
  171.                         }
  172.                     }
  173.                 }
  174.                 return $data;
  175.             };
  176.             $marker $rewritePath($this->marker);
  177.             $hotspots $rewritePath($this->hotspots);
  178.             return [
  179.                 'id' => $this->id,
  180.                 'path' => $image->getRealFullPath(),
  181.                 'alt' => $this->alt,
  182.                 'cropPercent' => $this->cropPercent,
  183.                 'cropWidth' => $this->cropWidth,
  184.                 'cropHeight' => $this->cropHeight,
  185.                 'cropTop' => $this->cropTop,
  186.                 'cropLeft' => $this->cropLeft,
  187.                 'hotspots' => $hotspots,
  188.                 'marker' => $marker,
  189.                 'thumbnail' => $this->thumbnail,
  190.                 'predefinedDataTemplates' => $this->getConfig()['predefinedDataTemplates'] ?? null,
  191.             ];
  192.         }
  193.         return null;
  194.     }
  195.     /**
  196.      * @return array
  197.      */
  198.     public function getConfig()
  199.     {
  200.         $config parent::getConfig();
  201.         if (isset($config['thumbnail']) && !isset($config['focal_point_context_menu_item'])) {
  202.             $thumbConfig Asset\Image\Thumbnail\Config::getByAutoDetect($config['thumbnail']);
  203.             if ($thumbConfig) {
  204.                 foreach ($thumbConfig->getItems() as $item) {
  205.                     if ($item['method'] == 'cover') {
  206.                         $config['focal_point_context_menu_item'] = true;
  207.                         $this->config['focal_point_context_menu_item'] = true;
  208.                         break;
  209.                     }
  210.                 }
  211.             }
  212.         }
  213.         return $config;
  214.     }
  215.     /**
  216.      * {@inheritdoc}
  217.      */
  218.     public function frontend()
  219.     {
  220.         if (!is_array($this->config)) {
  221.             $this->config = [];
  222.         }
  223.         $image $this->getImage();
  224.         if ($image instanceof Asset\Image) {
  225.             $thumbnailName $this->config['thumbnail'] ?? null;
  226.             if ($thumbnailName || $this->cropPercent) {
  227.                 // create a thumbnail first
  228.                 $autoName false;
  229.                 $thumbConfig $image->getThumbnailConfig($thumbnailName);
  230.                 if (!$thumbConfig && $this->cropPercent) {
  231.                     $thumbConfig = new Asset\Image\Thumbnail\Config();
  232.                 }
  233.                 if ($this->cropPercent) {
  234.                     $this->applyCustomCropping($thumbConfig);
  235.                     $autoName true;
  236.                 }
  237.                 if (isset($this->config['highResolution']) && $this->config['highResolution'] > 1) {
  238.                     $thumbConfig->setHighResolution($this->config['highResolution']);
  239.                 }
  240.                 // autogenerate a name for the thumbnail because it's different from the original
  241.                 if ($autoName) {
  242.                     $thumbConfig->generateAutoName();
  243.                 }
  244.                 $deferred true;
  245.                 if (isset($this->config['deferred'])) {
  246.                     $deferred $this->config['deferred'];
  247.                 }
  248.                 $thumbnail $image->getThumbnail($thumbConfig$deferred);
  249.             } else {
  250.                 // we're using the thumbnail class only to generate the HTML
  251.                 $thumbnail $image->getThumbnail();
  252.             }
  253.             $attributes array_merge($this->config, [
  254.                 'alt' => $this->alt,
  255.                 'title' => $this->alt,
  256.             ]);
  257.             $removeAttributes = [];
  258.             if (isset($this->config['removeAttributes']) && is_array($this->config['removeAttributes'])) {
  259.                 $removeAttributes $this->config['removeAttributes'];
  260.             }
  261.             // thumbnail's HTML is always generated by the thumbnail itself
  262.             return $thumbnail->getHtml($attributes);
  263.         }
  264.         return '';
  265.     }
  266.     /**
  267.      * {@inheritdoc}
  268.      */
  269.     public function setDataFromResource($data)
  270.     {
  271.         if (strlen($data) > 2) {
  272.             $data Serialize::unserialize($data);
  273.         }
  274.         $rewritePath = function ($data) {
  275.             if (!is_array($data)) {
  276.                 return [];
  277.             }
  278.             foreach ($data as &$element) {
  279.                 if (array_key_exists('data'$element) && is_array($element['data']) && count($element['data']) > 0) {
  280.                     foreach ($element['data'] as &$metaData) {
  281.                         // this is for backward compatibility (Array vs. MarkerHotspotItem)
  282.                         if (is_array($metaData)) {
  283.                             $metaData = new Element\Data\MarkerHotspotItem($metaData);
  284.                         }
  285.                     }
  286.                 }
  287.             }
  288.             return $data;
  289.         };
  290.         if (array_key_exists('marker'$data) && is_array($data['marker']) && count($data['marker']) > 0) {
  291.             $data['marker'] = $rewritePath($data['marker']);
  292.         }
  293.         if (array_key_exists('hotspots'$data) && is_array($data['hotspots']) && count($data['hotspots']) > 0) {
  294.             $data['hotspots'] = $rewritePath($data['hotspots']);
  295.         }
  296.         $this->id $data['id'] ?? null;
  297.         $this->alt $data['alt'] ?? null;
  298.         $this->cropPercent $data['cropPercent'] ?? null;
  299.         $this->cropWidth $data['cropWidth'] ?? null;
  300.         $this->cropHeight $data['cropHeight'] ?? null;
  301.         $this->cropTop $data['cropTop'] ?? null;
  302.         $this->cropLeft $data['cropLeft'] ?? null;
  303.         $this->marker $data['marker'] ?? null;
  304.         $this->hotspots $data['hotspots'] ?? null;
  305.         $this->thumbnail $data['thumbnail'] ?? null;
  306.         return $this;
  307.     }
  308.     /**
  309.      * {@inheritdoc}
  310.      */
  311.     public function setDataFromEditmode($data)
  312.     {
  313.         $rewritePath = function ($data) {
  314.             if (!is_array($data)) {
  315.                 return [];
  316.             }
  317.             foreach ($data as &$element) {
  318.                 if (array_key_exists('data'$element) && is_array($element['data']) && count($element['data']) > 0) {
  319.                     foreach ($element['data'] as &$metaData) {
  320.                         $metaData = new Element\Data\MarkerHotspotItem($metaData);
  321.                         if (in_array($metaData['type'], ['object''asset''document'])) {
  322.                             $el Element\Service::getElementByPath($metaData['type'], $metaData->getValue());
  323.                             $metaData['value'] = $el;
  324.                         }
  325.                     }
  326.                 }
  327.             }
  328.             return $data;
  329.         };
  330.         if (is_array($data)) {
  331.             if (array_key_exists('marker'$data) && is_array($data['marker']) && count($data['marker']) > 0) {
  332.                 $data['marker'] = $rewritePath($data['marker']);
  333.             }
  334.             if (array_key_exists('hotspots'$data) && is_array($data['hotspots']) && count($data['hotspots']) > 0) {
  335.                 $data['hotspots'] = $rewritePath($data['hotspots']);
  336.             }
  337.             $this->id $data['id'] ?? null;
  338.             $this->alt $data['alt'] ?? null;
  339.             $this->cropPercent $data['cropPercent'] ?? null;
  340.             $this->cropWidth $data['cropWidth'] ?? null;
  341.             $this->cropHeight $data['cropHeight'] ?? null;
  342.             $this->cropTop $data['cropTop'] ?? null;
  343.             $this->cropLeft $data['cropLeft'] ?? null;
  344.             $this->marker $data['marker'] ?? null;
  345.             $this->hotspots $data['hotspots'] ?? null;
  346.             $this->thumbnail $data['thumbnail'] ?? null;
  347.         }
  348.         return $this;
  349.     }
  350.     /**
  351.      * @return string
  352.      */
  353.     public function getText()
  354.     {
  355.         return $this->alt;
  356.     }
  357.     /**
  358.      * @param string $text
  359.      */
  360.     public function setText($text)
  361.     {
  362.         $this->alt $text;
  363.     }
  364.     /**
  365.      * @return string
  366.      */
  367.     public function getAlt()
  368.     {
  369.         return $this->getText();
  370.     }
  371.     /**
  372.      * @return string|null
  373.      */
  374.     public function getThumbnailConfig()
  375.     {
  376.         return $this->thumbnail;
  377.     }
  378.     /**
  379.      * @return string
  380.      */
  381.     public function getSrc()
  382.     {
  383.         $image $this->getImage();
  384.         if ($image instanceof Asset) {
  385.             return $image->getFullPath();
  386.         }
  387.         return '';
  388.     }
  389.     /**
  390.      * @return Asset\Image|ElementDescriptor|ElementInterface|null
  391.      */
  392.     public function getImage()
  393.     {
  394.         if (!$this->image) {
  395.             $this->image Asset\Image::getById($this->getId());
  396.         }
  397.         return $this->image;
  398.     }
  399.     /**
  400.      * @param Asset\Image|ElementDescriptor|ElementInterface|null $image
  401.      *
  402.      * @return $this
  403.      */
  404.     public function setImage($image)
  405.     {
  406.         $this->image $image;
  407.         if ($image instanceof Asset) {
  408.             $this->setId($image->getId());
  409.         }
  410.         return $this;
  411.     }
  412.     /**
  413.      * @param int $id
  414.      *
  415.      * @return $this
  416.      */
  417.     public function setId($id)
  418.     {
  419.         $this->id $id;
  420.         return $this;
  421.     }
  422.     /**
  423.      * @return int
  424.      */
  425.     public function getId()
  426.     {
  427.         return (int) $this->id;
  428.     }
  429.     /**
  430.      * @param array|string|Asset\Image\Thumbnail\Config $conf
  431.      * @param bool $deferred
  432.      *
  433.      * @return Asset\Image\Thumbnail|string
  434.      */
  435.     public function getThumbnail($conf$deferred true)
  436.     {
  437.         $image $this->getImage();
  438.         if ($image instanceof Asset\Image) {
  439.             $thumbConfig $image->getThumbnailConfig($conf);
  440.             if ($thumbConfig && $this->cropPercent) {
  441.                 $this->applyCustomCropping($thumbConfig);
  442.                 $thumbConfig->generateAutoName();
  443.             }
  444.             return $image->getThumbnail($thumbConfig$deferred);
  445.         }
  446.         return '';
  447.     }
  448.     /**
  449.      * @param Asset\Image\Thumbnail\Config $thumbConfig
  450.      *
  451.      * @return void
  452.      */
  453.     private function applyCustomCropping($thumbConfig)
  454.     {
  455.         $cropConfig = [
  456.             'width' => $this->cropWidth,
  457.             'height' => $this->cropHeight,
  458.             'y' => $this->cropTop,
  459.             'x' => $this->cropLeft,
  460.         ];
  461.         $thumbConfig->addItemAt(0'cropPercent'$cropConfig);
  462.         // also crop media query specific configs
  463.         if ($thumbConfig->hasMedias()) {
  464.             foreach ($thumbConfig->getMedias() as $mediaName => $mediaItems) {
  465.                 $thumbConfig->addItemAt(0'cropPercent'$cropConfig$mediaName);
  466.             }
  467.         }
  468.     }
  469.     /**
  470.      * {@inheritdoc}
  471.      */
  472.     public function isEmpty()
  473.     {
  474.         $image $this->getImage();
  475.         if ($image instanceof Asset\Image) {
  476.             return false;
  477.         }
  478.         return true;
  479.     }
  480.     /**
  481.      * {@inheritdoc}
  482.      */
  483.     public function getCacheTags(Model\Document\PageSnippet $ownerDocument, array $tags = []): array
  484.     {
  485.         $image $this->getImage();
  486.         if ($image instanceof Asset) {
  487.             if (!array_key_exists($image->getCacheTag(), $tags)) {
  488.                 $tags $image->getCacheTags($tags);
  489.             }
  490.         }
  491.         $getMetaDataCacheTags = function ($data$tags) {
  492.             if (!is_array($data)) {
  493.                 return $tags;
  494.             }
  495.             foreach ($data as $element) {
  496.                 if (array_key_exists('data'$element) && is_array($element['data']) && count($element['data']) > 0) {
  497.                     foreach ($element['data'] as $metaData) {
  498.                         if ($metaData instanceof Element\Data\MarkerHotspotItem) {
  499.                             $metaData get_object_vars($metaData);
  500.                         }
  501.                         if ($metaData['value'] instanceof Element\ElementInterface) {
  502.                             if (!array_key_exists($metaData['value']->getCacheTag(), $tags)) {
  503.                                 $tags $metaData['value']->getCacheTags($tags);
  504.                             }
  505.                         }
  506.                     }
  507.                 }
  508.             }
  509.             return $tags;
  510.         };
  511.         $tags $getMetaDataCacheTags($this->marker$tags);
  512.         $tags $getMetaDataCacheTags($this->hotspots$tags);
  513.         return $tags;
  514.     }
  515.     /**
  516.      * @return array
  517.      */
  518.     public function resolveDependencies()
  519.     {
  520.         $dependencies = [];
  521.         $image $this->getImage();
  522.         if ($image instanceof Asset\Image) {
  523.             $key 'asset_' $image->getId();
  524.             $dependencies[$key] = [
  525.                 'id' => $image->getId(),
  526.                 'type' => 'asset',
  527.             ];
  528.         }
  529.         $getMetaDataDependencies = function ($data$dependencies) {
  530.             if (!is_array($data)) {
  531.                 return $dependencies;
  532.             }
  533.             foreach ($data as $element) {
  534.                 if (array_key_exists('data'$element) && is_array($element['data']) && count($element['data']) > 0) {
  535.                     foreach ($element['data'] as $metaData) {
  536.                         if ($metaData instanceof Element\Data\MarkerHotspotItem) {
  537.                             $metaData get_object_vars($metaData);
  538.                         }
  539.                         if ($metaData['value'] instanceof Element\ElementInterface) {
  540.                             $dependencies[$metaData['type'] . '_' $metaData['value']->getId()] = [
  541.                                 'id' => $metaData['value']->getId(),
  542.                                 'type' => $metaData['type'],
  543.                             ];
  544.                         }
  545.                     }
  546.                 }
  547.             }
  548.             return $dependencies;
  549.         };
  550.         $dependencies $getMetaDataDependencies($this->marker$dependencies);
  551.         $dependencies $getMetaDataDependencies($this->hotspots$dependencies);
  552.         return $dependencies;
  553.     }
  554.     /**
  555.      * @param float $cropHeight
  556.      *
  557.      * @return $this
  558.      */
  559.     public function setCropHeight($cropHeight)
  560.     {
  561.         $this->cropHeight $cropHeight;
  562.         return $this;
  563.     }
  564.     /**
  565.      * @return float
  566.      */
  567.     public function getCropHeight()
  568.     {
  569.         return $this->cropHeight;
  570.     }
  571.     /**
  572.      * @param float $cropLeft
  573.      *
  574.      * @return $this
  575.      */
  576.     public function setCropLeft($cropLeft)
  577.     {
  578.         $this->cropLeft $cropLeft;
  579.         return $this;
  580.     }
  581.     /**
  582.      * @return float
  583.      */
  584.     public function getCropLeft()
  585.     {
  586.         return $this->cropLeft;
  587.     }
  588.     /**
  589.      * @param bool $cropPercent
  590.      *
  591.      * @return $this
  592.      */
  593.     public function setCropPercent($cropPercent)
  594.     {
  595.         $this->cropPercent $cropPercent;
  596.         return $this;
  597.     }
  598.     /**
  599.      * @return bool
  600.      */
  601.     public function getCropPercent()
  602.     {
  603.         return $this->cropPercent;
  604.     }
  605.     /**
  606.      * @param float $cropTop
  607.      *
  608.      * @return $this
  609.      */
  610.     public function setCropTop($cropTop)
  611.     {
  612.         $this->cropTop $cropTop;
  613.         return $this;
  614.     }
  615.     /**
  616.      * @return float
  617.      */
  618.     public function getCropTop()
  619.     {
  620.         return $this->cropTop;
  621.     }
  622.     /**
  623.      * @param float $cropWidth
  624.      *
  625.      * @return $this
  626.      */
  627.     public function setCropWidth($cropWidth)
  628.     {
  629.         $this->cropWidth $cropWidth;
  630.         return $this;
  631.     }
  632.     /**
  633.      * @return float
  634.      */
  635.     public function getCropWidth()
  636.     {
  637.         return $this->cropWidth;
  638.     }
  639.     /**
  640.      * @param array $hotspots
  641.      */
  642.     public function setHotspots($hotspots)
  643.     {
  644.         $this->hotspots $hotspots;
  645.     }
  646.     /**
  647.      * @return array
  648.      */
  649.     public function getHotspots()
  650.     {
  651.         return $this->hotspots;
  652.     }
  653.     /**
  654.      * @param array $marker
  655.      */
  656.     public function setMarker($marker)
  657.     {
  658.         $this->marker $marker;
  659.     }
  660.     /**
  661.      * @return array
  662.      */
  663.     public function getMarker()
  664.     {
  665.         return $this->marker;
  666.     }
  667.     /**
  668.      * {@inheritdoc}
  669.      */
  670.     public function rewriteIds($idMapping/** : void */
  671.     {
  672.         if (array_key_exists('asset'$idMapping) && array_key_exists($this->getId(), $idMapping['asset'])) {
  673.             $this->setId($idMapping['asset'][$this->getId()]);
  674.             // reset marker & hotspot information
  675.             $this->setHotspots([]);
  676.             $this->setMarker([]);
  677.             $this->setCropPercent(false);
  678.             $this->setImage(null);
  679.         }
  680.     }
  681.     /**
  682.      * @return array
  683.      */
  684.     public function __sleep()
  685.     {
  686.         $finalVars = [];
  687.         $parentVars parent::__sleep();
  688.         $blockedVars = ['image'];
  689.         foreach ($parentVars as $key) {
  690.             if (!in_array($key$blockedVars)) {
  691.                 $finalVars[] = $key;
  692.             }
  693.         }
  694.         return $finalVars;
  695.     }
  696. }