Контроллер компонента

Основная логика работы компонента реализуется в файле frontend.php.

Обзор контроллера

В кратце, работа контроллера сводится к следующим этапам:

  • Инициализация: Подключение всех необходимые классов (ядро, пользователи, …) и библиотек (теги, карма, …), загрузка модели
  • Постановка задачи: Получение параметров из URL страницы и определение действия, которое нужно совершить
  • Загрузка данных: Получение нужных записей из базы данных (или сохранение/удаление записей) с помощью модели
  • Решение задачи: Совершение необходимых операций над данными
  • Вывод: Передача обработанных данных в шаблон

:!: Важно: Контроллер должен заниматься только обработкой данных. В нем не должно быть работы с базой (функций *query()) и любого вывода (операторов echo). Взаимодействие с базой должно происходить только через модель, вывод данных - только через шаблоны.

Теперь создайте файл frontend.php в папке компонента и поместите в него каркас контроллера:

<?php
function guestbook(){
 
    //Инициализируем объекты, которые нам понадобятся
    //для работы: ядро, страница(шаблонизатор) и пользователь
    $inCore = cmsCore::getInstance();
    $inPage = cmsPage::getInstance();
    $inUser = cmsUser::getInstance();
 
    //загрузим модель
    $inCore->loadModel('guestbook');
 
    //создадим объект модели
    $model = new cms_model_guestbook();
 
    //Получаем текущее действие из URL страницы
    $do = $inCore->request('do', 'str', 'view_all');
 
 
    if ($do == 'view_all'){
 
        // ... здесь будет код для вывода всех сообщений ...
 
    }
 
 
    if ($do == 'add'){
 
        // ... здесь будет код для добавления сообщений ...
 
    }
 
    if ($do == 'delete'){
 
        // ... здесь будет код для удаления сообщений ...
 
    }
 
}

Как вы уже заметили, код контроллера состоит из одной большой функции, название которой совпадает с идентификатором компонента. В нашем случае это guestbook.

Внутри функции инициализируются нужные объекты и загружается модель, написанная нами в предыдущей части. Затем заполняется переменная $do, которая будет хранить в себе название текущей задачи. Пока наш компонент будет уметь решать три вида задач:

  • view_all - показ списка всех сообщений гостевой книги
  • add - добавление сообщений
  • delete - удаление сообщений

Давайте реализуем логику для каждой из этих задач.

Вывод всех сообщений

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

Пишем код:

    // ...
 
    if ($do == 'view_all'){
 
        //1. получаем сообщения из базы
        $messages = $model->getMessages();
 
        //2. узнаем, является ли текущий пользователь администратором
        $is_admin = $inUser->is_admin;
 
        //3. Устанавливаем заголовок страницы
        $inPage->setTitle("Гостевая книга");
 
        //4. подключаем шаблонизатор Smarty и сообщаем ему имя шаблона
        //   который нужно будет использовать для вывода списка сообщений
        $smarty = $inCore->initSmarty('components', 'com_guestbook_view_all.tpl');
 
        //5. передаем в шаблон список сообщений и флаг администратора
        $smarty->assign('messages', $messages);
        $smarty->assign('is_admin', $is_admin);
 
        //6. выводим шаблон на экран
        $smarty->display('com_guestbook_view_all.tpl');
 
        //7. завершаем работу компонента
        return;
 
    }
 
    // ...

Разберем подробнее что происходит:

1. Сначала мы вызываем метод getMessages() модели и результат (список сообщений) сохраняем в переменную $messages. Помните, что если в базе не окажется сообщений, то в этой переменной будет не массив, а логическое значение false. Этот момент мы рассмотрим позже, при создании шаблона.

