vendor/contao/core-bundle/src/Image/Studio/ImageResult.php line 159

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Image\Studio;
  11. use Contao\CoreBundle\Image\ImageFactoryInterface;
  12. use Contao\CoreBundle\Image\PictureFactory;
  13. use Contao\CoreBundle\Image\PictureFactoryInterface;
  14. use Contao\Image\DeferredImageInterface;
  15. use Contao\Image\DeferredResizerInterface;
  16. use Contao\Image\Image;
  17. use Contao\Image\ImageDimensions;
  18. use Contao\Image\ImageInterface;
  19. use Contao\Image\PictureConfiguration;
  20. use Contao\Image\PictureInterface;
  21. use Contao\Image\ResizeOptions;
  22. use Psr\Container\ContainerInterface;
  23. use Symfony\Component\Filesystem\Path;
  24. class ImageResult
  25. {
  26.     private ContainerInterface $locator;
  27.     private ?ResizeOptions $resizeOptions;
  28.     private string $projectDir;
  29.     /**
  30.      * @var string|ImageInterface
  31.      */
  32.     private $filePathOrImageInterface;
  33.     /**
  34.      * @var int|string|array|PictureConfiguration|null
  35.      */
  36.     private $sizeConfiguration;
  37.     /**
  38.      * Cached picture.
  39.      */
  40.     private ?PictureInterface $picture null;
  41.     /**
  42.      * Cached image dimensions.
  43.      */
  44.     private ?ImageDimensions $originalDimensions null;
  45.     /**
  46.      * @param string|ImageInterface                      $filePathOrImage
  47.      * @param array|PictureConfiguration|int|string|null $sizeConfiguration
  48.      *
  49.      * @internal Use the Contao\CoreBundle\Image\Studio\Studio factory to get an instance of this class
  50.      */
  51.     public function __construct(ContainerInterface $locatorstring $projectDir$filePathOrImage$sizeConfiguration nullResizeOptions $resizeOptions null)
  52.     {
  53.         $this->locator $locator;
  54.         $this->projectDir $projectDir;
  55.         $this->filePathOrImageInterface $filePathOrImage;
  56.         $this->sizeConfiguration $sizeConfiguration;
  57.         $this->resizeOptions $resizeOptions;
  58.     }
  59.     /**
  60.      * Creates a picture with the defined size configuration.
  61.      */
  62.     public function getPicture(): PictureInterface
  63.     {
  64.         if (null !== $this->picture) {
  65.             return $this->picture;
  66.         }
  67.         // Unlike the Contao\Image\PictureFactory the PictureFactoryInterface
  68.         // does not know about ResizeOptions. We therefore check if the third
  69.         // argument of the "create" method allows setting them.
  70.         $canHandleResizeOptions = static function (PictureFactoryInterface $factory): bool {
  71.             if ($factory instanceof PictureFactory) {
  72.                 return true;
  73.             }
  74.             $createParameters = (new \ReflectionClass($factory))
  75.                 ->getMethod('create')
  76.                 ->getParameters()
  77.             ;
  78.             if (!isset($createParameters[2])) {
  79.                 return false;
  80.             }
  81.             $type $createParameters[2]->getType();
  82.             return $type instanceof \ReflectionNamedType && ResizeOptions::class === $type->getName();
  83.         };
  84.         $factory $this->pictureFactory();
  85.         $arguments = [$this->filePathOrImageInterface$this->sizeConfiguration];
  86.         if (null !== $this->resizeOptions && $canHandleResizeOptions($factory)) {
  87.             $arguments[] = $this->resizeOptions;
  88.         }
  89.         return $this->picture $this->pictureFactory()->create(...$arguments);
  90.     }
  91.     /**
  92.      * Returns the "sources" part of the current picture.
  93.      */
  94.     public function getSources(): array
  95.     {
  96.         return $this->getPicture()->getSources($this->projectDir$this->staticUrl());
  97.     }
  98.     /**
  99.      * Returns the "img" part of the current picture.
  100.      */
  101.     public function getImg(): array
  102.     {
  103.         return $this->getPicture()->getImg($this->projectDir$this->staticUrl());
  104.     }
  105.     /**
  106.      * Returns the "src" attribute of the image. This will return a URL by
  107.      * default. Set $asPath to true to get a relative file path instead.
  108.      */
  109.     public function getImageSrc(bool $asPath false): string
  110.     {
  111.         if ($asPath) {
  112.             /** @var Image $image */
  113.             $image $this->getPicture()->getImg()['src'];
  114.             return Path::makeRelative($image->getPath(), $this->projectDir);
  115.         }
  116.         return $this->getImg()['src'] ?? '';
  117.     }
  118.     /**
  119.      * Returns the image dimensions of the base resource.
  120.      */
  121.     public function getOriginalDimensions(): ImageDimensions
  122.     {
  123.         if (null !== $this->originalDimensions) {
  124.             return $this->originalDimensions;
  125.         }
  126.         if ($this->filePathOrImageInterface instanceof ImageInterface) {
  127.             return $this->originalDimensions $this->filePathOrImageInterface->getDimensions();
  128.         }
  129.         return $this->originalDimensions $this
  130.             ->imageFactory()
  131.             ->create($this->filePathOrImageInterface)
  132.             ->getDimensions()
  133.         ;
  134.     }
  135.     /**
  136.      * Returns the file path of the base resource.
  137.      *
  138.      * Set $absolute to true to return an absolute path instead of a path
  139.      * relative to the project dir.
  140.      */
  141.     public function getFilePath(bool $absolute false): string
  142.     {
  143.         $path $this->filePathOrImageInterface instanceof ImageInterface
  144.             $this->filePathOrImageInterface->getPath()
  145.             : $this->filePathOrImageInterface;
  146.         return $absolute $path Path::makeRelative($path$this->projectDir);
  147.     }
  148.     /**
  149.      * Synchronously processes images if they are deferred.
  150.      *
  151.      * This will make sure that the target files physically exist instead of
  152.      * being generated by the Contao\CoreBundle\Controller\ImagesController
  153.      * on first access.
  154.      */
  155.     public function createIfDeferred(): void
  156.     {
  157.         $picture $this->getPicture();
  158.         $candidates = [];
  159.         foreach (array_merge([$picture->getImg()], $picture->getSources()) as $source) {
  160.             $candidates[] = $source['src'] ?? null;
  161.             foreach ($source['srcset'] ?? [] as $srcset) {
  162.                 $candidates[] = $srcset[0] ?? null;
  163.             }
  164.         }
  165.         $deferredImages array_filter(
  166.             $candidates,
  167.             static fn ($image): bool => $image instanceof DeferredImageInterface
  168.         );
  169.         if (empty($deferredImages)) {
  170.             return;
  171.         }
  172.         $resizer $this->locator->get('contao.image.legacy_resizer');
  173.         if (!$resizer instanceof DeferredResizerInterface) {
  174.             throw new \RuntimeException('The "contao.image.legacy_resizer" service does not support deferred resizing.');
  175.         }
  176.         foreach ($deferredImages as $deferredImage) {
  177.             $resizer->resizeDeferredImage($deferredImage);
  178.         }
  179.     }
  180.     private function imageFactory(): ImageFactoryInterface
  181.     {
  182.         return $this->locator->get('contao.image.factory');
  183.     }
  184.     private function pictureFactory(): PictureFactoryInterface
  185.     {
  186.         return $this->locator->get('contao.image.picture_factory');
  187.     }
  188.     private function staticUrl(): string
  189.     {
  190.         return $this->locator->get('contao.assets.files_context')->getStaticUrl();
  191.     }
  192. }