Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Рекурсия
 
 автор: Лена   (11.06.2008 в 09:22)   письмо автору
 
 

Для любителей рекурсии и Смарти.
Есть вот такая функция

<?php
include("dbopen.php");
function 
ShowTree($parent_id$lvl) {
  global 
$link;
  global 
$lvl;
  
$lvl++; 
  
$list = array(); // массив значений для Смарти
  
$sql "SELECT * FROM `modules` WHERE `pid_mod` = 26  AND `pm_id` = "$parent_id ." AND `visib` = 1 ORDER BY `id_mod`";
  
$result mysql_query($sql$link);
  if(
mysql_num_rows($result) > 0) {
    while (
$row mysql_fetch_assoc($result)) {
      
$list[] = $row;
      
$id $row['id_mod'];
      
$name $row['name'];
      
ShowTree($id$lvl);
      
$lvl--;
    }
  }
return 
$list;
}

echo 
"<pre>"
print_r(ShowTree(0,0));
echo 
"</pre>";



Выводится только родители, 0 уровень. Как вывести потомков? Где у меня ошибка? Если без разделения html и php, например, вот так:

if (mysql_num_rows($result) > 0)
    {
        echo("<UL>\n");
        while ( $row = mysql_fetch_array($result) )
        {
            $id = $row["id_mod"];
            echo("<LI>\n");
            echo("<nobr>");
            echo("<A HREF='?id=$id'>{$row["name"]}</A>&nbsp;&nbsp;\n");
            echo("</nobr>");
            ShowTree($id, $lvl);
            $lvl--;
        }
    echo("</UL>\n");
    }

все выводится нормально, и родители, и потомки. Помогите, пожалуйста, второй день бьюсь. Заранее спасибо

   
 
 автор: Trianon   (11.06.2008 в 10:42)   письмо автору
 
   для: Лена   (11.06.2008 в 09:22)
 

