Welcome Guest, Not a member yet? Register   Sign In
Using CI for controlling page hierarchical elements based on URI
#1

[eluser]MEM[/eluser]
On my model, I have a method responsible for retrieving database data, grab that information and, return an hierarchical array.

On my controller, I have a method that accepts one parameter.
That parameter, will be filled by the URI third segment. Then, it will use that ID, pass it to the model method, and also, call a view.

On my view, I'm trying to build a list of links based on the information that has come from the model (trough the controller).
However, that list of links should be larger or shorter according to the URI changes.

I will need to use recursion, in order to display child elements of the array. However, I want this recursion to be activated only when the URI matches some values.
:exclaim:

The question is now more structural then practical:
Where should we deal with this conditional? Should we build it on our view? Or on our controller? Can anyone provide me some sketch example to kick me out of this mud?


Regards,
Márcio
#2

[eluser]n0xie[/eluser]
I don't really understand your problem. If the recursion should only happen when it calls a certain controller/method, then there is no need to do an if statement?
#3

[eluser]MEM[/eluser]
I see your point.
Maybe I will have no need for a conditional, but besides that, I'm still not grasping how could this be done.

In order to better explain my question,
Please have a look on the following link:
http://www.nuvemk.com/c_categoria/seccao/1

On this page,
* Herbicidas
* Insecticidas
* Fungicidas

are child elements on the array. I don't what them to appear, on this page.
I want then to appear, only when we click the parent "Fitofármacos", hence, only when the URI third segment changes to match "Fitofármacos" id.

This works (try to click on "Fitofármacos") and you will see it work.
However, and this is the main issue, I'd like to preserve the parents links. (Right now, they disappear).

Hope this is clear, if not, please, I will provide all needed details.

Márcio
#4

[eluser]Phil Sturgeon[/eluser]
I did this and it REALLY hurt my head.

The model function is...

Code:
public function getByURL($segments = array())
    {
        // If the URI has been passed as a string, explode to create an array of segments
        if(is_string($segments))
        {
            $segments = explode('/', $segments);
        }
        
        // Work out how many segments there are
        $total_segments = count($segments);
        
        // Which is the target alias (the final page in the tree)
        $target_alias = 'p'.$total_segments;

        // Start Query, Select (*) from Target Alias, from Pages
        $this->db->select($target_alias.'.*');
        $this->db->from('pages p1');
        
        // Loop thorugh each Slug
        $level = 1;
        foreach( $segments as $segment )
        {
            // Current is the current page, child is the next page to join on.
            $current_alias = 'p'.$level;
            $child_alias = 'p'.($level - 1);
    
            // We dont want to join the first page again
            if($level != 1)
            {
                $this->db->join('pages '.$current_alias, $current_alias.'.parent_id = '.$child_alias.'.id');
            }
            
            // Add slug to where clause to keep us on the right tree
            $this->db->where($current_alias . '.slug', $segment);
    
            // Increment
            $level++;
        }
        
        // Can only be one result
        $this->db->limit(1);
        
        return $this->db->get()->row();
    }

It may look like a mess but if you can clean that down I will give you a medal. It works fine, just pass it $this->uri->segment_array();

The basic idea here is that I have pages that can be children of any other pages. Meaning I can have page1/page2/page3. The URI segment is called 'slug' and I check the slug at each level of the loop to keep the join accurate. This stops it wondering off and joining to incorrect children.

Let me know if this code is confusing as hell. I can write it up better this evening.
I alias each level p1, p2, p3, p4 etc dynamically and only request the highest level in the select(). That means if I have a page 4 levels deep, I don't want to return level 1, 2 or 3 data.
#5

[eluser]MEM[/eluser]
Ok... The true story is that I'm really newbie. And I'm programming alone. My only hope is mailing-lists and forums.
So, I was having several days for trying to understand how to grab hierarchical information on the database, I don't want to throw them away.
Confused

Phil, do you mind if we look into the code that I already have and try to insert CI uri->segment logic there? Can I have your help on that?

If so, I will post my model, controller and view code, hopping that, that could be a nice starting point for those who, like me, may be dying on the same "stuck HUGE stone". Confused


Please Advice,
Márcio
#6

[eluser]MEM[/eluser]
Again, the point is to have Parent and Childs to appear on the same page. When we click on a specific Parent and the URI changes to that ID, all the parents that were on the page AND the childs (if they exist) of that specific parent, should appear:

The model returns an hierarchical array*:

