2

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.

Erick G. Hagstrom
  • 4,873
  • 1
  • 24
  • 38
  • 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 Feb 15 '13 at 10:34
  • 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 Feb 15 '13 at 11:09
  • As promised - with some more documentation: http://www.dereuromark.de/2013/02/17/cakephp-and-tree-structures/ – mark Feb 17 '13 at 23:19
  • Thanks a lot Mark, i'm gonna read it right away! Thanks again for your help. – Julian Livin' in China Feb 19 '13 at 09:15

2 Answers2

0

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']));
mark
  • 21,691
  • 3
  • 49
  • 71
  • Thanks Mark, i'm gonna try it. I just have one "stupid" question because i don't know cakephp very well yet, the first code is to be put in the controller? And i hope it's not too much but what do i put in my view to display the result as a list ul-li? Thank you very much for your time and your help! Oh and by the way, when do you plan to put your tutorial online? – Julian Livin' in China Feb 15 '13 at 12:31
  • I updated my answer accordingly. Probably this sunday. But since the files are already online: Take a look at the test cases for the helper for further details on the above options and its usage as well as the expected output for those. – mark Feb 15 '13 at 13:06
  • ok that's great look forward to see it. I would appreciate if you could keep me touch when it's done then ;), just leave another comment i'll check the newt coming days for it :) Thanks again for your help – Julian Livin' in China Feb 15 '13 at 13:29
0

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);
Jojodmo
  • 23,357
  • 13
  • 65
  • 107
mate.gvo
  • 1,093
  • 14
  • 20