SitePoint Sponsor

User Tag List

Results 1 to 25 of 25

Hybrid View

  1. #1
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Adjacent List Navigator, anyone?

    Wondering if anyone has a class/classes for navigating thru an adjacent list set. I'm looking for something that will let me go thru the items as a list, and each item would have methods like, hasChildren(), isFirstChild(), isLastChild() and properties like parent, children, id, parent_id etc.

    Also be interested in seeing/hearing about ideas on an interface for something like this.

    Matt

  2. #2
    SitePoint Zealot sike's Avatar
    Join Date
    Oct 2002
    Posts
    174
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    have you looked at the php5 spl ? they have a recursive iterator which should do the trick.

    http://www.php.net/~helly/php/ext/sp...eIterator.html

    cheers
    Chris

  3. #3
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sadly, I don't have PHP5 available! Anything for PHP4?

  4. #4
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not too difficult I suppose,

    PHP Code:
    interface IComposite {
    public function 
    hasChildren();
    public function 
    getChildren();
    public function 
    getId();
    public function 
    attachIComposite $composite );

    Remember though, that when you refer to a child it's not the Composite that you are looking at it's self, but it's parent Composite instead, in regards to firstChild and lastChild class methods, so you need to reference a particular Composites parent, ie

    PHP Code:
    // a given node
    public function attachIComposite $composite ) {
    $composite -> setParent$this );
    $this -> children[$composite -> getId()] = $composite;

    So, before you validate if it's a first or last child, you need to locate that nodes parent, which the above does for you

    The other way to look at it is if you are looking instead, if a particular Composite has a first or last child of a specific node,

    PHP Code:
    // ...
    $body -> attach$searchbox = new SearchBox() );
    // so...
    class SearchBox extends Composite {
    protected 
    $id 'search';
    // ...

    You therefore need to pass the ID search into Body::isFirstChild( $id ); to verify that the SearchBox Composite actually is the first child of the Body Composite, or not. So, there are two approaches to how you tackle it, which one are you in favour of?

    The first approach, via the parent is more flexible in my view... If your not sure what I'm talking about, I can explain some more...

  5. #5
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey thanks. That gives me some ideas.

    My datasource is the standard result set from a database:
    indexed array/list where each item is an associative array. Each item with an "id" and a "parent_id" key/value.

    I was using an iterator at first but I want to stay generic (array) just to get started. I'd like to be able to just pass in the array to the object, have the object build a new list where each item is a "AdjacentListItem". The new list would be ordered to where it follows the id/parent_id relationship as a list. The list items would then have references to the other items. I'd like to have "dumb" items in the list that are really there as place holders for the start of a new list, and the end of a list.

    Some of the methods:

    // tells me if it's a marker or real item
    AdjacentListItem::isMarker()

    // the start of any item
    AdjacentListItem::isStart()

    // the end/closing of any item
    AdjacentListItem::isEnd()

    // returns reference to next item in list
    AdjacentListItem::next()

    // returns reference to previous item in list
    AdjacentListItem:revious()

    An example:
    PHP Code:
    $items = array(
        array(
            
    'id' => 1,
            
    'parent_id' => 0
        
    ),
        array(
            
    'id' => 2,
            
    'parent_id' => 0
        
    ),
        array(
            
    'id' => 3,
            
    'parent_id' => 2
        
    ),
        array(
            
    'id' => 4,
            
    'parent_id' => 0
        
    ),
        array(
            
    'id' => 5,
            
    'parent_id' => 4
        
    ),
        array(
            
    'id' => 6,
            
    'parent_id' => 4
        
    )
    );

    $list =& new AdjacentList($items);

    while(
    $item =& $list->fetch()){
        if(
    $item->isMarker()){
            echo 
    $item->isStart() ? '<ul>' '</ul>';
        }else{
            echo 
    $item->isStart() ? '<li>' $item->get('name') : '</li>';
        }


  6. #6
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'd like to have "dumb" items in the list that are really there as place holders for the start of a new list, and the end of a list.
    Why would you want to complicate matters? What I mean, is that I would use a Visitor in relation to your problem, so it's the visitor doing the visiting of each node, that would open up your functionality; In knowing that therefore, if you want to have your markers, why not just implement a more specific visitor for that given node(s) in question?

    So, you'd have your plain vanilla Visitor, and you'd have a Visitor for your start of list, and another one for the end of list, the last two respectively deal with their own functionality as you require; It's just a case of making sure that you have the proper Visitor do the visiting, on a per node basis.

    That is so cool about the Visitor in my view... It doesn't care what node it is in regards of it's use with the Composite pattern

  7. #7
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK I know what the Visitor does but honestly haven't used it that much. Would you mind giving me an example or an idea of how the "client" code would look? How do you have more than one visitor for an iteration? A collection of visitors? How would one visitor know what the next and previous items were. Obviously the more I think about it the more confused I am!

  8. #8
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK, here's what I have. I'd love to hear about how I can improve this. Some of this was taken from the Sitepoint PHP Anthology books. Also, I'd love to know what does and doesn't look right in terms of OOP.

    PHP Code:
    class AdjacentList {
        
        var 
    $items = array();
        var 
    $current_id null;
        var 
    $current null;
        var 
    $adjacent_list = array();
        
        function 
    AdjacentList($items$current_id=null){
            
    $this->items $items;
            
    $this->current_id $current_id;
            
    $this->build();
        }
        
        function 
    fetch () {
            
    $item each $this->adjacent_list );
            if ( 
    $item ) {
                return ( 
    $item['value'] );
            } else {
                
    reset $this->adjacent_list );
                return 
    false;
            }
        }
        
        function 
    build () {
            foreach(
    $this->items as $item_data) {
                
    $item =& new AdjacentListItem($item_data);
                
                if ( 
    $item->ID() == $this->current_id ){
                    
    $item->is_current true;
                    
    $this->current =& $item;
                }
                
                if ( 
    $item->isRoot() ) {
                    
    $this->adjacent_list[] =& $item;
                    
    $this->appendChildren($item);
                }
            }
            
    reset ($this->adjacent_list);
            
    $this->appendPrevAndNextItems();
        }
        
        function 
    appendChildren (& $theItem) {
            foreach (
    $this->items as $item_data ) {
                
    $item =& new AdjacentListItem($item_data);
                if ( 
    $theItem->ID() == $item->parentID() ) {
                    
    $item->parent =& $theItem;
                    
    $item->level $theItem->level 1;
                    
    $theItem->children[] =& $item;
                    
    $this->adjacent_list[] =& $item;
                    
    $this->appendChildren($item);
                }
            }
        }
        
        function 
    appendPrevAndNextItems(){
            
    $i 0;
            
    $prev null;
            foreach(
    array_keys($this->adjacent_list) as $key){
                
    $item =& $this->adjacent_list[$key];
                if(
    $prev){
                    
    $item->prev =& $prev;
                    
    $prev->next =& $item;                
                }
                
    $prev =& $item;
            }
        }
    }

    class 
    AdjacentListItem {
        
        var 
    $properties = array();
        
        var 
    $is_current false;
        
        var 
    $index null;
        var 
    $global_index null;
        
        var 
    $level 0;
        var 
    $parent null;
        var 
    $children = array();
        
        
    // reference to next item
        
    var $next null;
        
    // reference to previous item
        
    var $prev null;
        
        function 
    AdjacentListItem($properties){
            
    $this->properties $properties;
        }
        
        function 
    ID(){
            return 
    $this->get('id');
        }
        
        function 
    parentID(){
            return 
    $this->get('parent_id');
        }
        
        function 
    isRoot(){
            return 
    $this->get('parent_id') == 0;
        }
        
        function 
    isLastChild(){
            if(
    $this->parent){
                return 
    $this->parent->childrencount($this->parent->children) - ]->ID() == $this->ID();
            }else{
                return 
    $this->prev == null;
            }
        }
        
        function 
    isFirstChild(){
            if(
    $this->parent){
                
    $this->parent->children[0]->ID() == $this->ID();
            }else{
                return 
    $this->prev == null;
            }
        }
        
        function 
    get($property){
            if(isset(
    $this->properties[$property])){
                return 
    $this->properties[$property];
            }
        }
        
    }

    $items = array(
        array(
            
    'id' => 1,
            
    'parent_id' => 0,
            
    'name' => 'home'
        
    ),
        array(
            
    'id' => 2,
            
    'parent_id' => 0,
            
    'name' => 'products'
        
    ),
            array(
                
    'id' => 3,
                
    'parent_id' => 2,
                
    'name' => 'gallery'
            
    ),
        array(
            
    'id' => 4,
            
    'parent_id' => 0,
            
    'name' => 'contact'
        
    ),
            array(
                
    'id' => 5,
                
    'parent_id' => 4,
                
    'name' => 'staff'
            
    ),
            array(
                
    'id' => 6,
                
    'parent_id' => 4,
                
    'name' => 'students'
            
    )
    );

    $list =& new AdjacentList($items2);

    $html '<ul>';
    while(
    $item =& $list->fetch()){
        
    $html .= '<li>' $item->get('name');
        if( 
    count($item->children) ){
            
    $html .= '<ul>';
        }else{
            
    $html .= '</li>';
            if( 
    $item->parent && $item->isLastChild() ){
                
    $html .= '</ul></li>';
            }
        }
    }
    $html .= '</ul>';

    echo 
    $html

  9. #9
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That way, you don't need to do anything special to any nodes to let your scripts know about markers, etc; Remember that with the Composite, all child nodes themselves represent a whole, so I wouldn't like to hinge a bet that you could cleanly, implement what you want anyways, with the Composite...

    As the start and end marker nodes wouldn't comply with the other children, and their parents?

  10. #10
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think something looks wrong with the render code.
    Code:
    * 1
     * 1.1
      * 1.1.1
    * 2
    The transition from 1.1.1 to 2 would require a pair of </ul></li> output before the <li>2</li>

  11. #11
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmm, what do you mean exactly? Are you getting something else? Here is what I get (minus the indents) from the code:

    Code:
    <ul>
      <li>home</li>
      <li>products
        <ul>
          <li>gallery</li>
        </ul>
      </li>
      <li>contact
        <ul>
          <li>staff</li>
          <li>students</li>
        </ul>
      </li>
    </ul>

  12. #12
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh, thanks! OK here is crappy fix! I need to think more about all of this. Any ideas on a better solution?

    PHP Code:
    $list =& new AdjacentList($items2);

    $html '<ul>';
    while(
    $item =& $list->fetch()){
        
    $html .= '<li>' $item->get('name');
        if( 
    $item->hasChildren() ){
            
    $html .= '<ul>';
        }else{
            
    $html .= '</li>';
            if( 
    $item->parent && $item->isLastChild() ){
                
    $html .= str_repeat('</ul></li>'$item->level);
            }
        }
    }
    $html .= '</ul>';

    echo 
    $html

  13. #13
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you try it with this array of items you'll be an </li></ul> short.

    PHP Code:
    $items = array( 
        array( 
            
    'id' => 1
            
    'parent_id' => 0
            
    'name' => 'home' 
        
    ), 
        array( 
            
    'id' => 2
            
    'parent_id' => 0
            
    'name' => 'products' 
        
    ), 
            array( 
                
    'id' => 3
                
    'parent_id' => 2
                
    'name' => 'gallery' 
            
    ), 
            
        array(
            
    'id' => 7,
            
    'parent_id' => 3,
            
    'name' => 'somethingelse'
        
    ),
            
        array( 
            
    'id' => 4
            
    'parent_id' => 0
            
    'name' => 'contact' 
        
    ), 
            array( 
                
    'id' => 5
                
    'parent_id' => 4
                
    'name' => 'staff' 
            
    ), 
            array( 
                
    'id' => 6
                
    'parent_id' => 4
                
    'name' => 'students' 
            

    ); 

  14. #14
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is how I render lists, but I tend to use the Nested Set model, but I think if you calculate the depth perhaps a similar method could be used.

    PHP Code:
    interface DXNestedTreeListVisitor
    {
        function 
    visit($node);
    }

    class 
    DXNestedTreeList
    {
        protected 
    $visitor;
        protected 
    $tree;

        function 
    __construct($treeDXNestedTreeListVisitor $visitor)
        {
            
    $this->tree $tree;
            
    $this->visitor $visitor;
        }

        function 
    render($listType 'ol'$listItem 'li'$attr = array())
        {
            echo 
    '<'$listType;
            foreach(
    $attr as $name => $value)
                echo 
    ' 'htmlspecialchars($nameENT_COMPAT'UTF-8'), '="'htmlspecialchars($valueENT_COMPAT'UTF-8'), '"';
            echo 
    '>';

            unset(
    $depth);
            
    $firstDepth 0;
            foreach(
    $this->tree as $node)
            {
                if (isset(
    $depth))
                {
                    
    $depth -= $node->depth;
                    switch (
    $depth)
                    {
                        case -
    1: echo '<'$listType'>'; break;
                        case 
    0:    echo '</'$listItem'>'; break;
                        case 
    1: echo '</'$listItem'></'$listType'>'; break;
                        default: for(; 
    $depth 0; --$depth) echo '</'$listItem'></'$listType'>'; break;
                    }
                }
                else
                    
    $firstDepth $node->depth;

                echo 
    '<'$listItem'>';
                
    $this->visitor->visit($node);
                
    $depth $node->depth;
            }
            if (isset(
    $depth))
                for(; 
    $depth $firstDepth; --$depth) echo '</'$listItem'></'$listType'>';
            else
                echo 
    '</'$listType'>';
        }


  15. #15
    SitePoint Zealot johno's Avatar
    Join Date
    Sep 2003
    Location
    Bratislava, Slovakia
    Posts
    184
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Annotations support for PHP5
    TC/OPT™ Group Leader

  16. #16
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by johno
    Hi. That list doesn't come out correct either. I've posted what I'm getting below. How does a list item ever close itself with the way that's set up?

    [code]
    <ul>
    <li>
    Car
    <ul>
    <li>Engine
    <ul>
    <li>Rotor
    </ul>
    </li>
    <ul>
    <li>Stator
    </ul>
    </li>
    <ul>
    <li>Plugs
    </ul>
    </li>
    </ul>
    </li>
    <ul>
    <li>Wheels
    <ul>
    <li>Tube
    </ul>
    </li>
    </ul>
    </li>
    <ul>
    <li>Chassis
    </ul>
    </li>
    </ul>
    </li>
    [/php]

  17. #17
    SitePoint Zealot johno's Avatar
    Join Date
    Sep 2003
    Location
    Bratislava, Slovakia
    Posts
    184
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    Hi. That list doesn't come out correct either. I've posted what I'm getting below. How does a list item ever close itself with the way that's set up?

    ...
    There was a bug yeah. It's ok now. Thanks!
    Annotations support for PHP5
    TC/OPT™ Group Leader

  18. #18
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by johno
    There was a bug yeah. It's ok now. Thanks!
    That was fast! I re-wrote your code for PHP4, it works great. Really nice job! Where did you get the idea for this (composition, interface etc.) ? Why can't I ever be this clever?

    Anyway, here is what I ended up with (I'll be using yours if you don't mind!)

    PHP Code:
    class AdjacentList {
        
        
    // List/indexed array of associative arrays
        
    var $items;
        
    // id passed into second parram of constructor
        
    var $current_id;
        
    // the item found that matches the current_id
        
    var $currentItem null;
        
    // the sorted list of "AdjacentListItem"s
        
    var $adjacent_list = array();
        
        function 
    AdjacentList($items$current_id=null){
            
    $this->items $items;
            
    $this->current_id $current_id;
            
    $this->_build();
            
    $this->_finalize();
        }
        
        
    /*
            iterator method
            while($item =& $list->fetch()){
                
            }
        */
        
    function & fetch () {
            
    $item =& each ($this->adjacent_list);
            if (
    $item) {
                return ( 
    $item['value'] );
            } else {
                
    reset $this->adjacent_list );
                return 
    false;
            }
        }
        
        
    /*
            Go through all of the root elements
            Sets the is_current variable if it matches
            Sets the number for the item
            Appends it's children if any
        */
        
    function _build () {
            
    $number 0;
            foreach(
    $this->items as $item_data) {
                
    $item =& new AdjacentListItem($item_data);
                
                if ( 
    $item->ID() == $this->current_id ){
                    
    $item->is_current true;
                    
    $this->currentItem =& $item;
                }
                
                if ( 
    $item->isRoot() ) {
                    
    $this->adjacent_list[] =& $item;
                    
                    
    $item->number $number;
                    
    $number ++;
                    
                    
    $this->_appendChildren($item);
                }
            }
            
    // resort
            
    reset ($this->adjacent_list);
        }
        
        
    /*
            This sets the level and the number for child nodes recursively
        */
        
    function _appendChildren (& $theItem) {
            
    $number 0;
            foreach (
    $this->items as $item_data ) {
                
    $item =& new AdjacentListItem($item_data);
                if ( 
    $theItem->ID() == $item->parentID() ) {
                    
                    
    $item->parent =& $theItem;
                    
    $item->level $theItem->level 1;
                    
                    if ( 
    $item->ID() == $this->current_id ){
                        
    $item->is_current true;
                        
    $this->currentItem =& $item;
                    }
                    
                    
    $item->number $number;
                    
    $number ++;
                    
                    
    $theItem->children[] =& $item;
                    
    $this->adjacent_list[] =& $item;
                    
    $this->_appendChildren($item);
                }
            }
        }
        
        
    /*
            After the list has been sorted correctly, we can add next and previous referecenes to each item
            This is also where we set each nodes "global" index value
        */
        
    function _finalize(){
            
    $i 0;
            
    $prev null;
            foreach(
    array_keys($this->adjacent_list) as $key){
                
    $item =& $this->adjacent_list[$key];
                
    // set item index
                
    $item->index $i;
                
    $i++;
                
    //
                
    if($prev){
                    
    $item->prev =& $prev;
                    
    $prev->next =& $item;                
                }
                
    $prev =& $item;
            }
        }
    }

    class 
    AdjacentListItem {
        
        
    // properties for item (id, parent_id are required)
        
    var $properties;
        
    // indicates that the item is the item matching the id passed into the AdjacentList's second parameter
        
    var $is_current false;
        
    // The number of the item, relative to it's siblings
        
    var $number null;
        
    // The index of the item relative to the entire tree
        
    var $index null;
        
    // The depth
        
    var $level 0;
        
    // Reference to item's parent
        
    var $parent null;
        
    // Reference to items children
        
    var $children = array();
        
    // reference to next item
        
    var $next null;
        
    // reference to previous item
        
    var $prev null;
        
        function 
    AdjacentListItem($properties){
            
    $this->properties $properties;
        }
        
        function 
    isCurrent(){
            return 
    $this->is_current;
        }
        
        function 
    ID(){
            return 
    $this->get('id');
        }
        
        function 
    parentID(){
            return 
    $this->get('parent_id');
        }
        
        function 
    isRoot(){
            return 
    $this->get('parent_id') == 0;
        }
        
        function 
    hasChildren(){
            return 
    count($this->children);
        }
        
        function 
    level(){
            return 
    $this->level;
        }
        
        function 
    number(){
            return 
    $this->number;
        }
        
        function 
    index(){
            return 
    $this->index;
        }
        
        function 
    isLastChild(){
            if(
    $this->parent){
                return 
    $this->parent->childrencount($this->parent->children) - ]->ID() == $this->ID();
            }else{
                return 
    $this->prev == null;
            }
        }
        
        function 
    isFirstChild(){
            if(
    $this->parent){
                
    $this->parent->children[0]->ID() == $this->ID();
            }else{
                return 
    $this->prev == null;
            }
        }
        
        function 
    get($property){
            if(isset(
    $this->properties[$property])){
                return 
    $this->properties[$property];
            }
        }
        

    And the usage:
    PHP Code:
    $items = array( 
        array( 
            
    'id' => 1
            
    'parent_id' => 0
            
    'name' => 'home' 
        
    ), 
        array( 
            
    'id' => 2
            
    'parent_id' => 0
            
    'name' => 'products' 
        
    ), 
            array( 
                
    'id' => 3
                
    'parent_id' => 2
                
    'name' => 'gallery' 
            
    ), 

        array(
            
    'id' => 7,
            
    'parent_id' => 3,
            
    'name' => 'photos'
        
    ),
        
        array(
            
    'id' => 8,
            
    'parent_id' => 3,
            
    'name' => 'paintings'
        
    ),
        
        array(
            
    'id' => 9,
            
    'parent_id' => 8,
            
    'name' => 'oil'
        
    ),
        
        array( 
            
    'id' => 4
            
    'parent_id' => 0
            
    'name' => 'contact' 
        
    ), 
            array( 
                
    'id' => 5
                
    'parent_id' => 4
                
    'name' => 'staff' 
            
    ), 
            array( 
                
    'id' => 6
                
    'parent_id' => 4
                
    'name' => 'students' 
            

    );


    function 
    formatLIText( & $item){
        
    $item_html '<b><a href="?id=' $item->ID() . '">' $item->get('name') . '</a></b>';
        
    $item_html .= ', index: ' $item->index();
        
    $item_html .= ', number: ' $item->number();
        
    $item_html .= ', level: ' $item->level();
        if(
    $item->isCurrent()){
            
    $item_html '<span style="color:red">' $item_html '</span>';
        }
        return 
    $item_html;
    }

    $list =& new AdjacentList($items, @$_GET['id']);

    $html '<ul>';
    while(
    $item =& $list->fetch()){
        
    $html .= '<li>';
        
        
    $html .= formatLIText($item);
        
        if( 
    $item->hasChildren() ){
            
    $html .= '<ul>';
        }else{
            
    $html .= '</li>';
            if( 
    $item->parent && $item->isLastChild() ){
                
    $html .= str_repeat('</ul></li>'$item->level());
            }
        }
    }
    $html .= '</ul>';

    echo 
    $html

  19. #19
    SitePoint Zealot johno's Avatar
    Join Date
    Sep 2003
    Location
    Bratislava, Slovakia
    Posts
    184
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    That was fast! I re-wrote your code for PHP4, it works great. Really nice job! Where did you get the idea for this (composition, interface etc.) ? Why can't I ever be this clever?
    ...
    Go ahead and use it! I am happy that someone actually really does. The idea of algorithm for building nested list (buildTree) is really old and I first made it for some CMS document tree. Writer interface is a stolen idea from lastcraft's SimpleTest *Reporter/Scorer classes
    Annotations support for PHP5
    TC/OPT™ Group Leader

  20. #20
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is more like what I use for nested sets, it relies on the fact that things are in right display order, and using the relative levels of previous and current item to work out wether the current item is a new child (hence requiring <ul>) or wether the item is a sibling ($delta = 0) or wether the current item is further up the tree, and requires 1 or more closing </ul></li>s.


    PHP Code:
    $html '<ul>'
    unset(
    $previousLevel);
    while(
    $item =& $list->fetch()){

        if (isset(
    $previousLevel))
        {
            
    $delta $previousLevel $item->level;
            if (
    $delta 0)
              {
                  
    $html .= '<ul>';
            }
            else
            {
                
    $html .= '</li>';
                if (
    $delta 0)                
                    
    $html .= str_repeat('</ul></li>'$delta);
            }
        }
        else
            
    $previousLevel $item->level;
            
        
    $html .= '<li>' $item->get('name'); 
        
    $previousLevel $item->level;
    }
    $html .= '</li>';
    if (isset(
    $previousLevel) && $previousLevel 0)
        
    $html .= str_repeat('</ul></li>'$previousLevel);

    $html .= '</ul>'


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •