digitorum.ru

Как меня найти

Профиль

icq: 4415944

Генерация древовидных меню: djemscript vs php.

djemscript, php

Есть 3 менюшки для каталога:

При публикации одного документа (товара) нужно обновлять все 3 менюшки. Если делать это на djemscript, то трижды придется дергать базу что бы вынуть одни и те же данные.

На времени публикации это явно не здорово сказывается.

Чтобы минимизировать временные задержки и максимизировать удобство работы клиента будем строить все эти менюшки на php (но к базе, конечно же, лишний раз обращаться не будем).

Корень дерева:

<?php
	
	Class Catalogue_Tree extends Catalogue_Tree_NodeBase {
		
		/*
		* Узлы дерева
		*/
		private $nodes = array();
		
		/*
		* Конструктор
		*/
		public function __construct() {
			{{ подсчет товаров }}
			<foreach name="x" path="main.rus.catalogue.*" where="_type == 203">
				<set 'count_' ~ <foreach[x]._parent_id> = <var['count_' ~ <foreach[x]._parent_id>]> + 1>
			</foreach>
			{{ построение дерева }}
			<foreach name="x" path="main.rus.catalogue.*" where="_type in '201,202'" sort="_gsort">
				$this->nodes[<foreach[x]._id>] = new Catalogue_Tree_Node(
					array(
						'id' => <foreach[x]._id>,
						'type' => <foreach[x]._type>,
						'url' => '<foreach[x]._url.js>',
						'name' => '<foreach[x]._name>',
						'total' => <if <foreach[x]._type> == 202><var['count_' ~ <foreach[x]._id>]><else>null</if>
					),
					<if <foreach[x]._parent_id> == <['main.rus.catalogue']._id>>
						null
					<else>
						$this->nodes[<foreach[x]._parent_id>]
					</if>
				);
				<if <foreach[x]._parent_id> != <['main.rus.catalogue']._id>>
					$this->nodes[<foreach[x]._parent_id>]->addChild($this->nodes[<foreach[x]._id>]);
				<else>
					$this->children[] = $this->nodes[<foreach[x]._id>];
				</if>
			</foreach>
		}
		
		/*
		* Деструктор
		*/
		public function __descruct() {
			$this->nodes = array();
			$this->children = array();
			$this->parent = null;
		}
		
		/*
		* Вывести структуру
		*/
		public function structure() {
			foreach($this->children as $root) {
				print "\n" . $root->name;
				print $root->structure();
			}
		}
	}
	
?>

 

Узел дерева:

<?php
	
	Class Catalogue_Tree_Node extends Catalogue_Tree_NodeBase {
		
		/*
		* Данные ноды
		*/
		private $data;
		
		/*
		* Родитель
		*/
		private $parent;
		
		/*
		* Конструктор
		*/
		public function __construct($data, $parent) {
			$this->data = $data;
			$this->parent = $parent;
		}
		
		/*
		* Деструктор
		*/
		public function __descruct() {
			$this->children = array();
			$this->parent = null;
			$this->data = array();
		}
		
		/*
		* Добавить ребенка
		*/
		public function addChild($item) {
			$this->children[] = $item;
		}
		
		/*
		* Количество элементов в разделе
		*/
		public function size() {
			if($this->data['total'] !== null) {
				return $this->data['total'];
			}
			$size = 0;
			foreach($this->children as $child) {
				$size += $child->size();
			}
			return $size;
		}
		
		/*
		* Структура
		*/
		public function structure($level = 1) {
			foreach($this->children as $child) {
				print "\n";
				for($i = 0; $i<=$level; $i++) {
					print " ";
				}
				print $child->name . ' - ' . $child->size();
				print $child->structure($level + 1);
			}
		}
		
		/*
		* Геттер
		*/
		public function __get($k = '') {
			return isset($this->data[$k]) ? $this->data[$k] : '';
		}
		
		/*
		* Построить UL
		*/
		public function buildUl($active = array()) {
			$html = '<ul>';
			foreach($this->children as $child) {
				$html .= '<li><a href="' . $child->url . '">' . $child->name . '</a>';
				if($child->hasChildren()) {
					if(in_array($child->id, $active)) {
						$html .= $child->buildUl($active);
					}
				} else {
					$html .= ' (' . $child->size() . ')';
				}
				$html .='</li>';
			}
			return $html .= '</ul>';
		}
		
	}
	
?>

 

Общие методы для узлов дерева:

<?php
	
	Class Catalogue_Tree_NodeBase implements Iterator {
		
		/*
		* Позиция итератора
		*/
		public $iteratorPosition = 0;
		
		/*
		* Дети
		*/
		protected $children = array();
		
		/*
		* Есть ли дети
		*/
		public function hasChildren() {
			return count($this->children);
		}
		
		/*
		* Iterator: Возвращает итератор на первый элемент
		*/
		function rewind() {
			$this->iteratorPosition = 0;
		}
	
		/*
		* Iterator: Возвращает текущий элемент
		*/
		function current() {
			return $this->children[$this->iteratorPosition];
		}
	
		/*
		* Iterator: Возвращает ключ текущего элемента
		*/
		function key() {
			return $this->iteratorPosition;
		}
	
		/*
		* Iterator: Переходит к следующему элементу
		*/
		function next() {
			++$this->iteratorPosition;
		}
	
		/*
		* Iterator: Проверка корректности позиции
		*/
		function valid() {
			return isset($this->children[$this->iteratorPosition]);
		}
		
	}
	
?>

 

Ну и дальше уже строим менюшки средствами php. Например:

<table width="100%">
	<tr><?php
		
		$catalogueTree = new Catalogue_Tree();
		foreach($catalogueTree as $node) {
			if($node->type == 201) {
				?><td class="item_block">
					<h5><a href="<?php print $node->url; ?>"><?php print $node->name; ?></a></h5>
					<ul><?php
						foreach($node as $subnode) {
							?><li><a href="<?php print $subnode->url; ?>"><?php print $subnode->name; ?></a> <span>(<?php print $subnode->size(); ?>)</span></li><?php
						}
					?></ul>
				</td><?php
			}
		}
		
	?></tr>
</table>

 

Таким образом djemscript'ом мы обходим каталог всего 2 раза (подсчет количества товаров и получение разделов каталога - отправляем всего 2 SQL запроса), а не 6 раз. Мелочь, а приятно .

Catalogue_Tree инициализируется за 0.0005 секунды, сильно медленнее от этого сайт работать не будет