Atualizando um campo programaticamente, hook_node_update

13

Atualmente tentando atualizar um campo toda vez que um nó é criado ou atualizado. No entanto, o valor não está sendo preenchido no nó, tenho acesso ao objeto do nó com esse gancho específico? O que eu poderia estar perdendo?

  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 geral
fonte

Respostas:

16

Wrappers de metadados da entidade

A API da entidade fornece algumas classes de wrapper que você pode usar para lidar facilmente com entidades e alavancar os módulos de informações de propriedade da entidade fornecidos. Com a ajuda dos wrappers, você pode acessar as informações da propriedade, fazer um loop sobre propriedades conhecidas ou apenas obter / definir os valores de dados descritos etc.

Estes são alguns exemplos simples de uso, conforme encontrados no README:

Para utilizar essas informações (metadados), o módulo fornece algumas classes de wrapper que facilitam a obtenção e a configuração de valores. O wrapper suporta o uso encadeado para recuperar os wrappers das propriedades da entidade, por exemplo, para obter o endereço de email do autor do nó que se poderia usar:

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

Para atualizar o endereço de e-mail do usuário, pode-se usar

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

ou

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

Os wrappers sempre retornam os dados, conforme descrito nas informações da propriedade, que podem ser recuperadas diretamente via entity_get_property_info () ou no wrapper:

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

Para forçar a obtenção de um valor textual higienizado para a saída, pode-se usar, por exemplo,

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

para obter o título do nó higienizado. Quando uma propriedade já é retornada higienizada por padrão, como o corpo do nó, é possível obter os dados não higienizados como apareceriam em um navegador para outros casos de uso. Para isso, é possível ativar a opção 'decodificar', que garante que todos os dados higienizados sejam removidos e as tags HTML decodificadas antes da devolução da propriedade:

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

Dessa forma, sempre se obtém os dados como mostrado ao usuário. No entanto, se você realmente deseja obter o valor bruto e não processado, mesmo para dados textuais higienizados, é possível:

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

Mais exemplos:

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

Mais documentos : http://drupal.org/node/1021556

retif
fonte
Muito obrigado. Sua resposta me ajudou a dar alguma orientação sobre o que eu tinha que fazer. :) Rochas da comunidade !! \ m /
SGhosh
Isso funcionará em hook_node_update, mas não em hook_node_insert (). Você receberá um erro de chave primária duplicado no mysql, pois o módulo do nó e o seu código personalizado tentarão inserir o mesmo nó duas vezes (usando o mesmo ID do nó).
Leon.nk
14

Ligar field_attach_update('node', $node)para o final de hook_node_updatefuncionou para mim. Suponho que field_attach_insert('node', $node)no final hook_node_insertfuncionaria também. Portanto, uma função de amostra ficaria assim:

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

Não há necessidade de ligar node_load node_save ou devolver nada.

Penso que a razão para isto é que node_save, a partir da qual hook_node_updatee hook_node_insertchamado, agrupa todas as consultas de banco de dados em uma transação. (Observe a primeira linha de node_save:. $transaction = db_transaction()) Essas consultas não são chamadas até o node_savetérmino. A última consulta que é node_saveadicionada à transação é chamada de field_attach_update, que usa o objeto $ node como antes hook_node_update . Então, você precisa enfileirar outra consulta chamandofield_attach_update novamente. Pelo menos, essa é a minha compreensão do que está acontecendo.

Se estiver com problemas para alterar atributos que não são de campo do nó (por exemplo, $node->log), tente ligar _node_save_revision($node, $user->uid, 'vid');também. Isso não criará uma nova revisão.

grobemo
fonte
2

É assim que você altera os valores em um nó:

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);
Lança
fonte
4
undnão é realmente apropriado aqui, o OP já declarou no código que está usando $node->languageo código do idioma
Clive
Isso é super útil, graças a Clive e Lance, mas quero garantir que o valor do campo seja salvo sempre que o nó for salvo, daí o uso de hook_node_update. Seria possível retornar o nó $ neste gancho ou preciso absolutamente fazer um node_load? Eu realmente pensei que tinha o objeto de nó passado diretamente através de hook_node_update ....
generalconsensus
Ok, atualizei o código conforme sua recomendação - ele está no corpo original. Problema: loop infinito no qual a página não carrega e o mysql e o apache começam a atingir mais de 85% da carga na CPU. Definitivamente, existem alguns ciclos aqui. Alguma outra sugestão?
generalconsensus
Eu não posso te dizer o que está acontecendo. Mas provavelmente você tenta uma vez apenas carregar o nó, inserir algo no campo e salvá-lo usando node_save (). Ou apenas carregue, imprima algo (usando watchdog ou dpm () e salve-o novamente para ver se isso funciona.
Lance
O problema foi derivado de salvar o nó antes de salvá-lo, resultando em um loop recursivo. Escolha de gancho deficiente e construção deficiente
generalconsensus
1

Uma melhoria da solução de Lance acima, evitando o salvamento de um nó inteiro quando apenas alguns valores de campo são modificados:

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

Isso também pode ser útil para evitar efeitos colaterais node_save().

Origem: salvando os campos do nó sem salvar o próprio nó

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

amuli
fonte