Problem: EntityNG always returns FALSE if you check a field/property with isset() which has been deliberately set to an empty array before.
Use case: REST module has a PATCH operation to allow partial updates. It receives data that has set some fields/properties to be empty, indicating that the field should be deleted. Currently it is not possible to determine which property has been set to empty after an entity has been deserialized. See #1826688: REST module: PATCH/update.
Test case:
$entity = entity_create('entity_test', array('name' => 'klausi', 'user_id' => 1));
$isset = isset($entity->field_test_text);
dpm(intval($isset)); // FALSE as expected
$entity->field_test_text->value = 'foo';
$isset = isset($entity->field_test_text);
dpm(intval($isset)); // TRUE as expected
$entity->field_test_text = array();
$isset = isset($entity->field_test_text);
dpm(intval($isset)); // FALSE? WTF?
Solution: make the magic __isset() method work like the usual PHP isset().
Comments
Comment #1
klausiHere is the first patch.
I'm using a boolean flag to indicate whether a Field has been set or not. IMO that is the only clean way to determine if the field has been set or not.
I also added the methods unsetValue() and valueIsSet(), not sure in which interface they should end up. I'm also open for better naming suggestion, since we cannot use isSet() (reserved PHP function name).
Comment #2
fagoLooks like this got already committed as part of #1826688: REST module: PATCH/update - so we need to address any issues as follow-up.
Why do we need this flag? I think we should follow PHP and say isset if $value !== NULL. Let's avoid re-inventing things. Also, every additional object property raises memory usage!
Similarly, do we need separate set/get methods? Imho it should suffice to set NULL to unset it, while setting it to array() what make it empty but being set. -> That follows existing PHP semantics and thus should be what developers expect.
ditto.
We need a test which tests this unsetting vs setting it empty.
Comment #3
klausiSo this was accidentally committed with #1826688: REST module: PATCH/update. Lets develop a followup here if you disagree with the approach.
Otherwise I'm going to close this issue in the next weeks.
Comment #4
klausiCross post with fago. I'm going to look into this.
I think I remembered the semantics of isset() not correctly, because if you set a variable to NULL isset() will indeed return FALSE. Sorry for that.
Comment #5
klausiHopefully addressed all remarks from #2, please review.
Comment #7
fagohm, looks like the committed variant conflicts with #1869250: Various EntityNG and TypedData API improvements :/
So, we need to get it fixed to move with #1869250: Various EntityNG and TypedData API improvements. I'm working on fixing it on top of that issue right now to get tests green again. So maybe we should just incorporate it over there?
Comment #8
fagoLet's fix this with #1869250: Various EntityNG and TypedData API improvements, please review the patch over there.
Comment #9
klausiOk, so I'm calling this issue fixed since the required functionality got in and the improvements are developed in #1869250: Various EntityNG and TypedData API improvements.
Comment #10
fagoRe-opening and postponing on #1869250: Various EntityNG and TypedData API improvements for anything left (see http://drupal.org/node/1869250#comment-6891540)
Comment #11
fagounpostponing
Comment #12
klausiSo let's see if the remaining test case is already covered. Go testbot!
Comment #13
fagoWe already have
but still this is a good addition and verifies isset() behaves correctly - so yep let's add this.
Comment #14
catchCommitted/pushed to 8x., thanks!