Как сделать вывод списка статей?

Вывод списка статей (или каких-либо других объектов) относится к функционалу, который присутствует практически на любом сайте. Как сделать вывод подобного списка на G-Drive, можно прочитать в данной статье.

Ранее в статье «Как сделать пагинацию?» я уже приводил код, необходимый для вывода списка. Буду использовать его почти в неизменном виде, только уменьшу для наглядности значение $pp (определяющее максимальное количество статей, с анонсами или без, на отдельной странице списка), чтобы увеличить количество страниц списка, изменю имя используемой в обоих запросах таблицы table на site_articles и добавлю во второй запрос указание на выполнение сортировки по числовому полю aid в убывающем порядке: ORDER BY `aid` DESC. Также, чтобы не создавать две категории (одну для списка статей, другую для отдельных статей), обрамлю этот код следующим образом (читайте статью «Разделение кода модуля между категорией и ее объектами»):

<?php

if (empty($r1))
{
  $r0['module'] .= 'list';
  require PATH.'include/getrow.php';

  // здесь размещается код, о котором говорилось выше
}

Используемый выше включаемый файл (include/getrow.php):

<?php

function getrow(mysqli_result $result)
{
  if ($row = mysqli_fetch_assoc($result)) return $row;
  mysqli_free_result($result);
  return false;
}

Остается написать два шаблона (один для списка статей, другой для отдельной статьи), подготовить таблицу site_articles, не забыв наполнить ее содержимым, и подключить созданный модуль к сайту.

Шаблон списка статей (articleslist.php):

<?php

