Fork me on GitHub

My CakePHP Category Tree Helper

My CakePHP Category Tree Helper

Hey everyone. Not so much a tutorial here, but more so a snippet of code to help some of you out. My problem was with the CakePHP tree component. The way that the tree organised data in CakePHP works is through establishing a neighbour like system, where the elements are located through analysing not only the parent and children relationships but through where each element is located according to its neighbour. The problem i found with this when it comes to categories is that CakePHP does not seem to have a way to ignore this left and right neighbour checks, and in turn order the data.

So after asking around a bit i decided to write my own method of ordering my tree data in the database, which was a Category list to be used in a select box. My helper came out to be:

/app/views/helpers/tree.php

<?php
	
	class TreeHelper extends AppHelper {
		
		function indentTree($array, $counter=0){
			$ret = '';
			$array2 = array();
			$pre = '';
			for($i = 1;$i < $counter; $i++){
				$pre .= '--';
			}
			
			foreach($array as $key => $value){
				if($key == 'children'){
					if(isset($value['Category']) || (isset($value['children']) && sizeof($value['children']) > 0)){
						$indented[] = $this->indentTree($value, ++$counter);
					} else {
						if(sizeof($value) > 0) {
							$indented[] = $this->indentTree($value, $counter);
						}
					}
				}	elseif($key == 'Category'){
					$indented[$value['id']] = ' '.$pre.' '.$value['name'];
				}	elseif(isset($value['Category']['name'])){
					$indented[] = $this->indentTree($value, $counter);	
				}
			}
			return $this->flatten_array($indented, 2);
		}
		
		function flatten_array($array, $preserve_keys = 0, &$out = array()) {
			foreach($array as $key => $child){
				if(is_array($child)){
					$out = $this->flatten_array($child, $preserve_keys, $out);
				} elseif($preserve_keys + is_string($key) > 1){
					$out[$key] = $child;
				} else {
					$out[] = $child;
				}
			}
			return $out;
		}
		
	}	
	
?>

To use this simply include the helper in your controller via:

var $helpers = array('Html', 'Form', 'Text', 'Javascript', 'Tree');

And then within your action you must select the data in a threaded form, the same as GenerateTreeList would do, however pre-ordered:

$categories = $this->Category->find('threaded', array('order' => array('Category.name' => 'ASC')));
$this->set('categoriesList', $categories);

Next up you use the helper in your view via:

echo $form->input('parent_id', array('type'=>'select', 'options'=>$tree->indentTree($categoriesList), 'empty'=>'--------', 'div'=>'row'));

And thats it!
For me this will return an ordered flattened array of my categories to be used within the select box!
I know this explanation is a bit low but it should be enough to get you started! If you have any questions please comment and i will see what i can do to help you out!

Posted by voidet

Categorised under CakePHP
Bookmark the permalink or leave a trackback.

2 Comments

  1. Thanks for the helper !

    Very useful when the Tree & Translate behaviors are needed together.

    generatetreelist doesn’t seems to work with the Translate behaviors.

    February 13, 2011 @ 5:09 am
  2. Thanks, exactly what I was looking for!

    I made a change to the “indentTree” funciton on my end to make it a little more re-usable with different models:


    function indentTree($array, $modelName = "Category", $displayField = "name", $childField = "children", $counter=0){
    $ret = '';
    $array2 = array();
    $pre = '';
    for($i = 1;$i $value){
    if($key == $childField){
    if(isset($value[$modelName]) || (isset($value[$childField]) && sizeof($value[$childField]) > 0)){
    $indented[] = $this->indentTree($value, $modelName, $displayField, $childField, ++$counter);
    } else {
    if(sizeof($value) > 0) {
    $indented[] = $this->indentTree($value, $modelName, $displayField, $childField, $counter);
    }
    }
    } elseif($key == $modelName){
    $indented[$value['id']] = ' '.$pre.' '.$value[$displayField];
    } elseif(isset($value[$modelName][$displayField])){
    $indented[] = $this->indentTree($value, $modelName, $displayField, $childField, $counter);
    }
    }
    return $this->flatten_array($indented, 2);
    }

    September 13, 2011 @ 7:35 am

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

or