Home > Net >  Symfony 6 CollectionType and uploading multiple files
Symfony 6 CollectionType and uploading multiple files

Time:09-20

I'm new to Symfony and I'm struggling a lot trying to find a way to upload multiple files. I'm trying to build an app have apartment and each apartment can have multiple images.

Appartment(OneToMany) - Image(ManyToOne)

so I created 2 entities and added a field in my AppartmentTypeForm called 'image' which is a CollectionType::class of 'name' in my ImageTypeForm which is a FileType::class

I added some js to be able to add multiple input files by clicking a button

everything works until I submit the form,I cannot get the image names if I add 3 images and I try to

$photo = $form->get('image')->getData();

I will see my 3 arrays only the id of my apartment is set no name no file nothing.

I'm probably doing something wrong, but I can't see where.

Controller, as you will see iI tried to foreach my image data, but I can only get 1 of the file name and even when I try to flush() everything Symfony returns an error because it tries to set my database column 'name' as null...,

#[Route('/create_product', name: 'create_product', methods: ['GET', 'POST'])]
    public function createProduct(EntityManagerInterface $em, Request $request, SluggerInterface $slugger): Response
    {
        $image = new Image;
        $product = new Appartment;

        $form = $this->createForm(AppartmentTypeFormType::class, $product);


        $form->handleRequest($request);

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

            $product->setCreatedAt(new DateTime());
            $product->setUpdatedAt(new DateTime());
            $product->setCountry($form->get('country')->getData());
            $image->setCreatedAt(new DateTime());
            $image->setUpdatedAt(new DateTime());

            foreach ($form->get('image') as $formChild) {
                $uploadedImages = $formChild->get('name')->getData();
                $uploadedImage = $uploadedImages[0];
                $newFileName = $this->handleFile($slugger, $uploadedImage);
                $image->setName($newFileName);
            }
        }

        $em->persist($product);
        $em->persist($image);
        $em->flush();
        $this->addFlash('success', "votre produit a bien était ajouté");




        return $this->render('admin/create_product.html.twig', [
            'form' => $form->createView(),

        ]);
    }


    public function handleFile($slugger, $image)
    {

        $extension = '.' . $image->guessExtension();
        $originalFileName = $slugger->slug($image->getClientOriginalName());
        $newFileName = $originalFileName . uniqid() . $extension;
        try {
            $image->move($this->getParameter('uploads_directory'), $newFileName);
        } catch (FileException $fe) {
            //throw $th;
        }

        return $newFileName;
    }

Appartment Entity (OneToMany)

 #[ORM\ManyToOne(inversedBy: 'appartments')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Country $country = null;

  
    #[ORM\OneToMany(mappedBy: 'image', targetEntity: Image::class, cascade:["persist"])]
    private Collection $image;

    public function __construct()
    {
        $this->image = new ArrayCollection();
    }


    /**
     * @return Collection<int, Image>
     */
    public function getImage(): Collection
    {
        return $this->image;
    }

    public function addImage(Image $image): self
    {
        if (!$this->image->contains($image)) {
            $this->image->add($image);
            $image->setImage($this);
        }

        return $this;
    }

    public function removeImage(Image $image): self
    {
        if ($this->image->removeElement($image)) {
            // set the owning side to null (unless already changed)
            if ($image->getImage() === $this) {
                $image->setImage(null);
            }
        }

        return $this;
    }

Image Entity (ManyToOne)

#[ORM\Entity(repositoryClass: ImageRepository::class)]
class Image
{

    
    use TimestampableEntity;

    use SoftDeleteableEntity;

    
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;


    #[ORM\ManyToOne(inversedBy: 'image')]
    private ?Appartment $image = null;


    #[ORM\Column(length: 255)]
    private ?string $name = null;


    public function getId(): ?int
    {
        return $this->id;
    }


    public function getImage(): ?Appartment
    {
        return $this->image;
    }

    public function setImage(?Appartment $image): self
    {
        $this->image = $image;

        return $this;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }


}

AppartmentTypeForm

class AppartmentTypeFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('beds')
            ->add('price')
            ->add('city')
            ->add('address')
            ->add('postal_code')
            ->add('country',EntityType::class, [
                'class' => Country::class,
                'choice_label' => 'name'
            ])
            ->add('image', CollectionType::class, [
                'entry_type' => ImageTypeFormType::class,
                'constraints' => [
                    new Valid()
                ],


                'entry_options' => ['label' => false],
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'envoyer',
               
            ]);
}
public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Appartment::class,
            'allow_file_upload' => true
      
        ]);
    }
}

ImageTypeForm

class ImageTypeFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', FileType::class, [
                'label' => false,
                'constraints' => [
                    new All([
                        
                        new File(
                       [ "mimeTypes" => ["image/png",
                                "image/jpg",
                                "image/jpeg",
                                "image/gif"]]
                    )]),
                    new Valid(),
                ],
                'multiple' => true,
                'mapped' => false,
         
    
            ]);
    }

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

this is what I get when I

$image = form->get('image')->getData();

