Правильный вывод полей в Drupal 7

Original author: Stephen Tweeddale, ComputerMinds
Перевод статьи от ComputerMinds: Rendering Drupal 7 fields (the right way)

Краткий ответ

Используйте field_view_field()!

Полный ответ

Drupal 7 дает возможность работать с сущностями (Entities), а вместе с этим и мощный API для работы с полями, которые могут быть прикреплены к сущностям. Если Вы управляете полями через вкладки «Управление полями» и «Управление отображением» на странице типов материалов, то Drupal сам заботится о правильной работе с полями.

Однако, мы часто сталкиваемся с необходимостью отображения поля вне сущности. Типичным примером может быть отображение данных о авторе ноды в боковой колонке сайта. Конечно, такие модули, как Panels и CCK Blocks могут делать это самостоятельно, но сделать это вручную не так уж и сложно.

Возможно, Вы видели (или писали) код, который выглядит примерно так:

// Это неверный пример
$block['content'] = $node->field_name['und'][0]['safe_value'];


Копание в объекте ноды было довольно распространено в Drupal 6, и «safe_value» казалось бы, поможет избежать возможных проблем. Что в этом плохого? Давайте рассмотрим.

  1. Во-первых, элемент ['und'] является частью локализации поля в Drupal 7; прямой доступ к его значению приведет к проблемам в любой многоязычной среде.
  2. Получая доступ напрямую к значению поля, мы теряем возможность темизировать рендер поля и использовать базовую разметку.
  3. [0] [safe_value] явно обращается к первому значению поля — если вы хотите использовать каждое значение из нескольких значений поля — придется использовать цикл.
  4. Некоторые поля (например, node references) не имеют элемента safe_value, только value, — которые могут быть легко отображены без соответствующей предобработки. Это опасно, и не только потому, что node references содержит опасные данные (тот же nid), но и потому, что это вредная привычка привычка, особенно для новых разработчиков. Использование value других типов полей также может быть очень опасно.


К счастью, есть field_view_field()!

$output = field_view_field('node', $node, 'field_name');


Эта функция вернет очищенные значения (фикс 4) поля в полном объеме (фикс 3) на текущем языке (фикс 1) и в формате массива, готового к рендерингу, поэтому вы получите все связанные данные с разметкой (фикс 2). Победа! Если поле не имеет значения, функция будет использовать резервные участки языка логики, доступные для текущего языка. Вы также можете передать массив вариантов форматирования или задать режим просмотра в качестве дополнительного аргумента функции. Не правда ли, это отличный вариант?

Дополнительные советы

Предположим, вы хотите просто получить одно значение без разметки. Существует две Field API функций, которые помогут вам в этом случае. Во-первых, у нас field_get_items () которая возвращает поля элемента в правильном языке (опять же, вы можете указать язык, если вам это нужно). Вы можете покопаться там и получить исходные (raw) данные, возможно, для использования на стороне сервера или если вы хотите сделать что-то экзотическое, как, к примеру, вывод «alt» значения для поля изображения. Не забывайте, что вы имеете дело с необработанными данными и нужно сделать правильную предварительную обработку данных перед использованием значений, иначе вы создадите уязвимости в своем проекте.

Кроме того, есть еще одна удобная функция Field API, field_view_value (), она поможет, когда вы хотите получить одно значение поля с применением встроенных правил очистки данных. Эта функция также использует поле форматирования. Она принимает одно значение поля, которое берется из массива, возвращаемого field_view_value (). Вот пример:

$node = node_load($nid);
$field = field_get_items('node', $node, 'field_name');
$output = field_view_value('node', $node, 'field_name', $field[$delta]);


Где $delta — индекс поля, значение которого Вы хотите получить. Для единичного поля значение $delta будет 0. Все очень просто.

И, просто для удовольствия, вот последний пример с использованием некоторых параметров форматирования, которые указывают стиль ImageCache и делают ссылку на ноду. Этот пример будет работать так же, как field_view_value () и field_view_field ().

$node = node_load($nid);
$image = field_get_items('node', $node, 'field_image');
$output = field_view_value('node', $node, 'field_image', $image[0], array(
  'type' => 'image',
  'settings' => array(
    'image_style' => 'thumbnail',
    'image_link' => 'content',
  ),
));


