2
votes

For CakePHP 2

I would like to create a categories menu which would list the categories of my products. It's a 3 levels menu. Each category in the menu is a link that opens a page listing all the products that belong to it. So if the category is a parent one, it should list all the products contained in the children, the 2 sub-levels. Also, if the category is a children, it should link to a listing page of the products that belong to it.

With that said, here's what I've done so far.

I created my categories table according to cake's conventions with the following columns:

id--parent_id--lft--rght--name

Then my products' table:

id--name--slug--category_id

Now the Category.php model:

    <?php
class Category extends AppModel {

    public $name = 'Category';

    public $actsAs = array('Tree');

    public $belongsTo = array(
        'ParentCategory' => array(
            'className' => 'Category',
            'foreignKey' => 'parent_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
            )
        );

    public $hasMany = array(
        'ChildCategory' => array(
            'className' => 'Category',
            'foreignKey' => 'parent_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
            )
        );
}

I'm using the ProductsController to render the categories menu because this is the page that will hold this categories menu:

    <?php
class ProductsController extends AppController{

    public $uses = array('Product');

    public function index(){ 
       $this->layout = 'products';
       $this->loadModel('Category'); 
       $this->set('data',$this->Category->generateTreeList()); 
    }
}

and my index.ctp view:

<?php debug($categories); ?>

What i would like now is to build a nested ul-li menu of my categories that link to the products page they belong according to the tree.

<ul class="ulclass">
    <li class="liclass"><a href="category">category</a></li>
</ul>

I checked only for this kind of tutorial, unfortunately I didn't find anything well explained, I did find a TreeHelper but i have no idea how to use it >>> TreeHelper from Github

However, I would like to have the control on my category's tree menu by having the possibility to add css classes. If you think this helper can provide me this construction so it's fine then. But I have no idea how to use it though. And not to mention that I'm new to CakePHP :( but I want to learn it because it's a great tool.

I forgot something about my DB, do I have to add any other column in my tables to make this system work or is it correct as is?

Last thing, as I didn't find anything for CakePHP 2 about this categories/products dynamic tree menu, I will share the entire code on Github so that it can help many others.

2
If you would have waited a few more days, I was just about to write a tutorial/article on how to work with trees in cake - also on my improved version of the tree helper :) You need to leverage elements or callbacks here (I prefer the first).mark
Hi mark, seems great indeed! Right now i'm really stuck on this problem so i guess i have no choice but to wait :) However, would you have any advice regarding my system so that i can keep trying get something out of it?Julian Livin' in China
As promised - with some more documentation: dereuromark.de/2013/02/17/cakephp-and-tree-structuresmark
Thanks a lot Mark, i'm gonna read it right away! Thanks again for your help.Julian Livin' in China

2 Answers

0
votes

All right. Assuming you use my updated version:

// in your controller
$categories = $this->Model->children($id);
// or
$categories = $this->Model->find('threaded', array(...));

Then pass it down to the view.

// in your view ctp
$categories = Hash::nest($categories); // optional, if you used find(all) instead of find(threaded) or children()

$treeOptions = array('id' => 'main-navigation', 'model' => 'Category', 'treePath' => $treePath, 'hideUnrelated' => true, 'element' => 'node', 'autoPath' => array($currentCategory['Category']['lft'], $currentCategory['Category']['rght']));

echo $this->Tree->generate($categories, $treeOptions);

And here an example of the element in /Elements/node.ctp:

$category = $data['Category'];
if (!$category['active'] || !empty($category['hide'])) { // You can do anything here depending on the record content
    return;
}
echo $this->Html->link($category['name'], array('action' => 'find', 'category_id' => $category['id']));
0
votes

Here is a simple solution, Used in controller for index view. Later you use it by two for each loops for each $posts as $post and foreach $post['Post']['children'].

$posts = $this->Post->find('all', array('conditions' => array('parent_id'=>null)));
    foreach ($posts as $postKey => $post) {
        $posts[$postKey]['Post']['children'] = $this->Post->find('all', array('conditions' => array('parent_id'=>$post['Post']['id'])));
    }         
    $this->set('posts', $posts);