Code:
public function getSubCategorias($id_cat,$intDepth=2)
    {    
        
        $strSQL = 'SELECT c.id_cat,c.nome_cat,c.parent_id_cat FROM categoria c';
        $query = $this->db->query($strSQL);
        
        $arrQuery = $query->result_array();
        
        return $this->_parseResultTree($id_cat,$arrQuery,$intDepth, $intRunner=0);
        
    }


     private function _parseResultTree($intParentId,&$arrRows,$intDepth,$intRunner)
     {
        
        // stop at this depth, portanto, só devolve o array, caso a Depth seja igual ao Runner.
        if($intDepth == $intRunner)
        {
            return array();
        }
    
        $arrChildren = array();

        for($i=0;$i<count($arrRows);$i++)
        {
            if($intParentId == $arrRows[$i]['parent_id_cat'])
            {
                $arrChildren = array_merge($arrChildren,array_splice($arrRows,$i--,1));
            }
        }
    
        $intChildren = count($arrChildren);
        if($intChildren != 0)
        {
            for($i=0;$i<$intChildren;$i++)
            {
                $arrChildren[$i]['children'] = $this->_parseResultTree($arrChildren[$i]['id_cat'],$arrRows,$intDepth,$intRunner++);
            }        
        }
    
        return $arrChildren;
    
    }

The controller,grabs the URI and pass that URI to the model and load a template:

Code:
function seccao($id)
    {
    
        /*
        * Fetch category data from model
        */
        $cat = $this->M_Categoria->getCategoria($id);
    
        /*
        * Fetch main categories menu. (it's another menu).
        */  
        $data['menuprincipal'] = $this->M_Categoria->getCategoriasPrincipais();
    
        /*
        * Fetch category tree lower level categories - 2 levels
        */
        $data['menucategorias'] = $this->M_Categoria->getSubCategorias($cat->id_cat,2);
        
        /*
        * load data in template
        */
        $data['main'] = 'v_categoria';
        $data['titulo'] = "As nossas soluções para ".$cat->nome_cat;
        $this->load->vars($data);
        $this->load->view('geral_tpl');

     }


The view:

Code:
function parse_into_menu($arrMenu,$strChildKey,$strNameKey,$strIdKey,$intRunner=0)
{
    
    $strNL = "\n";
    $intMenu = count($arrMenu);
        
    //allow uri->segment inside a function
    $CI =& get_instance();
        
    
    for($i=0;$i<$intMenu;$i++)
    {
        if($i==0)
        {
           echo '<ul>',$strNL;
        }
        
        //Se o segment is equal to parent
        if ($CI->uri->segment(3)==$arrMenu[$i]['parent_id_cat'])
        {
            // show child:
            echo '<li>';
                echo anchor("c_categoria/seccao/".$arrMenu[$i][$strIdKey],$arrMenu[$i][$strNameKey]),$strNL;
            echo '</li>';
    
        }
    
        //if equal to child:
        else if ($CI->uri->segment(3) == $arrMenu[$i][$strIdKey])
        {
            
            //show child:
            echo '<li>';
                echo anchor("c_categoria/seccao/".$arrMenu[$i][$strIdKey],$arrMenu[$i][$strNameKey]),$strNL;
            echo '</li>';
            
            //and childs child: (recursion)
            echo '<li>';
                parse_into_menu($arrMenu[$i][$strChildKey],$strChildKey,$strNameKey,$strIdKey,$intRunner+1);
            echo '</li>';
            
            
            
    
        }
        //If not equal to anything:
        else
        {
         //show childs.    
         echo '<li>';
         echo anchor("c_categoria/seccao/".$arrMenu[$i][$strIdKey],$arrMenu[$i][$strNameKey]),$strNL;
         echo '</li>';
    
        }
        
        
        if($i==($intMenu-1))
        {
           echo '</ul>',$strNL;
        }
    
    }//fim do ciclo for
}

parse_into_menu($menucategorias,'children','nome_cat','id_cat');



*The structure of the returned array:
Code:
$print_r($menucategorias);
:

Array (
[0] => Array (
[id_cat] => 6
[nome_cat] => Fitofármacos
[parent_id_cat] => 1
[children] => Array (

[0] => Array (
[id_cat] => 9
[nome_cat] => Herbicidas
[parent_id_cat] => 6
[children] => Array ( ) )

[1] => Array (
[id_cat] => 10
[nome_cat] => Insecticidas
[parent_id_cat] => 6
[children] => Array ( ) )

[2] => Array (
[id_cat] => 11
[nome_cat] => Fungicidas
[parent_id_cat] => 6
[children] => Array ( )
)
)


)

[1] => Array (
[id_cat] => 7
[nome_cat] => Adubos
[parent_id_cat] => 1
[children] => Array ( )
)

[2] => Array (
[id_cat] => 8
[nome_cat] => Sementes
[parent_id_cat] => 1
[children] => Array ( )
)

)

The issue must be related only with the view part. When we click on the parent link, i'm unable to show both parent and child, side by side. Confused



Any help ???




Theme © iAndrew 2016 - Forum software by © MyBB