12

I've been looking into using the Entity Metadata Wrapper classes (defined by the entity module in Drupal 7) to access field values, as this seems to be a clean way of doing so.

There a couple of things that make this a bit awkward however. Assume I have a wrapper for a content type that defines a field named field_something as such:

$wrapper = entity_metadata_wrapper('node', node_load($nid));
$value = $wrapper->field_something->value();

The first problem I have is that I have no way of knowing before hand whether what I get is an actual value (a string, an entity, etc.), another metadata structure wrapper (when fields have multiple values) or an array (when fields have multiple properties).

I have found a way to answer those questions using the info() method:

$info = $wrapper->field_something->info();
$is_multi_value = (strpos($info['type'], 'list<') === 0);
$has_multiple_properties = isset($info['property info']]);

However that is hardly practical. Whenever I want to use a field without knowing it's definition before hand, I must take into account several cases. This makes my code quite heavy.

In order to deal with this I have written some code which:

  1. Ensures we always get returned an array, even if it's a single value field ;
  2. When there are multiple properties, return the value of the first column.

Point 1. here will always work, unless the caller want to know whether this was a single value field or not. Point 2 works in some cases, not all, but is convenient when it applies.

Here is the code:

function entity_metadata_simple_values($field) {
  $fields = array();
  $values = array();
  $info = $field->info();
  if (strpos($info['type'], 'list<') === 0) {
    foreach ($field->getIterator() as $field_iteration) {
      $fields[] = $field_iteration;
    }
  } else {
    $fields[] = $field;
  }
  foreach ($fields as $final_field) {
    $ff_info = $final_field->info();
    if (isset($ff_info['property info'])) {
      $column = reset(array_keys($ff_info['property info']));
      $values[] = $final_field->{$column}->value();
    } else {
      $values[] = $final_field->value();
    }
  }

  return $values;
}

So my question is: are there simpler/better ways to address this problem of getting values from the metadata wrapper when the field type is not known ?

4

Here are a few suggestions to make this process a little easier.

$wrapper->field_something->type();

will return the type of the field, ie node, taxonomy_term, integer, text etc. You could then handle the value returned from $wrapper->field_something->value() correctly.

Also

$wrapper->field_something->raw()

will return the raw value of the field. Which will either be an array in the case of multi valued fields of just the value. For instance an entity_reference will be the nid (or entity id) of the referenced entity, or an array of referenced entity id's.

  • Ooops, I entered that too quickly ! I wanted to add: $wrapper->field_something->type() returns the same information as the 'type' element of the array returned by $wrapper->field_something->info(). Crucially, it still returns a string "list<type>" for multi-valued types, so I still need a strpos (or equivalent) to work out it's multivalued (if I want to work it out before fetching it). – Alice Heaton Feb 27 '13 at 14:57
  • As for the second point: I can indeed work out if it's multi valued by testing the return of ->raw() or of ->value(), however I'd rather know before fetching the value, as if it's multi valued then I want to run it through a foreach loop with ->getIterator() rather than manually go through the array which requires me to re-create a wrapper for each item. – Alice Heaton Feb 27 '13 at 15:01
3

So as no one has come up with another solution, I will answer my own question:

There isn't a simpler way to access values of unknown field types when using entity metadata wrappers.

There are alternative methods to the one I initially described (for instance those pointed out by @thepearson). In particular this method is useful:

 entity_property_list_extract_type($type)

It will return the listed type if your type is a list (eg. 'integer' if your type is 'list<integer>'), or false if your type is not a list. Internally it does a strpos just like the code I initially posted, but I guess it's more future proof.

The conclusion is that:

  • Entity metadata wrappers work well if you have no idea of your field types, and want to carefully address each possible case ;

  • Entity metadata wrappers work well if you know exactly what types your fields are, and you want to use them ;

  • If you have only some ideas of what your field types are like (for instance all text, but you don't know if they are formatted or not, and you don't know if they are single or multi valued) then Entity metadata wrappers do not provide any short-cuts and you need to write your own as I did in the initial question.

1

For the single/multiple field check I've found it useful to test the wrapper object's type, which will be EntityListWrapper for a multi-value field and EntityValueWrapper for a single-value field:

<?php
...
$wrapper = entity_metadata_wrapper('user', $account);
// Get address, or first address if a multi-value field instance.
if (get_class($wrapper->field_address) == 'EntityListWrapper') {
  $value = $wrapper->field_address[0]->value();
}
else {
  $value = $wrapper->field_address->value();
}
  • Or even if($wrapper->field_name instanceof EntityListWrapper) {...} – rudolfbyker Apr 30 at 9:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.