We several times encountered an issue with the entity_metadata_wrapper when we try to access a value. For example, this is the following code throwing the exception this time :
// Load the author (user entity) of the node.
$wrapper_author = entity_metadata_wrapper('user', $node->uid);
// Get the value of an additional field (noderef) on the user.
$expert_profile = $wrapper_author->field_expert_profile_link->value();
// Load the related node (node entity) related to the author.
$wrapper_expert_profile = entity_metadata_wrapper('node', $expert_profile);
// Load the title of the related node.
$title = $wrapper_expert_profile->title->value();
This last line throws an exception visible in logs "EntityMetadataWrapperException: Missing data values. in EntityMetadataWrapper->value() (line 83 of /var/www/workspace/Capgemini.com/docroot/sites/all/modules/contrib/entity/includes/entity.wrapper.inc)." and a white page is displayed.
We face the same exception when we try to index the node in apachesolr :
> drush core-cron
WD cron: EntityMetadataWrapperException: Missing data values. in EntityMetadataWrapper->value() (line 83 of [error]
/var/www/workspace/Capgemini.com/docroot/sites/all/modules/contrib/entity/includes/entity.wrapper.inc).
From my understanding, the exception occured because the noderef (field field_expert_profile_link) references a nid which doesn't exist anymore. The first solution (the one which doesn't require a patch in any contributed module) could be a test after the entity_metadata_wrapper function to test the result, but it would involve a lot of code (only 2 or 3 lines but repeated each time the entity_metadata_wrapper function is used). The second solution could be a patch of the nodereference module. I understand noderefence should clean the value of the noderef when the referenced node is deleted (as it's addressed by this issue https://drupal.org/node/1346696). The last solution could be a patch of the entity module. We are not sure throwing an exception without catching it is also the best approach as it causes issues visible in the front office.
For this reason, we choose to create a patch for the entity.wrapper.inc to make the exception catched and not only thrown. Basically, I updated the EntityValueWrapper and EntityListWrapper value() implementations by adding a try/catch. I also implemented a value() method for the EntityStructureWrapper. If the exception is thrown by the EntityMetadataWrapper value() method, I only catch it and return NULL.
Feel free to comment the analys and the patch if you think it's not the best approach or if the patch should be improved.
Comment | File | Size | Author |
---|---|---|---|
#6 | entity_catch_exception-2122009-6.patch | 3.65 KB | hargobind |
#1 | entity_catch_exception-2122009-1.patch | 3.64 KB | vbouchet |
Comments
Comment #1
vbouchetComment #2
hockey2112 CreditAttribution: hockey2112 commentedYou are my hero. After much pulling-out of my hair, your solution fixed my issue. Thank you!
Comment #3
vbouchetComment #5
vbouchetThis patch need to be updated for the last version.
Comment #6
hargobindPatch rerolled against the latest version.
Comment #10
hargobindI rewrote this patch because I needed to address a WSOD on my site as well, but now that I look more into the code, I don't think it's the best approach. Sure it prevents critical failures, but it doesn't actually address the primary problem that the referenced entity is missing. As you said yourself, "noderefence should clean the value of the noderef when the referenced node is deleted (as it's addressed by this issue #1346696: On deletion of node/user, references to it are not removed)".
A couple of points:
watchdog()
to log that there is a missing noderef which will give site admins a way to clean up their content.