2. В начале компонента мы инициализировали объект $inUser, который хранит в себе информацию о текущем пользователе (который запрашивает страницу). Объект имеет несколько свойств, описывающих пользователя. Их названия и содержание совпадают с полями в таблице cms_users. Например:

  • $inUser→id : идентификатор пользователя (равен нулю если пользователь не авторизован)
  • $inUser→login : логин
  • $inUser→nickname : никнейм
  • $inUser→email : почтовый адрес
  • $inUser→is_admin : логическое свойство (true/false), показывающее входит ли пользователь в группу администраторов

3. Передаём объекту inPage созданному в самом начале заголовок страницы.

4. Подключаем шаблонизатор. Обратите внимание на два входящих параметра функции initSmarty(). Первый из них указывает название папки внутри папки шаблона сайта, второй - название файла шаблона компонента. Как вы помните, это название формируется по схеме com_<компонент>_<действие>.tpl. Соблюдение этого принципа позволит вам быстро находить нужный файл в дальнейшем.

5. Передаем переменные в шаблон. Для каждой переменной вызывается метод assign() шаблонизатора Smarty. Первый аргумент указывает как переменная будет называться в шаблоне (грубо говоря, название тега), второй - откуда брать ее значение. Лучше всего использовать одинаковые названия везде где это возможно, чтобы избегать путаницы.

6. Выводим шаблон. На самом деле вывод на экран будет происходить не здесь, а позже, после подготовки основного шаблона сайта. Однако в контексте контроллера можно считать что метод display() отправляет страницу в браузер.

7. Завершаем работу компонента оператором return. Это даст нам гарантию что никакой код расположенный ниже не выполнится даже случайно.

На примере простого действия по выводу списка сообщений хорошо видно преимущество модели MVC. Для получения сообщений из базы используется метод модели, это значит что при необходимости получить сообщения где-то еще не придется дублировать код. Мы можем добавить любую предварительную обработку данных получаемых из базы не трогая код контроллера. Вывод на экран тоже никак не привязан к коду контроллера и может быть легко заменен.

Следующим шагом создадим интерфейс для добавления сообщений.

Добавление сообщений

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

<input type="submit" name="send" value="Отправить сообщение">

При нажатии на кнопку форма будет отправляться обратно контроллеру и мы сможем проверить существование переменной $_POST['send']. Если она существует, значит нужно принять сообщение и сохранить его. Если нет - значит нужно показать форму:

    // ...    
 
    if ($do == 'add'){
 
        $is_send = $inCore->inRequest('send');
 
        if (!$is_send){            
            //... показываем форму ...            
        }
 
        if ($is_send){
            //... сохраняем сообщение ...
        }
 
    }
 
    // ...

Мы определяем наличие переменной $_POST['send'] при помощи метода inRequest() объекта ядра. Этот метод возращает true/false, в зависимости от наличия переменной.

Далее используем два условных оператора чтобы разделить логику на две части. Мы осознанно используем два if вместо одного if..else, т.к. это повышает читаемость кода (в случае с else нужно скроллить код вверх, чтобы увидеть определение условия для второго блока).

Вывод формы идентичен выводу списка сообщений. Разница лишь в том, что теперь нам не нужно передавать в шаблон никаких параметров:

    // ...    
 
        if (!$is_send){            
 
            //подключаем шаблон и выводим на экран
            $smarty = $inCore->initSmarty('components', 'com_guestbook_add.tpl');
            $smarty->display('com_guestbook_add.tpl');
 
        }
 
    // ...

Мы заранее определились, что каждое сообщение в нашей гостевой книге будет иметь тему (title) и текст (message). В форме будут два поля, значения которых нам нужно получить для сохранения в базу. Чтобы узнать ID автора воспользуемся объектом $inUser.

