Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2: do not update a form field if not provided

I have a form for my "Team" entity. This entity has an "image" field. This field is required on creation process, but not required on edit process. But right now, during edit process, if I don't provide any image in the file input, the empty input is still persisted, and so my database field is emptied during the process. How can I do to avoid persistence of this field, if nothing is provided in the form file input? So the entity keeps its old value for this field. Of course, if a file is provided, I want him to erase the old one.

My controller looks like this:

if ($request->getMethod() == 'POST') {

    $form->bind($request);

    if ($form->isValid()) {

        $em->persist($team);
        $em->flush();
        ...
    }
}

and part of my entity, dealing with image (I'm pretty sure I have to do something in here, but don't know what exactly):

/**
 * @ORM\PrePersist()
 * @ORM\PreUpdate()
 */
public function uploadImage() {
    // the file property can be empty if the field is not required
    if (null === $this->image) {
        return;
    }
    if(!$this->id){
        $this->image->move($this->getTmpUploadRootDir(), $this->image->getClientOriginalName());
    }else{
        $this->image->move($this->getUploadRootDir(), $this->image->getClientOriginalName());
    }
    $this->setImage($this->image->getClientOriginalName());
}

EDIT

Ok, I did some changes to this answer's code code, because apparently the event listener asks for a FormEvent instance in his callback, not a FormInterface instance.

$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
// Retrieve submitted data
$form = $event->getForm();
$item = $event->getData();

// Test if upload image is null (maybe adapt it to work with your code)
if (null !== $form->get('image')->getData()) {
    var_dump($form->get('image')->getData());
    die('image provided');
    $item->setImage($form->get('image')->getData());
}

});

When I provide an image, the script goes into the test, and die(), as expected. When I do not provide any file, the script doesn't go into the test if(), but my field in the database is still erased with an empty value. Any idea?

And as asked below, here is the Form

// src/Van/TeamsBundle/Form/TeamEditType.php

namespace Van\TeamsBundle\Form;

use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class TeamEditType extends TeamType // Ici, on hérite de ArticleType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // On fait appel à la méthode buildForm du parent, qui va ajouter tous les champs à $builder
        parent::buildForm($builder, $options);
        // On supprime celui qu'on ne veut pas dans le formulaire de modification
        $builder->remove('image')
        ->add('image', 'file', array(
            'data_class' => null,
            'required' => false
        ))
        ;


        $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
            // Retrieve submitted data
            $form = $event->getForm();
            $item = $event->getData();

            // Test if upload image is null (maybe adapt it to work with your code)
            if (null !== $form->get('image')->getData()) {
                var_dump($form->get('image')->getData());
                die('image provided');
                $item->setImage($form->get('image')->getData());
            }
        });


    }

    // On modifie cette méthode car les deux formulaires doivent avoir un nom différent
    public function getName()
    {
        return 'van_teamsbundle_teamedittype';
    }
}

and the whole Team entity:

<?php

namespace Van\TeamsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Team
 *
 * @ORM\Table()
 * @ORM\HasLifecycleCallbacks
 * @ORM\Entity
 * @ORM\Entity(repositoryClass="Van\TeamsBundle\Entity\TeamRepository") @ORM\Table(name="van_teams")
 */
