0
votes

I'm new in php and symfony I use a file service for the upload in symfony 2.8 I got 2 tables One Salon to many Files

I can upload multiple files in my newaction. The problem happened at the editAction of my SalonController.

I would like to remove the older files in order to add newfiles in my editfiles.html.twig. And I tried a foreach in order to get this array...

Could you help me please ?

Here is the error

Type error: Argument 1 passed to DefaultBundle\Service\FileService::upload() must be an instance of DefaultBundle\Entity\File, instance of Doctrine\ORM\PersistentCollection given, called in /var/www/html/salon-beaute/src/SalonBundle/Controller/SalonController.php on line 131

And the stack trace focused on the line 18 of the fileservice.php

public function upload(File $file = null, $type) {

Here is the my newaction and editaction of my SalonController

class SalonController extends Controller

{ /** * Creates a new salon entity. * * @Route("/new", name="salon_new") * @Method({"GET", "POST"}) */ public function newAction(Request $request) { $this->denyAccessUnlessGranted('ROLE_SALON'); $em = $this->getDoctrine()->getManager(); $salon = new Salon();

    $options = array('role' => $this->getUser()->getRoles(), 'page' => 'add');

    $form = $this->createForm( 'SalonBundle\Form\SalonType',$salon, $options);
    $user = $this->getUser();
    $form->handleRequest($request);

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

        $uploadService = $this->get('app.file');

        $myFiles = $form->get('file')->getData();

        foreach($myFiles['path'] as $new_file) {

            $file = new File();
            $file->setPath($new_file);
            $file->setSalon($salon);
            $salon->addFile($file);
            $uploadService->upload($file, 'salon');
            $em->persist($file);
        }

        $user->setSalon($salon);
        $salon->setEnable(false);
        $em->persist($user);
        $em->persist($salon);
        $em->flush();

        $this->get('email')->salon($salon);
        return $this->redirectToRoute('salon_show', array('id' => $salon->getId()));
    }
/**
 * Displays a form to edit an existing salon entity.
 *
 * @Route("/edit", name="salon_edit")
 * @Method({"GET", "POST"})
 * @Security("has_role('ROLE_SALON')")
 */
public function editAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $user = $this->getUser();
    $salon = $user->getSalon();
    $deleteForm = $this->createDeleteForm($salon);
    $options = array('role' => $this->getUser()->getRoles(), 'page' => 'edit');

    $editForm = $this->createForm('SalonBundle\Form\SalonType', $salon, $options);

    $editForm->handleRequest($request);

    if ($editForm->isSubmitted() && $editForm->isValid()) {
        // If new file
        $edit_file = $editForm->get('edit_file')->getData();
        if (!is_null($edit_file)) {
            $file_current = $salon->getFiles();
            $salon->getFiles($edit_file);
            if (!$this->get('app.file')->upload($salon->getFiles(), 'salon'))
                $salon->getFiles($file_current);
        }

        foreach($edit_file['path'] as $new_edit_file) {
            $file = new File();
            $file->setPath($new_edit_file);
            $file->setSalon($salon);
            $salon->addFile($file);
            $this->get('app.file')->upload($file);
            $em->persist($file);
        }

        $this->getDoctrine()->getManager()->flush();
        $this->addFlash('success', 'Le partenaire a bien été modifié');
        return $this->redirectToRoute('salon_show');
    }

    return $this->render('@Salon/salon/edit.html.twig', array(
        'salon' => $salon,
        'edit_form' => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    ));
}

    return $this->render('@Salon/salon/new.html.twig', array(
        'salon' => $salon,
        'form' => $form->createView(),
    ));
}

A portion of my SalonType

    class SalonType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $page = $options['page'];

        $builder
            ->add('name', TextType::class, array(
                'label' => 'Nom du salon'
            ))
            ->add('content', TextareaType::class, array(
                'label' => 'Descriptif'
            ))
            ->add('address_salon', AddressType::class, array(
                'label' => ' '
            ))
        ;

        if($page == 'add') {
            $builder
                ->add('file', FileType::class, array(
                    'label' => 'Vous pouvez téléchargez jusqu\'à 3 images',
                    'required' => false,
                    'mapped' =>false,
                ));
        }

        if($page == 'edit') {
            $builder
                ->add('edit_file', FileType::class, array(
                    'label' => 'Nouveau fichier',
                    'required' => false,
                    'mapped' => false
                ));
        };

    }



    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'SalonBundle\Entity\Salon',
            'role' => null
        ));
        $resolver
            ->setRequired(['page']);
    }


