УрокКорректная работа с полями в седьмом Друпале. Entity metadata wrappers.

В седьмой версии Друпала вывод полей был несколько изменён в связи с усовершенствованием многоязычной системы. Если раньше для вывода содержимого поля достаточно было написать так:

print $node->field_name[0]['value'];

то в семёрке добавился к полю ещё и язык (для одноязычных сайтов по умолчанию 'und' - undefined, константа LANGUAGE_NONE):

print $node->field_name[LANGUAGE_NONE][0]['value'];

Вывод значение поля стал чуть длиннее. Но если бы это было единственной проблемой - тогда и проблем бы не было :) Но здесь в игру вступают мультиязычные сайты. И получается, что если сайт наш англоязычный например, а мы пользовались кодом выше, то значение поля теперь получить не удастся, т.к. теперь надо его получать иначе:

print $node->field_name['en'][0]['value'];

На первый взгляд - беда, товарищи. Однако не всё так плохо, как казалось на первый взгляд: есть функция field_language(), которая способна возвращать код текущего языка поля. А дальше полученный код можно уже подставить при получении значения:

$lang = field_language('node', $node, 'field_name');
print $node->field_name[$lang][0]['value'];

Уже лучше - такой код поможет избежать коллапса при смене языка сайта. Однако дальше - лучше. В ядре нашлась ещё одна полезная функция field_get_items(). Она возвращает массив из всех значений поля. Например, если в поле только одно значение, то пользоваться ей так:

$field_values = field_get_items('node', $node, 'field_name');
print $field_values[0]['value'];

Если же количество значений больше одного, то можно их выводить циклом:

$field_values = field_get_items('node', $node, 'field_name');
foreach ($field_values as $field) {
  print $field['value'];
}

В принципе, второй вариант является более общим, т.к. работает и для случая с одним значением поля.

На самом деле, на этом можно было бы даже остановиться, однако не рассказать о возможностях Entity API для работы с полями было бы крайне неправильно. Итак,

Возможности Entity API по работе с полями

В этом модуле есть великолепная функция entity_metadata_wrapper(). Она возвращает объект, который является удобной обёрткой для вывода и изменения данных объекта вместе с его полями. Например, значение поля можно получить так:

$wrapper = entity_metadata_wrapper('node', $node);
print $wrapper->field_name->value();

Если же значений несколько, то можно воспользоваться такой конструкцией:

$wrapper = entity_metadata_wrapper('node', $node);
foreach ($wrapper->field_name as $field) {
  print $field->value();
}

Пример из README.txt модуля Entity API (получаем емейл автора материала):

$wrapper = entity_metadata_wrapper('node', $node);
$wrapper->author->mail->value();

Если вы хотите получить значение поля, которое может быть безопасно выведено на экран, то передайте в value() атрибут 'sanitize', установленный в TRUE (в этом случае все тэги будут выведены в виде текста).

print $wrapper->field_name->value(array('sanitize' => TRUE));

Также существует атрибут 'decode', который отвечает за раскодирование всех HTML сущностей поля и вырезание тэгов из текста:

print $wrapper->body->value->value(array('decode' => TRUE));

Если же вам понадобятся данные без обработки в том виде, в котором их ввёл пользователь, тогда воспользуйтесь таким методом:

print $wrapper->body->value->raw();

Ещё одной отличительной особенностью этого подуля является автоматическое определение полей, которые ссылаются на другую сущность. Например, если у вас поле ссылается на другой материал, то вы на лету можете использовать объект этого материала:

$wrapper = entity_metadata_wrapper('node', $node);
// Выведем заголовок материала, на которое ссылается поле.
print $wrapper->field_some_relation->value()->title;

Отдельно стоит отметить, что $wrapper->field_name - это и массив и объект одновременно. То есть вы можете использовать его как объект ($wrapper->field_name->value()) или как массив ($wrapper->field_name[0]). Говоря техническим языком, он реализует интерфейсы IteratorAggregate, ArrayAccess и Countable.

Ещё одна важная деталь, на которую можно было не обратить внимание: entity_metadata_wrapper() даёт доступ не только к полям, но и к самим сущностям. Поэтому если вы загрузили сущность через entity_metadata_wrapper(), вы можете продолжать с ней работать:

$node = node_load(123);
$wrapper = entity_metadata_wrapper('node', $node);
$wrapper->title = 'New title for the node';
$wrapper->save();

При использовании обёрточного класса из модуля Entity API есть один недостаток - поле будет отображаться через entity_metadata_wrapper() только в том случае, если поле было описано через hook_entity_property_info(). Все поля ядра и наиболее популярные поляиз контриб-модулей поддерживают такую обёртку, однако среди множества модулей можете наткнуться на всякое, поэтому не стоит об этом забывать.

Вдохновение черпал отсюда: http://pixeljets.com/blog/writing-robust-code-uses-fields-drupal-7.

Комментарии

Аватар пользователя mixartemev
mixartemev написал:

Извиняюсь за, может быть, глупый вопрос, но что писать вместо 'value' в строчке:
print $node->field_name[LANGUAGE_NONE][0]['value'];
?

05.05.2012 16:01
Аватар пользователя Spleshka
Spleshka написал:

В зависимости от типа поля, вместо 'value' может быть например 'tid', 'nid' и так далее. Хотя для текстовых полей именно 'value' работает. Какое у вас поле?

05.05.2012 19:25
Аватар пользователя mixartemev
mixartemev написал:

У меня текстовое, field_tags, с 'value' не работает, только так как я описал ниже

06.05.2012 01:33
Аватар пользователя mixartemev
mixartemev написал:

у меня в 7.12 получилось вывести поле только вот так:
print $node->field_name[LANGUAGE_NONE][0]['taxonomy_term']->name;

