Creating Tree Data Structure in Drupal
On this page
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 (opens in new window)
This issue is explaining how this module is working.
https://www.drupal.org/node/1862008 (opens in new window)
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:
- Adjacency List
- Materialized Path
- Nested Set
- 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 (opens in new window)
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!