Entity view (Content)

Creating Tree Data Structure in Drupal

By youfei
May. 4, 2016

Sometimes you don’t want to use taxonomy for a building node structures of a tree, as it creates huge problems when you're trying to export them as features and involves things like UUID, which is not perfect yet.

There is a project on Drupal.org utilizing tree structure with eneity reference module, however it is currently in lack of maintenance, maybe a bit difficult to use.

https://www.drupal.org/project/tree

This issue is explaining how this module is working.

https://www.drupal.org/node/1862008

However, a more manageable way may be creating a table in database for tree-structure management, and then associate the node id to each items in the table, in that method, the whole tree-structure is manageable by the Features module.

There are some different ways of implementing the data structure:

  1. Adjacency List
  2. Materialized Path
  3. Nested Set
  4. Closure Table

Each method has its pros and cons, depending on how often the data is saved and loaded. This form can conclude some characteristics of each method of implementation:

 

Read Speed

Write Speed

Space efficiency

Difficulty of implementation

Adjacency List

Low

High

High

Low

Materialized Path

Low

High

High

Medium

Nested Set

High

Low

Low

High

Closure Table

High

High

Very Low

High

 

More detailed analysis will be way off topic, for smaller projects with small metrics, each of them is a reasonably good method to use.

Some detailed comparison of those methods can be found here:

http://www.slideshare.net/billkarwin/models-for-hierarchical-data

 

Adjacency List

We will start with the easiest implementation: the adjacency list.

The idea is simple: have a field in the database to store the parent node.

First, we have to implement hook_schema() in the .install file in a newly created custom module. Let’s name the module mytree.

 

function mytree_schema(){

 $schema[‘mytree_table’] = array(

  'description' => 'The table for storing a custom tree structure.',

  'fields' => array(

   'tid' => array(

     'description' => 'The identifier for a tree node.’,

     'type' => 'serial',

     'unsigned' => TRUE,

     'not null' => TRUE,

     ),

    'pid' => array(

     'description' => 'The parent tree node id.’,

     'unsigned' => TRUE,

     'not null' => TRUE,

     ),

   ‘name’ => array(

       'description' => 'The name of the node.',

       'type' => 'varchar',

       'length' => 255,

       'not null' => TRUE,

       'default' => '',

     ),

    'nid' => array(

       'description' => 'The drupal node id which the tree node is associated to.',

       'type' => 'int',

       'unsigned' => TRUE,

     ),

      'weight' => array(

     'description' => 'The weight of entry, affecting the display orders.',

     'type' => 'int',

     'not null' => TRUE,

     'size' => 'normal',

     'default' => 0,

     ),

   ),

  'primary key' => array('tid'),

  );

 return $schema;

}

 

Note the nid will be storing node id of any Drupal nodes, in this way the existing nodes can be structured with our custom module. 

When you have the schema implemented, enable your custom module, so that you can verify the table in phpmyadmin by searching for the table name : mytree.

Next step is to create some apis for the data structure, say a CURD (create,update,read,delete) cycle.

 

function mytree_data_create($pid,$name,$nid,$weight)){

 $record = array(

   ‘pid’ => $pid,

   ‘name’ => $name,

   ‘nid’ => $nid,

   ‘weight’ => $weighg,

 );

 drupal_write_record(‘mytree_table’, $record);

 

}

 

function mytree_data_update($tid,$pid,$name,$nid,$weight){

$record = array(

   ‘tid’ => $tid,

   ‘pid’ => $pid,

   ‘name’ => $name,

   ‘nid’ => $nid,

   ‘weight’ => $weight,

 );

 if($tid != NULL){

   db_merge(‘mytree_table’)->key(array('tid' => $tid))->fields($record)->execute();

 }else{

   db_merge(‘mytree_table’)->key(array('name' => $name))->fields($record)->execute();

 }

 

}

 

function mytree_data_read(){

 $query = db_select(‘mytree_table’, 't');

 $result = $query->fields('t')

   ->orderBy('weight')

   ->execute()

   ->fetchAll();

 return $result;

}

 

function mytree_data_delete($tid){

db_delete(‘mytree_table’)->condition('tid',$tid)->execute();

}

 

These 4 are not all API functions you might going to need, write some more based on your needs retrieve items by name, id...etc

Some other interesting ways of implementing tree structure will be coming soon!