Изменение размера изображений
По дизайну страницы конференции фотографии должны быть размером не более 200x150 пикселей. Может тогда нам стоит оптимизировать и уменьшать изображения, в случае если загруженные фотографии превышают указанный максимальный размер?
Идеальным решением будет включить такую операцию в бизнес-процесс комментария: после проверки и перед публикацией комментария.
Давайте добавим новое состояние ready и переход optimize:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
--- a/config/packages/workflow.yaml
+++ b/config/packages/workflow.yaml
@@ -16,6 +16,7 @@ framework:
                 - potential_spam
                 - spam
                 - rejected
+                - ready
                 - published
             transitions:
                 accept:
@@ -29,13 +30,16 @@ framework:
                     to:   spam
                 publish:
                     from: potential_spam
-                    to:   published
+                    to:   ready
                 reject:
                     from: potential_spam
                     to:   rejected
                 publish_ham:
                     from: ham
-                    to:   published
+                    to:   ready
                 reject_ham:
                     from: ham
                     to:   rejected
+                optimize:
+                    from: ready
+                    to:   published
    Посмотрим, как визуально выглядит измененный бизнес-процесс, чтобы убедиться, что он корректно составлен:
1
$ symfony console workflow:dump comment | dot -Tpng -o workflow.png
    
Оптимизация изображений с помощью Imagine
Оптимизировать изображения будем через модуль GD (должен быть установлен на вашем компьютере) и Imagine:
1
$ symfony composer req "imagine/imagine:^1.2"
    Изменение размера изображения будет происходить в отдельном сервисном классе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
namespace App;
use Imagine\Gd\Imagine;
use Imagine\Image\Box;
class ImageOptimizer
{
    private const MAX_WIDTH = 200;
    private const MAX_HEIGHT = 150;
    private $imagine;
    public function __construct()
    {
        $this->imagine = new Imagine();
    }
    public function resize(string $filename): void
    {
        list($iwidth, $iheight) = getimagesize($filename);
        $ratio = $iwidth / $iheight;
        $width = self::MAX_WIDTH;
        $height = self::MAX_HEIGHT;
        if ($width / $height > $ratio) {
            $width = $height * $ratio;
        } else {
            $height = $width / $ratio;
        }
        $photo = $this->imagine->open($filename);
        $photo->resize(new Box($width, $height))->save($filename);
    }
}
    После оптимизации фотографии заменяем исходный файл на новый. Хотя, возможно, по каким-либо причинам вы решите оставить оригинальное изображение.
Добавление нового шага в бизнес-процесс
Добавьте в бизнес-процесс обработку нового состояния:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
--- a/src/MessageHandler/CommentMessageHandler.php
+++ b/src/MessageHandler/CommentMessageHandler.php
@@ -2,6 +2,7 @@
 namespace App\MessageHandler;
+use App\ImageOptimizer;
 use App\Message\CommentMessage;
 use App\Repository\CommentRepository;
 use App\SpamChecker;
@@ -21,10 +22,12 @@ class CommentMessageHandler implements MessageHandlerInterface
     private $bus;
     private $workflow;
     private $mailer;
+    private $imageOptimizer;
     private $adminEmail;
+    private $photoDir;
     private $logger;
-    public function __construct(EntityManagerInterface $entityManager, SpamChecker $spamChecker, CommentRepository $commentRepository, MessageBusInterface $bus, WorkflowInterface $commentStateMachine, MailerInterface $mailer, string $adminEmail, LoggerInterface $logger = null)
+    public function __construct(EntityManagerInterface $entityManager, SpamChecker $spamChecker, CommentRepository $commentRepository, MessageBusInterface $bus, WorkflowInterface $commentStateMachine, MailerInterface $mailer, ImageOptimizer $imageOptimizer, string $adminEmail, string $photoDir, LoggerInterface $logger = null)
     {
         $this->entityManager = $entityManager;
         $this->spamChecker = $spamChecker;
@@ -32,7 +35,9 @@ class CommentMessageHandler implements MessageHandlerInterface
         $this->bus = $bus;
         $this->workflow = $commentStateMachine;
         $this->mailer = $mailer;
+        $this->imageOptimizer = $imageOptimizer;
         $this->adminEmail = $adminEmail;
+        $this->photoDir = $photoDir;
         $this->logger = $logger;
     }
@@ -64,6 +69,12 @@ class CommentMessageHandler implements MessageHandlerInterface
                 ->to($this->adminEmail)
                 ->context(['comment' => $comment])
             );
+        } elseif ($this->workflow->can($comment, 'optimize')) {
+            if ($comment->getPhotoFilename()) {
+                $this->imageOptimizer->resize($this->photoDir.'/'.$comment->getPhotoFilename());
+            }
+            $this->workflow->apply($comment, 'optimize');
+            $this->entityManager->flush();
         } elseif ($this->logger) {
             $this->logger->debug('Dropping comment message', ['comment' => $comment->getId(), 'state' => $comment->getState()]);
         }
    Обратите внимание на автоматически доступную переменную $photoDir, так как ранее в одном из предыдущих шагов к этому имени переменной в контейнере мы привязали соответствующий параметр:
1 2 3 4
services:
    _defaults:
        bind:
            string $photoDir: "%kernel.project_dir%/public/uploads/photos"
    Хранение загруженных данных в продакшене
В конфигурационном файле .platform.app.yaml уже указана специальная директория для чтения и записи загруженных фотографий. Однако она смонтирована только локально. Чтобы к данной директории имели доступ веб-контейнер и воркер для обработки сообщений в очереди, нужно создать файловый сервис:
1 2 3 4 5 6 7 8 9 10
--- a/.platform/services.yaml
+++ b/.platform/services.yaml
@@ -11,3 +11,7 @@ varnish:
         vcl: !include
             type: string
             path: config.vcl
+
+files:
+    type: network-storage:1.0
+    disk: 256
    Используйте его для директории загруженных фотографий:
1 2 3 4 5 6 7 8 9 10 11
--- a/.platform.app.yaml
+++ b/.platform.app.yaml
@@ -35,7 +35,7 @@ web:
 mounts:
     "/var": { source: local, source_path: var }
-    "/public/uploads": { source: local, source_path: uploads }
+    "/public/uploads": { source: service, service: files, source_path: uploads }
 relationships:
     database: "database:postgresql"
    Этого должно быть достаточно для работы в продакшене.