Skip to content

Изменение размера изображений

По дизайну страницы конференции фотографии должны быть размером не более 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"

Изменение размера изображения будет происходить в отдельном сервисном классе:

src/ImageOptimizer.php
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
--- 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;
@@ -25,6 +26,8 @@ class CommentMessageHandler
         private WorkflowInterface $commentStateMachine,
         private MailerInterface $mailer,
         #[Autowire('%admin_email%')] private string $adminEmail,
+        private ImageOptimizer $imageOptimizer,
+        #[Autowire('%photo_dir%')] private string $photoDir,
         private ?LoggerInterface $logger = null,
     ) {
     }
@@ -54,6 +57,12 @@ class CommentMessageHandler
                 ->to($this->adminEmail)
                 ->context(['comment' => $comment])
             );
+        } elseif ($this->commentStateMachine->can($comment, 'optimize')) {
+            if ($comment->getPhotoFilename()) {
+                $this->imageOptimizer->resize($this->photoDir.'/'.$comment->getPhotoFilename());
+            }
+            $this->commentStateMachine->apply($comment, 'optimize');
+            $this->entityManager->flush();
         } elseif ($this->logger) {
             $this->logger->debug('Dropping comment message', ['comment' => $comment->getId(), 'state' => $comment->getState()]);
         }

Обратите внимание на автоматически доступную переменную $photoDir, так как ранее в одном из предыдущих шагов к этому имени переменной в контейнере мы привязали соответствующий параметр:

config/services.yaml
1
2
parameters:
    photo_dir: "%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
@@ -12,3 +12,7 @@ varnish:
         vcl: !include
             type: string
             path: config.vcl
+
+files:
+    type: network-storage:2.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:

Этого должно быть достаточно для работы в продакшене.

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version