Это рок!

Конечно, в случае, например, использование «field-as-a-block» Field API делает это действительно хорошо, чисто и просто. Мы имеем дело с визуализацией массивов, поэтому можем вносить изменения вплоть до срабатывания функции render(), которая вызывается в файле шаблона. И, используя field_view_field () и field_view_value () Вы можете быть уверены, что данные будут обработаны в соответствии со встроенными правилами очистки данных.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 15

    –1
    Берем 3 функции (отлично документированные в API) и пишем топик на хабр. Profit!
    В следующий раз напишите про другие 3 функции, вдруг кто-то о них не знает.
    Да, я видел, что это перевод.
    Да, обращение, скорее не к переводчику, а к автору.
      +3
      А по моему нормальная и достаточно полезная статья, особенно для начинающих друпалистов.
        0
        $output = field_view_field('node', $node, 'field_name');

        На самом деле этот код вернет рендер массив а не НТМЛ
        Что бы получить НТМЛ нужно его отрендерить:
        $output = render(field_view_field('node', $node, 'field_name'));
        0
        Читайте api.drupal.org, посоны! Там еще много интересного!

        Хотя не, не читайте, меньше конкурентов.
          0
          Уж лучше читать. Чтобы конкуренты не разбегались по другим ЦМС и не уводили к ним клиентов
            0
            Тут чувствуется, что у автора наболело :-), чёткое выражение того, что ему не очень хочется теперь работать с кодом, который ему достался вместе с заказчиком от предыдущих команд и этакий крик души «ребята, давайте API использовать». На самом деле, я за свою историю тоже повидал всяких извращений и не только с полями. Автор молодец, писать надо правильно!
            0
            Получается, что для получения одного значения одного поля ноды мне нужно загрузить весь объект ноды. Может я чего-то не понимаю, но как тут насчет производительности? Выдернуть это значение строчкой запроса как бы легче.
              0
              Значения полей сущности актуальны в контексте вывода самой сущности. В моей практике не возникало необходимости выводить значения полей отдельно от самой сущности.

              Но если стоит именно такая задача — да, сделать запрос к БД предпочтительнее.
              • UFO just landed and posted this here
                0
                Не нужно панически бояться загрузки ноды, поскольку она кешируется. Когда речь идет о сотнях нод, то конечно нужно искать какие то альтернативы.
                0
                … а как правильно сделать:
                $node->field_name['und'][0]['value'] = $content;
                  0
                  Точно так же, как и для safe_value:

                  $content = field_view_field('node', $node, 'field_name');

                  Или я неверно понял Ваш вопрос?
                    0
                    Все, дошло. Чтобы сохранить программно значение поля, необходимо загрузить объект сущности(ноды в Вашем случае), присвоить значение полям и сохранить сущность. Примерно так:

                    $node = node_load($nid);
                    $node->field_name[$node->language][0]['value'] = $value;
                    $node->field_name[$node->language][0]['safe_value'] = check_plain($value);
                    node_save($node);

                    Если нода имеет нейтральный язык, вместо $node->language используйте «und».
                      0
                      Странное форматирование в тэгах «code», но всё же код прикреплю =)

                      создание/редактирование field collection: drupal.org/node/1842304

                      $fc_item = entity_create('field_collection_item', array('field_name' => 'field_text_files')); $fc_item->setHostEntity('node', $my_node); $fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_item); $fc_wrapper->field_source_txt_filename->set('my_text_file.txt'); $fc_wrapper->save(true); node_save($my_node);

                      создание/редактирование обычного материала: www.leveltendesign.com/blog/randall-knutson/if-you-arent-using-entity-api-create-nodes-you-are-doing-it-wrong#.UPjgNx02YcQ

                      $node = new EntityDrupalWrapper('node', 1); $node->field_reference[0]->set(463); // Note that this is a multi value field. $node->field_text->set('Some Value'); // Note that this is a single value field. $node->save();
                  0
                  Какой-то Хабр злой стал. Нормальная статья для начинающих друпалистов.

                  Only users with full accounts can post comments. Log in, please.