
Originally Posted by
johno
There was a bug yeah. It's ok now. Thanks!
That was fast! I re-wrote your code for PHP4, it works great. Really nice job! Where did you get the idea for this (composition, interface etc.) ? Why can't I ever be this clever? 
Anyway, here is what I ended up with (I'll be using yours if you don't mind!)
PHP Code:
class AdjacentList {
// List/indexed array of associative arrays
var $items;
// id passed into second parram of constructor
var $current_id;
// the item found that matches the current_id
var $currentItem = null;
// the sorted list of "AdjacentListItem"s
var $adjacent_list = array();
function AdjacentList($items, $current_id=null){
$this->items = $items;
$this->current_id = $current_id;
$this->_build();
$this->_finalize();
}
/*
iterator method
while($item =& $list->fetch()){
}
*/
function & fetch () {
$item =& each ($this->adjacent_list);
if ($item) {
return ( $item['value'] );
} else {
reset ( $this->adjacent_list );
return false;
}
}
/*
Go through all of the root elements
Sets the is_current variable if it matches
Sets the number for the item
Appends it's children if any
*/
function _build () {
$number = 0;
foreach($this->items as $item_data) {
$item =& new AdjacentListItem($item_data);
if ( $item->ID() == $this->current_id ){
$item->is_current = true;
$this->currentItem =& $item;
}
if ( $item->isRoot() ) {
$this->adjacent_list[] =& $item;
$item->number = $number;
$number ++;
$this->_appendChildren($item);
}
}
// resort
reset ($this->adjacent_list);
}
/*
This sets the level and the number for child nodes recursively
*/
function _appendChildren (& $theItem) {
$number = 0;
foreach ($this->items as $item_data ) {
$item =& new AdjacentListItem($item_data);
if ( $theItem->ID() == $item->parentID() ) {
$item->parent =& $theItem;
$item->level = $theItem->level + 1;
if ( $item->ID() == $this->current_id ){
$item->is_current = true;
$this->currentItem =& $item;
}
$item->number = $number;
$number ++;
$theItem->children[] =& $item;
$this->adjacent_list[] =& $item;
$this->_appendChildren($item);
}
}
}
/*
After the list has been sorted correctly, we can add next and previous referecenes to each item
This is also where we set each nodes "global" index value
*/
function _finalize(){
$i = 0;
$prev = null;
foreach(array_keys($this->adjacent_list) as $key){
$item =& $this->adjacent_list[$key];
// set item index
$item->index = $i;
$i++;
//
if($prev){
$item->prev =& $prev;
$prev->next =& $item;
}
$prev =& $item;
}
}
}
class AdjacentListItem {
// properties for item (id, parent_id are required)
var $properties;
// indicates that the item is the item matching the id passed into the AdjacentList's second parameter
var $is_current = false;
// The number of the item, relative to it's siblings
var $number = null;
// The index of the item relative to the entire tree
var $index = null;
// The depth
var $level = 0;
// Reference to item's parent
var $parent = null;
// Reference to items children
var $children = array();
// reference to next item
var $next = null;
// reference to previous item
var $prev = null;
function AdjacentListItem($properties){
$this->properties = $properties;
}
function isCurrent(){
return $this->is_current;
}
function ID(){
return $this->get('id');
}
function parentID(){
return $this->get('parent_id');
}
function isRoot(){
return $this->get('parent_id') == 0;
}
function hasChildren(){
return count($this->children);
}
function level(){
return $this->level;
}
function number(){
return $this->number;
}
function index(){
return $this->index;
}
function isLastChild(){
if($this->parent){
return $this->parent->children[ count($this->parent->children) - 1 ]->ID() == $this->ID();
}else{
return $this->prev == null;
}
}
function isFirstChild(){
if($this->parent){
$this->parent->children[0]->ID() == $this->ID();
}else{
return $this->prev == null;
}
}
function get($property){
if(isset($this->properties[$property])){
return $this->properties[$property];
}
}
}
And the usage:
PHP Code:
$items = array(
array(
'id' => 1,
'parent_id' => 0,
'name' => 'home'
),
array(
'id' => 2,
'parent_id' => 0,
'name' => 'products'
),
array(
'id' => 3,
'parent_id' => 2,
'name' => 'gallery'
),
array(
'id' => 7,
'parent_id' => 3,
'name' => 'photos'
),
array(
'id' => 8,
'parent_id' => 3,
'name' => 'paintings'
),
array(
'id' => 9,
'parent_id' => 8,
'name' => 'oil'
),
array(
'id' => 4,
'parent_id' => 0,
'name' => 'contact'
),
array(
'id' => 5,
'parent_id' => 4,
'name' => 'staff'
),
array(
'id' => 6,
'parent_id' => 4,
'name' => 'students'
)
);
function formatLIText( & $item){
$item_html = '<b><a href="?id=' . $item->ID() . '">' . $item->get('name') . '</a></b>';
$item_html .= ', index: ' . $item->index();
$item_html .= ', number: ' . $item->number();
$item_html .= ', level: ' . $item->level();
if($item->isCurrent()){
$item_html = '<span style="color:red">' . $item_html . '</span>';
}
return $item_html;
}
$list =& new AdjacentList($items, @$_GET['id']);
$html = '<ul>';
while($item =& $list->fetch()){
$html .= '<li>';
$html .= formatLIText($item);
if( $item->hasChildren() ){
$html .= '<ul>';
}else{
$html .= '</li>';
if( $item->parent && $item->isLastChild() ){
$html .= str_repeat('</ul></li>', $item->level());
}
}
}
$html .= '</ul>';
echo $html;
Bookmarks