My fileType

    class FileType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('path', \Symfony\Component\Form\Extension\Core\Type\FileType::class, array(
                'label' => 'Image',
                'multiple' => true,
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => null,
        ));
    }
}

My fileService

    <?php
namespace DefaultBundle\Service;

use DefaultBundle\Entity\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class FileService {
    private $directory_root;
    private $directory_default;


    public function __construct($directory_root, $directory_default) {
        $this->directory_root = $directory_root;
        $this->directory_default = $directory_default;
    }

    public function upload(File $file = null, $type) {
        $path = $this->getDirectory($type);

        if (is_null($file))
            return false;

        // Get file (Class UploadFile)
        $file_uploaded = $file->getPath();

        if ($file_uploaded->getError())
            return false;

        // Move file
        $file_name = md5(uniqid()) . '.' . $file_uploaded->guessExtension();
        $file_uploaded->move($this->directory_root . $path, $file_name);

        // Update object file
        $path .= '/' . $file_name;
        $file->update($file_uploaded, $path);

        return true;
    }

    public function delete(File $file){
        $path = $this->directory_root.$file->getPath();
        if(file_exists($path))
            unlink($path);
    }

    private function getDirectory($type) {
        switch ($type) {
            default:
                return $this->directory_default;
        }
    }
}
1
Can you show us the code of your upload() method?DFayet
I add the upload method in my question. ThkAyay 95

1 Answers

1
votes

Your code is kinda messy, by that I mean you have lot of logic in your controller :-)

Just to know which line is the 131 in your controller?

You have an error here (don't know if it's the 131 line)

if (!$this->get('app.file')->upload($salon->getFiles(), 'salon'))

Here you send a collection to upload(), you said it yourself

One Salon to many Files

BUT before trying to hotfix this look at is tutorial here on how to handle multiple file upload.

Also this tutorial has the full demo source code available. The code is quite clear and you should be able to understand it easily.

Edit

If you don't want to rewrite your code you may want to hotfix your code like that

if (!is_null($edit_file)) {
    $file_current = $salon->getFiles();
    //$salon->getFiles($edit_file); What is the goal of this?
    foreach ($salon->getFiles() as $file) {
        // Note that now we send a single File object not a collection
        if (!$this->get('app.file')->upload($file, 'salon')) {
            $salon->setFiles($file_current); // You want to set the files no?
            break;
        }
    }
}

This is 200% ugly, and I'm not even sure if it will work. You should really think about refactoring your code.

Edit 2

The problem you have now is that you are mixing your File object and the UploadedFile object from symfony.

You do $file_uploaded = $file->getPath(); then you have the error

Call to a member function getError() on string

and it's normal because getPath() return a string.

I assume you have look the Uploader Service of the symfony doc. You can see they pass an UploadedFile object which is part of the symfony package, not a custom entity.

If I wanted to do a quick fix, which is definitely not what I recommend, I'll do something like this

// Your controller (newAction)
foreach($myFiles['path'] as $new_file) {
    // $new_file is an uploadedFile object, this is the file you want to upload
    $file = new File();
    $file->setPath($new_file);
    $file->setSalon($salon);
    $salon->addFile($file);
    $uploadService->upload($file, $new_file, 'salon');
    $em->persist($file);
}

// Your FileService
public function upload(File $file = null, UploadedFile $file_uploaded = null, $type) {
    $path = $this->getDirectory($type);

    if (is_null($file_uploaded) || is_null($file))
        return false;

    // Get file (Class UploadFile), No here you get the file path => a string
    //$file_uploaded = $file->getPath();

    if ($file_uploaded->getError())
        return false;

    //... end of your method
}