Деревья
Простое дерево
Строится при помощи добавления в модель поля типа Родитель "parent", которое хранит id родителя текущей записи. Для корневых записей значение данного поля равно "-1".
Внимание! Поле типа "parent" может быть в модели только одно.
Пример простого использования дерева при создании меню вложенных страниц.
<? class Pages extends Model { protected $name = "Меню страниц"; protected $model_elements = array( array("Активировать", "bool", "active", array("on_create" => true)), array("Отображать в меню", "bool", "in_menu", array("on_create" => true)), array("Название", "char", "name", array("required" => true)), array("Родительский раздел", "parent", "parent", array("max_depth" => 3)), array("Позиция", "order", "order"), array("Содержание", "text", "content", array("rich_text" => true)) ); } ?>
Связанное дерево
Для создания структуры вида "каталог -> каталог -> каталог -> товар" или "альбом -> альбом -> изображение" нужно связать модель с полем "parent" с другой моделью таким образом чтобы конечный родитель первой модели являлся внешним ключом для записей другой модели.
Пример создания связанного дерева для многоуровнего каталога товаров.
class Catalogs extends Model { protected $name = "Разделы каталога"; protected $model_elements = array( array("Активен", "bool", "active", array("on_create" => true)), array("Название", "char", "name", array("required" => true)), array("Каталог", "parent", "parent", array("parent_for" => "Products")), array("Ссылка", "url", "url"), array("Позиция", "order", "order") ); } class Products extends Model { protected $name = "Товары каталога"; protected $model_elements = array( array("Активен", "bool", "active", array("on_create" => true)), array("Название", "char", "name", array("required" => true)), array("Раздел каталога", "enum", "parent", array("foreign_key" => "Catalogs", "is_parent" => true)), array("Цена", "int", "price", array("required" => true)), array("Изображения", "multi_images","images"), array("Описание", "text", "desc", array("rich_text" => true)), array("Позиция", "order", "order") ); }
Специальные методы деревьев
Для быстрого доступа к родителям и потомкам в дереве предусмотрены специальные методы.
- getParents($id) - возвращает массив родительских записей (до записи со значением родительского поля равным -1). В результирующем массиве ключи - id записей, значения - названия записей соглаcно параметру "$name_field" из раздела Настройка модели.
- getChildren($id) - возвращает массив всех дочерних записей, рекурсивно обходя все ветви дерева. Результирующий массив строится аналогично предыдущему методу.
- displayBreadcrumbs($id, $url_first [, $url_field]) - отображает ссылочный путь до записи с переданным id. Возвращает последовательность html тэгов в виде
"ссылка -> ссылка -> ссылка -> span". Входящие параметры: id текущей записи, $url_first - первая часть url,
необязательный параметр $url_field - название поля в котором хранится текстовая ссылка для данной записи (для построения url вида "catalog/toys/"). Для предустановленной модели "Pages" ссылки автоматически строятся в виде "/page/4/" и "/contacts/" (без первой части).
$catalog = $mv -> catalogs -> findRecordById(43); //Родительские записи $parents = $mv -> catalogs -> getParents($catalog -> id); //Дочерние записи $children = $mv -> catalogs -> getChildren($catalog -> id); //Ссылочный путь для раздела каталога echo $mv -> catalogs -> displayBreadcrumbs($catalog -> id, "category", "url"); //Ссылочный путь для товара каталога echo $mv -> products -> displayBreadcrumbs($product -> id, "category"); //Ссылочный путь будет в виде <a href="/category/toys/">Игрушки</a> <a href="/category/balls/">Мячи</a> <span>Мяч красный</span>
Перечисленные методы могут также вызываться изнутри объекта модели. В примере ниже происходит определение страницы каталога на основе URL.
public function defineCatalogPage(Router $router) { $url_parts = $router -> getUrlParts(); $content = false; if(count($url_parts) == 2) if(is_numeric($url_parts[1])) $content = $this -> findRecord(array("id" => $url_parts[1], "active" => 1)); else $content = $this -> findRecord(array("url" => $url_parts[1], "active" => 1)); if($content) $this -> parents = $this -> getParents($content -> id); return $content; }
Далее рекурсивно строим меню каталога.
public function displayCatalogMenu($parent) { $rows = $this -> select(array("parent" => $parent, "active" => 1, "order->asc" => "order")); $html = ""; $root_path = $this -> root_path."category/"; foreach($rows as $row) { $active = ""; $children = false; if($row['id'] == $this -> id || array_key_exists($row['id'], $this -> parents)) { $children = $this -> select(array("parent" => $row['id'], "active" => 1)); $active = ' class="active"'; } $url = $root_path.($row['url'] ? $row['url'] : $row['id'])."/"; $html .= '<li><a'.$active.' href="'.$url.'">'.$row['name'].'</a>'; if($children) $html .= "<ul>".$this -> displayCatalogMenu($row['id'])."</ul>"; $html .= "</li>"; } return $html; } //Вызов данного метода в шаблоне <ul id="catalog"> <? echo $mv -> catalogs -> displayCatalogMenu(-1); ?> </ul>
Предыдущий раздел
Внешние ключи