Drupal → Программное изменение значения поля без вызова entity_save()

04.01.2013

Пример программного изменения значения поля field_category у материала типа article:

Способ 1

$node = node_load(123);
$node->original = $node;
$node->field_category['und'][0]['tid'] = 456;
foreach (field_info_instances('node', 'article') as $field_name => $field_info) {
  // Удаляем все поля кроме field_category
  if ($field_name != 'field_category') {
    unset($node->{$field_name});
  }
}
field_attach_presave('node', $node);
field_attach_update('node', $node);

Замечание: способ обнуляет значения полей типа File или Image. Обойти баг можно не удаляя из $node эти поля.

По материалам Saving node's fields without saving the node itself.

Способ 2

$node = node_load(123);
$node->field_category['und'][0]['tid'] = 456;
$field_info = field_info_field('field_category');
field_sql_storage_field_storage_write('node', $node, 'update', array($field_info['id']));
cache_clear_all("field:node:{$node->nid}", 'cache_field');

Замечание: при таком способе не вызывается никаких хуков из Field API, т.е. обновлённое поле не будет проиндексировано и т.п.

По тестам, обновление поля у 2000 нод занимает около 7 секунд с учётом node_load(). Если отказаться от node_load(), то тот же тест будет выполняться уже за 4 секунды:

$node = (object)array(
  'nid' => 123,
  'vid' => 123,
  'type' => 'article',
);
$node->field_category['und'][0]['tid'] = 456;
$field_info = field_info_field('field_category');
field_sql_storage_field_storage_write('node', $node, 'update', array($field_info['id']));
cache_clear_all("field:node:{$node->nid}", 'cache_field');

По материалам How To Insert and Update Only Specific Fields Of Your Entity In Drupal 7.

Написанное актуально для
Drupal 7
Похожие записи

Комментарии

dansamara
04.01.2013, 14:23

Если hook_entity_update не вызывается при таком трюке, то я бы воздержался от его использования.

Кстати, может через field_update_field будет проще?

ерунда) если найдёшь более красивый рабочий способ, буду только рад ;)

еще есть некоторое кол-во оберток у ctools, которые используются в fape
полагаю, что лучше копать в их сторону так как именно они взяты командой spark для edit

Игорь
23.01.2013, 14:00

Это: $node->original = $node; - точно нужно?
У меня сущность через ECK сделана и работает без этого?!

А так можно загрузить только одно поле (взято здесь)

$query = new EntityFieldQuery();
 $query->entityCondition('entity_type', 'node')
   ->entityCondition('bundle', 'article')
   ->propertyCondition('status', 1)
   ->fieldCondition('field_image', 'fid', 'NULL', '!=');
 $results = $query->execute();
 $articles = $results['node'];
 $fields = field_info_instances('node', 'article');
 $field_id = $fields['field_image']['field_id'];
 field_attach_load('node', $articles, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

Правда, у меня цепляются все поля. Не пойму, как сделать, чтобы было только одно. $field_id вроде бы указан :/

Когда использовал ваш метод при создании rules components для использования через Views BO, то поля не обновлялись. Cработал только node_save(). Интересно почему?

Сергей
16.09.2013, 13:15

Добрый день!
Существует ли способ изменения entity properties без вызова функции сохранения entity?

Спасибо, способ 2 очень помогло.
Кстати, там кэш не правильно чистится, должно быть
cache_clear_all("field:node:{$node->nid}", 'cache_field');

Дмитрий Анатольевич
13.03.2016, 03:46

Все бы хорошо, да только при изменении поля, Rules абсолютно не реагирует на событие "После обновления существующего материала"

Илья Юрьевич Музыка
03.06.2016, 09:19

Поддерживаю, как сделать чтобы рулсы срабатывали при изменении полей программно?

Добавить комментарий