Updated: Comment #8

Problem/Motivation

Is there a hasData() or isEmpty() method available in entity_metadata_wrapper()? I haven't seen one. I'd like to avoid messages similar to the error mentioned in #1928884: Provide more info when EntityMetadataWrapperException is invoked when a field happens to be empty. Right now I have to mix field access [if (field_get_items($entity_type, $entity, $field_name) ...] in with my metadata access just to avoid that error.

Proposed resolution

Create a new public method called hasProperty to be able to do something like:

if (!$wrapper->hasProperty('field_name')) {...}

Create a new public method called isEmpty to be able to do something like:

if (!$wrapper->field_name->isEmpty()) {...}

Remaining tasks

  • create the hasProperty public method.
  • create the isEmpty public method.

API changes

Before this issue

<?php
$infos
= $wrapper->getPropertyInfo();
if (!empty(
$infos['field_my_field']) || !empty($infos['field_my_other_field'])) {
 
$my_field = $wrapper->field_my_field->value();
 
$my_other_field = $wrapper->field_my_other_field->value();
  if (!empty(
$my_field)) {
   
// Do sth.
 
}
  elseif (!empty(
$my_other_field)) {
   
// Do sth else.
 
}
}
?>

After this issue

<?php
if ($wrapper->hasProperty('field_my_field') && !$wrapper->field_my_field->isEmpty()) {
 
// Do sth.
}
elseif (
$wrapper->hasProperty('field_my_other_field') && !$wrapper->field_my_other_field->isEmpty()) {
 
// Do sth else.
}
?>
Files: 
CommentFileSizeAuthor
#17 interdiff.txt758 bytesDuaelFr
#17 entity-add_helpers_to_deal_with_empty_or_uncertain_properties-2066373-17.patch1.36 KBDuaelFr
PASSED: [[SimpleTest]]: [MySQL] 630 pass(es).
[ View ]
#8 entity-add_isEmpty_method_expose_dataAvailable-2066373-8.patch1.34 KBDuaelFr
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]
#7 entity-add_isEmpty_method_expose_dataAvailable-2066373-7.patch1.23 KBDuaelFr
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]
#4 entity-add_isEmpty_method_expose_dataAvailable-2066373-4.patch665 bytesDuaelFr
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]
#4 interdiff.txt497 bytesDuaelFr
#2 entity-add_isEmpty_method_expose_dataAvailable-2066373-2.patch665 bytesDuaelFr
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]

Comments

NancyDru’s picture

There is a dataAvailable() method, but it is protected so we can't use it.

DuaelFr’s picture

Title:Add an isEmpty() method to improve DX» hasData() or isEmpty() method?
Category:feature» support
StatusFileSize
new665 bytes
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]

Here is a patch adding a new isEmpty public method.
I will update the issue summary to help the maintainer to review this.

This patch is part of the #1day1patch initiative.

DuaelFr’s picture

Title:hasData() or isEmpty() method?» Add an isEmpty() method to improve DX
Category:support» feature
Status:Active» Needs review
DuaelFr’s picture

Title:hasData() or isEmpty() method?» Add an isEmpty() method to improve DX
Category:support» feature
StatusFileSize
new497 bytes
new665 bytes
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]

I fixed a tiny mistake in the comment.

NancyDru’s picture

Awesome! Thanks, Edouard. It works great for me.

DuaelFr’s picture

Status:Needs review» Needs work

I have some issues with this new method. It's name suggests that it returns FALSE if the value exists and is not empty while it returns TRUE if the value does not exist or is empty (instead of throwing an exception). In fact, I never seen it returning TRUE and it continues to throw exceptions when used on a non-existing property or field...

I tried to replace it by the following code but it only fix the first behavior and still not allow to easily check if a field/property exists.

<?php
 
public function isEmpty() {
    try {
     
$value = $this->value();
    }
    catch (
EntityMetadataWrapperException $e) {
     
$value = FALSE;
    }
    return empty(
$value);
  }
