Модуль вывода содержания FB2 книги Drupal 7

Прежде чем браться за новый модуль, необходимо добавить еще одно поле Link к нашему типу материала «Book», о котором говорилось в прошлой статье. Назовем его «Содержание» (field_content_link), и в fb2upload.module добавим пару строк для его заполнения:

$new_node->field_content_link['und'][0]['url'] = $GLOBALS['base_url']."/fb2content/".$file->fid;
$new_node->field_content_link['und'][0]['title'] = "Содержание";

На этом изменения модуля fb2upload пока закончены.
Приступим к новому модулю fb2content. Вот его *.info файл:

name = FB2Content
description = Show content of FB2 book
core = 7.x
version = 7.x-1.x-dev
package = FB2

hook_menu реализуем следующим образом:

function fb2content_menu() {
  $items = array();
  $items['fb2content'] = array(
    'title' => 'Содержание книги',
    'page callback' => 'main_function',
    'access callback' => TRUE,
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

Вызываться модуль будет запросом /fb2content/book_id, где book_id — fid загруженной книги.
В main_function укажем следующий код:

function main_function($arg=-1) {
  $form="";
  if(intval($arg)<0)
  {
    drupal_set_message("Неправильный вызов модуля!", 'error');
    return "<p>Не передан идентификатор книги!</p>";
  }
  $query = db_select('file_managed', 'fm');
  $query->fields('fm', array('uri'));
  $query->condition('fm.fid', intval($arg));
  $result = $query->execute()->fetchObject();
  if(!isset($result->uri))
  {
    drupal_set_message("Не удалось получить адрес файла!", 'error');
    return "<p>Возникла ошибка :(</p>";
  }
  $content = array();
  $xml = simplexml_load_file(drupal_realpath($result->uri));
  $body=$xml->body;
  foreach($body->children() as $element)
    foreach ($body->children() as $element) {
      switch ($element->getName()) {
          case "section":
              $form .= "<li>Секция " . (++$i) . " " . strip_tags($element->title->asXML())."</li>";
              GetTitle($element, $content);
      }
  }
  return $form;
}

Первоначально проверим, правильно ли передан в функцию book_id и выведем сообщение об ошибке, если с ним возникли какие-то проблемы. Если с ним все ок, то дергаем из таблицы file_managed URI файла книги и грузим этот файл в парсер SimpleXML.
Далее берем первый элемент body и проходимся по всем его детям. Если его дочерний элемент — section, то добавляем в массив $content[] его заголовок. Однако, секции могут быть вложенными с неограниченным уровнем. Чтобы вывести все уровни, определим рекурсивную функцию GetTitle(), которая будет принимать на входе элемент, для которого нужно вывести содержание, и массив $content[], в который добавляются заголовки секций. Выглядеть эта функция будет следующим образом:

function GetTitle($section, &$content)
{
  foreach($section->children() as $element)
  {
    switch($element->getName())
    {
      case "section":
        $content[]=strip_tags($element->title->asXML(),"<p>");
        GetTitle($element, $content);
    }
  }
}
</p>

Стоит так же учесть, что у секций может и не быть заголовка (элемента title). Поэтому при выводе я решил добавить слово «Секция» и ее порядковый номер. На этом считаю задачу-миниму решенной, однако в дальнейшем этот модуль будет дорабатываться, ведь у книги может быть несколько элементов body, и сами эти элементы тоже могут содержать дочерний элемент title.
UPD.: В комментариях верно указали на лишний цикл. Засунул все в один.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *