SitePoint Sponsor

User Tag List

Results 1 to 6 of 6

Hybrid View

  1. #1
    SitePoint Addict
    Join Date
    Dec 2005
    Posts
    336
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    Displaying a Multilevel Tree

    Thanks to Rudy Limeback's tutorial about Categories and Subcategories and the Simply SQL book, I am writing better sql and reducing my queries in my scripts...

    But I am having an issue with displaying this format using Rudy's first example from Displaying all categories and subcategories: site maps and navigation bars

    My query gives me this
    animal birdie NULL NULL
    animal doggie companion chihuahua
    animal doggie companion poodle

    And I need PHP to output
    animal
    - birdie
    - doggie
    -- companion
    --- chihuahua
    --- poodle

    But it gives me
    animal
    animal
    - birdie
    animal
    - doggie
    etc etc

    Any tips on how make this happen the correct way (and faster, my code is very bloated..)?

  2. #2
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,135
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    First you need to build the tree.

    PHP Code:
    <?php
    class Animal {

        protected 
    $animals;    
        protected 
    $name;
        
        public function 
    __construct($name) {
        
            
    $this->animals = array();
            
    $this->name $name;
        
        }
        
        public function 
    matches($pk) {
        
            return 
    strcasecmp($pk,$this->getName())==0;
        
        }
        
        public function 
    getName() {
            return 
    $this->name;
        }
        
        public function 
    addAnimal(Animal $animal) {
        
            
    $this->animals[] = $animal;
        
        }
        
        public function 
    getAnimals() {
            return 
    $this->animals();
        }
        
        public function 
    hasAnimals() {
            return empty(
    $this->animals)?false:true;
        }
        
        public function 
    hasAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    true;
                }
            
            }
            
            return 
    false;
        
        }
        
        public function 
    getAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    $animal;
                }
            
            }        
        
        }
        
        public function 
    addRow($row,$runner=1) {
        
            if(!
    array_key_exists($runner,$row)) return;
            if(
    is_null($row[$runner])) return;
        
            if(
    $this->hasAnimals()===true && $this->hasAnimalByName($row[$runner])===true) {
                
    $childAnimal $this->getAnimalByName($row[$runner]);    
            } else {
                
    $childAnimal = new Animal($row[$runner]);
                
    $this->addAnimal($childAnimal);
            }
        
            
    $childAnimal->addRow($row,($runner+1));        
        
        }

    }

    $animals = array();
    $result = array(
        array(
    'animal','birdie',null,null)
        ,array(
    'animal','doggie','companion','chihuahua')
        ,array(
    'animal','doggie','companion','poodle')
    );

    foreach(
    $result as $row) {

        
    $currentRootAnimal null;
        
        if(!empty(
    $animals)) {
        
            foreach(
    $animals as $animal) {
                if(
    $animal->matches($row[0])===true) {
                    
    $currentRootAnimal $animal;
                    break;
                }
            }
        
        } else {
            
    $currentRootAnimal = new Animal($row[0]);
            
    $animals[] = $currentRootAnimal;
        }
        
        
    $currentRootAnimal->addRow($row,1);

    }

    echo 
    '<pre>',print_r($animals),'</pre>';
    ?>

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,135
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Actually this more like what you would want so that you can map each depth to the appropriate row key in the result set.

    PHP Code:
    <?php
    class Animal {

        protected 
    $animals;    
        protected 
    $name;
        
        public function 
    __construct($name) {
        
            
    $this->animals = array();
            
    $this->name $name;
        
        }
        
        public function 
    matches($pk) {
        
            return 
    strcasecmp($pk,$this->getName())==0;
        
        }
        
        public function 
    getName() {
            return 
    $this->name;
        }
        
        public function 
    addAnimal(Animal $animal) {
        
            
    $this->animals[] = $animal;
        
        }
        
        public function 
    getAnimals() {
            return 
    $this->animals();
        }
        
        public function 
    hasAnimals() {
            return empty(
    $this->animals)?false:true;
        }
        
        public function 
    hasAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    true;
                }
            
            }
            
            return 
    false;
        
        }
        
        public function 
    getAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    $animal;
                }
            
            }        
        
        }
        
        public function 
    addRow($row,$map,$runner=0) {
            
            if(!
    array_key_exists($runner,$map)) return;
            
    $key $map[$runner];
            if(!
    array_key_exists($key,$row)) return;
            if(
    is_null($row[$key])) return;
        
            if(
    $this->hasAnimals()===true && $this->hasAnimalByName($row[$key])===true) {
                
    $childAnimal $this->getAnimalByName($row[$key]);    
            } else {
                
    $childAnimal = new Animal($row[$key]);
                
    $this->addAnimal($childAnimal);
            }
        
            
    $childAnimal->addRow($row,$map,($runner+1));        
        
        }

    }

    $animals = array();
    $result = array(
        array(
    'animal','birdie',null,null)
        ,array(
    'animal','doggie','companion','chihuahua')
        ,array(
    'animal','doggie','companion','poodle')
    );

    foreach(
    $result as $row) {

        
    $currentRootAnimal null;
        
        if(!empty(
    $animals)) {
        
            foreach(
    $animals as $animal) {
                if(
    $animal->matches($row[0])===true) {
                    
    $currentRootAnimal $animal;
                    break;
                }
            }
        
        } else {
            
    $currentRootAnimal = new Animal($row[0]);
            
    $animals[] = $currentRootAnimal;
        }
        
        
    $currentRootAnimal->addRow($row,array(1,2,3));

    }

    echo 
    '<pre>',print_r($animals),'</pre>';
    ?>

  4. #4
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,135
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Will build the tree and make the menu.

    PHP Code:
    <?php
    class Animal {

        protected 
    $animals;    
        protected 
    $name;
        
        public function 
    __construct($name) {
        
            
    $this->animals = array();
            
    $this->name $name;
        
        }
        
        public function 
    matches($pk) {
        
            return 
    strcasecmp($pk,$this->getName())==0;
        
        }
        
        public function 
    getName() {
            return 
    $this->name;
        }
        
        public function 
    addAnimal(Animal $animal) {
        
            
    $this->animals[] = $animal;
        
        }
        
        public function 
    getAnimals() {
            return 
    $this->animals;
        }
        
        public function 
    hasAnimals() {
            return empty(
    $this->animals)?false:true;
        }
        
        public function 
    hasAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    true;
                }
            
            }
            
            return 
    false;
        
        }
        
        public function 
    getAnimalByName($name) {
        
            foreach(
    $this->animals as $animal) {
            
                if(
    $animal->matches($name)==true) {
                    return 
    $animal;
                }
            
            }        
        
        }
        
        public function 
    addRow($row,$map,$runner=0) {
            
            if(!
    array_key_exists($runner,$map)) return;
            
    $key $map[$runner];
            if(!
    array_key_exists($key,$row)) return;
            if(
    is_null($row[$key])) return;
        
            if(
    $this->hasAnimals()===true && $this->hasAnimalByName($row[$key])===true) {
                
    $childAnimal $this->getAnimalByName($row[$key]);    
            } else {
                
    $childAnimal = new Animal($row[$key]);
                
    $this->addAnimal($childAnimal);
            }
        
            
    $childAnimal->addRow($row,$map,($runner+1));        
        
        }
        
        public function 
    buildMenu() {

            if(
    $this->hasAnimals()===true) {
                echo 
    '<ul>',"\n";
                foreach(
    $this->getAnimals() as $item) {
                
                    if(
    $item->hasAnimals()===true) {
                
                        echo 
    '<li>',$item->getName();
                        
    $item->buildMenu();
                        echo 
    '</li>',"\n";
                
                    } else {
                
                        echo 
    '<li>',$item->getName(),'</li>',"\n";
                
                    }
                
                }
                echo 
    '</ul>',"\n";
            }

        }

    }

    $animals = array();
    $result = array(
        array(
    'animal','birdie',null,null)
        ,array(
    'animal','doggie','companion','chihuahua')
        ,array(
    'animal','doggie','companion','poodle')
    );

    foreach(
    $result as $row) {

        
    $currentRootAnimal null;
        
        if(!empty(
    $animals)) {
        
            foreach(
    $animals as $animal) {
                if(
    $animal->matches($row[0])===true) {
                    
    $currentRootAnimal $animal;
                    break;
                }
            }
        
        } else {
            
    $currentRootAnimal = new Animal($row[0]);
            
    $animals[] = $currentRootAnimal;
        }
        
        
    $currentRootAnimal->addRow($row,array(1,2,3));

    }

    if(!empty(
    $animals)) {
        echo 
    '<ul id="animal-menu">';
        foreach(
    $animals as $animal) {

            if(
    $animal->hasAnimals()===true) {
            
                echo 
    '<li>',$animal->getName();
                
    $animal->buildMenu();
                echo 
    '</li>',"\n";        
            
            } else {
            
            
            }

        }
        echo 
    '</ul>';
    }

    ?>

  5. #5
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is less flexible than what oddz posted, but I'm posting it in hopes it may help you understand the logic better. Hopefully you have a grasp of recursion, as this makes heavy use of it.

    PHP Code:
    // transforms array(1, 2, 3) to array(1 => array(2 => array(3 => array()))
    // stops when null is encountered
    function flatarray_to_heiarchy($array) { 
        
    $node array_shift($array);
        return 
    is_null($node) ? array() : array($node => flatarray_to_heiarchy($array));
    }

    function 
    to_html_tree($array) {
        
    $ul_content '';
        foreach (
    $array as $name => $children) {
            
    $more_ul_content count($children) ? to_html_tree($children) : '';
            
    $ul_content .= "<li>$name $more_ul_content</li>";
        }
        return 
    "<ul>$ul_content</ul>";

    PHP Code:
    $tree = array();
    while (
    $row mysql_fetch_assoc($result)) {
        
    $tree array_merge_recursive($treeflatarray_to_heiarchy($row));
    }
    // print_r($tree);
    echo to_html_tree($tree); 

  6. #6
    SitePoint Addict
    Join Date
    Dec 2005
    Posts
    336
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    oddz, crmalibu,
    Thank you both for the code ideas.

    To note, I will be pull more information than just the name

    Oddz, your code went way over my head and testing it out didn't do to well.
    Crmalibu, testing your code worked for just the name, but adding other stuff severly broke the output.

    My query that I will be using (toned it down and at a 2 levels)
    $query = "
    select
    r.id as r_id, r.name as r_name, r.uri as r_uri,
    r.date as r_date, r.status as r_status, r.entry_order as r_order,
    l1.id as l1_id, l1.name as l1_name, l1.uri as l1_uri,
    l1.date as l1_date, l1.status as l1_status, l1.entry_order as l1_order
    from entries as r
    left outer join entries as l1
    on l1.parent_id = r.id
    where r.parent_id isnull
    and r.type = 'page'
    order by
    r.entry_order,
    l1.entry_order
    ";
    The output:
    Array
    (
    [r_id] => 1
    [r_name] => Home
    [r_uri] =>
    [r_date] => 2009-05-10 04:10:02
    [r_status] => 1
    [r_order] => 0
    [l1_id] =>
    [l1_name] =>
    [l1_uri] =>
    [l1_date] =>
    [l1_status] =>
    [l1_order] =>
    )
    Array
    (
    [r_id] => 3
    [r_name] => TestPage
    [r_uri] => testpage
    [r_date] => 2009-05-10 04:10:02
    [r_status] => 1
    [r_order] => 0
    [l1_id] => 4
    [l1_name] => subPage
    [l1_uri] => subpage
    [l1_date] => 2009-05-10 04:10:02
    [l1_status] => 1
    [l1_order] => 0
    )
    Array
    (
    [r_id] => 3
    [r_name] => TestPage
    [r_uri] => testpage
    [r_date] => 2009-05-10 04:10:02
    [r_status] => 1
    [r_order] => 0
    [l1_id] => 7
    [l1_name] => SubTwo
    [l1_uri] => subtwo
    [l1_date] =>
    [l1_status] => 1
    [l1_order] => 1
    )


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
  •