Обновление поля программно, hook_node_update

13

В настоящее время пытается обновить поле каждый раз, когда узел создается или обновляется. Однако значение не заполняется в узле, есть ли у меня доступ к объекту узла с этим конкретным хуком? Чего мне не хватать?

  function vbtoken_node_update($node) {


      entity_get_controller('node')->resetCache(array($node->nid));


      $types = node_type_get_types(); //What are the current Node Content Types?
      $yes = ($types['volunteer_project']->type);

      if($node->type === $yes){


        $hash = md5($node->title . $node->nid . $node->nid);
        $hashed = substr($hash, 0, 6);
        $node = node_load($node->nid);
        $node->tcode[$node->language][0]['value'] = $hashed;
        node_save($node);

        watchdog('vbtoken', 'Added a new Token code to %nid', array('%nid' => $node->nid));

        }
        else 
        {
          dpm('not working dude');
        }

    }
generalconsensus
источник

Ответы:

16

Обертки метаданных сущностей

API-интерфейс сущности предоставляет некоторые классы-обертки, которые вы можете использовать для упрощения работы с сущностями и для использования предоставленных информационных модулей свойств сущностей. С помощью упаковщиков вы можете получить доступ к информации о свойствах, просмотреть известные свойства или просто получить / установить значения описанных данных и т. Д.

Вот несколько простых примеров использования, которые можно найти в README:

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

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

Для обновления почтового адреса пользователя можно использовать

$wrapper->author->mail->set('sepp@example.com');

или

$wrapper->author->mail = 'sepp@example.com';

Оболочки всегда возвращают данные, как описано в информации о свойствах, которая может быть получена непосредственно через entity_get_property_info () или из обертки:

$mail_info = $wrapper->author->mail->info();

Чтобы принудительно получить текстовое значение, очищенное для вывода, можно использовать, например,

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

получить очищенный заголовок узла. Когда свойство уже возвращено очищенным по умолчанию, как и тело узла, возможно, требуется получить необработанные данные так, как они будут отображаться в браузере для других вариантов использования. Для этого можно включить опцию «decode», которая гарантирует, что для любых очищенных данных теги удаляются, а объекты HTML декодируются до того, как возвращается свойство:

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

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

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

Больше примеров:

$wrapper->body->set(array('value' => "content"));
$wrapper->field_text[0] = 'the text';
$wrapper->field_text[0]->set(array('value' => "content"));
$wrapper->field_text2->summary = 'the summary';
$wrapper->field_text2->value = 'the text';

$wrapper->save();
$wrapper->delete();

Больше документов : http://drupal.org/node/1021556

retif
источник
Огромное спасибо. Ваш ответ помог мне понять, что мне нужно делать. :) Сообщество рулит !! \ м /
С.Г. Хош
Это будет работать с hook_node_update, но не с hook_node_insert (). Вы получите двойную ошибку первичного ключа от mysql, так как и модуль узла, и ваш пользовательский код будут пытаться вставить один и тот же узел дважды (используя один и тот же идентификатор узла).
leon.nk
14

Звонок field_attach_update('node', $node)в конце hook_node_updateсработал для меня. Я предполагаю, что field_attach_insert('node', $node)в конце hook_node_insertтоже будет работать. Итак, пример функции будет выглядеть так:

function mymodule_node_update($node) {
  $new_value = // ...do some stuff to compute a new value for the field.
  $node->field_my_field[LANGUAGE_NONE][0]['value'] = $new_value;
  field_attach_update('node', $node);
}

Там нет необходимости звонить node_load node_saveили возвращать что-либо.

Я думаю, что причина этого заключается в том node_save, что , откуда hook_node_updateи hook_node_insertвызываются, оборачивает все запросы к базе данных в транзакции. (Обратите внимание на первую строку node_save:. $transaction = db_transaction()) Эти запросы не вызываются до node_saveзавершения. Последний запрос, который node_saveдобавляет к транзакции, вызывается из field_attach_update, который использует объект $ node, как и прежде, hook_node_update вызывается. Поэтому вам нужно поставить в очередь другой запрос, позвонив field_attach_updateснова. По крайней мере, это мое понимание того, что происходит.

Если у вас возникли проблемы с изменением неполевых атрибутов узла (например, $node->log), попробуйте _node_save_revision($node, $user->uid, 'vid');тоже позвонить . Это не создаст новую ревизию.

grobemo
источник
2

Вот как вы меняете значения на узле:

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);
копье
источник
4
undздесь не совсем уместно, OP уже указал в коде, который они используют $node->languageдля кода языка
Клайв
Это очень полезно, благодаря Клайву и Лэнсу, но я хочу убедиться, что значение поля сохраняется при каждом сохранении узла, поэтому я использую hook_node_update. Можно ли было бы вернуть $ узел в этом хуке, или мне абсолютно необходимо сделать node_load? Я действительно думал, что объект узла был передан напрямую через hook_node_update ....
generalconsensus
Итак, я обновил код в соответствии с вашей рекомендацией - он в оригинальном теле. Проблема: Бесконечный цикл, в котором страница не загружается, а mysql и apache начинают загружать процессор на 85% больше. Определенно, здесь происходит некоторое зацикливание. Любые другие предложения?
общий консенсус
Я не могу сказать вам, что происходит. Но, вероятно, вы пытаетесь один раз просто загрузить узел, ввести что-то в поле и сохранить его с помощью node_save (). Или просто загрузите, напечатайте что-нибудь (используя watchdog или dpm () и сохраните его снова, чтобы увидеть, работает ли это
Lance
Проблема возникла из-за того, что узел был сохранен до его сохранения, что привело к рекурсивному циклу. Плохой выбор хуков и плохая сборка
generalconsensus
1

Улучшение решения Lance, описанное выше, позволяет избежать сохранения всего узла при изменении только нескольких значений поля:

$node = node_load($nodeID);
// for each field whose value remains unchanged
unset($node->field_<field-name>); 
// for each field whose value changes
$node->field_<field-name>[LANGUAGE_NONE][0]['value'] = <new-value>;
field_attach_update('node', $node);
entity_get_controller('node')->resetCache(array($node->nid));

Это также может быть полезно, чтобы избежать побочных эффектов node_save().

Источник: сохранение полей узла без сохранения самого узла

https://www.urbaninsight.com/2011/10/24/saving-nodes-fields-without-saving-node-itself

Амули
источник