Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony Form Field Attribute empty_data Ignored

According to the Symfony 2.4 Documentation, any form field that is not required, but submitted without any value (default value for choice fields or empty value for text fields), will be saved to the entity with a NULL value. So if your entity field is defined as NOT NULL (e.g. not nullable=true), when you persist the entity you will get a nasty error:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'shell' cannot be null

So the documentation says that if you don't want it to use NULL as the default value, you can kindly specify the empty_data attribute on a text or choice field. However, this is not working for me.

Entity Field (not nullable):

/**
 * @ORM\Column(type="string")
 */
protected $shell = '';

Form Builder (not required):

->add('shell', 'choice', array(
    'label' => 'Shell',
    'choices' => array('shell' => 'Fancy Pants'),
    'required' => false,
    'empty_data' => ''
))

Am I misunderstanding this empty_data attribute? Am I missing some important setting elsewhere? What is the recommended way of doing this?

UPDATE

This Github ticket explains that this was an issue back in 2012, and it hasn't been fixed yet.

That means that everyone who is using the form builder, is forced to make any field that is not required into a nullable field? That seems pretty opinionated for the framework... there are lots of reasons we don't want to use NULL when a default '' or 0 doesn't have unique meaning and we don't need a NULL. For many queries, having to check for the presence of both field=0 OR field=NULL, is a pain.

Is there some better solution other people are using?

like image 619
Chadwick Meyer Avatar asked Jul 16 '14 23:07

Chadwick Meyer


4 Answers

  1. Do not use empty_data option.
  2. And use the placeholder attribute.
  3. Ex:
    array(
       'label' => 'textExample',
        'required' => false,
        'disabled' => false,
        'read_only' => true,
        'attr' => array('placeholder' => 'DefaultValue')
        )

like image 147
XOC Avatar answered Sep 21 '22 22:09

XOC


I do it the way suggested, but sets a default value in the Entity class. So insted of setting null the Entity is fixing that it sets 0 or something others.

public function __construct() { 
      $this->shell = 0;
}

Or, you can take care of it in the setter:

public function setShell($shell) {
      $this->shell = $shell;

      if ( !is_numeric($shell) ) {
             $this->shell = 0;
      }
      return $this;
}

Maybe not the best practice, but It works to not have nullable values.

like image 5
Anders Avatar answered Oct 11 '22 07:10

Anders


Another possible workaround is to create a simple DataTransfromer and attach it to the required field. Example:

<?php
namespace Interprac\Bundle\UtilityBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class NullToEmptyTransformer implements DataTransformerInterface
{
    /**
     * Does not transform anything
     *
     * @param  string|null $value
     * @return string
     */
    public function transform($value)
    {
        return $value;
    }

    /**
     * Transforms a null to an empty string.
     *
     * @param  string $value
     * @return string
     */
    public function reverseTransform($value)
    {
        if (is_null($value)) {
            return '';
        }

        return $value;
    }
}

Attach the transformer to a single field:

$nameSuffix = $builder->create('name_suffix', 'choice', array(
        'label'   => 'Name Suffix',
        'choices' => PR::getSMSFSuffixes(),
))->addModelTransformer(new NullToEmptyTransformer());

$builder->add($nameSuffix);
like image 4
b.b3rn4rd Avatar answered Oct 11 '22 06:10

b.b3rn4rd


You can since 2.6, use a combination of placeholder and empty data in your form class.

        $builderInterface->add('gender', 'choice', array(
            'required' => false,
            'choices' => array(
                'M'     => 'Male',
                'F'     => 'Female',
                'I'     => 'I dont want to specify'
            ),
            'placeholder' => 'Choose Gender',
            'empty_data'  => 'I'
        ));
like image 1
crafter Avatar answered Oct 11 '22 05:10

crafter