Wednesday 3 April 2013

Drupal node structure and adding/modifying values for Entity References

Nodes come with default fields which are handled by Drupal automatically and which you will not be shown or allowed to edit (usually). One field that the user can edit directly, but is mandatory and cannot be removed is the Title field. This field can be renamed to something more suitable for the Content Type of the node, but it cannot be removed. Drupal uses it for displaying the title on a page as a node is expected to have a Title and a body, and maybe some other fields. The title is also used for search indexing so it is important to choose a good title to display in search results.

Here is an example of a node I created of the Content Type "phenotype" in a project I'm working on. In Black are the fields that Drupal manages and in Green are the fields that I created.

Node: stdClass Object (
[type] => phenotype
[title] => Nespas
[field_phenotype_id] => Array ( [und] => Array ( [0] => Array ( [value] => 2 ) ) )
[field_line] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => 129-Nespas/H ) ) )
[field_parameter_key] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => ESLIM_001_001_004 ) ) )
[field_pipeline] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => EUMODIC Pipeline 1 ) ) )
[field_score] => Array ( [und] => Array ( [0] => Array ( [value] => 1.0 ) ) )
[field_zygosity] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => HOMOZYGOUS ) ) )
[field_europhenome_id] => Array ( [und] => Array ( [0] => Array ( [value] => 10475 ) ) )
[field_mp_id] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => ) ) )
[field_mp_term] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => ) ) )
[field_sex] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => F ) ) )
[field_mgi_id] => Array ( [und] => Array ( [0] => Array ( [value_format] => [format] => [value] => MGI:1861674 ) ) )
[field_gene_id_ref] => Array ( [und] => Array ( [0] => Array ( [target_id] => 75729 ) ) )

[language] => und
[created] => 1364996308
[status] => 1
[promote] => 0
[sticky] => 0
[uid] => 1
[revision] =>
[comment] => 1
[menu] => Array ( [link_title] => [mlid] => 0 [plid] => 0 [menu_name] => main-menu [weight] => 0 [options] => Array ( ) [module] => menu [expanded] => 0 [hidden] => 0 [has_children] => 0 [customized] => 0 [parent_depth_limit] => 8 )
[migrate] => Array ( [machineName] => PhenotypeNode )
[changed] => 1364996308
[timestamp] => 1364996308
[log] =>
[nid] => 94430
[tnid] => 0
[translate] => 0
[vid] => 94430


A few things to note:

  1. Language was left as undefined (und). If you set yours to English or something else then you need to adapt your code accordingly.
  2. Some of these fields are of type Entity Reference. Often, the "value" key is set, but with Entity References it is the "target_id" field that needs setting.
  3.  The code to generate this is watchdog('phenotype', print_r(node_load($node_id), true))); And the output is accessible in the logs (Reports > Recent Log Messages).
The problem I was having was how to set an Entity Reference field that can hold unlimited references with a value programatically. First I tried assigning raw reference ids to the field, then I tried array('value' => $nid), but neither of these worked. So after a few hours I did the print_r() of the node above and got the clue to making it work:

$lang = 'und';
$node = node_load($gene_node_id);
foreach ($phenotype_refs as $ref_id)
   $node->field_phenotype_ref[$lang][] = array('target_id' => $ref_id);
node_save($node);

And that did it. You need to set the target_id key. So now the Gene node has a list of references to Phenotype nodes.

I hope this saves someone some time.