class Team
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=100)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="countryCode", type="string", length=2)
     */
    private $countryCode;

    /**
     * @ORM\ManyToOne(targetEntity="Van\TeamsBundle\Entity\Game")
     * @ORM\JoinColumn(nullable=false)
     */
    private $game;

    /**
     * @ORM\ManyToOne(targetEntity="Van\TeamsBundle\Entity\Statut")
     * @ORM\JoinColumn(nullable=false)
     */
    private $statut;

    /**
     * @var string $image
     * @Assert\File( maxSize = "1024k", mimeTypesMessage = "Please upload a valid Image")
     * @ORM\Column(name="image", type="string", length=255)
     */
    private $image;



    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Team
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set countryCode
     *
     * @param string $countryCode
     * @return Team
     */
    public function setCountryCode($countryCode)
    {
        $this->countryCode = $countryCode;

        return $this;
    }

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

    /**
     * Set image
     *
     * @param string $image
     * @return Team
     */
    public function setImage($image)
    {
        $this->image = $image;

        return $this;
    }

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

    /**
     * Set game
     *
     * @param \Van\TeamsBundle\Entity\Game $game
     * @return Team
     */
    public function setGame(\Van\TeamsBundle\Entity\Game $game)
    {
        $this->game = $game;

        return $this;
    }

    /**
     * Get game
     *
     * @return \Van\TeamsBundle\Entity\Game 
     */
    public function getGame()
    {
        return $this->game;
    }

    /**
     * Set statut
     *
     * @param \Van\TeamsBundle\Entity\Statut $statut
     * @return Team
     */
    public function setStatut(\Van\TeamsBundle\Entity\Statut $statut)
    {
        $this->statut = $statut;

        return $this;
    }

    /**
     * Get statut
     *
     * @return \Van\TeamsBundle\Entity\Statut 
     */
    public function getStatut()
    {
        return $this->statut;
    }






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

    protected function getUploadRootDir() {
        // the absolute directory path where uploaded documents should be saved
        // return $this->getTmpUploadRootDir();
        return __DIR__ . '/../../../../web/uploads/';
    }

    protected function getTmpUploadRootDir() {
        // the absolute directory path where uploaded documents should be saved
        return __DIR__ . '/../../../../web/uploads_tmp/';
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function uploadImage() {
        // the file property can be empty if the field is not required
        if (null === $this->image) {
            return;
        }
        if(!$this->id){
            $this->image->move($this->getTmpUploadRootDir(), $this->image->getClientOriginalName());
        }else{
            $this->image->move($this->getUploadRootDir(), $this->image->getClientOriginalName());
        }
        $this->setImage($this->image->getClientOriginalName());
    }

    /**
     * @ORM\PostPersist()
     */
    public function moveImage()
    {
        if (null === $this->image) {
            return;
        }
        if(!is_dir($this->getUploadRootDir())){
            mkdir($this->getUploadRootDir());
        }
        copy($this->getTmpUploadRootDir().$this->image, $this->getFullImagePath());
        unlink($this->getTmpUploadRootDir().$this->image);
    }

    /**
     * @ORM\PreRemove()
     */
    public function removeImage()
    {
        unlink($this->getFullImagePath());
        rmdir($this->getUploadRootDir());
    }
}

EDIT 2

I did that. When I provide an image, it is saved in the image field in the database and redirection to my index page occurs. When I don't provide any image, redirection doesn't occur, and the following message appears above my file input in my form: "The file could not be found." In my TeamEditType class, I did the following, so the image should not be required.

$builder->remove('image')
->add('image', 'file', array(
    'data_class' => null,
    'required' => false
))
;
like image 976
VaN Avatar asked Mar 21 '14 11:03

VaN


2 Answers

As of Symfony 2.3, you can simply use the PATCH http method, as documented here.

    $form = $this->createForm(FooType::class, $foo, array(
        'action' => $this->generateUrl('foo_update', array('id' => $foo->getId())),
        'method' => 'PATCH',
    ));

It's an easy way to make a partial update of an entity using your main form, without rendering all the fields.

like image 179
Roubi Avatar answered Sep 19 '22 05:09

Roubi


One approach in Symfony 2.4 (further information in Symfony2 coockbook) :

public function buildForm(FormBuilderInterface $builder, array $options)
{
 // $builder->add() ... 

 $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormInterface $form) {
        // Retrieve submitted data
        $form = $event->getForm();
        $image = $form->getData();

        // Test if upload image is null (maybe adapt it to work with your code)
        if (null !== $form->get('uploadImage')->getData()) {
            $image->setUploadImage($form->get('uploadImage')->getData());
        }
    });
}

Edit

It seems that you already test your prepersit data. Try the following :

   public function setImage($image)
   {
        if($image !== null) {
            $this->image = $image;

            return $this;
        } 
    }
like image 28
Debflav Avatar answered Sep 19 '22 05:09

Debflav