?>

May we create another method allowing to do something like this ?

<?php
$wrapper
->doesExist('my_suspicious_field');
?>

Or may we change the isEmpty method to have something more like this ?

<?php
$wrapper
->isEmpty('my_suspicious_field');
?>
DuaelFr’s picture

Title:Add an isEmpty() method to improve DX» Add an isEmpty() and hasChild() methods to improve DX
Status:Needs work» Needs review
StatusFileSize
new1.23 KB
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]

This patch introduces an EntityStructureWrapper::hasChild() method that checks if the given child exists without throwing an exception.

It allows to do things like this :

<?php
if ($wrapper->hasChild('field_my_field') && $wrapper->field_my_field->isEmpty()) {
 
// Do something.
}
?>
DuaelFr’s picture

StatusFileSize
new1.34 KB
PASSED: [[SimpleTest]]: [MySQL] 409 pass(es).
[ View ]

Sorry, I forgot to include the EntityMetadataWrapper::isEmpty() as exposed in #6

Here is a new patch containing the isEmpty() from #6 and the hadChild() from #7

DuaelFr’s picture

Issue summary:View changes

Issue summary update.

NancyDru’s picture

Thanks, Edouard.

As long as we are at it, I ran into one this morning: it would be nice to do $wrapper->id(). In my case I am accessing a node, but I have others where I access a user or a profile. It would be nice to get the entity's id field without having to know what kind of entity it is ($wrapper->nid->value() vs. $wrapper->uid->value()

DuaelFr’s picture

I think you should use the existing getIdentifier() public method.

DuaelFr’s picture

Issue summary:View changes

Updated issue summary.

joachim’s picture

if (!$wrapper->hasChild('field_name')) {...}

I'm not sure hasChild() is the right name for that method. Elsewhere, these are called properties, aren't they? And if, say, I have an entityreference field on users, I get a chain of properties $node_wrapper->author->entityref_to_node... child doesn't seem right when these can double back on themselves and be circular...

DuaelFr’s picture

Hi joachim, thank you for your review.
I am sorry but I don't get the point, probably because of the language barrier.

The purpose of this hasChild() method is to safely check if there is a field or a property named like this on the entity before querying it to avoid having to deal with Exceptions. We could name it hasComponent() if it suits better to the concept.

If you think it could lead to an infinite loop in some cases I may have coded it wrong. I don't remember why I didn't use the getPropertyInfo() method instead of get() but if you think it could be better and safer I can rewrite my patch.

joachim’s picture

My point was entirely about the method name. hasProperty() would be my suggestion.

And I don't mean there's an infinite loop in the code, not at all!

I meant that with the properties that are references to other entities, you can loop round. Eg:

- node has an 'author' property to the user entity
- you can put an entityref field on users that points to nodes, and this will define a property

So if the field on the user points to a node that the user is the author of, you can go $user_wrapper->node_field->author->value() and you're back where you started. Hence 'child' doesn't seem to really fit.

garphy’s picture

hasProperty() seems like a better fit.
it's close to hasOwnProperty() in ECMAScript-ish dynamic languages.

DuaelFr’s picture

Isn't it confusing to use "property" in the name of a method that can check the existence of properties and fields?

@joachim: sorry for the misunderstanding about the circular relations.

joachim’s picture

To Entity API metadata wrappers, everything is a property: $node->title becomes the title property, and a node FieldAPI field field_foo becomes the field_foo property.

DuaelFr’s picture

Title:Add an isEmpty() and hasChild() methods to improve DX» Add an isEmpty() and hasProperty() methods to improve DX
Issue summary:View changes
StatusFileSize
new1.36 KB
PASSED: [[SimpleTest]]: [MySQL] 630 pass(es).
[ View ]
new758 bytes

Here is a new patch.

DuaelFr’s picture

Issue summary:View changes