Using left_id and right_id for nesting

This article is about how to use left_id and right_id for nesting, like phpBB 3.0's forums table.

Submitted by Lord Le Brand on 26 Apr 2008, 10:15

Basics
Checking for children
SELECT queries

Basics #

First of all, what do they mean? left_id is the left boundary of the item, right_id logically is its right boundary - numerically this would be bottom and top boundaries. When the item has no nested items, the values are adjacent (That means right_id is just one higher than left_id). If it has nested items the left_id of the nested item is one higher than its parent's left_id, and its parent's right_id is one higher than the nested item's right_id.
Example:


Module nameleft_idright_id
Single12
Parent36
Child45


Checking for children #

To determine wheter an item has children, you no longer have to use a separate query. You can now determine this by checking if the left_id and right_id are adjacent. If they are, the item has no chilren; if they aren't, the item does have children. Here's an example code to determine whether an item in array $foo has children:
Code: Select all
for ($i 0$size sizeof($foo); $i $size$i++)
{
    (...)
    if (
$foo[$i]['right_id'] == $foo[$i]['left_id'] + 1)
    {
        
// $foo[$i] doesn't have children!
    
}
    else
    {
        
// $foo[$i] has children!
    
}
    (...)
}   


SELECT queries #

left_id is not only used to check for children, it is also used for ordering data. When selecting items from the database, you use left_id in the ORDER BY clause, and parent_id in the WHERE clause, to get the right set of items. Here's an example query that selects all toplevel items:
Code: Select all
SELECT *
   FROM items_table
   WHERE parent_id = 0
   ORDER BY left_id ASC

You can also go fancy and select a whole tree of items. The first way you would think of is a recursive query - of course, this is not recommended - but there is another, very simple way. This example is based on a part of the loop used in phpBB-3.0's make_jumpbox() function:
Code: Select all
    $right $padding 0;
    
$padding_store = array('0' => 0);

    while (
$row $db->sql_fetchrow($result))
    {
        
// If this row's left_id is lower than the previous right_id, it means this is a child of the previous.
        
if ($row['left_id'] < $right)
        {
            
$padding++;
            
$padding_store[$row['parent_id']] = $padding;
        }
        
// And if it's higher and not adjacent it's one or more levels higher
        
else if ($row['left_id'] > $right 1)
        {
            
$padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
        }

        
$right $row['right_id'];
        (...)

        
$spacer '';
        for (
$i 0$i $padding$i++)
        {
            
// Set some padding spacer
            
$spacer .= '&nbsp; &nbsp;';
        }

        
$forum_title $spacer $forum_title;
        (...)
    }   


// More to come
 

Changelog:

by Lord Le Brand on 26 Apr 2008, 10:18: Shortened URL title on Igor's request

License:

All articles in the knowledge base are licensed under the phpbbmodders beerware-nc license.

Back to category


Knowledge Base index