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

Форум PHP

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

 

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

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

тема: Алгоритм вложенности каталогов
 
 автор: diman   (06.10.2009 в 15:48)   письмо автору
 
 

Понадобилось изменить скрипт новостей под статьи (это неважно) с возможностью добавлять новый каталог, подкаталог, а если надо то и подподкаталог и т. д. Не подскажите алгоритм или намек как лучше это организовать. Если сделать только один каталог (рубрику), то нет проблем, а если много... Не буду же я для отдельного подкаталога писать отдельную таблицу в БД. Может можно одну таблицу для это сделать, но как отслеживать вложенность? Что-то я совсем запутался.

  Ответить  
 
 автор: neadekvat   (06.10.2009 в 15:55)   письмо автору
 
   для: 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 категории, это понятно, я думаю.
Вот примерно по этому принципу можно сделать.

  Ответить  
 
 автор: diman   (06.10.2009 в 20:05)   письмо автору
 
   для: neadekvat   (06.10.2009 в 15:55)
 

Да, вполне понятно. Спасибо

  Ответить  
 
 автор: class   (05.02.2010 в 20:10)   письмо автору
 
   для: neadekvat   (06.10.2009 в 15:55)
 

Тоже интересовал вопрос неограниченной вложенности.

Только есть ещё и другой вопросик.

Как вывести эту саму навигацию, т.е. показывать сколько каталогов уже прошли (автоматически).


//Вот такое надо вывести:

С корневой мы перешли на "Подкатегория 1".
Должно вывести навигацию так:

Главная >> Подкатегория 1

Потом мы перешли в "ПодПодкатегория 1".
Должно вывести так:

Главная >> Подкатегория 1 >> ПодПодкатегория 1

//и т.д.

  Ответить  
 
 автор: neadekvat   (05.02.2010 в 20:50)   письмо автору
 
   для: class   (05.02.2010 в 20:10)
 

Не берусь говорить, насколько хорошим является решение (и можно ли его вообще назвать хорошим), но можно, например, той же рекурсией, только в обратном порядке - начиная от имеющегося каталога пойти по его parent_id, потом у найденного каталога искать его parent_id и так пока не дойдем до нуля.

  Ответить  
 
 автор: class   (05.02.2010 в 22:10)   письмо автору
 
   для: neadekvat   (05.02.2010 в 20:50)
 

Ну с этим понятно, я тоже так думал, но хотелось бы решение увидеть в коде ))
т.е. такой код, чтобы пока не дошло до нуля выводило записи.

  Ответить  
 
 автор: neadekvat   (05.02.2010 в 22:26)   письмо автору
 
   для: 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>';
}
?>

Пардон, если что. Писал "на коленке", т.е. в поле ввода сообщения. Главное - общий принцип моей идеи показать. Если кто-то покажет лучше (уверен, такие будут), буду рад.

  Ответить  
 
 автор: class   (05.02.2010 в 23:41)   письмо автору
 
   для: neadekvat   (05.02.2010 в 22:26)
 

Спасибо!
Вроде как работает, только тут что то с сортировкой массива.
Беспорядочно выводит навигацию при большой вложенности.


Вот добавлял в базу отрывок алфавита.

Вот так вывело:
Главная » Ё » А » Б » В » Г » Д » Е » Ж » З » И » К » Л » М » Н » О » П » Р » С » Т » У

  Ответить  
 
 автор: neadekvat   (05.02.2010 в 23:46)   письмо автору
 
   для: class   (05.02.2010 в 23:41)
 

Замените rsort() на krsort(), там же по ключам надо. Постоянно забываю.

  Ответить  
 
 автор: class   (05.02.2010 в 23:50)   письмо автору
 
   для: class   (05.02.2010 в 23:41)
 

Решил проблему сортировкой
krsort() вместо rsort()

  Ответить  
 
 автор: neadekvat   (05.02.2010 в 23:59)   письмо автору
 
   для: class   (05.02.2010 в 23:50)
 

О чем я и сказал 4мя минутами раньше вас =)

  Ответить  
 
 автор: class   (06.02.2010 в 00:22)   письмо автору
 
   для: neadekvat   (05.02.2010 в 23:59)
 

Пока я писал - вы уже написали о этой сортировке :)

Спасибо за помощь!

  Ответить  
 
 автор: diman   (30.05.2010 в 13:49)   письмо автору
 
   для: 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 только вложенные имена подрубрик. Как это осуществить? Или может что-нибудь получше предложите?

  Ответить  
 
 автор: Trianon   (30.05.2010 в 15:35)   письмо автору
 
   для: 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); // пока есть родительская категория



Заметьте, я выполнил преобразование, вообще не касаясь предметной области.
Просто как робот.

  Ответить  
 
 автор: neadekvat   (30.05.2010 в 16:43)   письмо автору
 
   для: Trianon   (30.05.2010 в 15:35)
 

Наконец-то!) Я три месяца ждал, когда меня исправят (не в смысле, что я знал ответ, а в смысле, что не знал как реализовать лучшее решение)
Спасибо :)

  Ответить  
 
 автор: Diman   (30.05.2010 в 18:45)   письмо автору
 
   для: 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');


А в таком коде какие будут предложения по улучшению?

  Ответить  
 
 автор: Trianon   (31.05.2010 в 02:13)   письмо автору
 
   для: Diman   (30.05.2010 в 18:45)
 

предложение одно.
Подсчитать количество запросов к БД при, допустим, сотне строк в таблице категорий.

  Ответить  
Rambler's Top100
вверх

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