2. Перевод модели с базы данных на файлы
Отделение модели от контроллера в архитектуре MVC предоставляет разработчикам множество преимуществ. Одно из них — свободное изменение источника данных. То есть если приложение работает с БД, то чтобы перевести его на работу, например, с XML-базой нужно лишь изменить код модели. Главное чтобы её методы возвращали то что раньше, а как они реализованы внутри — приложению не важно. Сейчас мы рассмотрим перевод приложения с одного источника данных на другой на практике, а точнее — на нашей гостевой книге. Мы переведём её с использования MySQL на текстовые файлы. Храниться они у нас будут в папке «data» в корне хоста. Каждая запись будет находятся в отдельном файле. Каждый файл за место имени будет иметь номер записи, то есть это будут файлы без расширения с именами типа 1,2,3 и т.д. Внутри у них будут содержаться те же данные (автор, e-mail, дата публикации и текст), но в виде сериализованного массива.
Приступим непосредственно к программированию. При работе с данными нам понадобятся 2 хэлпера - «Directory»(http://code-igniter.ru/user_guide/helpers/directory_helper.html) и «File»(http://code-igniter.ru/user_guide/helpers/file_helper.html). Их подключение мы организуем в конструкторе нашей модели:
PHP код:
function __construct()
{
parent::Model();
$this->load->helper('Directory');
$this->load->helper('File');
}
Рассмотрим первый метод - «getLastAnswers». Алгоритм его работы будет такой. Сначала мы получим массив всех файлов которые есть в директории. Затем мы с помощью цикла отберём 10 отзывов, которые нам нужны, и вернём массив с ними. Ниже я приведу код метода, а после него опишу каждую строку чтобы у Вас не возникло каких-либо вопросов.
PHP код:
function getLastAnswers($start_limit)
{
// Получаем список файлов в директории
$directory = directory_map('./data/',true);
// Сортируем имена файлов в порядке убывания
rsort($directory);
$i = 0;
$answers = Array();
foreach($directory as $file)
{
// Пропускаем столько отзывов сколько нужно
$start_limit--;
if($start_limit > 0) continue;
// Ломаем цикл если счётчик насчитал 10 сообщений
if($i == 10) break;
// Считываем данные из файла и заносим в массив ответов
$data = read_file('./data/'.$file);
$answers[] = unserialize($data);
// Увеличиваем на 1 счётчик сообщений
$i++;
}
return $answers;
}
В самом начале с помощью функции «directory_map» helper`a «Directory» мы получаем всё содержимое папки ответов. Так как файлы у нас имеют цифровые имена то мы сортируем результат функцией «rsort» для того чтобы расположить их в массиве в порядке убывания. То есть файлы с последними ответами будут в начале, а с самыми первыми — в конце. Затем мы создаём счётчик сообщений «i». Он будет увеличиваться при обработке каждого следующего сообщения для того чтобы мы могли контролировать выводимое количество сообщений — как только обработано 10 штук сразу останавливаем цикл. Далее мы циклом «foreach» обрабатываем массив с содержимым директории. В начале цикла помещён код который уменьшает переменную «start_limit». Сделано это вот зачем. Например пользователь пройдёт на вторую страницу гостевой книги и тогда в «start_limit» будет лежать число 10, означающее что нам нужно пропустить 10 отзывов которые были на первой странице и только потом вывести следующий десяток. При начале цикла «start_limit» уменьшается на единицу, и если он больше нуля цикл начинается сначала. То есть пока цикл не сработает в холостую 10 раз выборка сообщений не начнётся. Так мы заменили SQL-конструкцию «LIMIT». Дальше происходит проверка счётчика сообщений — если он равен 10 (в массив помещено 10 сообщений) то цикл прекращает работу с помощью оператора «break» и функция возвращает массив результатов. Если же нет, то происходит считывание следующего файла с сообщением, его разсериализация и помещение в массив сообщений.
Перейдём к функции «getAnswersCount». В ней мы просто будем получать количество файлов в директории. Это будет выполнять функция «directory_files_count», которую мы добавим в хелпер «Directory». Создайте файл «MY_Directory_helper.php» в папке «application/helpers/» и поместите в нём следующий текст:
PHP код:
<?php
function directory_files_count($source)
{
return count(directory_map($source));
}
?>
Этим мы расширили функционал хэлпера «Directory». Функция «direactory_map» возвращает содержимое указанной директории в виде массива, а наша функция просто возвратит количество записей в этом массиве. Теперь, в функции получения количества ответов нам нужно просто вызвать «directory_files_count» и вернуть её результат:
PHP код:
function getAnswersCount()
{
return directory_files_count('./data/');
}
Возьмёмся за последнюю функцию — «addAnswer». Алгоритм её работы прост — сначала мы организуем массив данных сообщения (автор, текст и т.д.). Затем определяем номер последнего отзыва, увеличиваем его на единицу, тем самым получая имя следующего файла, и записываем в этот файл сериализованный массив с ранее сформированныи данными.
PHP код:
function addAnswer($author,$email,$text)
{
$pub_date = time();
// Формируем массив пришедших к нам данных
$answer = Array();
$answer['author'] = $author;
$answer['email'] = $email;
$answer['pub_date'] = $pub_date;
$answer['text'] = $text;
// Получаем список файлов из папки
// А фактически - массив чисел
$files = directory_map('./data/',true);
// Получаем максимальное число из этого массива
// (последний отзыв)
$last_file = @max($files);
// Прибавляем к нему единицу, чем получаем
// номер следующего комментария
$next_file = intval($last_file)+1;
// Ну и записываем файл
write_file('./data/'.$next_file,serialize($answer));
}
Вас может удивить значёк «@» у функции «max» и пропуск переменной «last_file» через функцию «intval». Дело в том что если в гостевой книге нет ни одного отзыва то не будет и списка чисел, который мы должны передать функции «max». Следовательно она выдаст ошибку. чтобы этой ошибки не вывелось мы и подставили к ней знак «@». При тех же условиях функция «max» ничего не вернёт в переменную «last_file», поэтому для того чтобы пустоту преобразовать в 0 (нам ведь нужно число т.к. мы его потом увеличиваем на единицу) мы используем функцию «intval». Вот и всё. Модель нами перенесена полностью на текстовые файлы. Можете сами в этом убедится обратившись к приложению. Полностью рабочий код этой части статьи Вы можете взять в файле «gb_gile.zip»