14

I have a Symfony2 form with a variety of fields, including one optional text field called recap.

This recap field saves perfectly when there's some text in it, but when the field is left blank, I get this error:

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

That's right - the column recap can't be null. I set it that way on purpose. Null means unknown. When the user leaves recap blank, the value of recap is not unknown; it's blank.

My question is how to get Symfony to save recap as '' when it's blank, not null.

Jason Swett
  • 43,526
  • 67
  • 220
  • 351
  • Isn't this more of a problem on Doctrine's end? In that case, you could set the default value of the class' property to an empty string our use a custom `DBAL\Types`, which casts a null value to an emppty string. – dbrumann Mar 29 '12 at 15:41
  • I think you're right about it being on Doctrine's end. Setting the default value to an empty value didn't work for me, although I have seen claims in multiple places that that should work, which confuses me. – Jason Swett Mar 29 '12 at 16:02

7 Answers7

15

Go to your Entity and go to the declaration of the variables.

/**
 * @var string $name
 *
 * @ORM\Column(type="string", length=50)
 */
public $recap = '';

you can assign a default value for $recap.

Or otherway when you have the function setRecap you can check if empty or not set and set the value you expect.

public function setRecap($recap) {
   $this->recap = !isset($recap) ? '': $recap;
}

Or you set the default Value in your form Type to '' but i think then its not what you expect.

René Höhle
  • 26,716
  • 22
  • 73
  • 82
  • Interesting. Neither of your suggestions worked by alone but when used together they did the trick. Thanks! – Jason Swett Mar 29 '12 at 15:54
  • 2
    @ThomasDecaux: Then you should work with doctrine ;) thats wrong... Doctrine overwrite and build only functions that don't exist. – René Höhle Aug 12 '12 at 12:16
  • Cool, but still, its always a bad habit to mix your code with auto generated one, and this question is related to Form component so the solution must be in the same scope – Thomas Decaux Aug 12 '12 at 19:24
  • 6
    @ThomasDecaux: no, you _absolutely_ can modify the "generated" code (which doesn't necessarily even need to be generated). http://symfony.com/doc/current/book/doctrine.html#generating-getters-and-setters "This command makes sure that all of the getters and setters are generated for the Product class. This is a safe command - you can run it over and over again: it only generates getters and setters that don't exist (i.e. it doesn't replace your existing methods)." You shouldn't treat the Entities like some Doctrine magic, they are just regular PHP classes. – Matt Oct 01 '13 at 06:06
  • This is a pretty nasty hack. IF Sf2 or Doctrine fix the broken handling of empty strings, you could have unexpected results. – Acyra Sep 29 '14 at 11:19
11

True, lost many hours on it ;-( the "transformation" is hardcoded in component Form.php line 1113 !

private function viewToNorm($value)
{
    $transformers = $this->config->getViewTransformers();

    if (!$transformers) {
        return '' === $value ? null : $value;
    }

    for ($i = count($transformers) - 1; $i >= 0; --$i) {
        $value = $transformers[$i]->reverseTransform($value);
    }

    return $value;
}

In my opinion, its a big error (because is the role of DataTransformer, not Form). So the solution is to create your own DataTransformer and associate it to the text type. Currently I am losing so much time with Symfony2, always seeking in the sources these kind of little hack ;-(

Thomas Decaux
  • 21,738
  • 2
  • 113
  • 124
  • 3
    I was getting close to logging a bug about this because it seems utterly stupid. If you read their docs really closely it basically says if a text field is marked as required, an empty string will end up as an empty string but, if the field is optional, an empty string will be converted to `null`. See [empty_data](http://symfony.com/doc/current/reference/forms/types/text.html#empty-data) and [required](http://symfony.com/doc/current/reference/forms/types/text.html#required). – jxmallett Dec 11 '15 at 07:00
  • @thomas-decaux I have the same pain with Symfony2 - are you still working with it or have you found a better solution? – PeterB May 12 '16 at 09:33
  • @jxmallett Did you ever log a bug? It'd make a great DX (Developer eXperience) ticket for Symfony – PeterB May 12 '16 at 09:33
7

I have another solution for this issue:

create dummy class

class EmptyString {
    public function __toString() {
        return '';
    }
}

and set

$builder->add('recap', 'text', [
    'empty_data' => new EmptyString(),
]);

When entity will be stored to DB, it will automatically converted to empty string.

oradwell
  • 392
  • 1
  • 12
Li0N
  • 71
  • 1
  • 2
  • This was the solution for me too. I found that empty text boxes were treated as null values, and then forced directly into a sql statement, bypassing the Entity setter, so you can't catch null values there. – Mark B May 03 '16 at 07:44
  • 1
    Why not doing just 'empty_data'=>'' ? – the_nuts Jun 16 '16 at 12:02
  • @the_nuts Because that's transformed to null, at least with symfony 2.4 – glerendegui Sep 08 '16 at 16:27
5

I think you're taking the problem the wrong way: when the user leaves recap blank the value is unknown because not provided . For example you don't say that an empty birthdate field means that birthdate is equaled to '' but that birthdate is unknown. Same goes for addresss, etc...

So if your user isn't required to fill this field then it seems that the most relevant response is in fact to set your field as being nullable

  • I don't agree on this. A "complementary information" text field can either be empty (there is no complementary information) or null (unknown or irrelevant) – theredled Apr 09 '18 at 21:24
2

Just came across similar error in Symfony2:

My entity:

/**
 * @ORM\Column(type="boolean")
 */
protected $Valid;

My form:

$builder->add('Valid', 'hidden');

Now for true values, field is rendered correctly with value="1", but for false values field is rendered with value="", which leads to:

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

While I would expect it to be rendered as value="0".

Of course setValid() method can be enhanced to set the right value:

public function setValid($valid)
{
    $this->Valid = ($valid ? true : false);
}

Which work arounds the issue, not fixes it.

Marek
  • 181
  • 1
  • 5
2

In Forms, you can do:

$builder
->add('optionalField', TextType::class, ['required'=>false, 'empty_data'=>''])
the_nuts
  • 5,634
  • 1
  • 36
  • 68
-1

I also came across this problem. And an elegant solution was suggested to me was: to make this definition @ORM\Column(type="string", length=50, nullable=true)

Shimon S
  • 4,048
  • 2
  • 29
  • 34
  • Never use nullable value in a DB ! Its very bad for performance, prefer "" or 0. – Thomas Decaux Aug 12 '12 at 11:52
  • @ThomasDecaux have you got any references for that? Is that for a particular RDBMS? – ncatnow Jul 25 '13 at 03:49
  • 1
    there's a good discussion on performance issues with NULL values (for SQL-alikes) here: [link](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) – Ben Aug 01 '13 at 03:53