以编程方式更新字段,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');
        }

    }

Answers:


16

实体元数据包装器

实体API提供了一些包装器类,您可以使用它们来轻松处理实体并利用所提供的实体属性信息模块。在包装器的帮助下,您可以访问属性信息,遍历已知属性或仅获取/设置描述的数据值等。

这些是自述文件中的一些简单用法示例:

为了利用此信息(元数据),模块提供了一些包装器类,这些包装器类易于获取和设置值。包装器支持链接用法,以检索实体属性的包装器,例如,获取节点作者的邮件地址,可以使用:

$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


非常感谢。您的回答使我对我必须做的事情有一些指导。:)社区摇滚!!\ m /
SGhosh

这将适用于hook_node_update,但不适用于hook_node_insert()。由于node模块和您的自定义代码都将尝试两次将同一节点插入两次(使用相同的节点ID),因此您将从mysql中获得重复的主键错误。
leon.nk 2015年

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_savehook_node_updatehook_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');。这不会创建新的修订版。


2

这是更改节点上的值的方式:

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);

4
und在这里不是很合适,OP已经在代码中声明了他们正在使用$node->language的语言代码
Clive

这对Clive和Lance很有帮助,但是我想确保只要保存节点就保存字段值,因此我使用hook_node_update。是否有可能在此挂钩中返回$ node,或者我是否绝对必须做一个node_load?我真的以为我有直接通过hook_node_update传递的节点对象...
generalconsensus 2012年

好的,我根据您的建议更新了代码-该代码位于原始正文中。问题:无休止的循环,其中页面无法加载,并且mysql和apache开始在cpu上加载超过85%的负载。肯定这里有一些循环。还有其他建议吗?
generalconsensus 2012年

我不能告诉你怎么回事。但是可能您只尝试一次加载节点,在字段中输入内容,然后使用node_save()保存它。或只是加载,打印一些内容(使用看门狗或dpm()并再次保存以查看其是否有效。)
Lance 2012年

该问题源自保存节点之前保存节点,从而导致递归循环。钩子选择
不当

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.