|
|
|
| У меня вертикальное меню, которое занимается выводом контента.
Вот код:
<?php
include("configs/dbopen.php");
require ("smarty/Smarty.class.php");
$smarty = new Smarty;
function ShowTree($parent_id){
global $link, $smarty, $list;
$sql = "SELECT * FROM `menu` WHERE `pid` = ". $parent_id ." ORDER BY `id_menu`";
//echo "(st): $sql<br>";
$result = mysql_query($sql, $link);
if ($parent_id!=0) $list .= "<ul> <!-- parent = $parent_id -->\n";
while ($row = mysql_fetch_assoc($result)){
$id = $row["id_menu"];
$list.= "<LI><A HREF='?id=$id'>".htmlspecialchars($row['title'])."</A>";
$sql = "SELECT * FROM `menu` WHERE `pid`=$id";
//echo "(in): $sql<br>";
$r2 = mysql_query($sql, $link);
if (mysql_num_rows($r2) > 0)
$list.= showTree($id);
$list.= "</li>\n";
}
if ($parent_id!=0) $list .= "</ul> <!-- parent = $parent_id -->\n";
}
ShowTree(0);
//print $list;
$smarty->assign('arr', $list);
$smarty->display("menu.tpl");
?>
|
Да, еще к этому меню стили добавляются и JS.
Как видно, я разбила вывод уровней на два запроса к базе. Один вытягивает родителей, другой - потомков. Вот у меня вопрос такой: если использовать два запроса, то какие в этом способе недостатки или преимущества по сравнению с одним запросом к базе, когда одним запросом вытягивается весь список. Что лучше два запроса или один? | |
|
|
|
|
|
|
|
для: Лена
(04.07.2008 в 14:05)
| | в операторе if (mysql_num_rows($r2) > 0) что находится под условием? | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 14:19)
| | Не совсем поняла вопрос. Если в базе есть ряды-потомки, то они выводятся и записываются в переменную, которая потом идет в шаблон: $list.= showTree($id); | |
|
|
|
|
|
|
|
для: Лена
(04.07.2008 в 14:25)
| | >Не совсем поняла вопрос. Если в базе есть ряды-потомки, то они выводятся и записываются в переменную, которая потом идет в шаблон: $list.= showTree($id);
Вот именно. = showTree($id);
Это означает, что функция showTree ПО идее должна уметь возвращать хоть какой-то результат.
Где в Вашей функции хоть один оператор return? | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 14:29)
| | Нет. Можно и по-другому. Если переменная объявляется как глобальная, то возвращать из функции ничего не надо. Результат автоматически записывается в эту переменную. И return тогда не нужно.
У меня в начале было так:
global $link, $smarty, $list;
Результат записывается в $list
Так sim5 меня учил. | |
|
|
|
|
|
|
|
для: Лена
(04.07.2008 в 14:39)
| | Всё правильно говорите.
Но тогда и присваивать результат функции не следует. Результата-то нет?
Вместо $list .= showTree($id); нужно написать просто showTree($id); | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 14:48)
| | Позволю небольшое пояснение. Лена обратилась ко мне по Скайп, что лучше два или один запрос к базе. Ответив, что лучше конечно один, а посмотрев что формирует код, предположил, что второй запрос делается для того, чтобы узнать - если у полученного из первого запроса id потомки, так как от этого будет зависить, какие указывать стили (или id объектов) для элементов меню (вложенность). Вот я и посоветовал описать все это на форуме, тем более, что есть на нем философ MySQL (на вопрос кто это, я назвал вас Trianon:)), который не только грамотно объяснит достоинства, поможет не просто составить запрос, но и объяснит суть процесса. А вы на разных языках начали...)) | |
|
|
|
|
|
|
|
для: sim5
(04.07.2008 в 15:32)
| | Значит пример (04.07.2008 в 14:05) был неполон?
Я, честно сказать, не знаю что комментировать.
я вижу что запрос данных об элементе меню выполняется два раза - один раз при переборе элементов, и другой буквально сразу же - внутри рекурсивного вызова.
Фактически на сервер следуют пары одинаковых запросов. | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 15:51)
| | Полон или нет был пример, сказать не могу. Я не видел CSS для меню, но мне показали пример HTML-кода меню:
<div class="suckerdiv">
<ul id="suckertree1">
<li><a href="#">Главная</a></li>
<ul>
<li><a href="#">JavaScript</a></li>
<ul>
<li><a href="#">PHP 4</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#">CSS</a></li>
</ul>
</div>
|
И если все так, то думается, достаточно будет добавить аргументом функции еще и уровень вложения, по которому определять вложенность. В противном случае (как я понимаю) требуется запросом узнавать не только, что pid=parent, но и есть ли категории с id равными pid, то есть - имеет ли запрашиваемая категория потомков. | |
|
|
|
|
|
|
|
для: sim5
(04.07.2008 в 16:29)
| | Вот в этом примере 4-я снизу строка </li> явно чужая. Во всяком случае соответствующего открывающего тега я не нашел.
Уровень вложенности необязательно передавать параметром.
Его можно посчитать в статической переменной.
ShowTree()
{
static $level=0;
++$level;
.....
ShowTree()
....
--level;
return $list;
} | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 17:04)
| | Нет, закрывающие теги элементов LI на месте - это родительские элементы. Картина немного прояснилась - я увидел JS и CSS. Нужно формировать в функции уровень, проверять его, формируя родительские элементы UL и LI. Этого должно хватить. Иначе суть вопроса в объедении в одном запросе - получить pid равное parent, одновременно узнавая есть ли у этого id потомки. В общем я так все понял. | |
|
|
|
|
|
|
|
для: sim5
(04.07.2008 в 17:29)
| | Тогда может быть Вы мне это проясните?
<div class="suckerdiv">
<ul id="suckertree1">
<li><a href="#">Главная</a></li>
<ul>
<li><a href="#">JavaScript</a></li>
<ul>
<li><a href="#">PHP 4</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#">CSS</a></li>
</ul>
</div>
|
Потому что я двух открывающих тэгов в этом коде не вижу | |
|
|
|
|
|
|
|
для: Trianon
(04.07.2008 в 18:14)
| | )) Это мой недосмотр, я сократил пример кода, оставив по одному родителю и их потомков, что бы покороче было, когда выставлял меню, потому так получилось. | |
|
|
|
|
|
|
|
для: sim5
(04.07.2008 в 18:31)
| | Код, преложенный Trianon`ом, работает нормально.
Но, если в функции формировать уровень, то получается вот что:
<?php
include("configs/dbopen.php");
require ("smarty/Smarty.class.php");
$smarty = new Smarty;
function showTree($parent_id,$level) {
global $link, $list;
$sql = "SELECT * FROM `menu` WHERE `pid` = ". $parent_id ." ORDER BY `id_menu`";
//echo $sql."<br>";
$result = mysql_query($sql) or die (mysql_error());
if ($level > 0 && mysql_num_rows($result) > 0) {
$ulopn = "<ul>";
$ulcls = "</ul></li>";
$list = substr($list, 0, -5);
} else $ulopn = $ulcls = "";
$list .= $ulopn;
while ($row = mysql_fetch_row($result)) {
$list.= "<li><A HREF=\"?id=$row[0]\">".htmlspecialchars($row[2])."</A></li>";
showTree($row[0],$level++);
}
$list .= $ulcls;
}
//$list = "<div class='suckerdiv'>";
//$list .= "<ul id='suckertree1'>";
showTree(0,0);
//$list .= "</ul>";
//$list .= "</div>";
$smarty->assign('arr', $list);
$smarty->display("menu1.tpl");
?>
|
При этом содержимое выводится следующим образом(на вот таких уровнях):
Пункт1
Пункт1.1.
Пункт 1.2.
Пункт 2
Пункт 3
Пункт 3.1.
Пункт 3.2
А надо, чтобы Пункт1.1 и Пункт 1.2 выпадали, как и Пункт 3.1, Пункт 3.2. Получается стиль не срабатывает для потомков Пункта 1.
Где ошибка? | |
|
|
|
|
|
|
|
для: Лена
(07.07.2008 в 09:28)
| | а) Вместо showTree($row[0],$level++); нужно написать showTree($row[0],$level+1);
б) в строках $ulopn = "<ul>";
$ulcls = "</ul></li>";
Вы почему-то готовитесь открыть один тег , а закрыть - два. | |
|
|
|
|
|
|
|
для: Trianon
(07.07.2008 в 11:37)
| | Если у нас есть вложенные элементы, то у элемента-родителя вырезаем substr() закрывающий тэг LI:
$list = substr($list, 0, -5);
Если вложения идут, например, вот так:
<li><ul>
<li></li>
<li></li>
</ul>
получается, что родительский элемент LI все еще открыт (потому как мы вырезали substr() конечный тэг). Поэтому надо его закрыть, у меня это: $ulcls = "</ul></li>"; Поэтому в случае вложений открывается один тэг, а закрывается - два. Если же мы имеем дело с родителем, то конечный LI не вырезается. | |
|
|
|
|
|
|
|
для: Лена
(07.07.2008 в 12:34)
| | Всё равно это не повод, так над тегами издеваться.
Вот:
<?php
include("configs/dbopen.php");
require ("smarty/Smarty.class.php");
$smarty = new Smarty;
function showTree($parent_id,$level)
{
global $link, $list;
$sql = "SELECT * FROM `menu` WHERE `pid` = ". $parent_id ." ORDER BY `id_menu`";
//echo $sql."<br>";
$result = mysql_query($sql) or die (mysql_error());
if ($level > 0 && mysql_num_rows($result) > 0)
{
$ulopn = "<ul>";
$ulcls = "</ul>";
} else $ulopn = $ulcls = "";
$list .= $ulopn;
while ($row = mysql_fetch_row($result))
{
$list.= "<li><A HREF=\"?id=$row[0]\">".htmlspecialchars($row[2])."</A>";
showTree($row[0],$level+1);
$list.="</li>";
}
$list .= $ulcls;
}
//$list = "<div class='suckerdiv'>";
//$list .= "<ul id='suckertree1'>";
showTree(0,0);
//$list .= "</ul>";
//$list .= "</div>";
$smarty->assign('arr', $list);
$smarty->display("menu1.tpl");
?>
|
| |
|
|
|
|
|
|
|
для: Trianon
(07.07.2008 в 12:51)
| | Пути решений могут быть разными. Спасибо за все. | |
|
|
|
|
|
|
|
для: Лена
(04.07.2008 в 14:05)
| | Тот же код с одним запросом.
<?php
include("configs/dbopen.php");
require ("smarty/Smarty.class.php");
$smarty = new Smarty;
function ShowTree($parent_id)
{
global $link;
$list = '';
$sql = "SELECT * FROM `menu` WHERE `pid` = ". $parent_id ." ORDER BY `id_menu`";
//echo "(st): $sql<br>";
$result = mysql_query($sql, $link);
if(mysql_num_rows($result))
{
if ($parent_id!=0) $list .= "<ul> <!-- parent = $parent_id -->\n";
while ($row = mysql_fetch_assoc($result))
{
$id = $row["id_menu"];
$list.= "<LI><A HREF='?id=$id'>".htmlspecialchars($row['title'])."</A>";
$list.= showTree($id);
$list.= "</li>\n";
}
if ($parent_id!=0) $list .= "</ul> <!-- parent = $parent_id -->\n";
}
return $list;
}
$list = ShowTree(0);
//print $list;
$smarty->assign('arr', $list);
$smarty->display("menu.tpl");
?>
|
Касательно достоинств /недостатков:
Нагрузка на БД в два раза меньше.
Затрачиваемый php объем памяти меньше.
Код проще. | |
|
|
|