src/App/Subscriber/Filesystem/LooseFileOptimizationSubscriber.php line 83

Open in your IDE?
  1. <?php
  2. namespace App\Subscriber\Filesystem;
  3. use App\Component\Blobs\BlobManagers\LooseFileBlobManager;
  4. use App\Entity\Filesystem\LooseFile;
  5. use App\Model\Vendor\Blitline\BlitlineJob;
  6. use App\Model\Vendor\Blitline\CropBlitlineFunction;
  7. use App\Model\Vendor\Blitline\NoopBlitlineFunction;
  8. use App\Model\Vendor\Blitline\ResizeToFitBlitlineFunction;
  9. use App\Service\Vendors\Blitline\BlitlineProcessor;
  10. use Cms\CoreBundle\Util\Doctrine\EntityManager;
  11. use Platform\QueueBundle\Event\AsyncEvent;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. final class LooseFileOptimizationSubscriber implements EventSubscriberInterface
  14. {
  15.     private const OPTIMIZATIONS__THUMB = [
  16.         'constraint' => 200,
  17.         'quality' => 75,
  18.     ];
  19.     private const OPTIMIZATIONS__PREVIEW = [
  20.         'constraint' => 1200,
  21.         'quality' => 75,
  22.     ];
  23.     private const OPTIMIZATIONS = [
  24.         LooseFile::TYPES__IMAGE => [
  25.             LooseFileBlobManager::SUFFIXES__HUGE => [
  26.                 'constraint' => 1000,
  27.                 'quality' => 75,
  28.             ],
  29.             LooseFileBlobManager::SUFFIXES__LARGE => [
  30.                 'constraint' => 800,
  31.                 'quality' => 75,
  32.             ],
  33.             LooseFileBlobManager::SUFFIXES__MEDIUM => [
  34.                 'constraint' => 600,
  35.                 'quality' => 75,
  36.             ],
  37.             LooseFileBlobManager::SUFFIXES__SMALL => [
  38.                 'constraint' => 400,
  39.                 'quality' => 75,
  40.             ],
  41.             LooseFileBlobManager::SUFFIXES__TINY => [
  42.                 'constraint' => 300,
  43.                 'quality' => 75,
  44.             ],
  45.         ],
  46.     ];
  47.     // DI
  48.     protected EntityManager $em;
  49.     protected BlitlineProcessor $blitline;
  50.     protected LooseFileBlobManager $blobs;
  51.     public function __construct(
  52.         EntityManager $em,
  53.         BlitlineProcessor $blitline,
  54.         LooseFileBlobManager $blobs
  55.     )
  56.     {
  57.         $this->em $em;
  58.         $this->blitline $blitline;
  59.         $this->blobs $blobs;
  60.     }
  61.     /**
  62.      * {@inheritDoc}
  63.      */
  64.     public static function getSubscribedEvents(): array
  65.     {
  66.         return [
  67.             'temp_file_resize' => [
  68.                 ['handleResizing'0],
  69.             ],
  70.         ];
  71.     }
  72.     /**
  73.      * @param AsyncEvent $event
  74.      * @return void
  75.      */
  76.     public function handleResizing(AsyncEvent $event): void
  77.     {
  78.         // obtain the file in question
  79.         $file $this->em->getRepository(LooseFile::class)->find($event->getParam('file'));
  80.         if ( ! $file) {
  81.             // TODO: do we need to throw an error or something?
  82.             return;
  83.         }
  84.         // make sure it is an image file
  85.         if ( ! $file->isType(LooseFile::TYPES__IMAGE)) {
  86.             return;
  87.         }
  88.         // get crop info
  89.         $crop $event->getParam('crop') ?: null;
  90.         // handle cropping, if no cropping we want to use a different function altogether
  91.         // this needs to be a high quality image
  92.         $func = ( ! $crop ? new NoopBlitlineFunction() : new CropBlitlineFunction())
  93.             ->setQuality(100)
  94.             ->setIdentifier($this->blobs->getCropSuffix($file))
  95.             ->setS3Destination(
  96.                 $this->blobs->storage()->bucket(),
  97.                 $this->blobs->getCropPath($file)
  98.             );
  99.         if ($func instanceof CropBlitlineFunction) {
  100.             $func->setCropBox(
  101.                 $crop['x'],
  102.                 $crop['y'],
  103.                 $crop['width'],
  104.                 $crop['height']
  105.             );
  106.         }
  107.         // handle the optimization based on the "cropped" image
  108.         $func
  109.             // do thumb cropping first as that is what is needed first
  110.             ->appendFunction(
  111.                 (new ResizeToFitBlitlineFunction())
  112.                     ->setWidth(self::OPTIMIZATIONS__THUMB['constraint'])
  113.                     ->setOnlyShrinkLarger(true)
  114.                     ->setAutoSharpen(true)
  115.                     ->setQuality(self::OPTIMIZATIONS__THUMB['quality'])
  116.                     ->setIdentifier($this->blobs->getThumbSuffix($file))
  117.                     ->setS3Destination(
  118.                         $this->blobs->storage()->bucket(),
  119.                         $this->blobs->getThumbPath($file)
  120.                     )
  121.             )
  122.             // then do generic preview resizing
  123.             ->appendFunction(
  124.                 (new ResizeToFitBlitlineFunction())
  125.                     ->setWidth(self::OPTIMIZATIONS__PREVIEW['constraint'])
  126.                     ->setOnlyShrinkLarger(true)
  127.                     ->setAutoSharpen(true)
  128.                     ->setQuality(self::OPTIMIZATIONS__PREVIEW['quality'])
  129.                     ->setIdentifier($this->blobs->getPreviewSuffix($file))
  130.                     ->setS3Destination(
  131.                         $this->blobs->storage()->bucket(),
  132.                         $this->blobs->getPreviewPath($file)
  133.                     )
  134.             )
  135.         ;
  136.         // handle optimizations
  137.         if (isset(self::OPTIMIZATIONS[$file->getType()])) {
  138.             foreach (self::OPTIMIZATIONS[$file->getType()] as $optimization => $config) {
  139.                 $func->appendFunction(
  140.                     (new ResizeToFitBlitlineFunction())
  141.                         ->setWidth($config['constraint'])
  142.                         ->setOnlyShrinkLarger(true)
  143.                         ->setAutoSharpen(true)
  144.                         ->setQuality($config['quality'])
  145.                         ->setIdentifier($this->blobs->getOptimizationSuffix($file$optimization))
  146.                         ->setS3Destination(
  147.                             $this->blobs->storage()->bucket(),
  148.                             $this->blobs->getOptimizationPath($file$optimization)
  149.                         )
  150.                 );
  151.             }
  152.         }
  153.         // create the blitline job
  154.         $job = (new BlitlineJob($this->blobs->getUploadUrl($file)))
  155.             ->appendFunction($func);
  156.         // run the job; this is async...
  157.         try {
  158.             $id $this->blitline->exec($job);
  159.             $event->getOutput()->writeln(sprintf(
  160.                 'Blitline job #%s is running...',
  161.                 $id
  162.             ));
  163.             $this->em->save(
  164.                 $file
  165.                     ->setRemoteJobId($id)
  166.                     ->setStatus(LooseFile::STATUSES__PROCESSED)
  167.             );
  168.             $event->getOutput()->writeln(array_map(
  169.                 static function (string $url) {
  170.                     return sprintf(
  171.                         'Expecting URL: %s',
  172.                         $url
  173.                     );
  174.                 },
  175.                 [
  176.                     $this->blobs->getUploadUrl($file),
  177.                     $this->blobs->getCropUrl($file),
  178.                     $this->blobs->getPreviewUrl($file),
  179.                     $this->blobs->getThumbUrl($file),
  180.                     ...self::OPTIMIZATIONS[$file->getType()] ? array_map(
  181.                         function (string $optimization) use ($file) {
  182.                             return $this->blobs->getOptimizationUrl($file$optimization);
  183.                         },
  184.                         array_keys(self::OPTIMIZATIONS[$file->getType()])
  185.                     ) : []
  186.                 ]
  187.             ));
  188.         } catch (\Exception $e) {
  189.             $event->getOutput()->writeln(sprintf(
  190.                 'ERROR: %s',
  191.                 $e->getMessage()
  192.             ));
  193.         }
  194.     }
  195. }