Php как вывести дерево из mysql. JsTree — деревья это так просто. Построение дерева в функции _initTree, используем jstree
Сегодня наша цель, создать иерархическую структуру категорий. Нам важно чтобы было удобно хранить категории и чтобы было легко выводить их там где нам надо.
Иногда простое кажется сложным, именно по этому выложу несколько фрагментов кода, которые я надеюсь вам пригодятся для реализации php категорий в виде дерева.
Итак, структура должна состоять из id категории (id), из названия категории (name) и конечно id родительской категории (parent_id). В MySQL это выглядит так:
CREATE TABLE IF NOT EXISTS `category` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `parent_id` int(11) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;
Минимальная и понятная структура таблицы для хранения категорий.
INSERT INTO `category` (`id`, `name`, `parent_id`) VALUES (1, "Телефоны и планшеты", "0"), (2, "Автомобили", "0"), (3, "Samsung", "1"), (4, "Apple", "1"), (5, "LG", "1"), (6, "Ford", "2"), (7, "Lexus", "2"), (8, "BMW", "2"), (9, "Galaxy Tab 4", "3"), (10, "Galaxy S6", "3");
Там где значение parent_id=0, у данной категории нет родительской категории.
Тут все понятно и просто. Теперь присутпим к выводу списка категорий. Но для правильного вывода списка, нам нужно сначала получить весь список php категорий, а уже потом с помощью рекурсии сформировать наше дерево. Следующая функция предназначена для получения этого списка:
Function get_cat() { //запрос к базе данных $sql = "SELECT * FROM category"; $result = mysql_query($sql); if(!$result) { return NULL; } $arr_cat = array(); if(mysql_num_rows($result) != 0) { //В цикле формируем массив for($i = 0; $i < mysql_num_rows($result);$i++) { $row = mysql_fetch_array($result,MYSQL_ASSOC); //Формируем массив, где ключами являются адишники на родительские категории if(empty($arr_cat[$row["parent_id"]])) { $arr_cat[$row["parent_id"]] = array(); } $arr_cat[$row["parent_id"]] = $row; } //возвращаем массив return $arr_cat; } }
//получаем массив каталога $result = get_cat();
Теперь нужна функция с рекурсией
Function view_cat($arr,$parent_id = 0) { //Условия выхода из рекурсии if(empty($arr[$parent_id])) { return; } echo "
- ";
//перебираем в цикле массив и выводим на экран
for($i = 0; $i < count($arr[$parent_id]);$i++) {
echo "
- " .$arr[$parent_id][$i]["name"].""; //рекурсия - проверяем нет ли дочерних категорий view_cat($arr,$arr[$parent_id][$i]["id"]); echo " "; } echo "
Теперь осталось только вывести каталог на экран с помощью рекурсивной функции
View_cat($result);
И в общем то и всё. Таким образом мы можем получить полное дерево категорий с бесконечными подкатегориями.
Строится при помощи добавления в модель поля типа Родитель "parent" , которое хранит id родителя текущей записи. Для корневых записей значение данного поля равно "-1".
Внимание! Поле типа "parent" может быть в модели только одно.
Пример простого использования дерева при создании меню вложенных страниц.
Связанное дерево
Для создания структуры вида "каталог -> каталог -> каталог -> товар" или "альбом -> альбом -> изображение" нужно связать модель с полем "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/" (без первой части).
И так для начала опишу с чем мы будем работать и что нам понадобится.
Система
: PHP 5 и выше, mySQL 4 и выше
Вспомогательные классы
: dbsql.class.php (класс для работы с базой данных)
Класс вложенных категорий
: classTreeCategory.php (непосредственно основной класс, ниже приведен его листинг и пояснения.
Создаем таблицу в БД, следующей структуры:
Просмотр кода MYSQL
В данной таблице присутствует поле ID — порядковый номер категории, podcat — имеет значение ноль у категорий первого порядка или ID родительской категории, name — название категории.
Пример работы класса, вывод категорий списком с подкатегориями:
Просмотр кода PHP
include ("dbsql.class.php" ) ; include ("classTreeCategory.php" ) ; $DB = new DB_Engine("mysql" , $settings [ "dbHost" ] , $settings [ "dbUser" ] , $settings [ "dbPass" ] , $settings [ "dbName" ] ) ; // подключаемся к БД, с указанием данных доступа $category = new TreeCategory ($DB ) ; // передаем в класс категорий, объект работы с БД $category -> table = "category" ; // название таблицы в БД с категорийми $array = $category -> getCategory () ; // получаем все категории из БД в виде многоуровневого массива, отсортированные и вложенные уже в нужном нам порядке $category -> outCategory ($array , "option" ) ; // подготовка вывода категорий (формируем HTML), передаем массив с категориями echo $category -> html ; // вывод категорий в виде HTML name |
Как видно из примера выше, все предельно просто, создаем новый объект $category, устанавливаем с какой таблицей БД работаем: ‘category’, далее получаем из таблицы список всех категорий уже оформленный в виде массива и разложенных в иерархичном порядке, с учетом всех подкатегорий. затем передаем массив в метод outCategory() который формирует для нас готовый HTML код, который остается только вывести в браузер.
Метод outCategory(), как мы видим принимает два параметра @array и @string в первом параметре массив со всеми категориями, а во втором строка содержащая значение option
или table
, это значени указывает какой тип HTML кода требуется сформировать.
Значение option
Просмотр кода HTML
-категория1 --подкатегория 1 ---подподкатегория 1 -категория 2 |
Для вставки данного HTML кода в поле select какой либо формы.
Значение table — формирует следующий HTML код:
Просмотр кода HTML
Этот HTML код удобен для вставки в таблицу которая отображает все наши категории подкатегории.
Класс имеет также следующие методы:
deleteItem($id);
— удаляет одну категорию, не смотря на вложенные
delCategory($array, $id);
— удаляет категорию со всеми вложенными подкатегориями, $array — массив со всеми категориями подготовленный методом $category->getCategory(), $id- номер удаляемой категории
addItem();
— данный метод следует вызывать если вы хотите добавить категорию, при этом этот метод считывает значения из данных переданных методом POST, т.е. из массива $_POST.
$name=$this->PHP_slashes(strip_tags($_POST[‘name’])); // имя категории
$podcat=intval($_POST[‘podcat’]); // ID родительской категории, если указан 0 категория будет в корне.
updateItem()
; — аналогично предыдущему методу, кроме того что данный метод обновляет категорию, её название и уровень вложенности.
Весь класс писался в течении часа и разумеется имеет недочеты, но все этот поправимо. Его использование целесообразно в обучающих целях, хотя впрочем немного допилив его, вы сможете встроить его в любую систему и наслаждаться его работой)).
Буду признателен если в комментариях вы предложите собственные варианты решения данной задачи — организации категорий бесконечного уровня вложенности.
Получает элементы (термины) указанной таксономии по указанным параметрам.
До версии WP 4.5 первый параметр get_terms() был названием таксономии или списком таких названий:
$terms = get_terms("post_tag", [ "hide_empty" => false, ]);
С версии WP 4.5 название таксономии нужно указывать в элементе массива taxonomy в параметре $args , а не во втором параметре, как это было раньше:
$terms = get_terms([ "taxonomy" => "post_tag", "hide_empty" => false, ]);
Обратная совместимость работает (функция понимает устарелый вызов).
C версии 4.6. появился класс мета запросов WP_Term_Query{} . И теперь функция get_terms() является оберткой для этого класса.
✈ 1 раз = 0.015166с = тормоз | 50000 раз = 33.29с = очень медленно | PHP 7.1.11, WP 4.9.5
ВозвращаетМассив/WP_Error/строка.
- Массив объектов WP_Term - при успешном получении.
- array() (пустой массив) - если термины не найдены.
- WP_Error - если любой из указанных таксономий не существует.
- Количество найденных терминов (в виде строки) - если fields = count .
Аргументы, в соответствии с которыми будет получен результат.
Среди них обязательным является аргумент $args["taxonomy"] в котором указывается название таксономии или несколько названий таксономий в массиве.
$deprecated(строка/массив)
До версии 4.5 в этом аргументе указывались параметры $args, а первом параметре $args указывались называния таксономий. С версии 4.5 названия таксономий указываются в аргументе $args["taxonomy"] .
По умолчанию: массив аргументов по умолчанию
По умолчанию: все . object_ids(число/массив)
Укажите тут число или массив чисел, чтобы получить термины, у которых поле object_id таблицы wp_term_relationships совпадет с указанными значениями.
Обычно в поле object_id находятся ID записей к которым прикреплен термин.
Include(строка/массив)
ID терминов, которые нужно включить в выборку. Если указать этот параметр, то многие другие станут бесполезными. Парсится через wp_parse_id_list() .
По умолчанию: ""
exclude(строка/массив)
ID терминов, которые нужно исключить. Парсится через wp_parse_id_list() .
По умолчанию: ""
exclude_tree(строка/массив)
ID родительских терминов, которые нужно исключить. Исключена будет вся ветка.
Парсится через wp_parse_id_list() .
По умолчанию: ""
offset(число)
Верхний отступ в запросе. Сколько первых элементов пропустить. Указывать нужно число. По умолчанию без отступов.
orderby(строка)
Поле по которому сортировать результат. Может быть:
- id или term_id - по ID.
- name - по названию. По умолчанию.
- count - по полю count в term_taxonomy - по количеству записей.
- slug - по альтернативному названию.
- description - по описанию.
- term_group - по группе.
- include - по порядку указанному в параметре $include
- slug__in - с версии 4.9. В порядке указанном в параметре $slug.
- meta_value - по значению произвольного поля
- meta_value_num - по значению произвольного поля, значение будет интерпретироваться как число, а не строка.
- ключ "meta_query" - в параметре $meta_query мы можем указать параметры запроса по метаполям, и там же указать ключ для конкретного запроса. Этот ключ можно использовать как ключ для сортировки по соответствующему метаполю.
- none - не сортировать
parent - по полю parent.
По умолчанию: "id"
order(строка)Направление сортировки, указанной в параметре "orderby":
- ASC - по порядку, от меньшего к большему (1, 2, 3; a, b, c);
- DESC - в обратном порядке, от большего к меньшему (3, 2, 1; c, b, a).
По умолчанию: "ASC"
Hide_empty(логический)
Скрывать ли термины в которых нет записей. 1(true) - скрывать пустые, 0(false) - показывать пустые.
По умолчанию: true
fields(строка)
Какие поля возвращать в результирующем массиве. Может быть:
- all - Вернуть массив объектов (все данные) - по умолчанию;
- ids - вернуть массив чисел;
- names - вернуть массив строк.
- count - (3.2+) возвращает количество найденных терминов.
- id=>parent - вернуть массив, где ключ = ID термина, а значение = ID родительского термина.
- id=>slug - вернуть массив, где ключ = ID термина, а значение = слаг (название для УРЛ) термина.
- id=>name - вернуть массив, где ключ = ID термина, а значение = название (имя) термина.
По умолчанию: "all"
count(логический) true - вернет количество терминов. В этом случае, перебивает параметр fields .false - вернет массив объектов терминов. name(строка/массив) Укажите тут строку или массив строк, чтобы получить термины с указанными названиями.
По умолчанию: "" slug(строка/массив) Укажите тут строку или массив строк, чтобы получить термины с указанными ярлыками (слагами).
По умолчанию: "" hierarchical(логический)
Включать ли в результат термины, которые имеют не пустые дочерние термины (в которых есть записи). Т.е. в массив будут включены пустые термины, если у их дочерних терминах есть записи, даже если аргумент " hide_empty " равен true .
- true - да, включить;
- false - нет, не включать.
По умолчанию: true
Search(строка)
Поиск по названиям термина и его ярлыку. Получит термины в названиях которых есть вхождение указанной тут строки. Т.е. запрос выглядит так: LIKE "%search_string%" .
По умолчанию: ""
name__like(строка)
Показать термины, в названии которых есть указанная строка. Поиск по строке.
По умолчанию: ""
description__like (строка)
Показать термины, в описании которых есть указанная строка. Поиск по строке.
По умолчанию: ""
pad_counts(логический)
Если передать true, то число которое показывает количество записей в родительских категориях будет суммой своих записей и записей из дочерних категорий. По умолчанию подсчитываются только свои записи.
pad_counts зависит от параметра parent потому что подсчет записей идет на уровне PHP и если например указать parent=0 , то будут получены только верхние термины и pad_counts не сможет правильно посчитать кол-во записей в дочерних терминах. Чтобы обойти это ограничение, нужно получить все термины, не указывая parent , а потом в PHP удалить ненужные... Вот пример такого кода:
$terms = get_terms(array("hide_empty" => 0, "orderby" => "name", "order" => "ASC", "taxonomy" => "category", "pad_counts" => 1)); // оставим только термины с parent=0 $terms = wp_list_filter($terms, array("parent"=>0));
По умолчанию: false
get(строка)Если указать "all" то будут жёстко отключены параметры: childless , child_of , hide_empty , hierarchical и pad_counts . "Жёстко" - значит перебьет текущие установки для этих параметров. "Отключены" - значит им будет установлен параметр false или 0.
Обычно используется для удобства, когда нужно получить термины на низком уровне, не для вывода, а для дальнейшей работы с ними, чтобы не следить за значениями упомянутых параметров...
// фрагмент кода if ("all" == $args["get"]) { $args["childless"] = false; $args["child_of"] = 0; $args["hide_empty"] = 0; $args["hierarchical"] = false; $args["pad_counts"] = false; }
По умолчанию: ""
child_of(число)ID родительского термина. Вывести элементы таксономии, которые являются дочерними разделами указанного элемента. Будут получены все уровни вложенности, все дерево.
Если указаны несколько таксономий, параметр будет проигнорирован.
По умолчанию: 0
Parent(число)
ID родительского термина, чтобы получить только прямых потомков.
Будет получен только первый уровень вложенности, а не все дерево как в параметре child_of . Если указать 0, то будут выведены термины верхнего уровня.
По умолчанию: ""
Term_taxonomy_id(число/массив)
Укажите тут число или массив чисел, чтобы получить термины, у которых поле term_taxonomy_id совпадет с указанными значениями.
По умолчанию: ""
cache_domain(строка)
(3.2+) Позволяет установить уникальные ключ кэша, который будет использоваться в get_terms() при объектном кэшировании (object cache). Например, если вы используется один из фильтров get_terms(), чтобы изменить запрос (например "terms_clausses"), установив "cache_domain" в уникальное значение, позволить не перезаписывать сохраненный кэш для одинаковых запросов.
По умолчанию: "core"
update_term_meta_cache(логический)
true - загрузить кэш метаданных, чтобы потом их можно было быстро получить. Кэш подгружается для полученных элементов.
По умолчанию: true
meta_query(массив)
Запрос для получения элементов на основе метаданных. Смотрите WP_Meta_Query .
meta_key(строка)
Получит термины у которых есть указанное метаполе. Можно использовать в связке с meta_value .
По умолчанию: ""
meta_value(строка)
Получит термины у которых значение метаполя равно указанному значению. Всегда используется в связке с meta_key .
По умолчанию: ""
suppress_filter(логический)
Подавлять работу фильтров или нет? Если выставить в true, то фильтр get_terms просто не будет работать для текущего запроса терминов.
По умолчанию: false (фильтры работают)
Данные в массиве будут отсортированы по количеству записей (orderby=count) в каждой категории. Категории у которых нет записей все равно будут включены в массив (hide_empty=0).
$myterms = get_terms("category", "orderby=count&hide_empty=0");
#2 Выведем на экран список названий всех разделов таксономии "my_taxonomy": $terms = get_terms("my_taxonomy"); if($terms && ! is_wp_error($terms)){ echo "- ";
foreach($terms as $term){
echo "
- ". $term->name ." "; } echo "
В данном примере каждый $term из цикла foreach($terms as $term) , будет содержать такую информацию:
=> 162 => Здоровье => zdorove => 0 => 170 => my_taxonomy => => 0 => 2
#3 Вывод рубрик через разделитель// получаем все термины из таксономии my_term $args = array("hide_empty=0"); $terms = get_terms("my_term", $args); // собираем их и выводим if (!empty($terms) && !is_wp_error($terms)) { $count = count($terms); $i=0; $term_list = "
"; foreach ($terms as $term) { $i++; $term_list .= "name) . "">" . $term->name . ""; if ($count != $i) { $term_list .= " · "; } else { $term_list .= "
"; } } echo $term_list; } /* в итоге получим подобный код: */ Список измененийС версии 2.3.0 | Введена. |
С версии 4.2.0 | Introduced "name" and "childless" parameters. |
С версии 4.4.0 | Introduced the ability to pass "term_id" as an alias of "id" for the orderby parameter. Introduced the "meta_query" and "update_term_meta_cache" parameters. Converted to return a list of WP_Term objects. |
С версии 4.5.0 | Changed the function signature so that the $args array can be provided as the first parameter. Introduced "meta_key" and "meta_value" parameters. Introduced the ability to order results by metadata. |
С версии 4.8.0 | Introduced "suppress_filter" parameter. |