extra('head-section', '
<style type="text/css">
ul.pagination li { display: inline; list-style: none; }
li.active { font-weight: bold; }
</style>');

?>
<h1><?= $page['name'] ?></h1>
<?= $page['content'] ?>


<!-- Список статей, с анонсами или без -->
<?php while ($row = getrow($result)): ?>
<h2><a href="/<?= $page['id'] ?>/<?= $row['id'] ?>"><?= $row['name'] ?></a></h2>
<?php endwhile; ?>

<!-- Навигация по страницам списка статей -->
<nav>
  <ul class="pagination">
<?php for ($i = $first; $i <= $last; $i++): ?>
    <li<?= $i == $pn ? ' class="active"' : '' ?>><a href="<?= pagelink($i) ?>"><?= $i ?></a></li>
<?php endfor; if ($pc > $last): ?>
    <li><a href="<?= pagelink($i) ?>">Еще</a></li>
<?php endif; ?>
  </ul>
</nav>

Шаблон отдельной статьи (articles.php):

<h1><?= $page['name'] ?></h1>
<?= $page['content'] ?>

Создание таблицы site_articles и примерной записи этой таблицы:

CREATE TABLE `site_articles` (
  `aid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id` varchar(16) NOT NULL,
  `name` tinytext NOT NULL,
  `content` text NOT NULL,
  PRIMARY KEY (`aid`),
  UNIQUE (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2;

INSERT INTO `site_articles` (`aid`, `id`, `name`, `content`) VALUES
(1, 'my-first-article', 'Моя первая статья', '<p>Контент</p>');

Запрос на подключение модуля:

INSERT INTO `site_categories` (`id`, `name`, `content`, `bits`) VALUES
('articles', 'Статьи', '<p>Краткое пояснение к списку</p>', 54);

Расшифровка значения поля bits (54 = 1101102):

  • 112 – использовать режим подключения файлов x3 для подключения файла articles.d.php с основным кодом модуля и файла вложенного шаблона articles.php (это имя может измениться на articleslist.php непосредственно во время выполнения за счет команды $r0['module'] .= 'list' в основном коде модуля);
  • 0 – запретить GET-параметр p для отдельных статей;
  • 1 – разрешить GET-параметр p для списка статей;
  • 102 – использовать режим разрешений 2 для автоматической предвыборки данных отдельной статьи из базы данных.

Демонстрация: /articles – пробуем!

Комментарии: 7

  1. Всеволод

    Начинаю читать и сразу вижу $r1, потом $r0. Что это такое и где это писать?

  2. Михаил

    Вы, видимо, не пользуетесь G-Drive, раз задаете такой вопрос. Что такое $r0 и $r1, можно прочитать в описании движка. Писать нужно в файле articles.d.php (articles – это слаг, т.е. символьный идентификатор, категории; все остальное, в том числе и местоположение этого файла, при необходимости можно изменить, отредактировав соответствующим образом код движка).

    Если вы не имеете код упомянутого движка или не планируете его использовать, можете реализовать логику первого фрагмента кода из статьи любым доступным способом, например при использовании адресов /articles.php[?id=ТУТ_СЛАГ] можно написать так:

    if (empty($_GET['id']))
    {
      // код для списка статей
    }
    else
    {
      // код для отдельной статьи
    }
    

    Только в этом случае, естественно, все необходимые запросы и валидацию входных параметров вам нужно будет делать самостоятельно.

  3. ashuroff

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

  4. Михаил

    Для работы с базой данных это не всегда оптимально, взять хотя бы ветвление из данной статьи или код G-Drive, в котором предварительная работа с базой данных выполняется еще до обращения к файлу для работы с базой данных конкретного модуля. Однако в простейшем случае при помощи ветвления достаточно задать только имя обработчика (для этого идеально подойдет тернарный оператор), после чего использовать обобщенный код, подходящий для любого значения условия из ветвления, например:

    // ветвление, не затрагивающее работу с базой данных, можно
    // разместить до кода открытия соединения с базой данных
    $module = empty($_GET['id']) ? 'articleslist' : 'articles';
    
    if ($link = mysqli_open())
    {
      // подключаем файл для работы с базой данных
      require PATH.$module.'.database.php';
    
      mysqli_close($link);
    }
    else error(503);
    
    // подключаем файл шаблона
    require PATH.$module.'.template.php';
    

    На ветвление с переменной $link в условии не обращайте особого внимания. Это обработка ошибки открытия соединения с базой данных в стиле G-Drive. В случае использования при обработке ошибки исключений или прерываний достаточно написать что-то вроде $link = mysqli_open() or die(); вместо данного ветвления.

    В конце приведенного кода происходит подключение требуемого шаблона. Предполагается, что внутри него помимо размещения специфичного кода вы также будете подключать блоки, необходимые для формирования страницы в целом (header, footer, sidebar и т.п.). Существует и другой подход к формированию страницы в целом. В конце приведенного кода можно подключать общий шаблон страницы с жестко заданным в коде подключения именем, а уже внутри этого шаблона подключать специфичный шаблон с именем, зависящим от значения переменной $module. Подобный подход в G-Drive является основным, правда, он используется в несколько усовершенствованном виде: подключение специфичного шаблона происходит не внутри, а до подключения общего шаблона (это возможно благодаря буферизации в памяти результата выполнения специфичного шаблона). Такое усовершенствование в частности позволяет видоизменять из специфичного шаблона содержимое общего шаблона в любом месте внутри него (см. определение переменной 'head-section' в первом шаблоне из статьи), хотя в G-Drive то же самое можно сделать и при помощи заголовочного файла – это еще один вспомогательный файл, который может быть у модуля.

  5. Михаил

    При использовании G-Drive в качестве имени одного из обработчиков внутри кода модуля можно использовать исходное имя модуля, как это показано в статье. Это позволяет в ряде случаев использовать неполное ветвление.

    В G-Drive данные категории (название списка, «краткое пояснение к списку» и т.п.) и отдельной статьи будут выбираться автоматически, поэтому внутри кода модуля нет необходимости работать с базой данных, когда нужно вывести страницу отдельной статьи. Правда, в более общем случае страница отдельной статьи может содержать по сути такой же список, только не статей, а, например, комментариев. Также страница отдельной статьи может содержать дополнительные метаданные, отсутствующие у указанной в адресе абстрактной категории, например, данные какой-то конкретной тематической категории, к которой относится статья.

  6. Всеволод

    Как использовать функцию getrow, если нужно вывести дважды один и тот же список?

  7. Михаил

    Для многократного вывода списка можно использовать дополнительную функцию «предпросмотра»:

    function preview(mysqli_result $result)
    {
      if ($row = mysqli_fetch_assoc($result)) return $row;
      mysqli_data_seek($result, 0);
      return false;
    }
    

    Также можно расширить функционал функции getrow, добавив логический параметр, указывающий, какое действие следует выполнить, mysqli_data_seek($result, 0) или mysqli_free_result($result):

    function getrow(mysqli_result $result, $preview = false)
    {
      if ($row = mysqli_fetch_assoc($result)) return $row;
      if ($preview) mysqli_data_seek($result, 0);
      else mysqli_free_result($result);
      return false;
    }
    

    При любой реализации вы сначала используете функцию «предпросмотра» и только для вывода последнего списка вызываете функцию getrow без указания логического параметра.

    Можно получать список заранее в более удобном для вывода виде, например в виде массива записей. Для этого у mysqli_result есть специальный метод fetch_all (функция mysqli_fetch_all). Также заранее после получения списка в массиве можно освободить результат. А уже потом делать вывод из массива при помощи цикла foreach:

    $rows = mysqli_fetch_all($result, MYSQLI_ASSOC);
    mysqli_free_result(result);
    ...
    foreach ($rows as $row):
    

    Цикл foreach можно использовать и непосредственно на значении $result, но здесь имеется все та же проблема с освобождением результата при выводе:

    foreach ($result as $row):
    

    В общем-то неосвобождение результата не считается серьезной ошибкой.

Отправить комментарий

Ваш адрес E-mail не будет опубликован.