chtouk
chtouk

Reputation: 311

Symfony : how to set a file type in an edit form?

I have this error when I want to edit an "event" in my form with symfony :

"The form's view data is expected to be a "Symfony\Component\HttpFoundation\File\File", but it is a "string". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "string" to an instance of "Symfony\Component\HttpFoundation\File\File"."

I follow the documentation and adding this in my controller :

$event->setEventImage(
            new File($this->getParameter('images_dir').'/'.$event->getEventImage())
        );

But it does not change anything I don't understand why.

So there is my entity :

  /**
     *
     * @ORM\Column (type="string")
     * @Assert\NotBlank(message="Merci de charger un fichier au format image.")
     * @Assert\File(mimeTypes={ "image/*" })
     */
    private $eventImage;
  public function getEventImage(): ?string
    {
        return $this->eventImage;
    }

    public function setEventImage(string $eventImage): self
    {
        $this->eventImage = $eventImage;

        return $this;
    }

And my Controller :

 #[Route('/{id}/edit', name: 'events_edit', methods: ['GET','POST'])]
    public function edit(Request $request, Events $event, SluggerInterface $slugger): Response
    {

        $event->setEventImage(
            new File($this->getParameter('images_dir').'/'.$event->getEventImage())
        );

        $form = $this->createForm(EventsType::class, $event);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            /** @var UploadedFile $eventImage */
            $eventImage = $form->get('eventImage')->getData();

            // this condition is needed because the 'eventImage' field is not required
            // so the Image file must be processed only when a file is uploaded
            if ($eventImage) {
                $originalFilename = pathinfo($eventImage->getClientOriginalName(), PATHINFO_FILENAME);
                // this is needed to safely include the file name as part of the URL
                $safeFilename = $slugger->slug($originalFilename);
                $newFilename = $safeFilename . '-' . uniqid() . '.' . $eventImage->guessExtension();

                // Move the file to the directory where images are stored
                try {
                    $eventImage->move(
                        $this->getParameter('images_dir'),
                        $newFilename
                    );
                } catch (FileException $e) {
                    // ... handle exception if something happens during file upload
                }

                // updates the 'eventImage' property to store the image file name
                // instead of its contents
                $event->setEventImage($newFilename);
            }
            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute('events_index', [], Response::HTTP_SEE_OTHER);
        }

        return $this->renderForm('events/edit.html.twig', [
            'event' => $event,
            'form' => $form,
        ]);
    }

And my EventsType :

public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title')
            ->add('subtitle')

            ->add('content', CKEditorType::class, [
                'label' => 'content',
                'required' => false,
            ])
            ->add('dateEvent', DateTimeType::class, [
                'widget' => 'single_text',
                'label' => 'Date d\'arrivée : '
            ])
            ->add('place')
            ->add('dateDead', DateType::class, [
                'widget' => 'single_text',
                'label' => 'Date limite d\'inscription : '
            ])
            ->add('numberPersonRestricted')
            ->add('eventImage', FileType::class, [
                'label' => 'Image (fichier image)',
                'required' => false,
                'constraints' => [
                    new File([
                        'maxSize' => '1024k',
                        'mimeTypes' => [
                            'image/*',
                        ],
                        'mimeTypesMessage' => 'Please upload a valid image',
                    ])
                ]
            ])
        ;
    }

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

Upvotes: 1

Views: 4146

Answers (1)

ABLY Eric
ABLY Eric

Reputation: 11

        ->add('eventImage', FileType::class, [
            'label' => 'Image (fichier image)',
            'required' => false,
            'constraints' => [
                new File([
                    'maxSize' => '1024k',
                    'mimeTypes' => [
                        'image/*',
                    ],
                    'mimeTypesMessage' => 'Please upload a valid image',
                ])
            ]
            'data_class' => null
        ])

in your formtype, you can add the parameter 'data_class' => null (like the example above) to eventImage will remove warning and work if you add new file but for edit if you don't add new file it should persist null in your bd.

To overcome this problem in order to be able to pre-fill the file field if a file exists is to do something like pointing to the location of the file. i.e. the path of the file that is saved in your database.

So what you're doing is checking your view to see if a file exists for the file path that exists in the database and then pre-filling it by doing something like this (don't forget to change with your upload path):

 {% if form.eventImage.vars.data %} <img src="{{ asset('/uploads/directory/' ~ form.eventImage.vars.data.filename) }}"/>{% endif %}

Upvotes: 1

Related Questions