05.05.2012 16:01
Аватар пользователя Ravil
Ravil написал:

привет! вопрос есть - как обратиться правильно к чекбоксу в семерке? пишу так

function mymodule_form_alter(&$form, &$form_state, $form_id) {
    if (($form_id == 'test2_node_form') && ($form['field_cbox']) === true))  {

те мне надо проверить статус чекбокса при сохранении формы.
Спасибо

22.10.2012 09:01
Аватар пользователя 1541
1541 написал:

Добрый день. Пытаюсь получить число из поля при помощи передачи его через URL, написал код на ссылку

<a  href="<?php print base_path(); ?>&<? php print field_r_price[0]['value']; ?>forma-zakaza.html?product=<?php print drupal_get_title();?>&price=<?php print field_get_items('node', node_load(8), 'field_r_price');?> ">заказать товар</a>

но выдает ошибку на страничке вместо ссылки. Необходимо как понятно одно значение. Что посоветуете, как быть?

01.12.2012 03:13
Аватар пользователя Spleshka
Spleshka написал:

Ошибка здесь (№1):

<? php print field_r_price[0]['value']; ?>

И здесь (№2):

<?php print field_get_items('node', node_load(8), 'field_r_price');?>

Функция field_get_items() возвращает массив. Вам надо сначала:

$items = field_get_items('node', node_load(8), 'field_r_price');

А потом уже выводить $items[0]['value']; в качестве значения поля.

01.12.2012 12:22
Аватар пользователя 1541
1541 написал:

А вот это

$items[0]['value']

где писать? я в значении по умолчанию в поле пишу %get[$item], мне вместо него вставлять?

01.12.2012 15:56
Аватар пользователя 1541
1541 написал:

так чтоли?

<a  href="<?php print base_path(); ?>&<?php print field_get_items('node', node_load(8), 'field_r_price');?>forma-zakaza.html?product=<?php print drupal_get_title();?>&price=<<? php print $node->field_r_price[LANGUAGE_NONE][0]['value']; ?> ">заказать товар</a>
01.12.2012 16:04
Аватар пользователя 1541
1541 написал:

Переменная передает массив, по %get[name_item] выдает Array, не могу понять как вывести значение поля.У меня там простая цена указана..

02.12.2012 16:05
Аватар пользователя 1541
1541 написал:

Вобщем так и не понял куда лепить вот это $items[0]['value'] поэтому стал передавать значение явно, т.е. прописывая его в запросе. К сожалению так и не дождался ответа..

02.12.2012 16:48
Аватар пользователя Spleshka
Spleshka написал:

@1541, вам сначала php надо подучить...
<?php print $items[0]['value']; ?> надо писать вместо :

  • <?php print field_get_items('node', node_load(8), 'field_r_price');?>
  • <?php print field_r_price[0]['value']; ?>
02.12.2012 18:27
Аватар пользователя 1541
1541 написал:

Спасибо большое. С ПХП я и правда не дружен. Вот докачиваю урок от "Специалист" и Бойко. Какой лучше посоветуете? Ваш вариант сейчас попробую.

02.12.2012 18:48
Аватар пользователя 1541
1541 написал:

что то я совсем уж наверное тугодум. сделал как Вы сказали, получил конструкцию вида:

<a  href="<?php print base_path(); ?>&pric=<?field_get_items('node', node_load(8), 'field_r_price');?>forma-zakaza.html?
product=<?php print drupal_get_title();?>&
price=<?php print pric[0]['value']; ?>">заказать товар</a>

на что браузер мне пишет: Parse error: syntax error, unexpected '[' in Z:\home\art1\www\modules\php\php.module(80) : eval()'d code on line 3. Наверняка надо как то иначе мне это вставлять, только ума не приложу как.

02.12.2012 18:59
Аватар пользователя 1541
1541 написал:

Перечитал еще раз статью и понял что и как.. Благодаря Вашим подсказкам:) Получил конструкцию вида:

<a href="<?php print base_path(); ?>forma-zakaza.html?
product=<?php print drupal_get_title();?>&
price=<?php $items = field_get_items('node', node_load(8), 'field_r_price'); 
print $items[0]['value']; ?>
">заказать товар</a>

Все здорово, переменная передалась, спасибо Вам большое.

02.12.2012 21:10
Аватар пользователя staryi
staryi написал:

Добрый день. Не могу вывести значение поля в шаблоне node--event.tpl, просто ничего не выводиться, как-будто из этого шаблона нет доступа к полям. Вот код которым пробую это сделать:
$node = node_load($nid);
print ($node->field_event_date['und'][0]['value']);
print ($node->field_event_date['und'][0]['value2']);

$date_values = field_get_items('node', $node, 'field_event_date');
print ($date_values[0]['value']);
print ($date_values[0]['value2']);

Но не ошибок, не значений не выводиться. Можете подсказать, делаю на друпал 7

10.01.2013 09:45
Аватар пользователя sergeybelya
sergeybelya написал:

Первая строка некорректна, в шаблоне node.tpl.php объект $node уже есть. Последние строки тоже лишние.

10.01.2013 14:50
Аватар пользователя staryi
staryi написал:

Да, спасибо за ответ.

Заработало. Действительно убрал $node = node_load($nid);.

Но странность в том, что заработало сначала print ($node->field_event_date[0]['value']); - без ['und'] , работало какое-то время, даже написал небольшую логику обработки этих дат, потом перестало. Добавил ['und'] и снова заработало.

11.01.2013 03:05
Аватар пользователя mNigma
mNigma написал:

Кто подскажет, как получить все возможные значения поля? Например у поля типа список.
В базе они хранятся в content_node_field -> global_settings

09.03.2015 20:52

Комментировать