Вывести полное содержание всех книг (book) на сайте в виде иерархии

24 Май 2008
Опубликовано VladSavitsky

Решение

Полное содержание лучше вывести как отдельную страницу, а не блок, потому что блок имеет как правило небольшие размеры:

  1. Создаём страницу,
  2. Вставляем код подходящей версии Друпал,
  3. Выставляем формат ввода: "PHP",
  4. Сохраняем.

Drupal 5

function book_tree_recurse_all($nid, $depth, $children) {
  if ($depth > 0) {
    if ($children[$nid]) {
      foreach ($children[$nid] as $foo => $node) {

          if ($tree = book_tree_recurse_all($node->nid, $depth - 0, $children)) {
             $output .= '<li class="expanded">';
             $output .= l($node->title, 'node/'. $node->nid);
             $output .= '<ul>'. $tree .'</ul>';
             $output .= '</li>';
          } else {
             $output .= '<li class="leaf">'. l($node->title, 'node/'. $node->nid) .'</li>';
          }
      }
    }
  }
  return $output;
}

function book_tree_expanded($parent = 0, $depth = 3) {
  $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.nid = b.nid AND n.vid = b.vid WHERE n.status = 1 AND n.moderate = 0 ORDER BY b.weight, n.title'));

  while ($node = db_fetch_object($result)) {
    $list = $children[$node->parent] ? $children[$node->parent] : array();
    array_push($list, $node);
    $children[$node->parent] = $list;
  }

  if ($tree = book_tree_recurse_all($parent, $depth, $children)) {
    return '<div class="menu"><ul>'. $tree .'</ul></div>';
  }
}
print book_tree_expanded(0);

Drupal 6

function book_toc_recursive($bid, $pid) {
  $sql = "SELECT a.mlid, b.link_path, b.link_title FROM {book} a INNER JOIN {menu_links} b ON a.mlid = b.mlid WHERE (a.bid=%d) AND (b.plid=%d) order by a.mlid";
 
  $result = db_query(db_rewrite_sql($sql), $bid, $pid);
  if ($result) {
    print "<ul>";
    while ($data = db_fetch_object($result)) {
      print "<li>" . l($data->link_title, $data->link_path) . "</li>";
      book_toc_recursive($bid, $data->mlid);
    }
    print "</ul>";
  }
}

$all_books=book_get_books();
foreach ($all_books as $book_id=>$link) {
   book_toc_recursive($book_id, 0);
}

<?php
//v.7
unset($output);
function is_book_page_new($changed) {
  //Период, в течении которого статьи считаются новыми.
  if ($changed>strtotime("-7 day")) return ' class="changed"';
}
function book_toc_recursive($bid, $pid) {
  $sql="SELECT b.mlid, ml.link_path, ml.link_title, ml.has_children, n.changed FROM book b INNER JOIN menu_links AS ml ON b.mlid = ml.mlid, {node} AS n WHERE (b.bid=%d) AND (ml.plid=%d) AND b.nid=n.nid AND n.status=1 ORDER BY b.mlid";
  $result = db_query(db_rewrite_sql($sql), $bid, $pid);
  if ($result) {
    while ($data = db_fetch_object($result)) {
      $output.='<li'.is_book_page_new($data->changed).'>'.l($data->link_title, $data->link_path);
      if ($data->has_children)  $output.='<ul>'.book_toc_recursive($bid, $data->mlid).'</ul>';
      $output.='</li>';
    }
  }
  return $output;
}
$all_books=book_get_books();
foreach ($all_books as $book_id=>$link) {
   print '<ul class="book_toc">'.book_toc_recursive($book_id, 0).'</ul>';
}
?>

Использованные материалы

Полезные ссылки

Изменения в модуле Book в Друпал 6

Комментарии

а у меня код для 6ки выводит такую ошибку:
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order by a.mlid)' at line 1 query: SELECT a.mlid, b.link_path, b.link_title FROM book a INNER JOIN menu_links b ON a.mlid = b.mlid INNER JOIN node_access na ON na.nid = n.nid WHERE (na.grant_view >= 1 AND ((na.realm = 'all' AND na.gid = 0) OR (na.realm = 'domain_site' AND na.gid = 0) OR (na.realm = 'domain_id' AND na.gid = 0)) ) AND ( (a.bid=3) AND (b.plid=0) order by a.mlid) in /www/odints/www/htdocs/ng/includes/common.inc(1537) : eval()'d code on line 5.

