Part of the EllisLab Network
   
14 of 14
14
MPTtree, Hieararchical trees in a database table
Posted: 28 June 2011 08:50 AM   [ Ignore ]   [ # 131 ]  
Sr. Research Associate
Avatar
RankRankRankRankRank
Total Posts:  4115
Joined  11-04-2008

A node is the parent of another node if $child->lft > $parent->lft and $child->rgt < $parent->rgt.

Note that this is true for any parent of the child node, not only for the immediate parent. If you only need the immediate parent, you need to query the database, get all records where lft < $child[‘lft’], rgt > $child[‘rgt’], order ASC on rgt, and LIMIT 1 to get the parent node.

 Signature 

WanWizard.eu | Modular CI, an HMVC solution | DataMapper ORM

Profile
 
 
Posted: 28 June 2011 10:12 AM   [ Ignore ]   [ # 132 ]  
Summer Student
Total Posts:  5
Joined  06-28-2011

Thank you for getting back to me so quickly. Armed with your response and the fact that while generating the menu I am aware what the current page is, I was able to use the current page’s lft and rgt values against the node I was outputting like so:

if ($current['lft'>= $node['lft'&& $current['rgt'<= $node['rgt']{
   $classes[] 
'active';

This seems to be working and I’m now trying hard to understand the logic.

The only down side is that all of the nodes are children of “Home” and so on every page “Home” is also highlighted. I’ve put a temporary hack in place until I can think of a better solution.

Profile
 
 
Posted: 28 June 2011 11:13 AM   [ Ignore ]   [ # 133 ]  
Sr. Research Associate
Avatar
RankRankRankRankRank
Total Posts:  4115
Joined  11-04-2008

Since you’re storing the result in an array, why not loop over it, and wipe all ‘active’ entries but the last one?

 Signature 

WanWizard.eu | Modular CI, an HMVC solution | DataMapper ORM

Profile
 
 
Posted: 28 June 2011 11:58 AM   [ Ignore ]   [ # 134 ]  
Summer Student
Total Posts:  5
Joined  06-28-2011

Not entirely sure I follow. A better snippet might have been…

foreach ($tree as $node{
   $classes 
= array();
   if ((
$current['lft'>= $node['lft'&& $current['rgt'<= $node['rgt']{
      $classes[] 
'active';
   
}
   $str 
.= '<li' . (count($classes) ? ' class="' implode(' '$classes) . '"' '') . '><a href="' . ($node['url']) . '">' $node['menu_title''</a>';

   if (
$CI->page_tree->count_children($node['lft']$node['rgt'])) {
      $str 
.= get_menu($CI->page_tree->get_children_where($node['lft']$node['rgt'], array('hidden' => 0'date(publish_date) <=' => date("Y-m-d"), 'show_in_menu' => 1)), $current$level+1$max_level);
   
}

   $str 
.= '</li>';
   
$i++;
Profile
 
 
Posted: 28 June 2011 12:28 PM   [ Ignore ]   [ # 135 ]  
Sr. Research Associate
Avatar
RankRankRankRankRank
Total Posts:  4115
Joined  11-04-2008

I don’t understand this code. If you have three parents, you’ll end up with ‘active active active’ in the last <li>?

Why not:

// first the direct parent node of the current node
$active false;
foreach (
$tree as $index => $node{
   
if (($current['lft'>= $node['lft'&& $current['rgt'<= $node['rgt']{
      $active 
$index;
   
}
}

foreach ($tree as $index => $node{
   $str 
.= '<li' . ($index == $active) ? ' class="active"' '') . '><a href="' . ($node['url']) . '">' $node['menu_title''</a>';

   if (
$CI->page_tree->count_children($node['lft']$node['rgt'])) {
      $str 
.= get_menu($CI->page_tree->get_children_where($node['lft']$node['rgt'], array('hidden' => 0'date(publish_date) <=' => date("Y-m-d"), 'show_in_menu' => 1)), $current$level+1$max_level);
   
}

   $str 
.= '</li>';
   
$i++;
 Signature 

WanWizard.eu | Modular CI, an HMVC solution | DataMapper ORM

Profile
 
 
Posted: 28 June 2011 12:42 PM   [ Ignore ]   [ # 136 ]  
Summer Student
Total Posts:  5
Joined  06-28-2011

The code snippet is within a get_menu function, which is called recursively to process all child nodes.

If for example, you’re on page “One A” the menu output ends up looking like (I’ve removed a tags this post won’t send otherwise):

<ol>
   <
li>Home</li>
   <
li class="active">Item One
      
<ol>
         <
li class="active">One A</li>
         <
li>One B</li>   
      </
ol>
   </
li>
   <
li>Item Two</li>
   <
li>Item Three</li>
</
ol

This allows me to highlight the top level parent item “Item One” in the menu

Profile
 
 
Posted: 22 April 2012 07:04 PM   [ Ignore ]   [ # 137 ]  
Summer Student
Total Posts:  1
Joined  04-17-2012

Hi to all!
I am pretty new at CI, but in the past two months I managed to learn quite a bit, and I already successfully completed two medium-size web project with this incredible framework.

This is my first serious approach at MVC pattern, and so fa I have to say that CI is really great because of his small footprint, loose dependencies and GREAT documentation.

I became interested in hyerarchical data representation in mysql, and I found this great library.

I am on CI 2.1.0, php 5.3.

I managed to adapt this 1.7.x library to work with CI 2.1 and I am currently correcting few bugs in the code, implementing some new methods and trying to implement transactions.

I am quite a newbie in (my)sql, but if I’m not wrong, it seems that this library does not play well with unstable mysql servers-connections: table locking is implemented but not transactions, and because the queries does not use the “select for update” statement, I think this library is not transaction-safe. There is risk of leaving gaps or breaking the tree if every single query is automatically auto-committed.

I am still a newbie in sql, so I didn’t want to go through an entire query rewriting to remove table locks and rewrite every query in the form of “select for update” statement, to make them transacton and concurrency safe, so I decided to remove internal table locking and manually lock-unlock the tables when calling the library and executing an updating statement. At the same time, setting an autocommit = 0, a commit/rollback and an unlock tables at the right places seems to do the trick well.

Unfortunately I have not documented my editings on mpttree code, but If you confirm me that my work is going in the right direction, I could manage to take some time to tidy up my work and post an updated-modifyed version of mpttree, 2.1.x ready and with some new functions implemented.

For example, I doubled every function making an ***_byid($id) version, because pointing a node with his lft attribute doesn’t play well with concurrency: InnoDB never assigns two identical Ids, but a $lft value intended to point a deleted node could erroneously point at a new/wrong node.. and this is obviously an unwanted behaviour.

I also tested and slightly edited the insert_sorted function, that I see it’s not documented in the manual.
This function allows to insert a node at a specified place, and to order same-level children alphabetically.
This is a GREAT feature, because this way there’s no need to alphabetically order the results of a traversing query, making for a slightly slower insert but for a super fast alphabetically ordered displaying. Great!


==> Let me know if you are interested in some contribution, but please keep in mind that I am quite a newbie in php-sql-ci, so I take no responsibility for problems or anti-patterns I may use.

Thank you smile

Profile
 
 
   
14 of 14
14