cakephp: An empty string should be NULL
I faced this issue multiple times already. You can work around this issue but I think it should be a part of the ORM.
Table:
CREATE TABLE categories
(
id INTEGER PRIMARY KEY NOT NULL,
name VARCHAR(128) NOT NULL,
meta_title VARCHAR(255)
);
ORM usage:
$entity = $this->Categories->newEntity($this->request->data);
$this->Categories->save($entity);
Current result:
| id | name | meta_title |
|---|---|---|
| 1 | Test |
Should be:
| id | name | meta_title |
|---|---|---|
| 1 | Test | NULL |
As I mentioned above you can work around this behavior with Behaviors/Callbacks but I think this should be something which is handled directly inside the ORM. Saving an empty string inside a NULLable field isn’t the proper usage of NULL.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 9
- Comments: 28 (25 by maintainers)
Commits related to this issue
- Marshal empty string to null for BoolType. Refs #9678 — committed to cakephp/cakephp by ADmad 5 years ago
If someone is interested in a work-around would be:
This is especially important with foreign keys (which are supposed to be nullable if optional), but also with string fields and alike. If an empty string is posted one would want to have null here saved in most cases. Otherwise you risk data inconsistency and false results on find().
You either make it not nullable and can use != ‘’ for checking (which I did in 2.x always), or you use null and IS/ISNOT null check. But having to allow both means you will end up with both in your app (from different ways of input) - and as a consequence you have always conditions like
where field != '' AND field IS NOT NULLetc. if you ever forget to add both you miss out some records on finding, which introduces bugs. I have seen so much of that error prone code everywhere in apps…👍 For a more core internal solution in the long run, but I am fine with any behavior opt-in for 3.3/3.4.
Ran into this. Agree that if DB schema has ‘allow null’ on a field and that entity sets that field is an empty string, it should be set to null in the DB, not and empty string.
My issue use case:
I have a form where the ‘email’ is optional, but if it’s provided then it must be unique (enforced via the isUnique buildRules).
When folks leave that field blank, is should be ‘NULL’ in the DB, but right now it gets inserted as an empty string. So when a user tries to add a new record with no email provided they are unable, as they get error with ‘record already exists’ for the email field…
OK, so I released the Nullable behavior in Shim 1.4.0 as proof of concept and along with some tests that show the usually expected behavior. With the 3.3.7 core release those tests will then all pass I assume. People interested in getting their DB clean can already use that right away.
We should probably now find a way to get those fixes into the core somehow.
@ionas Yes it is and the behavior shouldn’t be changed as @markstory already mentioned.
What about nullable
INTandBOOLEANfields? How would0and''be handled there?Found my own answer: char(36) casts “” to NULL, varchar(36) leaves “” as “”.
I agree, for
BoolTypeempty string should be marshalled tonullnotfalse. We can change this in 4.0.But for
StringTypeauto converting empty string to null is not something that core should do. Those who need this behavior can easily handle it at app level with a behavior.I also found a fixture issue here due to some testing with nullable columns: https://github.com/cakephp/cakephp/issues/9686
Thanks @steefaan Based on your input I made a test case here for all kind of types: https://github.com/dereuromark/cakephp-shim/commit/e8794cf2340502129dace06d96593c23136f3bf2#diff-e4ba1b1125865b7f834ad66a4059c6f0R35 Looks like this behavior approach indeed fixes the issue for both bool and string type.
I even tried to add back the empty string as possible nullish value - when explicitly set as default value in the schema: https://github.com/dereuromark/cakephp-shim/pull/9 But maybe this is too much? I wonder why is not really working out? The schema default is still
nullhere for some reason.@josegonzalez You are missing the whole point. allowEmpty false would only create the mess and inconsistency we just talked about the last 10+ comments 😃
It should be, but I wanted to make sure you didn’t want to change that behavior as well.
Isn’t a nullable int with empty
''coming in already stored as null? Same for bool with incoming''? That would be the “intuitive” expectation. Because in that case someone put the form field to “empty=>true” which means optional, which means nullable.0and1for bool should be treated as always, same for0for int.