Create a Messenger for multiple image upload traitment

40 Views Asked by At

I have a project under Symfony 7. My form has a FileType field in order to upload several images. It works very well but depending on the number of images, it can be very long, I would like to queue this sequence via Messenger so that the user can continue browsing.

My problem is while retrieving the image array, serialization of UploadFile is not allowed. However, I need it to fill my loop which is in my Handler.

This is where I am :

My Service for Picture (move and resize)

<?php

class PictureService implements PictureServiceInterface
{

    public function __construct(private readonly ParameterBagInterface $params){}

    /**
     * @param UploadedFile $picture
     * @param string|null $folder
     * @param int|null $width
     * @param int|null $height
     * @return string
     * @throws \Exception
     */
    public function add(UploadedFile $picture, ?string $folder = '', ?int $width = 250, ?int $height = 250): string
    {
        $file = md5(uniqid()) . '-utilauto29.jpg';
        //Récupère les inforamtions de l'image (taille)
        $picture_meta = getimagesize($picture->getRealPath());

        if($picture_meta === false){
            throw new \Exception("Invalid image format");
        }

        $picture_src = match ($picture_meta['mime']) {
            'image/png' => imagecreatefrompng($picture->getRealPath()),
            'image/jpeg' => imagecreatefromjpeg($picture->getRealPath()),
            'image/webp' => imagecreatefromwebp($picture->getRealPath()),
            default => throw new \Exception("Invalid image format"),
        };

        $path = $this->params->get('u_images_folder') . $folder;

        // Create destination folder
        if(!file_exists($path . '/thumbs/')){
            mkdir($path . '/thumbs/', 0755, true);
        }

        $img_manager = new ImageManager(new Driver());
        $img_manager->read($picture)->save($path . '/' . $file);
        $img_manager->read($picture)->resizeCanvas($width, $height)->save($path . '/thumbs/thumb-' . $file);

        return $file;
    }
}

My Controller

<?php

class OfferUpdateController extends CrudController
{

    #[Route('/admin/offer/u/{id}', name: 'admin_offer_update')]
    public function update(Request $request, Offer $offer, MessageBusInterface $messageBus): Response
    {
        $form = $this->createForm(OfferType::class, $offer);
        $form->handleRequest($request);

        if($form->isSubmitted() && $form->isValid()) {
            /** @var ClickableInterface $uploadPictures */
            $uploadPictures = $form->get('uploadPictures');
            if($uploadPictures->isClicked()) {
                $pictures = $form->get('images')->getData(); // Problem is here
                $messageBus->dispatch(new OfferUploadPictureMessage($pictures, $offer->getId()));
            }
            //$this->em->flush();
            $this->addFlash('success', 'Annonce modifiée avec succés.');
        }

        return $this->render('admin/offer/update.html.twig', [
            'menu' => 'offer',
            'form' => $form,
            'offer' => $offer
        ]);
    }
}

My Messenger

<?php


final class OfferUploadPictureMessage
{
    public function __construct(public readonly array $form, public readonly int $offerId){}
}

My MessengerHandler

<?php

#[AsMessageHandler]
final class OfferUploadPictureMessageHandler
{
    const WIDTH = 1280; // width for redim picture
    const HEIGHT = 720; // height for redim picture

    public function __construct(
        private readonly EntityManagerInterface $em,
        private readonly PictureServiceInterface $pictureService
    ){}

    public function __invoke(OfferUploadPictureMessage $message)
    {
        $offer = $this->em->getRepository(Offer::class)->findOneBy(['id' => $message->offerId]);
        foreach ($message->form as $picture){
            $folder = "/ads/{$offer->getId()}";
            $file = $this->pictureService->add($picture, $folder, self::WIDTH, self::HEIGHT);
            $pic = new Picture();
            $pic->setFilename($file);
            $pic->setFileSize($picture->getSize());
            $pic->setCover(false);
            $offer->addPicture($pic);
        }
        $this->em->flush();
    }
}

FormType

<?php

class OfferType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
           //
            ->add('images', FileType::class, [
                'label' => "Sélectionnez des photos pour cet album",
                'multiple' => true,
                'mapped' => false,
                'required' => false
            ])
            ->add('uploadPictures', SubmitType::class, [
                'label' => 'Téléverser',
                'attr' => [
                    'class' => "btn btn-header-info"
                ]
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Offer::class,
        ]);
    }
}

I don't know if this is good practice, I'm just starting to use Messenger.

How to return the information of each image to then persist in Doctrine ?

Thanks !

0

There are 0 best solutions below