Edit file name in entity with Symfony

2019-09-02 16:50发布

问题:

Hello (excuse my English, not too confident with it)

I'm actually working on a Symfony website that display some spectacles' information. For now, I need to add an image when I create one of them. I managed to do so with the help of this tutorial.

It basically works like this: I upload an image into site's directory and then send file's name to the entity (Store in a MySQL database). I can then display the image in spectacle's details.

The issue appeared when I want to edit a spectacle. I can't update the image's name. I have two only possibilities are to 1/not edit the entity, or to 2/change the image name and then get a random one that I can't display anymore (these names are usually like /tmp/phpWb8kwV)

My image is instantiate like this in the entity (in Spectacle.php):

/**
* @var string
*
* @ORM\Column(name="image", type="string", length=255)
* @Assert\NotBlank(message="Veuillez ajouter une image à votre spectacle.")
* @Assert\File(mimeTypes={ "image/png" })
*/
private $image;

And the FormType for the spectacle's form is made like this (in SpectacleType.php):

 public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('nom')
            ->add('lieu')
            ->add('dateSpectacle', null, array(
                'label' => 'Date du spectacle',
            ))
            ->add('annee')
            ->add('image',FileType::class, array(
                'label' => 'Image du spectacle',
                'required' => false, //(Still need to provide a file to finalize the creation/edit)
            ));
}

And the controller to acces this page is made like this (in SpectacleController.php):

/**
 * Creates a new spectacle entity.
 *
 * @Route("/new", name="admin_spectacle_new")
 * @Method({"GET", "POST"})
 */
public function newAction(Request $request)
{
    $spectacle = new Spectacle();
    $form = $this->createForm('FabopBundle\Form\SpectacleType', $spectacle);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
//--------------------------------------------------------------------
        $file = $spectacle->getImage();            
        $fileName = (md5(uniqid())).'.'.$file->guessExtension();            
        // moves the file to the directory where image are stored
        $file->move(
            $this->getParameter('img_directory'), //(Define in the service.yml)
            $fileName
        );
        $spectacle->setImage($fileName); //(Don't know how to handle file names without this line)
//---------------------------------------------------------------------
        $em->persist($spectacle);
        $em->flush();
        return $this->redirectToRoute('admin_spectacle_show', array('id' => $spectacle->getId()));
    }

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

The function that is routed to the edit view is approximatively the same, but i can't use

$spectacle->setImage($fileName);

There is two possibilities to solve this: I would like being able to update the new filename in the entity (with the other information) or being able to update the entity without changing filename.

I hope I was clear enough to explain my problem... Thanks in advance for your responses.

回答1:

I had this problem when trying to upload a PDF/TEXT.. file. But for managing images, I advice you to use ComurImageBundle, it helps you a lot and your problem will be resolved. It's very simple, you download the bundle like it's explained in this link. Then you modify your code like this : 1/ Instantiation of your image in Spectacle.php (your image is stored in the DB like string)

 /**
 * @ORM\Column(type="string", nullable=true)
 */
private $image;

2/ Update your base ( php bin/console doctrine:schema:update --force)

3/ Add these functions to your Spectacle.php after updating your DB schema, these functions let you upload and stock your images under specific directory (web/uploads/spectacles) and don't forget to add this two libraries

use Symfony\Component\HttpFoundation\File\UploadedFile;

use Symfony\Component\Validator\Constraints as Assert;

  /**
 * @Assert\File()
 */
private $file;

/**
 * Sets file.
 *
 * @param UploadedFile $file
 */
public function setFile(UploadedFile $file = null)
{
    $this->file = $file;
}

/**
 * Get file.
 *
 * @return UploadedFile
 */
public function getFile()
{
    return $this->file;
}

/**
 * @ORM\PrePersist
 */
public function preUpload()
{
    if (null !== $this->file) {
        $this->image = uniqid() . '.' . $this->file->guessExtension();
    }
}

/**
 * @ORM\PostPersist
 */
public function upload()
{
    if (null === $this->file) {
        return;
    }

    // If there is an error when moving the file, an exception will
    // be automatically thrown by move(). This will properly prevent
    // the entity from being persisted to the database on error
    $this->file->move($this->getUploadRootDir(), $this->image);
}

public function getUploadDir()
{
    return 'uploads/spectacles';
}

public function getBaseUrl()
{
    $currentPath = $_SERVER['PHP_SELF'];

    $pathInfo = pathinfo($currentPath);

    return substr($pathInfo['dirname']."/", 1);
}

public function getUploadRootDir()
{
    return $this->getBaseUrl() . $this->getUploadDir();
}

public function getWebPath()
{
    return null === $this->image ? null : $this->getUploadDir() . '/' . $this->image;
}

public function getAbsolutePath()
{
    return null === $this->image ? null : $this->getUploadRootDir() . '/' . $this->image;
}

4/ Modify the FormType (SpectacleType.php)like this

use Comur\ImageBundle\Form\Type\CroppableImageType;

  public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('nom')
            ->add('lieu')
            ->add('dateSpectacle', null, array(
                'label' => 'Date du spectacle',
            ))
            ->add('annee')
            ->add('image', CroppableImageType::class, array('label' => 'Image', 'required' => true,
            'uploadConfig' => array(
                'uploadUrl' => $myEntity->getUploadDir(),       // required - see explanation below (you can also put just a dir path)
                'webDir' => $myEntity->getUploadRootDir(),              // required - see explanation below (you can also put just a dir path)
                'fileExt' => '*.png',  // required - see explanation below (you can also put just a dir path)
                'showLibrary' => false,
            ),
            'cropConfig' => array(
                'minWidth' => 128,
                'minHeight' => 128,
                'aspectRatio' => true,
            )
        ));    
}

5/ Remove all these lines from your controller you won't need them

//--------------------------------------------------------------------
        $file = $spectacle->getImage();            
        $fileName = (md5(uniqid())).'.'.$file->guessExtension();            
        // moves the file to the directory where image are stored
        $file->move(
            $this->getParameter('img_directory'), //(Define in the service.yml)
            $fileName
        );
        $spectacle->setImage($fileName); //(Don't know how to handle file names without this line)
//---------------------------------------------------------------------

6/ That's it you can call the form of your image in new.html.twig and edit.html.twig, all will get well, try it please and notify me if there is any problem.



回答2:

The solution was stupid ...

In fact, the controller to access the edit route didn't have those lines:

$em = $this->getDoctrine()->getManager();
...
$em->persist($spectacle);
$em->flush();

I need to finish this quickly. If i have more time later, i'll try to make it work with the ComurImageBundle.

Thank you for your help, i'll be more carefull next time ...