Actualización de un campo mediante programación, hook_node_update

13

Actualmente intento actualizar un campo cada vez que se crea o actualiza un nodo. Sin embargo, el valor no se está rellenando dentro del nodo, ¿tengo acceso al objeto de nodo con este gancho en particular? ¿Qué me podría estar perdiendo?

  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');
        }

    }
consenso general
fuente

Respuestas:

16

Contenedores de metadatos de entidad

La API de entidad proporciona algunas clases de contenedor que puede usar para tratar fácilmente con entidades y aprovechar los módulos de información de propiedad de entidad proporcionados. Con la ayuda de los contenedores, puede acceder a la información de la propiedad, recorrer las propiedades conocidas o simplemente obtener / establecer los valores de datos descritos, etc.

Estos son algunos ejemplos de uso simples que se encuentran en el archivo README:

Para hacer uso de esta información (metadatos), el módulo proporciona algunas clases de contenedor que facilitan la obtención y el establecimiento de valores. El contenedor admite el uso encadenado para recuperar contenedores de propiedades de entidad, por ejemplo, para obtener la dirección de correo del autor de un nodo, se podría usar:

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

Para actualizar la dirección de correo del usuario, se podría usar

$wrapper->author->mail->set('[email protected]');

o

$wrapper->author->mail = '[email protected]';

Los contenedores siempre devuelven los datos como se describe en la información de la propiedad, que se puede recuperar directamente a través de entity_get_property_info () o desde el contenedor:

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

Para forzar la obtención de un valor textual desinfectado para la salida, se puede usar, por ejemplo

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

para obtener el título del nodo desinfectado. Cuando una propiedad ya se devuelve desinfectada de manera predeterminada, como el cuerpo del nodo, uno posiblemente quiera obtener los datos no desinfectados como aparecerían en un navegador para otros casos de uso. Para hacerlo, se puede habilitar la opción 'decodificar', que garantiza que para cualquier información desinfectada se eliminen las etiquetas y se decodifiquen las entidades HTML antes de que se devuelva la propiedad:

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

De esa manera, uno siempre obtiene los datos como se muestran al usuario. Sin embargo, si realmente desea obtener el valor sin procesar, incluso para los datos textuales desinfectados, puede hacerlo a través de:

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

Más ejemplos:

$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();

Más documentos : http://drupal.org/node/1021556

retif
fuente
Muchas gracias. Su respuesta me ayudó a darme una idea de lo que tenía que hacer. :) ¡La comunidad es genial! \ m /
SGhosh
Esto funcionará en hook_node_update pero no en hook_node_insert (). Obtendrá un error duplicado de la clave principal de mysql, ya que tanto el módulo de nodo como su código personalizado intentarán insertar el mismo nodo dos veces (utilizando la misma identificación de nodo).
leon.nk
14

Llamar field_attach_update('node', $node)al final de hook_node_updatetrabajado para mí. Supongo que field_attach_insert('node', $node)al final hook_node_inserttambién funcionaría. Entonces, una función de muestra se vería así:

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);
}

No hay necesidad de llamar node_load node_saveo devolver nada.

Creo que la razón de esto es que node_save, a partir de la cual hook_node_updatey hook_node_insertse llama, envuelve todas las consultas de la base de datos en una transacción. (Tenga en cuenta la primera línea de node_save:. $transaction = db_transaction()) Estas consultas no se llaman hasta que node_savefinaliza. Se node_savellama a la última consulta que se agrega a la transacción field_attach_update, que usa el objeto $ node como se llama antes hook_node_update . Por lo tanto, debe poner en cola otra consulta llamando field_attach_updatenuevamente. Al menos, esa es mi comprensión de lo que está sucediendo.

Si tiene problemas para cambiar los atributos que no son de campo del nodo (por ejemplo, $node->log), intente llamar _node_save_revision($node, $user->uid, 'vid');también. Esto no creará una nueva revisión.

grobemo
fuente
2

Así es como cambia los valores en un nodo:

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);
lanza
fuente
44
undno es realmente apropiado aquí, OP ya ha indicado en el código que están usando $node->languagepara el código de idioma
Clive
Eso es súper útil gracias a Clive y Lance, pero quiero asegurarme de que el valor del campo se guarde cada vez que se guarda el nodo, de ahí mi uso de hook_node_update. ¿Sería posible devolver el $ nodo en este enlace o tengo que hacer una carga de nodo? Realmente pensaba que tenía el objeto de nodo pasa directamente a través de hook_node_update ....
generalconsensus
Ok, actualicé el código según su recomendación: está en el cuerpo original. Problema: bucle sin fin en el que la página no se carga y tanto mysql como apache comienzan a alcanzar más del 85% de carga en la CPU. Definitivamente hay algunos bucles pasando aquí. ¿Cualquier otra sugerencia?
consenso general
No puedo decirte qué está pasando. Pero probablemente intente una vez simplemente cargar el nodo, ingresar algo en el campo y guardarlo usando node_save (). O simplemente cargue, imprima algo (usando watchdog o dpm () y guárdelo nuevamente para ver si esto funciona.
Lance
El problema se derivó de haber guardado el nodo antes de guardarlo, lo que resultó en un bucle recursivo. Mala elección de gancho y mala construcción
consenso general
1

Una mejora de la solución anterior de Lance, que evita guardar un nodo completo cuando solo se modifican unos pocos valores de campo:

$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));

Esto también podría ser útil para evitar los efectos secundarios de node_save().

Fuente: guardar campos del nodo sin guardar el nodo en sí

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

amuli
fuente