PHP framework CodeIgniter: контроллер и представления

Владимир | | CodeIgniter, PHP.

логотип для каталога книг
В предыдущих выпусках мы начали разработку небольшого сайта, представляющего собой обычный каталог. Кратко напомню, о чем шла речь в предыдущих статьях.

В первой части мы установили и настроили фрэймворк (CodeIgniter).
Во второй – определились с требованиями к нашему приложению, создали БД, написали каркас контроллера и разобрались с передачей параметров в ссылках.
В третьей части описана модель нашего приложения, т.е. мы создали класс, выполняющий все операции с данными.

Подключаем модель к контроллеру

Для этого в конструкторе контроллера (system/application/controllers/catalog.php) добавляем строку

$this->load->model('catalogmodel');

Обратите внимание, что имя файла модели указывается без расширения (.php). Это правило относится и ко всем остальным компонентам фрэймворка (библиотекам, представлениям).

У вас мог возникнуть вопрос: «Почему подключение выполняется именно в конструкторе?». Тут все просто. Подключить модель можно в любом из методов. Но тогда она будет доступна только внутри этого метода, а т.к. оба метода нашего контроллера используют одну и ту же модель, то лучше подключить ее в конструкторе (не дублируется код).

Теперь мы можем вызывать методы модели. Например,

$this->catalogmodel->getAllBooks();
$this->catalogmodel->getBookDetails($bookid);


Как видите, CodeIgniter создал объект catalogmodel, с помощью которого мы и работаем с моделью. Кстати, обратите внимание, мы не используем функции include() и require(). Все необходимые вызовы выполняются объектом load.

Переходим к методам контроллера. В первой части мы уже объявили эти методы.
Первый метод называется index() и служит для создания главной страницы каталога.

function index() {
    $pageData['title'] = "Каталог книг - главная";
    $pageData['books'] = $this->catalogmodel->getAllBooks();
    if ($pageData['books'] == false) {
        $pageData['errDescription'] = "Книги не найдены";
    }
    $this->load->view("main", $pageData);
}

Здесь мы сталкиваемся еще с одной возможностью CodeIgniter, а именно передачей данных из контроллера в представление.

Все, что нам нужно сделать, это создать массив с данными, которые нужны для формирования страницы, и передать его во втором параметре метода view() (строка 7). Учтите, что массив должен быть ассоциативным, т.к. в представлении ключи используются для доступа к данным.

О представлениях мы поговорим чуть ниже, а сейчас разберемся какие данные нужно передавать. Прежде всего, это данные из БД, т.е. информация о книгах. Поэтому в строке 3 мы читаем эти данные из базы (с помощью модели) и сохраняем их в $pageData['books']. Если метод getAllBooks() вернул false, мы создаем элемент массива $pageData['errDescription'] с описанием ошибки.

Кроме того, мы передаем еще и заголовок страницы $pageData['title']. В общем-то, он может быть и постоянным, но вдруг вы захотите добавить в него какую-нибудь информацию (например, количество записей).

После того, как массив сформирован, мы загружаем представление (строка 7).

Представление (согласно архитектуре MVC) формирует страницу, которая будет отправлена браузеру. Как мы уже говорили, все представления должны находиться в папке system/application/views. Т.к. мы загружаем представление с именем main, то файл представления должен называться main.php.

<?php
$this->load->view('header');
?>
<h1>Каталог книг</h1>
<ul>
<?php
if (isset($errDescription)) {
echo "<h1>".$errDescription."</h1>";
}
else {
foreach ($books as $book) {
echo "<li>";
echo "<p>".anchor('catalog/bookdetails/'.$book['id'], $book['title'])."</p>";
echo "<p>Автор: ".$book['author']."</p>";
echo "<p>Жанр: ".$book['genre']."</p>";
echo "<p>Страниц: ".$book['pages']."</p>";
echo "</li>";
}
}
?>
</ul>
<?php
$this->load->view('footer');
?>

Разберем, что мы здесь написали. Прежде всего, обратите внимание, что в строках 2 и 23 мы загружаем два других представления ('header' и 'footer'), т.е. заголовок и завершение страницы. Это, конечно, не обязательно, но эти фрагменты будут повторяться во всех страницах, поэтому удобно вынести их в отдельные файлы.Теперь посмотрите на строки 7-9. Здесь мы проверяем, установлена ли переменная $errDescription. Эту переменную автоматически создает фрэймворк, если в массиве $pageData был создан элемент с ключом errDescription (как вы помните, этот элемент создается, если книги в БД отсутствуют).

