О проекте

Данный сайт попытка повысить коммуникацию самых активных разработчиков на CMS Drupal - блоггеров. Если Вы ведете свой блог о Друпале, значит Вы готовы делиться вашими знаниями, помочь другим. Не всегда ваши знания доходят до потребителя. Задача данного сайта агрегировать знания различных блогов в единую ленту и привести на Ваши блоги активных пользователей.

Активность пользователей на Вашем сайте будет дополнительным стимулом к дальнейшей работе.

Удачи во всех Ваших начинаниях!

Создание надежного кода для полей, в седьмом Друпале

-17 votes
+
-

Это перевод моего блогпоста Writing robust code that uses fields, in Drupal 7
В семерке изменился способ прямого доступа к полям (cck в друпале 6.x). В шестерке мы пишем:
<?php$field_val = $node->field_yourfield[0]['value'];?>
В семерке уже надо писать:
<?php$field_val = $node->field_yourfield[LANGUAGE_NONE][0]['value'];?>
(во всяком случае, так рекомендуют писать официальные доки).
То есть, у нас появилось разделение значений поля по языкам.
Я уж не знаю, насколько это упростило создание кода, который хорошо работает с несколькими языками (сложных мультиязычных проектов в d7 я пока не делал) - надеюсь, упростило серьезно, но для "обычных" сайтов с одним активным языком этот подход добавляет некоторую головную боль разработчикам.
Проблема здесь в том, что надеяться на правильную работу константы LANGUAGE_NONE нельзя!
Если админ сайта включает модуль Locale, и, например, активирует англ. язык, ваш код надо будет менять на что-то типа:
<?php$field_val = $node->field_yourfield['en'][0]['value'];?>
Очевидно, что программистам нужен более надежный способ доступа к значением полей, вне зависимсти от языковых настроек на сайте.
Первый подход: field_language()
Первый способ который я попробовал - определение активного языка для поля и ноды.
"Главный" язык контента:http://api.drupal.org/api/drupal/developer--globals.php/global/language_...
Для поля:http://api.drupal.org/api/drupal/modules--field--field.multilingual.inc/...
Но это работает не совсем так как я ожидал - когда ноды только создаются, если нода создается на англ. языке, все еще приходится использовать константу LANGUAGE_NONE. (Не могу дать 100% гарантию что это работает именно так, потому что уже прошло некоторое кол-во времени с момента моих разбирательств - но проблемы были в том что приходилось в разные этапы жизни ноды работать то с LANGUAGE_NONE то с ключом языка ('en', 'ru')
<?php$language = field_language('node', $node, 'field_yourfield'); $field_val = $node->field_yourfield[$language][0]['value'];?>
Я погуглил и нашелВторой подход: field_get_items()
http://www.davereid.net/content/hlkd7fotw-field-get-items
<?php$field_val = field_get_items('node', $node, 'field_yourfield');?>
который работает неплохо. Но этот подход не совершенен - т.к. в одну строку кода не получится дернуть, например, второе значение в массиве multiple поля. (Я имею ввиду, что не получится сделать field_get_items('node', $node, 'field_yourfield')[1] - ну, во всяком случае, до php5.4) .
Так же, если вам надо быстрый доступ до пяти полей ноды, придется вызывать field_get_items() пять раз, по разу на каждое поле, а значит ваш код будет выглядеть... не идеально, мягко говоря.
и вот третий подход который я обнаружил, мне он показался самым удобным:
Третий подход: entity_metadata_wrapper
entity_metadata_wrapper это вспомогательный объект из клевого модуля Entity (fago - мой герой)
вот как выглядит его использование:
<?php$obj = entity_metadata_wrapper('node', $node);$field = $obj->field_yourfield->value();?>
ну, неплохо - но пока не супер :) Что действительно круто, так это то что можно используя entity_metadata_wrapper подгружать объекты reference (поля user reference, node reference) на лету:
<?php$involved_users = array();//grab usernames from user reference field of a node$project = entity_metadata_wrapper('node', $node);// field_users is user reference fieldforeach ($project->field_users as $acc) {  $involved_users[] = $acc->value()->name;}
var_dump($involved_users);?>

когда мы вызываем метод value(), entity_metadata_wrapper знает, что поле - это user reference поле, и подгружает нужный аккаунт пользователя на лету. В шестерке это выглядело бы так:
<?php// Drupal6 code$involved_users = array();//grab usernames from user reference field of a node
// field_users is user reference field, $project is nodeforeach ($project->field_users as $acc) {  $acc_object = user_load($acc['uid']);  $involved_users[] = $acc_object->name;}
var_dump($involved_users);?>

Что еще интересно - $project->field_users это не массив, это объект, т.е. можно вызвать $project->field_users->value() чтобы получить массив всех аккаунтов на которое поле ссылается (говорим про multiple поле, опять же).
В то же время, этот объект поддерживает доступ как к массиву, т.е. можно использовать $project->field_users[0] или скормить field_users foreach'у как в примере выше. Если говорить языком PHP5, класс объекта поля реализует интерфейсы IteratorAggregate, ArrayAccess и Countable.
Еще немного примеров из readme.txt модуля entity:
<?php$wrapper->author->mail = 'sepp@example.com'; ?>

Чтобы получить текстовое значение, очищенное для безопасного вывода на экран, можно использовать
$wrapper->title->value(array('sanitize' => TRUE));
(в примере - получение заголовка ноды или entity). Если свойство возвращается "очищенным" по умолчанию, например body у ноды, возможно понадобится получить "неочищенное" значение. Для этого есть опция 'decode', которая гарантирует что все теги будут убраны, а HTML сущности раскодированы:
$wrapper->body->value->value(array('decode' => TRUE));
Т.е. так возвращаются данные в виде в каком они должны показываться пользователю. Если вам надо совсем сырые данные, без процессинга:
$wrapper->body->value->raw();

Еще можно сохранять ноды (и сущности, конечно):
<?php$node = node_load(323);$wrapper = entity_metadata_wrapper('node', $wrapper);$wrapper->title = 'New title for the node';$wrapper->save();?>
Небольшая подсказка: для создания сущностей используем entity_create() или шорткат - entity_property_values_create_entity - которая принимает массив значений.
Я свй выбор сделал и в основном использую третий подход в своем коде.
Апдейт от Tom Nightingale:
Надо упомянуть что entity_metadata_wrapper работает только с полями которые "описали" свою структуру Entity API через свои хуки property_info(). Многие contrib модули все еще должны обновиться чтобы правильно заработать.
Blog categories: Drupal

Полный оригинальный материал:

Sidashin.ru