Acessando valores de tipos de campos desconhecidos ao usar entity_metadata_wrapper

12

Estou estudando o uso das classes Entity Metadata Wrapper (definidas pelo módulo de entidade no Drupal 7) para acessar valores de campo, pois essa parece ser uma maneira limpa de fazer isso.

No entanto, existem algumas coisas que tornam isso um pouco estranho. Suponha que eu tenho um wrapper para um tipo de conteúdo que define um campo nomeado field_somethingcomo tal:

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

O primeiro problema que tenho é que não tenho como saber de antemão se o que recebo é um valor real (uma string, uma entidade etc.), outro invólucro da estrutura de metadados (quando os campos têm vários valores) ou uma matriz (quando campos possuem várias propriedades).

Eu encontrei uma maneira de responder a essas perguntas usando o info()método:

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

No entanto, isso não é prático. Sempre que eu quiser usar um campo sem saber sua definição antes, devo levar em consideração vários casos. Isso torna meu código bastante pesado.

Para lidar com isso, escrevi um código que:

  1. Garante que sempre recebemos uma matriz de retorno, mesmo que seja um campo de valor único;
  2. Quando houver várias propriedades, retorne o valor da primeira coluna.

O ponto 1. aqui sempre funcionará, a menos que o chamador deseje saber se esse foi um campo de valor único ou não. O ponto 2 funciona em alguns casos, não em todos, mas é conveniente quando aplicável.

Aqui está o código:

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

Portanto, minha pergunta é: existem maneiras melhores / mais simples de resolver esse problema de obter valores do wrapper de metadados quando o tipo de campo não é conhecido?

Alice Heaton
fonte

Respostas:

4

Aqui estão algumas sugestões para facilitar esse processo.

$wrapper->field_something->type();

irá retornar o tipo do campo, ou seja node, taxonomy_term, integer, textetc. Você poderia, então, tratar o valor retornado a partir $wrapper->field_something->value()corretamente.

Além disso

$wrapper->field_something->raw()

retornará o valor bruto do campo. Qual será um arrayno caso de campos com vários valores apenas do valor. Por exemplo, um entity_referenceserá o nid(ou ID da entidade) da entidade referenciada ou um arraydos IDs da entidade referenciada.

thepearson
fonte
Opa, entrei muito rápido! Eu queria adicionar: $ wrapper-> field_something-> type () retorna as mesmas informações que o elemento 'type' da matriz retornada por $ wrapper-> field_something-> info (). Fundamentalmente, ele ainda retorna uma string "list <type>" para tipos com vários valores, portanto, ainda preciso de strpos (ou equivalente) para calcular seu valor múltiplo (se eu quiser trabalhar antes de buscá-lo).
Alice Heaton
Quanto ao segundo ponto: de fato, posso descobrir se é multi-valor testando o retorno de -> raw () ou de -> value (), mas prefiro saber antes de buscar o valor, como se ele fosse multi-valor. Quero executá-lo através de um loop foreach com -> getIterator (), em vez de passar manualmente pela matriz, o que exige que eu recrie um wrapper para cada item.
Alice Heaton
3

Portanto, como ninguém encontrou outra solução, responderei minha própria pergunta:

Não uma maneira mais simples de acessar valores de tipos de campos desconhecidos ao usar wrappers de metadados da entidade.

Existem métodos alternativos ao que eu descrevi inicialmente (por exemplo, os apontados por @thepearson). Em particular, este método é útil:

 entity_property_list_extract_type($type)

Ele retornará o tipo listado se o seu tipo for uma lista (por exemplo, 'integer' se o seu tipo for 'list <integer>') ou false se o seu tipo não for uma lista. Internamente, ele faz strops como o código que eu publiquei inicialmente, mas acho que é mais uma prova de futuro.

A conclusão é que:

  • Os wrappers de metadados da entidade funcionam bem se você não tem idéia dos seus tipos de campo e deseja abordar cuidadosamente cada caso possível;

  • Os wrappers de metadados da entidade funcionam bem se você sabe exatamente quais são os seus campos e deseja usá-los;

  • Se você tiver apenas algumas idéias de como são os seus tipos de campo (por exemplo, todo o texto, mas você não sabe se eles estão formatados ou não, e não sabe se são únicos ou com vários valores), os wrappers de metadados da entidade não forneça atalhos e você precisa escrever o seu próprio, como fiz na pergunta inicial.

Alice Heaton
fonte
1

Para a verificação de campo único / múltiplo, achei útil testar o tipo de objeto do invólucro, que será EntityListWrapperpara um campo de valores múltiplos e EntityValueWrapperpara um campo de valor único:

<?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();
}
Fonante
fonte
Ou até mesmoif($wrapper->field_name instanceof EntityListWrapper) {...}
rudolfbyker