i´m using a getAllThreaded call to get some categories and want to
build a category menu which has a highligting(css) class set for its
parent(s) and itself when clicked.
building a stateless menu is not that hard, but keeping track of the
parent categories really beat the shxx out of me. I had this problem in
several cms systems and could never really solve it.
After those stateless tries i found a pretty neat looking walker class
in the new wordpress 2.1beta. i started building a helper whit it,
which just gets the raw categories(unthreaded) and builds a menu tree.
navigation features should be:
- accept any cake array which uses the selfjoining parent_id
- markup from top parent to current element
- define the depth to walk down
- flexible output
- easy call in view
the following code did not really worked because if the nested
menuitems are not directly behind each other in the cat array the
nesting fails. this is probably due to my lack of knowledge about
recursion or coding in general. (In Wordpress they are using this class
to iterate over array of objects). So this needs some heavy recoding!
Anyway i´ll post it here and maybe somebody with an equal problem can
help me out or even better, propose a smarter solution than this one.
please don´t be to hard on me if you think this is crap.
helper file walker.php:
<?php
// A class for displaying various tree-like structures.
#Extend the Walker class to use it, see examples at the bottom
class Walker
{
var $tree_type;
var $db_fields;
//abstract callbacks must be overwritten in subclass
function start_lvl($output) { return $output; }
function end_lvl($output) { return $output; }
function start_el($output) { return $output; }
function end_el($output) { return $output; }
/**
[EMAIL PROTECTED] walk an array and
* @param array $elements - a cake dataset array [0]=>array['category']
* @param string $type, name of the subarray -> cakespecific
array[Category: type ][id]
* @param int $to_depth - how deep shal we go
*/
function walk($elements, $type, $to_depth)
{
$args = array_slice(func_get_args(), 2);
$parents = array();
$depth = 1;
$previous_element = '';
$output = '';
#local id field
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
//padding at the end so we need to know when to stop
$last_element[$type][$id_field] = 0;
$last_element[$type][$parent_field] = 0;
$elements[] = $last_element;
$flat = ($to_depth == -1) ? true : false;
foreach ( $elements as $element )
{#debug($previous_element);
if ( $flat)
{ // If flat, start and end the element and skip the
level checks.
if ( isset($element[$type][$id_field]) &&
$element[$type][$id_field] != 0 )
{// Start the element.
$cb_args = array_merge( array($output,
$element, $depth - 1),
$args);
$output =
call_user_func_array(array(&$this, 'start_el'),
$cb_args);
}
if ( isset($element[$type][$id_field]) &&
$element[$type][$id_field] != 0 )
{// End the element.
$cb_args = array_merge( array($output,
$element, $depth - 1),
$args);
$output =
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}
continue;
}
// Walk the tree.
if ( !empty($previous_element) &&
$element[$type][$parent_field] ==
$previous_element[$type][$id_field] )
{ // Previous element is my parent. Descend a level.
array_unshift($parents, $previous_element);
$depth++; //always do this so when we start the
element further
down, we know where we are
if ( !$to_depth || ($depth < $to_depth) )
{ //only descend if we're below $to_depth
$cb_args = array_merge( array($output,
$depth - 1), $args);
$output =
call_user_func_array(array(&$this, 'start_lvl'),
$cb_args);
}
else
{ // If we've reached depth, end the previous
element.
$cb_args = array_merge( array($output,
$previous_element, $depth -
1), $args);
$output =
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}
}
else if ( !empty($previous_element)
&& $element[$type][$parent_field] ==
$previous_element[$type][$parent_field])
{
// On the same level as previous element.
if ( !$to_depth || ($depth <= $to_depth) )
{
$cb_args = array_merge( array($output,
$previous_element, $depth -
1), $args);
$output =
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}
}
else if ( $depth > 1 )
{
// Ascend one or more levels.
if ( !$to_depth || ($depth <= $to_depth) )
{
$cb_args = array_merge( array($output,
$previous_element, $depth -
1), $args);
$output =
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}
while ( $parent = array_shift($parents) )
{
$depth--;
if ( !$to_depth || ($depth < $to_depth)
)
{
$cb_args = array_merge(
array($output, $depth - 1), $args);
$output =
call_user_func_array(array(&$this, 'end_lvl'),
$cb_args);
$cb_args = array_merge(
array($output, $parent, $depth - 1),
$args);
$output =
call_user_func_array(array(&$this, 'end_el'),
$cb_args);
}
if (!empty($parents[0]) &&
$element[$type][$parent_field] ==
$parents[0][$type][$id_field] )
{#parent id of current element equals
parents id .. get out
break;
}
}
}
else if ( !empty($previous_element) )
{
// Close off previous element.
if ( !$to_depth || ($depth <= $to_depth) )
{
$cb_args = array_merge( array($output,
$previous_element, $depth -
1), $args);
$output =
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}
}
// Start the element.
if ( !$to_depth || ($depth <= $to_depth) )
{
if ( $element[$type][$id_field] != 0 )
{
$cb_args = array_merge( array($output,
$element, $depth - 1),
$args);
$output =
call_user_func_array(array(&$this, 'start_el'),
$cb_args);
}
}
$previous_element = $element;
}
return $output;
}
}
/*
here we just overwrite the emtpy output methods of the parent
the parent jus has the walk method
*/
class CatWalk extends Walker
{
var $tree_type = 'category';
var $db_fields = array ('parent' => 'parent_id', 'id' => 'id');
function start_lvl($output, $depth)
{
$indent = str_repeat("\t", $depth);
$output .= "$indent<ul>\n";
return $output;
}
function end_lvl($output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
return $output;
}
/**
[EMAIL PROTECTED] called for every data element
*/
function start_el($output, $data, $depth, $current_page)
{
$args = func_get_args(); # get the other args containing the
current
session cat info
if ( $depth )
{
$indent = str_repeat("\t", $depth);
}
else
{
$indent = '';
}
$css_class = 'page_item';
$_current_page = $args[4];# has current category from session
containing id and parent id
if ($data['Category']['id'] == $_current_page['id'] )
{#current item
$css_class .= ' current_page_item';
}
elseif ( $data['Category']['id'] == $_current_page['parent_id']
)
{#parent of current cat
$css_class .= ' current_page_parent';
}
$output .= $indent . '<li class="' . $css_class . '">
<a href="../index/' .
$data['Category']['id'] .
'" title="' . $data['Category']['name']
. '">'
. $data['Category']['name'] . '</a>';
return $output;
}
function end_el($output, $page, $depth) {
$output .= "</li>\n";
return $output;
}
}
/* implementation */
class WalkerHelper extends Helper
{
var $helpers = array('Session');
function cat($data,$depth)
{
$current_cat = $this->Session->read('Category'); # get id and
parent
id for current cat
$walk = new CatWalk();
return $walk->walk($data,'Category',$depth,$current_cat);
}
}
in the view this is then called like this:
echo $walker->cat($cats,4);
where cats looks like this:
$cats[0]=> ['Category'] =>['id'] [parent_id][name] ..
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Cake PHP" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---