В основном цикле (строки 11 — 18) мы формируем обычный список с данными из массива. Вот здесь есть один интересный момент. Это использование функции anchor(). В принципе, она создает обычную ссылку, но при этом используются настройки из конфигурационного файла (system/application/config/config.php). А если конкретнее, используется переменная $config['base_url'], значение которой должно указывать на адрес сайта (например, http://www.my_site.domen/).

В первом параметре функции мы указываем вторую часть адреса, в данном случае это адрес страницы, которую мы хотим загрузить (в формате: имя_контроллера/имя_метода/параметры). Во втором – текст ссылки.

Таким образом, мы для каждой книги каталога создали ссылку на страницу с ее подробным описанием.

Использование anchor() позволяет упростить перенос сайта на другой домен. Если вы делаете все правильно, т.е. нигде, кроме файла config.php не прописываете ссылки на домен, то при переносе сайта вам потребуется только изменить значение $config['base_url'] в этом файле.

Перед использованием функции anchor() нужно подключить вспомогательную библиотеку, в которой она находится. Для этого, открываем файл system/application/config/autoload.php, ищем в нем массив вспомогательных библиотек, и добавляем в него библиотеку url.

$autoload['helper'] = array('url');

Чтобы получить представление о конечном результате, посмотрите на файлы header.php и footer.php.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
<head>
<title><?php echo $title; ?></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="<?php echo base_url(); ?>/css/styles.css" />
</head>
<body>
</body>
</html>

Как видите, в них находятся обычный заголовок и завершение страницы. Стоит обратить внимание на два момента в заголовке.

Во-первых, для создания заголовка мы используем переменную $title, которую устанавливаем в контроллере.

Во-вторых, при подключении таблицы стилей мы используем функцию base_url(). Как вы, наверное, догадались, она возвращает значение $config['base_url'] из config.php.
Примечание. Здесь предполагается, что файл styles.css размещен в папке css/, которая находится в DOCUMENT_ROOT, т.е. там же где и index.php.

Теперь взгляните на диаграмму. На ней показал порядок формирования главной страницы сайта.

Создание главной страницы каталога (миниатюра)

Запрос браузера передается контроллеру (catalog.php), который получает данные с помощью модели (catalogmodel.php) и загружает представление (main.php). Представление формирует страницу, которая отсылается назад браузеру.

В этом и заключается смысл архитектуры MVC. Модель выполняет работу с данными (чтение, запись в БД и т.п.), представление – формирует страницу, а контроллер – обрабатывает запросы и обеспечивает взаимодействие компонентов.

Главное преимущество такой архитектуры в том, что можно заменять отдельные компоненты, не затрагивая остальные. Например, если вы захотите хранить информацию о книгах в текстовом файле вместо БД. Вам нужно будет только переписать методы модели.

Мы подробно разобрали создание главной страницы каталога. Код создания страницы с подробным описанием книги практически идентичен. Поэтому я его приведу без описания.

В контроллере:

function bookdetails($bookid) {
    $pageData['bookdetails'] = $this->catalogmodel->getBookDetails($bookid);
    if ($pageData['bookdetails'] == false) {
        $pageData['errDescription'] = "Выбранная книга не найдена";
    }
    $pageData['title'] = $pageData['bookdetails']['title'];
    $this->load->view("bookdetails", $pageData);
}

Представление (файл bookdetails.php).

<?php
    $this->load->view('header');
?>
<?php
if (isset($errDescription)) {
    echo "<h1>".$errDescription."</h1>";
}
else {
    echo "<p><strong>Название:</strong> ".$bookdetails['title']."</p>";
    echo "<p><strong>Автор:</strong> ".$bookdetails['author']."</p>";
    echo "<p><strong>Жанр:</strong> ".$bookdetails['genre']."</p>";
    echo "<p><strong>Страниц:</strong> ".$bookdetails['pages']."</p>";
    echo "<p><strong>Аннотация:</strong> ".$bookdetails['annotation']."</p>";
}
?>
<?php
    echo "<p>".anchor("", "На главную")."</p>";
    $this->load->view('footer');
?>

Как видите, разница заключается только в том, что метод контроллера принимает в качестве параметра id книги и вызывает соответствующий метод модели. А в представлении отсутствует цикл, т.к. мы выводим информацию только об одной книге.

Если хотите посмотреть, как работает этот каталог, скачайте архив с исходным кодом. В нем находится дистрибутив CodeIgniter и исходники каталога. Кроме того, в нем вы найдете файл db_backup.sql, который можно импортировать с помощью phpMyAdmin и не заполнять базу данных самостоятельно.

Примечание. В архиве находятся две папки: system – дистрибутив CI и public_html – в ней находится index.php (основной контроллер), т.е. отсюда выполняется вход в каталог. Более подробное описание находится в файле setup.txt, который вы найдете в архиве.

Удачи!