doums
doums

Reputation: 450

My Uploader Files with symfony and doctrine

I have a problem with my uploader files system. First of all I followed this : http://symfony.com/doc/current/controller/upload_file.html

In fact the uploader is "simply" a file input -> filetype, in a form. A user can publish an article with an image. Ok.

Currently my uploader works well. But my problem occurs when I try to edit an existing entity : Because in the edit form, the user have to select his file even if he want not change his file. Is not userfriendly. I would like change that.

my controller :

public function editAction($id, Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $article = $em->getRepository('PMPlatformBundle:Article')->find($id);
    if (null === $article) {
        throw new NotFoundHttpException("L'article d'id " . $id . " n'existe pas.");
    }
            $article->setImgName(
                new File($this->getParameter('images_directory').'/'.$article->getImgName())
            );
            $form = $this->get('form.factory')->create(TextOnlyType::class, $article);
    if ($request->isMethod('POST'))
    {
        if ($form->handleRequest($request)->isValid())
        {
            $em->flush();
            $this->addFlash(
            );
            return $this->redirectToRoute('pm_platform_view', array('slug' => $article->getSlug()));
        }
        else
        {
            $this->addFlash(
            );
        }
    }
    return $this->render('PMPlatformBundle:Article:edit.html.twig', array(
        'article' => $article,
        'form'   => $form->createView(),
    ));
}

my event listener :

class ImageUploadListener
{
    private $uploader;
    protected $oldImg;
    protected $imageDir;

    public function __construct(PMImageUploader $uploader, $oldImg = null, $imageDir)
    {
        $this->uploader = $uploader;
        $this->oldImg = $oldImg;
        $this->imagetDir = $imageDir;
    }

    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        $this->uploadFile($entity);
    }

    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity instanceof Image) {
            $this->oldImg = $args->getOldValue('imgName');
            $this->uploadFile($entity);
        }
    }

    public function postUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        if (!$entity->getImgName() instanceof UploadedFile) {
        return;
    }
        if ($entity instanceof Image) {
            $oldImg = $this->oldImg;
            $this->removeOldFile($entity, $oldImg);
        }
    }

    public function postRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity instanceof Image) {
            $imgName = $entity->getImgName();
            $this->removeOldFile($entity, $imgName);
        }
    }

    private function uploadFile($entity)
    {
        if ($entity instanceof Image) {
            $image = $entity->getImgName();
            if (!$image instanceof UploadedFile) {
                return;
            }
            $imageName = $this->uploader->fileSave($image, "image");
            $entity->setOriginalImgName($image->getClientOriginalName());
            $entity->setImgName($imageName);
        }
    }

    private function removeOldFile($entity, $fileName)
    {
        if ($entity instanceof Image && $fileName) {
            $this->uploader->fileRemove($fileName, "image");
        }
    }
}

Article entity :

class Image extends Article
{
    /**
     * @var string
     *
     * @ORM\Column(name="img_name", type="string", length=255, nullable=false)
     * @Assert\Image(
     *     maxSize = "10Mi",
     *     minWidth = 400,
     *     maxWidth = 10000,
     *     minHeight = 400,
     *     maxHeight = 10000
     * )
     */
    private $imgName;

    /**
     * @var string
     *
     * @ORM\Column(name="original_img_name", type="string", length=255, nullable=false)
     */
    private $originalImgName;

    /**
     * Set imgName
     *
     * @param string $imgName
     *
     * @return Image
     */
    public function setImgName($imgName)
    {
        $this->imgName = $imgName;

        return $this;
    }

    /**
     * Get imgName
     *
     * @return string
     */
    public function getImgName()
    {
        return $this->imgName;
    }

and my form type :

class ImageType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title',          TextType::class)
            ->add('description',    TextareaType::class)
            ->add('imgName',        FileType::class, array(
                'label' => 'Importer votre image',
                'required' => false,
            ))
            ->add('tags',           TextType::class, array('required' => false))
            ->add('send',           SubmitType::class, array('label' => 'Envoyer'));
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PM\PlatformBundle\Entity\Image'
        ));
    }
}

Ok so as I tell you before, when a user edit his article, and not selects a file whit input file, this article is updated with a NULL file. How I can change that for this article to be updated with the same file as one before update ?

Upvotes: 0

Views: 64

Answers (2)

doums
doums

Reputation: 450

Ok it's done whit that changes :

class ImageUploadListener
{
    private $uploader;
    protected $oldImg;
    protected $imageDir;

    public function __construct(PMImageUploader $uploader, $oldImg = null, $imageDir)
    {
        $this->uploader = $uploader;
        $this->oldImg = $oldImg;
        $this->imagetDir = $imageDir;
    }

    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        $this->uploadFile($entity);
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Image) {
            $this->oldImg = $entity->getImgName();
        }
    }

    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity instanceof Image) {
            if (!$entity->getImgName()) {
                $entity->setImgName($this->oldImg);
            }
            else {
                $this->uploadFile($entity);
                $this->removeOldFile($entity, $this->oldImg);
            }
        }
    }

    public function postRemove(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity instanceof Image) {
            $imgName = $entity->getImgName();
            $this->removeOldFile($entity, $imgName);
        }
    }

    private function uploadFile($entity)
    {
        if ($entity instanceof Image) {
            $image = $entity->getImgName();
            if (!$image instanceof UploadedFile) {
                return;
            }
            $imageName = $this->uploader->fileSave($image, "image");
            $entity->setOriginalImgName($image->getClientOriginalName());
            $entity->setImgName($imageName);
        }
    }

    private function removeOldFile($entity, $fileName)
    {
        if ($entity instanceof Image && $fileName) {
            $this->uploader->fileRemove($fileName, "image");
        }
    }
}

Upvotes: 0

Mikhail Prosalov
Mikhail Prosalov

Reputation: 4363

The postLoad event occurs every time you load an entity from the database. In your case the best approach is to create a custom event and dispatch it from the editAction.

Upvotes: 1

Related Questions