1

I'm working on a project where a user is able to upload a file. My code works when a single file is uploaded, but I need to change it so a user is able to upload multiple files.

I want to store the files in my database as String. Currently it is stored as example: "file1.png". When uploading multiple files I would like it to be stored as "file1.png;file2.png;file3.png". However when I add the "multiple => true" in the form, I get an error when pressing submit by the validator that the input needs to be a String.

My best guess is that I need to use Data transformers, but after reading the docs I still don't know how to approach this. ?

Data Transform

This is the controller (currently it expects a single file, as for multiple I would use foreach):

\#\[Route('/new', name: 'app_blog_new', methods: \['GET', 'POST'\])\]
\#\[IsGranted('IS_AUTHENTICATED')\]
public function new(Request $request, BlogRepository $blogRepository, SluggerInterface $slugger, MailerInterface $mailer): Response
{
$blog = new Blog();
$form = $this-\>createForm(BlogType::class, $blog);
$form-\>handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $additionalImages = $form->get('additional_images')->getData();
        if ($additionalImages) {
            $originalFilename = pathinfo($additionalImages->getClientOriginalName(), PATHINFO_FILENAME);
            $safeFilename = $slugger->slug($originalFilename);
            $newFilename = $safeFilename . '-' . uniqid() . '.' . $additionalImages->guessExtension();
    
            try {
                $additionalImages->move(
                    $this->getParameter('blogimage_directory'),
                    $newFilename
                );
            } catch (FileException $e) {
                // ... handle exception if something happens during file upload
            }
    
            $blog->setAdditionalImages($newFilename);
        }
}

If I add "multiple => true' to this form I get an "expected String" error on the front. This is the form used to upload images to a blog:


public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder
        ->add('title')
        ->add('additional_images', FileType::class, [
            'label' => 'Additional images',
            'mapped' => false,
            'multiple' => true,
            'required' => false,
            'constraints' => [`your text`
                new File([
                    'maxSize' => '1024k',
                    'mimeTypes' => [
                        'image/*',
                    ],
                    'mimeTypesMessage' => 'Please upload a valid image',
                ])
            ],
        ]);
        $builder->get('additional_images')
            ->addModelTransformer(new CallbackTransformer(
                function ($additionalAsArray) {
                    // transform the array to a string
                    return implode('; ', $additionalAsArray);
                },
                function ($additionalAsString) {
                    // transform the string back to an array
                    return explode('; ', $additionalAsString);
                }
            ))
        ;
}

This is the blog entity class which contains the image(s)

#[ORM\Entity(repositoryClass: BlogRepository::class)]
class Blog
{
    #[ORM\Column(type: Types::TEXT, nullable: true)]
    private ?string $additional_images = null;
}

I tried adding 'multiple => true' to the form and it works, as the user is able to select multiple files. But after submitting I get "implode(): Argument #1 ($pieces) must be of type array, string given"

1 Answer 1

2

I found out that all I had to do was add "new All" to the form:

    ->add('additional_images', FileType::class, [
        'label' => 'Additional images',
        'mapped' => false,
        'required' => false,
        'multiple' => true,
        'constraints' => [
            new All([
                new File([
                    'maxSize' => '1024k',
                    'mimeTypes' => [
                        'image/*',
                    ],
                    'mimeTypesMessage' => 'Please upload a valid image',
                ])
            ])
        ],
    ]);

And made my controller work with an array:

    $additionalImages = $form->get('additional_images')->getData();
    if ($additionalImages) {
        $result = array();
        foreach ($additionalImages as $image)
        {
            $originalFilename = pathinfo($image->getClientOriginalName(), PATHINFO_FILENAME);
            $safeFilename = $slugger->slug($originalFilename);
            $newFilename = $safeFilename . '-' . uniqid() . '.' . $image->guessExtension();

            try {
                $image->move(
                    $this->getParameter('blogimage_directory'),
                    $newFilename
                );
            } catch (FileException $e) {
                // ... handle exception if something happens during file upload
            }
            $result[] = $newFilename;
        }
        $blog->setAdditionalImages(implode(";", $result));

}

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.