Мутация book или каталог из книги.

Главные вкладки

Аватар пользователя player player 20 мая 2008 в 12:42

Был у меня тут недавно случай. Нужно было сделать каталог. Причем для каталога выдвигалось 3-а основных требования.

  1. Простота в управлении (а именно автоматическое создание меню)
  2. Неограниченный уровень вложенности
  3. Вывод подчиненного материала (node) на странице родителя в виде таблицы с картинками.

Искал решение, даже ветку завел Book, Node Hierarchy что еще позволяет делать иерархию? , попробовал category который глючный и сложный для простого обывателя. В итоге пришел к выводу, что по управляемости стандартный book самый простой (генерирует меню автоматически), и каталог слепить можно. Да только вот беда, в book нельзя сделать вывод тизеров материала, а можно выводить лишь названия подчиненного материала. Но разве для drupal это проблема? Конечно нет.
Решение:
Для начала снабдим нашу страницу подшивки изображением. В этотм нам поможет CCK и его доп. модуль imagefield. Ну и contemplate нам понадобится для красивого оформления этого дела. Работу с данными инструментами описывать не буду, т.к. на форуме и так много всего про них сказано. Будем считать что у нас в странице подшивки есть поле изображения
Лезем в код нашего любимого модуля book и ищем там все функции со словом theme_. Находим 3-и функции.
theme_book_navigation($node)
theme_book_export_html($title, $content)
theme_book_admin_table($form)
Ну и как Вы думаете какая нам нужна? Конечно theme_book_navigation($node). Так что берем и смело копируем её в template.php.
function theme_book_navigation($node) {
$output = '';
$links = '';

if ($node->nid) {
$tree = book_tree($node->nid); // получает меню навигации

// генерирует массив ссылок (те что в node.tpl.php $links)
if ($prev = book_prev($node)) {
drupal_add_link(array('rel' => 'prev', 'href' => url('node/'. $prev->nid)));
$links .= l(t('‹ ') . $prev->title, 'node/'. $prev->nid, array('class' => 'page-previous', 'title' => t('Go to previous page')));
}
if ($node->parent) {
drupal_add_link(array('rel' => 'up', 'href' => url('node/'. $node->parent)));
$links .= l(t('up'), 'node/'. $node->parent, array('class' => 'page-up', 'title' => t('Go to parent page')));
}
if ($next = book_next($node)) {
drupal_add_link(array('rel' => 'next', 'href' => url('node/'. $next->nid)));
$links .= l($next->title . t(' ›'), 'node/'. $next->nid, array('class' => 'page-next', 'title' => t('Go to next page')));
}

if (isset($tree) || isset($links)) {
$output = '';
if (isset($tree)) {
$output .= $tree;
}
if (isset($links)) {
$output .= ''. $links .'';
}
$output .= '';
}
}

return $output;
}
?>
Как видите это еще не решение проблемы, т.к. содержание навигации создается не theme_book_navigation а book_tree($node->nid). Собственно все ясно. Нам нужно написать свою book_tree которая будет возвращать не только ссылки но и картинки например.
Для того чтобы посмотреть код booktree можно опять таки взглянуть в код модуля.
Ого оказывается что она состоит еще из одной функции book_tree_recurse. Не слишком ли много функций? Для нашей задачи хватит вполне 2-х функций расположенных в template.php. В book_tree есть функция которая рекурсивно обходит книгу в поиске её детей для создания навигации.
Именно её мы и заменим на свою сама же book_tree для нашей задачи особо не нужна
Ниже уже готовый для моего случая код с некоторым комментариями.
function combustion_book_navigation($node) {
$output = '';
if ($node->nid) {
//$tree = book_tree($node->nid);
// Код ниже взят из book_tree
$depth = 3;
$prnt = $node->nid;
$result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.vid = b.vid WHERE n.status = 1 ORDER BY b.weight, n.title'));
while ($node = db_fetch_object($result)) {
$list = isset($children[$node->parent]) ? $children[$node->parent] : array();
$list[] = $node;
$children[$node->parent] = $list;
}
// наша функция, аналог book_tree_recurse
$tree = my_tree_recurse($prnt, $depth, $children, $unfold = array());

if (isset($tree)) {
$output .= '';
if (isset($tree)) {
$output .= '

'.$tree.'

';
}
$output .= '';
}
}
return $output;
}

//$td это счетчие тегов

