Skip to content

Formaat van afbeeldingen wijzigen

Op het ontwerp van de conferentiepagina's zijn de foto's beperkt tot een maximale grootte van 200 bij 150 pixels. Hoe optimaliseren en verkleinen we afbeeldingen als het geüploade origineel groter is dan de limieten?

Dat is een taak die perfect toegevoegd kan worden aan de comment workflow, waarschijnlijk vlak nadat de reactie gevalideerd is en vlak voordat deze gepubliceerd wordt.

Laten we een nieuwe ready state en een optimize transitie toevoegen:

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

Genereer een visuele weergave van de nieuwe workflowconfiguratie om te valideren dat deze beschrijft wat we willen:

1
$ symfony console workflow:dump comment | dot -Tpng -o workflow.png

Afbeeldingen optimaliseren met Imagine

Optimalisatie van afbeeldingen wordt uitgevoerd door GD (controleer of de GD-extensie in je lokale PHP-installatie is ingeschakeld) en Imagine:

1
$ symfony composer req "imagine/imagine:^1.2"

De grootte van een afbeelding kan aangepast worden via de volgende service class:

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);
    }
}

Na het optimaliseren van de foto, slaan we het nieuwe bestand op in plaats van het originele bestand. Misschien wil je het originele beeld wel ergens bewaren.

Een nieuwe stap in de workflow toevoegen

Wijzig de workflow om de nieuwe state af te handelen:

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()]);
         }

Merk op dat $photoDir automatisch wordt geïnjecteerd omdat we in een vorige stap een container bind hebben gedefinieerd voor deze variabelenaam:

config/services.yaml
1
2
3
4
services:
    _defaults:
        bind:
            string $photoDir: "%kernel.project_dir%/public/uploads/photos"

Opslaan van geüploade gegevens in productie

We hebben al een speciale lezen-schrijven directory gedefinieerd voor geüploade bestanden in .platform.app.yaml, maar de mount is lokaal. Als we willen dat de webcontainer en de message consumer toegang krijgen tot dezelfde mount, moeten we een file service toevoegen:

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

Gebruik het als foto-upload-directory:

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"

Dit zou voldoende moeten zijn om de functie in productie te laten werken.

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