Ribbo
Ribbo

Reputation: 439

Find the top level parent

I have a MySQL table with id, category_id (parent id), and url.

I have a class that looks something like this. I have removed all unnecessary functions.

class categoriesBuilder
{
    var $items = array();
    var $html  = array();

    function fetch_assoc_all( $sql )
    {
        $result = mysql_query( $sql, $this->conn );

        if ( !$result ){
            return false;
        }

         $assoc_all = array();

         while( $fetch = mysql_fetch_assoc( $result ) ){
                $assoc_all[] = $fetch;
        }

        mysql_free_result( $result );

        return $assoc_all;
    }

    function get_categories()
    {
        $sql = 'SELECT id, category_id, url FROM categories ORDER BY category_id, id;';

        return $this->fetch_assoc_all( $sql );
    }

    function get_category_string($root_id=0)
    {
        $this->html  = array();
        $this->items = $this->get_categories();

        foreach ( $this->items as $item )
            $children[$item['category_id']][] = $item;

        // loop will be false if the root has no children
        $loop = !empty( $children[$root_id] );

        // initializing $parent as the root
        $parent = $root_id;
        $parent_stack = array();

        while ( $loop && ( ( $option = each( $children[$parent] ) ) || ( $parent > $root_id ) ) )
        {
            if ( $option === false )
            {
                $parent = array_pop( $parent_stack );
            }
            elseif ( !empty( $children[$option['value']['id']] ) )
            {
                array_push( $parent_stack, $option['value']['category_id'] );

                $parent = $option['value']['id'];

                // HTML for menu item containing childrens (open)
                $this->html[] = $option['value']['url'] . "/";
            }
            else
            {
                $this->html[] = $option['value']['url'] . "/";
            }
        }

        return implode($this->html );
    }
}

I need a function that returns only the top level parent. there may be several sub categories.

i.e.

In this example if i entered 3, 4 or 5 into the function the output would be 1. if i entered 6 i would get 2.

I also need a similar function that shows all parent folders.

for example if i entered 3 i would get 1 but if i entered 4 or 5 i would get 1-3

Thanks for your help.

Upvotes: 2

Views: 2393

Answers (1)

CarpeNoctumDC
CarpeNoctumDC

Reputation: 1760

Assuming your DB is like this:

(1, 0, URL1), (3, 1, URL3), (4, 3, URL4), (5, 3, URL5), (2, 0, URL2), (6, 2, URL6)

Then you just need to walk up the list

e.g.

function get_top_parent($category_id, $root_id=0)
{
    // Grab the id's and category's
    $item_list = array();
    foreach($this->items as $item) {
        $item_list[$item['id']] = $item['category_id'];
    }

    $current_category = $category_id;

    while(TRUE) {
        if ($item_list[$current_category] == $root_id) {
            // Check to see if we have found the parent category.
            return $current_category;
        } else {
            // update our current category
            $current_category = $item_list[$current_category];
        }
    }

}

function get_parents($category_id, $root_id=0) 
{
    $parents = array();
    // Grab the id's and category's
    $item_list = array();
    foreach($this->items as $item) {
        $item_list[$item['id']] = $item['category_id'];
    }

    $current_category = $category_id;
    while(TRUE) {
        // Check to see if we have found the root category.
        if ($item_list[$current_category] == $root_id) {
            return $parents;
        } else {
            // update our current category and parents
            $current_category = $item_list[$current_category];
            array_unshift($parents, $current_category);
        }
    }

}

reworked to return URL (I did not verify this code but it should work):

function get_top_parent($category_id, $root_id=0) 
{ 
    // Grab the id's and category's 
    $item_list = array(); 
    foreach($this->items as $item) { 
        $item_list[$item['id']] = array(
            'category_id'   => $item['category_id'],
            'url'           => $item['url']
        );
    } 

    $current_category = $category_id; 

    while(TRUE) { 
        if ($item_list[$current_category]['category_id'] == $root_id) { 
            // Check to see if we have found the parent category. 
            return $item_list[$current_category]['url']; 
        } else { 
            // update our current category 
            $current_category = $item_list[$current_category]['category_id']; 
        } 
    } 

} 

function get_parents($category_id, $root_id=0)  
{ 
    $parents = array(); 
    // Grab the id's and category's 
    $item_list = array(); 
    foreach($this->items as $item) { 
        $item_list[$item['id']] = array(
            'category_id' => $item['category_id'],
            'url' => $item['url']
        );
    } 

    $current_category = $category_id; 
    while(TRUE) { 
        // Check to see if we have found the root category. 
        if ($item_list[$current_category]['category_id'] == $root_id) { 
            return $parents; 
        } else { 
            $temp_array = array(
                'category_id'   => $current_category
                'url'           => $item_list[$current_category]['url']
            );
            // update our current category and parents 
            $current_category = $item_list[$current_category]['category_id']; 
            array_unshift($parents, $temp_array); 
        } 
    } 

} 

The first function returns the URL, the second function should return an array of arrays... You will have the standard index, with "category_id" and "url" as nested/sub arrays... (If in doubt, just do a print_r of the return value to see what I mean)

again, i checkced the origional code but not the update...

Upvotes: 1

Related Questions