<?php
include("dbopen.php");
function 
ShowTree($parent_id$list
{
  global 
$link;
  
$sql "SELECT * FROM `modules` 
           WHERE `pid_mod` = 26  AND `pm_id` = "
$parent_id ." AND `visib` = 1 
           ORDER BY `id_mod`"
;
  
$result mysql_query($sql$link);
  
$levlist = array(); 
   while (
$row mysql_fetch_assoc($result)) 
        
levlist[] = $row;
   
mysql_free_result($result);
   foreach(
$levlist as $row)
   {
        
$list[] = $row;
        
$list ShowTree($row['id_mod'], $list);
   }
   return 
$list;

ShowTree(0, array());
?>

   
 
 автор: Лена   (11.06.2008 в 11:44)   письмо автору
 
   для: Trianon   (11.06.2008 в 10:42)
 

Теперь я передаю полученное из функции значение в шаблон. После вашего кода добавляю:
$smarty->assign('arr',$list);
$output=$smarty->fetch("menu.tpl");

и пишет ошибку: Parse error: parse error, unexpected $end in s:\home\myproject.ua\www\moduls\menu\menu2.php on line 25
25 - закрывающий тег php

   
 
 автор: Trianon   (11.06.2008 в 11:55)   письмо автору
 
   для: Лена   (11.06.2008 в 11:44)
 

Покажите Ваш код.
Явно где-то пропущена }
Я, кстати, слегка наврал в вызове. Функция возвращает результат:


print_r(ShowTree(0, array()));

   
 
 автор: Лена   (11.06.2008 в 12:05)   письмо автору
 
   для: Trianon   (11.06.2008 в 11:55)
 

Скобку добавила. Функция была не закрыта. Теперь пишет
Notice: Undefined variable: list in s:\home\myproject.ua\www\moduls\menu\menu2.php on line 21
Вот весь код:

<?php
function ShowTree($parent_id$list){
global 
$link;
$sql "SELECT * FROM `modules` 
           WHERE `pid_mod` = 26  AND `pm_id` = "
$parent_id ." AND `visib` = 1 
           ORDER BY `id_mod`"
;
$result mysql_query($sql$link);
$levlist = array(); 
    while (
$row mysql_fetch_assoc($result)){
        
$levlist[] = $row;
       
mysql_free_result($result);
       foreach(
$levlist as $row){
        
$list[] = $row;
        
$list ShowTree($row['id_mod'], $list);
       }
   return 
$list;

}
ShowTree(0, array());

$smarty->assign('arr',$list);
$output=$smarty->fetch("menu.tpl");
?> 

   
 
 автор: Trianon   (11.06.2008 в 12:11)   письмо автору
 
   для: Лена   (11.06.2008 в 12:05)
 

Вы расстановкой скобок изрядно исказили код, нарушив логику.
Если Вам совсем невмоготу без лишних скобок - поставьте их так:

<?php
function ShowTree($parent_id$list){
global 
$link;
$sql "SELECT * FROM `modules` 
           WHERE `pid_mod` = 26  AND `pm_id` = "
$parent_id ." AND `visib` = 1 
           ORDER BY `id_mod`"
;
    
$result mysql_query($sql$link);
    
$levlist = array(); 

    while (
$row mysql_fetch_assoc($result)){
        
$levlist[] = $row;
    }

    
mysql_free_result($result);

    foreach(
$levlist as $row){
        
$list[] = $row;
        
$list ShowTree($row['id_mod'], $list);
    }

   return 
$list;


$list ShowTree(0, array());

$smarty->assign('arr',$list);
$output=$smarty->fetch("menu.tpl");
?> 

   
 
 автор: Лена   (11.06.2008 в 12:23)   письмо автору
 
   для: Trianon   (11.06.2008 в 12:11)
 

А зачем здесь освобождать память mysql_free_result($result), если в конце сценария она и так освободится? Мне как-то не жалко места в памяти...
Я загрузила скрипт - и на меня смотрит чистый лист. Попробовала вот так: $list = ShowTree(0, array());
print_r($list); - распечатался массив из базы. Смарти меня где-то неправильно понимает. Что скажете?

   
 
 автор: sim5   (11.06.2008 в 12:27)   письмо автору
 
   для: Лена   (11.06.2008 в 12:23)
 

Просто дальше - либо отдать переменную $output в Смарти шаблон, либо просто без перехвата шаблона menu.tpl, передать полученный массив в шаблон Смарти.

   
 
 автор: Лена   (11.06.2008 в 12:30)   письмо автору
 
   для: sim5   (11.06.2008 в 12:27)
 

Передала в Смарти. Странно, но выводится все в один столбик - и родители, и потомки, вот так:
1 родитель
потомок
потомок
2 родитель
потомок
потомок
и так дальше. Не сработала рекурсия!!!
Интересно уже стало, а вообще такое в природе возможно? Чтобы через Смарти передавать рекурсию?

   
 
 автор: sim5   (11.06.2008 в 12:49)   письмо автору
 
   для: Лена   (11.06.2008 в 12:30)
 

Нельзя передать в Смарти рекурсию, в шаблон передается просто массив, и если этот массив многомерный, другими словами, учитывает уровни вложения категорий, то его просто нужно правильно разложить в шаблоне. Иначе в функцию запроса к базе, добавить уровень вложения категорий, уже опираясь на который, разложить массив в шаблоне.

   
 
 автор: Trianon   (11.06.2008 в 12:33)   письмо автору
 
   для: Лена   (11.06.2008 в 12:23)
 

Приведите краткий пример (пусть даже без БД) в котором конструкция
$smarty->assign('arr',$list);
$output=$smarty->fetch("menu.tpl");

выведет нечто похожее на то, что Вам надо. Буквально на три-пять строк.

И приведите, пожалуйста,структуру таблицы.
дальше можно будет думать, как помочь.

   
 
 автор: Лена   (11.06.2008 в 12:51)   письмо автору
 
   для: Trianon   (11.06.2008 в 12:33)
 

Краткий пример здесь не получится. Привожу длинный и некраткий, как я делаю:
Есть шаблон index.tpl, к которому подключается menu.tpl вот так: {include file="menu.tpl"}

index.tpl выводится с помощью index.php: $output=$smarty->fetch("index.tpl");
print $output;

Код menu.tpl:

<div class = "suckerdiv">
{if !empty($arr)}
    <ul id="suckertree1">
        {foreach from=$arr item=row}
            <LI>
            <nobr><A HREF='?id={$row.id_mod}' class="mainmenu">{$row.name}</A></nobr>
            </LI>
        {/foreach}
    </UL>
{/if}
</div>


В свою очередь menu.tpl обрабатывается той самой рекурсивной функцией. Подключаются к основному шаблону стили и в итоге должно получиться вот такое: в столбик - родители, наводишь указатель - справа вываливаются потомки (это с помощью JS), а у меня сейчас все в одном столбике.
Структура таблицы такая:
id_mod - id модуля
pm_id - id родителя модуля в меню
pid_mod - родитель для модуля в общей структуре сайта (вся страница делится на menu,left,content, right)
name - название модуля
index_filename - индекс-файл, через который модуль вызывается
tpl - название файла шаблона
stl - название файла стиля
descr - описание модуля
visib - подключен модуль или нет

   
 
 автор: sim5   (11.06.2008 в 13:19)   письмо автору
 
   для: Лена   (11.06.2008 в 12:51)
 

$smarty->fetch перехватывает шаблон вместо вывода его на экран, при этом он будет обработан, и переменная которой присвоен результат работы этого шаблона, содержит готовый HTML-код. Можно конечно теперь echo или print, но к чему тогда шаблоны? Там где необходимо теперь вывести код меню, нужно просто указать, если это в index.tpl, то, например:
$smarty->assign("menu", $output); //передали результат в шалон index.tpl
//а в index.tpl выводим где-то в нужном месте
{$menu}
Или в этом месте нужно делать подключение шаблона menu.tpl, который и будет обрабатывать переданную ему перменную {$arr}:
{if $arr}
раскладываем массив
{/if}
Обход массива должен учитывать структуру вашего меню, а она в свою очередь должна подчинятся уровню вложений категорий возвращаемых из рекурсии. Можно в рекурсивном запросе описать непосредствено элементы меню и порядок их вложения, в зависимоти от уровня вложения категорий, и в готовом уже виде передать это в шаблон.

   
 
 автор: Лена   (11.06.2008 в 14:21)   письмо автору
 
   для: sim5   (11.06.2008 в 13:19)
 

В menu.php получаю данные из функции и направляю их в шаблон menu.tpl, перехватываю результат:
$list = ShowTree(0, array());
$smarty->assign('arr',$list);
$output=$smarty->fetch("menu.tpl");

В index.php подключаю индекс-файл модуля меню и передаю результат работы menu.php:
include("moduls/menu/menu2.php");
$smarty->assign("menu", $output);
$out=$smarty->fetch("index.tpl");
print $out;

Дальше в шаблоне index.tpl вывожу перехваченные данные в отдельную ячейку:
<td>
{if $arr}
{include file="menu.tpl"}
{/if}
</td>
И все равно меню выводится в один столбец.

   
 
 автор: sim5   (11.06.2008 в 14:45)   письмо автору
 
   для: Лена   (11.06.2008 в 14:21)
 

То что вы передали так, это так и надо делать, если пользоваться шаблонами. Но от этого, вложений категорий не появиться, проблема этого не в способе подключения.
Лучше описать сами элементы меню (UL, LI, A) в функции ShowTree, при этом возвращаемое значение из функции будет равно уже готовому меню, останется только подключить его в шаблоне без обхода. У вас простое меню, поэтому не придется его править, так как его элементы будут у вас вложены в любом случае в контейнер DIV. Если ID этого контейнера будет равно, например, menu, то в CSS вы сможете определить положение и вид для всех его элементов.
Что касается "все в один столбик", то, если вложение ваших категорий не превышает 2 (у каждого родителя один потомок), то достаточно будет проверять в функции ShowTree() значение pm_id, и если оно равно 0, то вы описываете корневой элемент меню, если нет, то вложенный в родителя элемент меню.

   
 
 автор: Лена   (11.06.2008 в 15:09)   письмо автору
 
   для: sim5   (11.06.2008 в 14:45)
 

Зачем описывать в ShowTree элементы меню (UL, LI, A) и делать уже изначально готовое меню со всеми обходами, а потом передавать эту смесь php и html в шаблон, когда весь смысл этих мучений - разделить php и html?
Приведите пример, как проверять в функции ShowTree() вложения.

   
 
 автор: sim5   (11.06.2008 в 15:25)   письмо автору
 
   для: Лена   (11.06.2008 в 15:09)
 

Просто потому, что в этой функции проще будет описать все элементы меню - меню у вас простое, внешней правки его будет достаточно с помощью CSS. JS же в меню служит, скорее всего, для управления видимостью его элементов, работая опять таки со стилями его. Применение шаблонов, совсем не означает, что нужно забыть об обработке данных там, где это сделать выгоднее, чтобы потом усложнять задачу в шаблоне. Если же вы хотите раскладывать полученный масиив в шаблоне, то проверяйте значание родителя во время уже цикла Смарти - если рано 0, то это верхний уровень, значит: UL LI A, если нет, то следуя HTML коду меню, прописывать вложение элемента второго уровня.
Я не обладаю способностями Макаренко, для меня лучше "один раз потрогать, чем сто раз услышать"), поэтому, если будут затруднения - вышлите мне дамп таблицы и сам код меню, я приготовлю все у себя.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования