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

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