//...
 
        if ($is_send){
 
            //1. получаем все параметры сообщения
            $title      = $inCore->request('title', 'str');
            $message    = $inCore->request('message', 'str');
            $user_id    = $inUser->id;
 
            //2. если не указана тема или сообщение
            if (!$title || !$message){
 
                //сохраняем текст ошибки в сессию
                cmsCore::addSessionMessage('Укажите тему и сообщение!', 'error');
 
                //и делаем редирект обратно на форму, завершая выполнение скрипта
                $inCore->redirectBack(); exit;
 
            }
 
            //3. добавляем сообщение и получаем его номер
            $message_id = $model->addMessage($title, $message, $user_id);
 
            //4. если номер сообщения получен
            if ($message_id){
                //сохраняем текст успеха в сессию
                cmsCore::addSessionMessage('Сообщение успешно добавлено!', 'success');
            }
 
            //5. если по каким-то причинам сообщение не добавилось
            if (!$message_id){
                //сохраняем текст неудачи
                cmsCore::addSessionMessage('Ошибка добавления сообщения!', 'error');
            }
 
            //6. делаем редирект на список сообщений и завершаем скрипт
            $inCore->redirect('/guestbook'); exit;
 
        }
 
//...

Разберем подробнее:

1. Сначала мы получаем входящие переменные при помощи метода request(). Этот метод может возвращать значения переданные как GET так и POST-запросом и имеет три параметра:

   $inCore->request('название_переменной', 'тип_переменной', 'значение_по_умолчанию');

Название переменной совпадает с названием поля в форме. Тип переменной задается одним из четырех значений:

  • int - число
  • str - строка (html-теги вырезаются)
  • html - html-код (теги не вырезаются)
  • array - массив

Третий параметр задает значение по-умолчанию, которое будет присвоено переменной если она не была передана из формы. Если значение по-умолчанию не задано, используется пустая строка.

2. Далее мы смотрим указаны ли тема и текст сообщения. Если не указаны, помещаем в сессию пользователя уведомление об ошибке с помощью статического метода cmsCore::addSessionMessage(). Первый параметр этого метода - это текст который нужно будет показать пользователю, второй - тип сообщения:

  • error - ошибка (красный текст)
  • success - успех (зеленый текст)
  • info - информация (нейтральный текст)

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

Если произошла ошибка (тема или текст не были указаны), после сохранения уведомления в сессию мы делаем редирект на предыдущую страницу и завершаем скрипт.

3. Если ошибок не было, С помощью метода addMessage() нашей модели сохраняем текст сообщения гостевой книги. В ответ получаем id созданного сообщения.

4, 5. Проверяем полученный id, если вместо числа (вдруг) вернется false то мы передадим пользователю сообщение об ошибке, иначе - об успехе.

6. Делаем редирект на список сообщений. Любая обработка форм должна завершаться редиректом, во избежание появления вопроса «Вы хотите отправить данные заново?» со стороны браузера после обновления страницы. Еще один важный момент - любой редирект должен завершаться выходом из скрипта.

Удаление сообщений

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

Логика простая:

  1. получаем ID сообщения (будет передаваться методом GET как часть адреса страницы /guestbook/deleteXX.html);
  2. проверяем, является ли текущий пользователь администратором (свойство $inUser→is_admin установлено в true);
  3. если все правильно, удаляем сообщение с помощью метода deleteMessage() определенного нами ранее в модели;
  4. делаем редирект обратно к списку сообщений.

Реализация:

    // ...    
 
    if ($do == 'delete'){
 
        //получаем ID сообщения
        $message_id = $inCore->request('message_id', 'int', 0);
 
        //если ID не получен или пользователь не администратор, делаем редирект обратно
        if (!$message_id || !$inUser->is_admin) {
            $inCore->redirectBack(); exit;
        }    
 
        //удаляем сообщение
        $model->deleteMessage($message_id);
 
        //делаем редирект обратно к списку сообщений
        $inCore->redirectBack(); exit;
 
    }
 
    // ...

Теперь наш контроллер готов, он умеет показывать список сообщений, добавлять новые и удалять имеющиеся. Следующим шагом нам нужно связать действия контроллера с URL-адресами страниц.

Что дальше?

 
разработка/компоненты/контроллер_компонента.txt · Последние изменения: 2011/08/25 21:45 От neochapay