И это у всех пользователей, кроме user #1

Skirr | Июн 8th, 2008 в 5:29 после полудня

Я вам рекомендую отключить вывод ошибок/предупреждений в браузер, а сохранять их и давать просматривать только админам.
В данном случае ошибку вызывает файл common.inc, а не сниппет из статьи - почитайте внимательно сообщение об ошибке.

VladSavitsky | Июн 13th, 2008 в 1:10 утра

Стоит уточнить, что в запросах таблицы "book" и "menu_links" могут иметь другие названия, если указывали префикс при установке. У меня например это drpl_. соответственно таблицы называются "drpl_book" и "drpl_menu_links".

И еще.
Я бы посоветовал чуть переделать код (иначе под элементами у которых нет дочерних появляются пустые ul /ul потому что if($result) - не работает). Хотя Это конечно мелочи.

function book_toc_recursive($bid, $pid) {
  $sql = "SELECT a.mlid, b.link_path, b.link_title FROM book a INNER JOIN menu_links b ON a.mlid = b.mlid WHERE (a.bid=%d) AND (b.plid=%d) order by a.mlid";
 
  $result = db_query(db_rewrite_sql($sql), $bid, $pid);
++  if ($result) {
++  $data = db_fetch_object($result);
++  }

---  if ($result) {
++  if ($data) {
    print "<ul>";
---  while ($data = db_fetch_object($result)) {
++  while ($data) {
      print "<li>" . l($data->link_title, $data->link_path) . "</li>";
      book_toc_recursive($bid, $data->mlid);
++  $data = db_fetch_object($result);
    }
    print "</ul>";
  }
}
$all_books=book_get_books();
foreach ($all_books as $book_id=>$link) {
   book_toc_recursive($book_id, 0);
}

Tankha | Авг 17th, 2008 в 1:57 после полудня

Tankha, спасибо за замечание.
Для того, чтобы учесть префикс в имени таблицы нужно обернуть имя таблицы в фигурные скобки - я это исправил в рецепте. То есть нужно использовать {book} - тогда Друпал сам всё сделает за нас. Но ошибка у товарища выше была не в этом...

Про лишние теги. На главной странице у нас работает этот скрипт для Д6. Вот ссылка на проверку валидности: http://validator.w3.org/check?uri=http://drupalcookbook.ru/

Раньше такие теги были, но причиной оказалось то, что были некорректные записи в базе данных в таблицах book и menu_links. После того, как вручную всё исправил - этих тегов нет.

VladSavitsky | Авг 25th, 2008 в 3:19 после полудня

Пользуйте такой код и будет Вам счастье

<?php
//v.8
unset($output);
function is_book_page_new($changed) {
//Период, в течении которого статьи считаются новыми.
if ($changed>strtotime("-7 day")) return ' class="changed"';
}
function book_toc_recursive($bid, $pid) {
$sql="SELECT b.mlid, ml.link_path, ml.link_title, ml.has_children, n.changed FROM {book} b INNER JOIN {menu_links} AS ml ON b.mlid = ml.mlid, {node} AS n WHERE (b.bid=%d) AND (ml.plid=%d) AND b.nid=n.nid AND n.status=1 ORDER BY b.mlid";
$result = db_query(db_rewrite_sql($sql), $bid, $pid);
if ($result) {
while ($data = db_fetch_object($result)) {
$output.='

  • changed).'>'.l($data->link_title, $data->link_path);
    if ($data->has_children) $output.='
      '.book_toc_recursive($bid, $data->mlid).'

    ';
    $output.='

  • ';
    }
    }
    return $output;
    }
    $all_books=book_get_books();
    foreach ($all_books as $book_id=>$link) {
    print '

      '.book_toc_recursive($book_id, 0).'

    ';
    }
    ?>

    Гость | Ноя 21st, 2008 в 3:34 после полудня
     
     
     

    RSS-лента новостей

    Dries Buytaert по-русски
    ]]>Русский поиск Drupal]]>

    Перенос сайта из Joomla в Drupal
    Перенос сайта из WordPress в Drupal

    ]]> Drupal - это бесплатная система управления контентом с открытым исходным кодом ]]>