dd($image) return me this
AdminController.php on line 50:
Doctrine\Common\Collections\ArrayCollection {#1191 ▼
  -elements: array:3 [▼
    0 => App\Entity\Image {#1343 ▼
      -id: null
      -image: App\Entity\Appartment {#526 ▶}
      -name: null
      #createdAt: null
      #updatedAt: null
      #deletedAt: null
    }
    1 => App\Entity\Image {#1247 ▼
      -id: null
      -image: App\Entity\Appartment {#526}
      -name: null
      #createdAt: null
      #updatedAt: null
      #deletedAt: null
    }
    2 => App\Entity\Image {#1257 ▼
      -id: null
      -image: App\Entity\Appartment {#526}
      -name: null
      #createdAt: null
      #updatedAt: null
      #deletedAt: null
    }
  ]
}

and this is what I get when I do it for files

$photo = $request->files;
dd($photo); return me this

AdminController.php on line 50:
Symfony\Component\HttpFoundation\FileBag {#55 ▼
  #parameters: array:1 [▼
    "appartment_type_form" => array:1 [▼
      "image" => array:3 [▼
        0 => array:1 [▼
          "name" => array:1 [▼
            0 => Symfony\Component\HttpFoundation\File\UploadedFile {#60 ▼
              -test: false
              -originalName: "FaYS3XxWQAAesmS.jpg"
              -mimeType: "image/jpeg"
              -error: 0
              path: "C:\xampp\tmp"
              filename: "php6EE1.tmp"
              basename: "php6EE1.tmp"
              pathname: "C:\xampp\tmp\php6EE1.tmp"
              extension: "tmp"
              realPath: "C:\xampp\tmp\php6EE1.tmp"
              aTime: 2022-09-18 08:43:33
              mTime: 2022-09-18 08:43:32
              cTime: 2022-09-18 08:43:32
              inode: 2251799814701650
              size: 129133
              perms: 0100666
              owner: 0
              group: 0
              type: "file"
              writable: true
              readable: true
              executable: false
              file: true
              dir: false
              link: false
              linkTarget: "C:\xampp\tmp\php6EE1.tmp"
            }
          ]
        ]
        1 => array:1 [▼
          "name" => array:1 [▼
            0 => Symfony\Component\HttpFoundation\File\UploadedFile {#43 ▼
              -test: false
              -originalName: "FUR6LQ3X0AQxOIW.jpg"
              -mimeType: "image/jpeg"
              -error: 0
              path: "C:\xampp\tmp"
              filename: "php6EE2.tmp"
              basename: "php6EE2.tmp"
              pathname: "C:\xampp\tmp\php6EE2.tmp"
              extension: "tmp"
              realPath: "C:\xampp\tmp\php6EE2.tmp"
              aTime: 2022-09-18 08:43:33
              mTime: 2022-09-18 08:43:32
              cTime: 2022-09-18 08:43:32
              inode: 1970324837991018
              size: 69872
              perms: 0100666
              owner: 0
              group: 0
              type: "file"
              writable: true
              readable: true
              executable: false
              file: true
              dir: false
              link: false
              linkTarget: "C:\xampp\tmp\php6EE2.tmp"
            }
          ]
        ]
        2 => array:1 [▼
          "name" => array:1 [▼
            0 => Symfony\Component\HttpFoundation\File\UploadedFile {#42 ▼
              -test: false
              -originalName: "8fecc63aa4d247d6895b0de17e38b858.jpg"
              -mimeType: "image/jpeg"
              -error: 0
              path: "C:\xampp\tmp"
              filename: "php6EE3.tmp"
              basename: "php6EE3.tmp"
              pathname: "C:\xampp\tmp\php6EE3.tmp"
              extension: "tmp"
              realPath: "C:\xampp\tmp\php6EE3.tmp"
              aTime: 2022-09-18 08:43:33
              mTime: 2022-09-18 08:43:32
              cTime: 2022-09-18 08:43:32
              inode: 1688849861280373
              size: 565083
              perms: 0100666
              owner: 0
              group: 0
              type: "file"
              writable: true
              readable: true
              executable: false
              file: true
              dir: false
              link: false
              linkTarget: "C:\xampp\tmp\php6EE3.tmp"
            }
          ]
        ]
      ]
    ]
  ]
}

I'm sorry it's a bit long, but I tried to search everywhere couldn't find a response

thank you.

So little Edit:
When I submit my file my images are renamed and uploaded in my uploads_directory I don't know how or why. I changed nothing, but still how can I get my database column name to be equal to my file name.

Second Edit:
I managed to upload 1 image in my db by changing

$image->setName($newFileName);
$em->persist($image)

by this:

$em->persist($image->setName($newFileName));

but I still can't get all my images to get in database.

CodePudding user response:

Move $image = new Image; and $em->persist($image); to the foreach section

...
foreach ($form->get('image') as $formChild) {
    $image = new Image;                    // added
    $image->setCreatedAt(new DateTime());  // added
    $image->setUpdatedAt(new DateTime());  // added

    $uploadedImages = $formChild->get('name')->getData();
    $uploadedImage = $uploadedImages[0];
    $newFileName = $this->handleFile($slugger, $uploadedImage);
    $image->setName($newFileName);
    
    $em->persist($image); // added
}
...
  • Related