в таблице
function my_tree_recurse($nid, $depth, $children, $unfold = array(), $td = 0) {
$output = '';
if ($depth > 0) {
if (isset($children[$nid])) {
foreach ($children[$nid] as $foo => $node) {
if ($td == 0) $output .= ' ';
$td++;
$output .= "
";
if (in_array($node->nid, $unfold)) {
if ($tree = my_tree_recurse($node->nid, $depth - 1, $children, $unfold)) {
$output .= '
  • ';
    $output .= l($node->title, 'node/'. $node->nid);
    $output .= '

    ';
    $output .= '

  • ';
    }
    else {
    $output .= '

  • '. l($node->title, 'node/'. $node->nid) .'
  • ';
    }
    }
    else {
    // если есть вложенная структура
    if ($tree = my_tree_recurse($node->nid, 1, $children)) {
    // node_load считаю достаточно ресурсоемкой функцией. тут больше для примера
    $nd = node_load($node->nid);
    // field_[0]['filename'] можно посмотреть как называется
    // ваш массив в contemplate
    $output .= "nid."'>field_[0]['filename']."'/>";
    $output .= "

    ".l($nd->title, 'node/'. $nd->nid)."

    ";
    $output .= "".$nd->teaser."";
    }
    else {
    // если последние дети
    $nd = node_load($node->nid);
    $output .= "nid."'>field_[0]['filename']."'/>";
    $output .= "

    ".l($nd->title, 'node/'. $nd->nid)."

    ";
    $output .= "".$nd->teaser."";
    }
    }
    // вывод в 3-и колонки
    $output .= "

    ";
    if ($td == 3) {
    $output .= '

    ';
    $td = 0;
    }
    }
    }
    }
    return $output;
    }
    ?>
    __________________________
    Bite my shiny, metal ass!

    Комментарии

    Аватар пользователя VladSavitsky VladSavitsky 20 мая 2008 в 14:15

    "Неограниченный уровень вложенности"
    Насколько я понимаю в Друпал 6 есть ограничение на количество вложенности для модуля Book (9 уровней). В Друпал. 5 такого не было. Но я не проверял предел вложенности.

    Аватар пользователя VladSavitsky VladSavitsky 20 мая 2008 в 14:34

    Для 5ки вложенность не ограничена - в 6ке есть ограничение.

    Подскажите, пожалуйста, как мне в Друпал 6 вывести развернутый список всей иерархии книг на одной странице?
    Я сделал для Друпал 5: http://drupal.ru/book/toc
    Но для Друпал 6 всё поменялось...

    Аватар пользователя Skirr Skirr 21 мая 2008 в 18:56

    VladSavitsky wrote:
    Для 5ки вложенность не ограничена - в 6ке есть ограничение.

    Подскажите, пожалуйста, как мне в Друпал 6 вывести развернутый список всей иерархии книг на одной странице?
    Я сделал для Друпал 5: http://drupal.ru/book/toc
    Но для Друпал 6 всё поменялось...


    неуверен, но может поможет http://api.drupal.org/api/file/modules/book/book-all-books-block.tpl.php...
    Покрайне мере пишут что в блоке можно вывести всё меню.

    Аватар пользователя shumod shumod 9 июня 2008 в 17:56

    Попробовал сделать по описанию - вылезает ошибка:
    Fatal error: Cannot redeclare theme_book_navigation() (previously declared in Z:\home\new\www\modules\book\book.module:481) in Z:\home\new\www\themes\garland\template.php on line 125

    Аватар пользователя gor gor 9 июня 2008 в 20:08

    shumod wrote:
    Попробовал сделать по описанию - вылезает ошибка:
    Fatal error: Cannot redeclare theme_book_navigation() (previously declared in Z:\home\new\www\modules\book\book.module:481) in Z:\home\new\www\themes\garland\template.php on line 125

    вместо дословного theme_book_navigation() необходимо theme заменить на имя вашей темы. Для garland это garland.

    Аватар пользователя player player 9 июня 2008 в 19:54

    А все точно по описанию сделали? Для начала скопируйте код просто

    <?php
    garland_book_navigation() {
    return "IT WORKS!";
    }
    ?>
    в Z:\home\new\www\themes\garland\template.php И посмотрите что выведется там где была навигация..

    Аватар пользователя shumod shumod 10 июня 2008 в 12:26

    player wrote:
    А все точно по описанию сделали?

    Сделал следующее:

    • вырезал "function theme_book_navigation($node) { и т. д. " из book.module и вставил в template.php, изменил theme на garland.
    • заменил book_tree_recurse($parent, $depth, $children, $unfold) в book.module на my_tree_recurse($nid, $depth, $children, $unfold = array(), $td = 0)
    • вставил function combustion_book_navigation($node) и function my_tree_recurse($nid, $depth, $children, $unfold = array(), $td = 0) в book.module
    • заработало, ссылки на дочерние страницы пропали, только при вставке

    garland_book_navigation() {
    return "IT WORKS!";
    }
    опять вылезает ошибка :
    Parse error: syntax error, unexpected '{' in Z:\home\new\www\themes\garland\template.php on line 38

    Аватар пользователя gor gor 10 июня 2008 в 17:01

    Quote:
    опять вылезает ошибка :
    Parse error: syntax error, unexpected '{' in Z:\home\new\www\themes\garland\template.php on line 38

    на 38 строке кода в указаном файле вы допустили ошибку.
    Возьмите учебник по PHP и почитайте его, если же вам это не интересно - попросите какого нить друга програмиста помочь (которому вы доверите доступ к своему сайту) или наймите специалиста, который поможет вам за деньги.

    Аватар пользователя Tankha Tankha 7 августа 2008 в 1:25

    Третий день пытаюсь сделать тоже самое для 6-ки... В конечном итоге уперся в один неразрешимый пока вопрос (использую CCK и contemplate) - как получить список дочерних страниц книги?

    Добавлено:
    Пересмотрел все таблицы. Где же хранится ссылка на родителя?
    Мда. Друпал оказывается не так прост как была надежда.

    Аватар пользователя axel axel 7 августа 2008 в 11:37

    В D6 структура book завязана на меню. См. в таблице book есть ссылка mlid, после см. таблицу menu_links WHERE module = 'book'. Там есть plid - родитель для mlid.

    Аватар пользователя alhoff alhoff 5 марта 2009 в 0:10

    to Tankha:Третий день пытаюсь сделать тоже самое для 6-ки... В конечном итоге уперся в один неразрешимый пока вопрос (использую CCK и contemplate) - как получить список дочерних страниц книги?

    Выложите результаты работы, в задних рядах тоже интересуются!!! : )