MPTT (Modified Preorder Tree Traversal)

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
William
Forum Contributor
Posts: 332
Joined: Sat Oct 25, 2003 4:03 am
Location: New York City

MPTT (Modified Preorder Tree Traversal)

Post by William »

I'm currently building my first category structure using MPTT and I'm a bit confused on how I'm supposed to make a "category browser". Basically a page will display a listing of the most parent categories and then when you click on a category it will show it's children along with the top most categories.

This is easy with the adjacent model but the more I dig deeper into MPTT it's not clicking on how to do something like that. Does anyone have a simple example on how to display ONLY the children of a specific node but not their children?

Thanks

Edit: For people that don't know what MPTT is SitePoint has a good article explaining it. http://www.sitepoint.com/article/hierar ... atabase/2/
User avatar
McInfo
DevNet Resident
Posts: 1532
Joined: Wed Apr 01, 2009 1:31 pm

Re: MPTT (Modified Preorder Tree Traversal)

Post by McInfo »

Related topic: Creating endless subcategory levels?

Related topic: How to implement dynamic hierarchical menu structure?

Edit: This post was recovered from search engine cache.
Last edited by McInfo on Tue Jun 15, 2010 1:15 pm, edited 1 time in total.
User avatar
William
Forum Contributor
Posts: 332
Joined: Sat Oct 25, 2003 4:03 am
Location: New York City

Re: MPTT (Modified Preorder Tree Traversal)

Post by William »

That is the adjacency list model not MPTT. I'm debating on maybe making a mix between the both by adding parent_id but I'm looking for a possible solution that sticks with pure MPTT.
User avatar
McInfo
DevNet Resident
Posts: 1532
Joined: Wed Apr 01, 2009 1:31 pm

Re: MPTT (Modified Preorder Tree Traversal)

Post by McInfo »

I've been playing around with this.

I added a "Vegetable" category to the SitePoint hierarchy because I wanted to make sure my script could locate more than two subcategories.
mptt.png
mptt.png (7.48 KiB) Viewed 811 times
The new table data looks like this:

Code: Select all

+--------+-----------+-----+-----+
| parent | title     | lft | rgt |
+--------+-----------+-----+-----+
| -      | Food      |   1 |  20 |
| Food   | Fruit     |   2 |  11 |
| Fruit  | Red       |   3 |   6 |
| Red    | Cherry    |   4 |   5 |
| Fruit  | Yellow    |   7 |  10 |
| Yellow | Banana    |   8 |   9 |
| Food   | Vegetable |  12 |  13 |
| Food   | Meat      |  14 |  19 |
| Meat   | Beef      |  15 |  16 |
| Meat   | Pork      |  17 |  18 |
+--------+-----------+-----+-----+
I hope you can understand what is happening in this script even though I have not included the classes necessary to make it run. The two classes are still works-in-progress, so I don't want to release them yet. Just ignore everything before line 16.

Code: Select all

<?php
error_reporting(E_ALL);
header('Content-Type: text/plain');
 
// These classes are not available
require_once 'EasyDB.class.php';
require_once 'TextTable.class.php';
 
// EasyDB's ->query() method runs a query and stores the result rows in ->data
// The database table name is "categories"
$db = new EasyDB('categories');
 
// TextTable makes formatted text tables
$tt = new TextTable();
 
// Where to start; The "lft" of the root node
$left = 1; // 1
 
// Gets the root category (Food)
$db->query('SELECT * FROM `category` WHERE `lft` = '.$left);
 
// The first node to the left of Food (Fruit)
$left  = $db->data[0]['lft'] + 1; // 2
 
// The first node to the right of Food (Meat)
$right = $db->data[0]['rgt'] - 1; // 19
 
$children = array();
do {
    // Gets the next child
    $db->query('SELECT * FROM `category` WHERE `lft` = '.$left);
   
    // Adds the child to the list of children
    $children[] = $db->data[0];
   
    // The next child is the child to the right of the current child
    $left = $db->data[0]['rgt'] + 1; // 12, 14, 20
 
// The loop ends when the circle is closed
} while ($db->data[0]['rgt'] < $right); // (19 < 19) == FALSE
 
// Displays a text table of the root category's children
echo $tt->getTextTable($children);
?>
The script found the three children of the Food category:

Code: Select all

+--------+-----------+-----+-----+
| parent | title     | lft | rgt |
+--------+-----------+-----+-----+
| Food   | Fruit     |   2 |  11 |
| Food   | Vegetable |  12 |  13 |
| Food   | Meat      |  14 |  19 |
+--------+-----------+-----+-----+
If line 17 is changed to

Code: Select all

$left = 2;
the script will find the children of the Fruit category.

Code: Select all

+--------+--------+-----+-----+
| parent | title  | lft | rgt |
+--------+--------+-----+-----+
| Fruit  | Red    |   3 |   6 |
| Fruit  | Yellow |   7 |  10 |
+--------+--------+-----+-----+
If I didn't explain this very well or I'm not making sense, it's because I'm up past my bedtime.

Edit: This post was recovered from search engine cache.
Attachments
mptt.png
mptt.png (7.48 KiB) Viewed 915 times
Post Reply