|
|
|
| Понадобилось изменить скрипт новостей под статьи (это неважно) с возможностью добавлять новый каталог, подкаталог, а если надо то и подподкаталог и т. д. Не подскажите алгоритм или намек как лучше это организовать. Если сделать только один каталог (рубрику), то нет проблем, а если много... Не буду же я для отдельного подкаталога писать отдельную таблицу в БД. Может можно одну таблицу для это сделать, но как отслеживать вложенность? Что-то я совсем запутался. | |
|
|
|
|
|
|
|
для: diman
(06.10.2009 в 15:48)
| | Две таблицы.
категории:
id | parent_id
статьи:
id | cat_id | title| text
Для корневой категории parent_id будет 0, для подкатегорий parent_id будет содержать id родительно директории, как можно догадаться
id | parent_id
1 | 0
2 | 0
3 | 1
4 | 1
5 | 2
6 | 3
здесь категории с id 1 и 2 - корневые, 3,4 - покатегории в категории 1, 5 - подкатегория в категории 2, а 6 - подкатегория в подгокатигории 3.
В статьях в cat_id указываете id категории, это понятно, я думаю.
Вот примерно по этому принципу можно сделать. | |
|
|
|
|
|
|
|
для: neadekvat
(06.10.2009 в 15:55)
| | Да, вполне понятно. Спасибо | |
|
|
|
|
|
|
|
для: neadekvat
(06.10.2009 в 15:55)
| | Тоже интересовал вопрос неограниченной вложенности.
Только есть ещё и другой вопросик.
Как вывести эту саму навигацию, т.е. показывать сколько каталогов уже прошли (автоматически).
//Вот такое надо вывести:
С корневой мы перешли на "Подкатегория 1".
Должно вывести навигацию так:
Главная >> Подкатегория 1
Потом мы перешли в "ПодПодкатегория 1".
Должно вывести так:
Главная >> Подкатегория 1 >> ПодПодкатегория 1
//и т.д.
|
| |
|
|
|
|
|
|
|
для: class
(05.02.2010 в 20:10)
| | Не берусь говорить, насколько хорошим является решение (и можно ли его вообще назвать хорошим), но можно, например, той же рекурсией, только в обратном порядке - начиная от имеющегося каталога пойти по его parent_id, потом у найденного каталога искать его parent_id и так пока не дойдем до нуля. | |
|
|
|
|
|
|
|
для: neadekvat
(05.02.2010 в 20:50)
| | Ну с этим понятно, я тоже так думал, но хотелось бы решение увидеть в коде ))
т.е. такой код, чтобы пока не дошло до нуля выводило записи. | |
|
|
|
|
|
|
|
для: class
(05.02.2010 в 22:10)
| |
<?php
$cat_id = intval($_GET['cat_id']);
$links = array();
function navigation($cat_id) {
global $links;
$query = mysql_query("SELECT * FROM cats WHERE id = $cat_id");
$arr = mysql_fetch_assoc($query);
// $arr['id'] - id категории
// $arr['parent_id'] - id родительской категории
// $arr['name'] - имя категории
$links[] = array('name' => $arr['name'], 'id' => $arr['id']); // открытая категория
if(!$arr['parent_id']) { // если родительской категории нет
return true;
} else {
navigation($arr['parent_id']);
}
}
navigation($cat_id);
// сортируем массив от конца к началу,
// т.к. пункты добавлялись справа налево, а в России как-то больше слева-направо принятно
rsort($links);
echo 'Главная';
foreach($links as $link) {
echo ' » <a href="?cat_id=' . $link['id'] . '">' . $link['name'] . '</a>';
}
?>
|
Пардон, если что. Писал "на коленке", т.е. в поле ввода сообщения. Главное - общий принцип моей идеи показать. Если кто-то покажет лучше (уверен, такие будут), буду рад. | |
|
|
|
|
|
|
|
для: neadekvat
(05.02.2010 в 22:26)
| | Спасибо!
Вроде как работает, только тут что то с сортировкой массива.
Беспорядочно выводит навигацию при большой вложенности.
Вот добавлял в базу отрывок алфавита.
Вот так вывело:
Главная » Ё » А » Б » В » Г » Д » Е » Ж » З » И » К » Л » М » Н » О » П » Р » С » Т » У
|
| |
|
|
|
|
|
|
|
для: class
(05.02.2010 в 23:41)
| | Замените rsort() на krsort(), там же по ключам надо. Постоянно забываю. | |
|
|
|
|
|
|
|
для: class
(05.02.2010 в 23:41)
| | Решил проблему сортировкой
krsort() вместо rsort() | |
|
|
|
|
|
|
|
для: class
(05.02.2010 в 23:50)
| | О чем я и сказал 4мя минутами раньше вас =) | |
|
|
|
|
|
|
|
для: neadekvat
(05.02.2010 в 23:59)
| | Пока я писал - вы уже написали о этой сортировке :)
Спасибо за помощь! | |
|
|
|
|
|
|
|
для: neadekvat
(05.02.2010 в 22:26)
| | Скрипт хороший, но привязка идет непосредственно к id каталогу, а если мне скажем нужно вывести полностью из БД в иерархическом списке всю структуру. Помогите решить задачку.
Пробовал сам, у меня немного другие переменные, но это не суть важно.
$sql="Select * From articlecat Where hide='show'";
$ct=mysql_query($sql);
if(mysql_num_rows($ct)>0){
while($cat = mysql_fetch_array($ct)){
if (!$cat['id_parent']){
//echo "<ul><a href=?link=2&id_catalog=".$cat['id_catalog'].">".$cat['name']."</a></ul>";
}
else {
navigation($cat['id_catalog']);
krsort($links);
foreach($links as $link) {
echo ' » <a href="?link=2&id_catalog=' . $link['id'] . '">' . $link['name'] . '</a>';
$links = array();
}
}
echo "<hr>";
}
}
|
Но тогда пустые каталоги, без вложения, не будут видны. Чтобы это осуществить нужно переделать функцию navigation(), чтобы она вводила в массив $links только вложенные имена подрубрик. Как это осуществить? Или может что-нибудь получше предложите? | |
|
|
|
|
|
|
|
для: neadekvat
(05.02.2010 в 22:26)
| | ну вот.
Классический пример лишней рекурсии.
Идею (даже не идею, а данность), что для формирования пути узел-корень нужен всего лишь цикл, я продвигаю здесь уже четвертый или пятый раз.
При чем последний - не позднее прошлой недели.
Очевидно, имеет смысл опять привести теоретическое обоснование.
функция вида
<?
function recursive()
{
некие операторы;
if(некое_условие)
recursive();
}
|
формально преобразуется к варианту
<?
function itterative()
{
do
{
некие операторы;
}
while(некое_условие);
}
|
если, конечно эти некие операторы сами по себе рекурсивного вызова не содержат.
Это теория.
Теперь практика.
Ваш код
<?
if(!$arr['parent_id']) { // если родительской категории нет
return true;
} else {
navigation($arr['parent_id']);
}
|
содержит лишний else, поскольку после return выполнение всё равно прекращено.
И лишние скобки, поскольку одиночные операторы в составной блок объединять смысл невелик.
А значит
<?
if(!$arr['parent_id'])
return true; // если родительской категории нет
navigation($arr['parent_id']);
|
А с учетом того, что это последний код в функции - вызов можно поставить под условие напрямую:
<?
if($arr['parent_id'])
navigation($arr['parent_id']); // если родительской категории есть
return true;
|
А учитывая Ваш контекст, выйдет:
<?
function navigation($cat_id) {
global $links;
$query = mysql_query("SELECT * FROM cats WHERE id = $cat_id");
$arr = mysql_fetch_assoc($query);
// $arr['id'] - id категории
// $arr['parent_id'] - id родительской категории
// $arr['name'] - имя категории
$links[] = array('name' => $arr['name'], 'id' => $arr['id']); // открытая категория
if($arr['parent_id'])
navigation($arr['parent_id']); // если родительской категории есть
return true;
}
|
Вот мы и пришли к каноническому виду для упразднения рекурсии.
<?
function navigation($cat_id)
{
global $links;
do
{
$query = mysql_query("SELECT * FROM cats WHERE id = $cat_id");
$arr = mysql_fetch_assoc($query);
// $arr['id'] - id категории
// $arr['parent_id'] - id родительской категории
// $arr['name'] - имя категории
$links[] = array('name' => $arr['name'], 'id' => $arr['id']); // открытая категория
}
while(($cat_id = $arr['parent_id']) != 0); // пока есть родительская категория
}
|
Заметьте, я выполнил преобразование, вообще не касаясь предметной области.
Просто как робот. | |
|
|
|
|
|
|
|
для: Trianon
(30.05.2010 в 15:35)
| | Наконец-то!) Я три месяца ждал, когда меня исправят (не в смысле, что я знал ответ, а в смысле, что не знал как реализовать лучшее решение)
Спасибо :) | |
|
|
|
|
|
|
|
для: neadekvat
(30.05.2010 в 16:43)
| | Становится проще читать такой код. Очень хорошее решение.
Для вывода иерархического списка использую следующий
function menu_nav( $id_parent, $tabl )
{
$query="SELECT * FROM ".$tabl." WHERE id_parent =".$id_parent." And hide='show' ORDER BY pos ";
$result=mysql_query($query);
if(!$result)
{
echo "Ошибка обращения к таблице каталога menu_navigation()";
}
if (mysql_num_rows($result) > 0)
{
echo("<ul >\n");
while ( $row = mysql_fetch_array($result) )
{
$ID1 = $row["id_catalog"];
echo("<li>\n");
if (!$row['id_parent']){
echo $row["name"];
} else
echo("<a href=?link=2&id_catalog=".$ID1.">".$row["name"]."</a>"." \n");
menu_nav($ID1,$tabl);
}
echo("</ul>\n");
}
}
menu_nav(0,'articlecat');
|
А в таком коде какие будут предложения по улучшению? | |
|
|
|
|
|
|
|
для: Diman
(30.05.2010 в 18:45)
| | предложение одно.
Подсчитать количество запросов к БД при, допустим, сотне строк в таблице категорий. | |
|
|
|