使用entity_metadata_wrapper时访问未知字段类型的值


12

我一直在研究使用实体元数据包装程序类(由Drupal 7中的实体模块定义)来访问字段值,因为这样做似乎是一种干净的方法。

但是,有几件事情使这有些尴尬。假设我有一个内容类型的包装器,该包装器定义了一个field_something这样命名的字段:

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

我遇到的第一个问题是我无法事先知道我得到的是实际值(字符串,实体等),另一个元数据结构包装器(当字段具有多个值时)还是数组(当字段具有多个属性)。

我找到了一种使用该info()方法回答这些问题的方法:

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

但是,这几乎不可行。每当我想使用字段而不事先知道其定义时,都必须考虑几种情况。这使我的代码很繁重。

为了解决这个问题,我写了一些代码:

  1. 确保我们总是返回一个数组,即使它是单个值字段也是如此;
  2. 当有多个属性时,返回第一列的值。

要点1.这里始终有效,除非调用者想知道这是否是单个值字段。Point 2在某些情况下(并非全部)有效,但适用时很方便。

这是代码:

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;
}

所以我的问题是:当字段类型未知时,是否有更简单/更好的方法来解决从元数据包装中获取值的问题?

Answers:


4

这里有一些建议,可以使此过程更轻松一些。

$wrapper->field_something->type();

将返回现场,即类型nodetaxonomy_termintegertext等你可以再处理来自返回的值$wrapper->field_something->value()正确。

$wrapper->field_something->raw()

将返回该字段的原始值。这要么是array在刚刚值的多值字段的情况。例如,a entity_reference将是nid引用实体的(或实体ID),或者是array引用实体ID的。


糟糕,我输入得太快了!我想添加:$ wrapper-> field_something-> type()返回与$ wrapper-> field_something-> info()返回的数组的'type'元素相同的信息。至关重要的是,它仍然为多值类型返回一个字符串“ list <type>”,因此我仍然需要一个strpos(或等效值)来计算它的多值(如果我想在获取它之前对其进行计算)。
爱丽丝·希顿2013年

关于第二点:我确实可以通过测试-> raw()或-> value()的返回值来确定它是否是多值的,但是我更希望在获取值之前知道它是否是多值的,然后我想通过-> getIterator()通过foreach循环运行它,而不是手动遍历数组,这需要我为每个项目重新创建包装器。
爱丽丝·希顿

3

因此,由于没有人想出另一种解决方案,因此我将回答我自己的问题:

没有使用实体元数据包时,未知的字段类型的访问值的简单的方法。

除了我最初描述的方法以外,还有其他方法(例如,@ thepearson指出的方法)。该方法特别有用:

 entity_property_list_extract_type($type)

如果您的类型是列表,它将返回列出的类型(例如,如果您的类型是'list <integer>',则为'integer');如果您的类型不是列表,则返回false。在内部,它像我最初发布的代码一样执行strpos,但我想它是将来的证明。

结论是:

  • 如果您对字段类型一无所知,并且想仔细解决每种可能的情况,则实体元数据包装器会很好地工作。

  • 如果您确切知道字段是什么类型并且想要使用它们,则实体元数据包装器可以很好地工作。

  • 如果您仅对字段类型的内容有一些想法(例如,所有文本,但是您不知道它们是否设置格式,也不知道它们是单值还是多值),那么实体元数据包装器不提供任何捷径,您需要像在最初的问题中一样编写自己的捷径。


1

对于单/多字段检查,我发现测试包装对象的类型很有用,该对象将EntityListWrapper用于多值字段和EntityValueWrapper单值字段:

<?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();
}

甚至if($wrapper->field_name instanceof EntityListWrapper) {...}
rudolfbyker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.