Изменить стиль страницы

Создание контроллера

Создайте файл /components/com_myquestions/controller.php(метод addQuestion() скопируйте из файла /components/com_myquestions/myquestions.php, убрав параметр $option):

<?php defined('_JEXEC') or die('Restricted access'); jimport('joomla.application.component.controller'); class QuestionController extends JController { function display() { $document =& JFactory::getDocument(); $viewName = JRequest::getVar('view', 'all'); $viewType = $document->getType(); $view = &$this->getView($viewName, $viewType); $model =& $this->getModel($viewName, 'ModelMyQuestions'); if (!JError::isError($model)) { $view->setModel($model, true); } $view->setLayout('default'); $view->display(); } function showForm() { $document =& JFactory::getDocument(); $viewName = JRequest::getVar('view', 'question'); $viewType = $document->getType(); $view = &$this->getView($viewName, $viewType); $user =&JFactory::getUser(); if($user->name) $view->user_name = $user->name; else $view->user_name = ''; $view->display('form'); } function addQuestion() { … } } ?>

В методе display() мы получаем название запрашиваемого представления и тип текущего документа, который одновременно является и типом представления. Затем получаем ссылку на соответствующее представление и ссылку на одноименную модель. Добавляем модель к представлению, назначив ее по умолчанию. Задаем имя макета - default и вызываем метод JView::display(), который выполнит скрипт /components/com_myquestions/views/all/tmpl/default.php.

В методе showForm() мы также получаем объект-представитель текущего пользователя JFactory::getUser(), чтобы подставить его имя в форму для написания вопроса. Выражение $view->display('form') отображает шаблон из файла default_form.php(т.е. имя файла в данном случае строится по схеме "default"+"_"+tpl, где tpl - параметр функции display()).

Метод addQuestion() добавляет новый вопрос в базу данных точно так же, как это делалось ранее. Обратите внимание на то, что название этого метода совпадает со значением, которое хранилось в скрытом элементе task формы для добавления вопроса:

<input type="hidden" name="task" value="addquestion"/>

Напишем код для создания объекта контроллера. Откройте файл /components/com_myquestions/myquestions.phpи замените существующий код следующим:

<?php defined('_JEXEC') or die('Restricted access'); require_once(JPATH_COMPONENT.DS.'controller.php'); JTable::addIncludePath(JPATH_ADMINISTRATOR. DS.'components'.DS.'com_myquestions'.DS.'tables'); $controller = new QuestionController(); $controller->execute(JRequest::getVar('task')); $controller->redirect(); ?>

С помощью строки require_once(JPATH_COMPONENT.DS.'controller.php') подключается содержимое файла, содержащего код класса контроллера.

Изменение шаблона SEF-ссылок

Шаблон SEF-ссылок, использовавшийся нами до сих пор, не годится для применения в компоненте MVC, т.к. включает только переменные task и id. Для компонента MVC в URL должно быть задано еще по меньшей мере значение view.

Возможно, вы заметили, что в коде фронтенда, переделанном с учетом модели MVC, мы строили URL по шаблону option/view/task/idпри включенных SEF и option=com_myquestions&view=value1&task=value2&id=value3 в противном случае. Для наглядности ниже приведено несколько примеров таких ссылок (таблица 6.1).

Таблица 6.1. Примеры ссылок, использующихся в MVC-версии компонента myquestions Ссылка view task id Значение /myquestions/category/show/1category show 1 Просмотр категории #1 /myquestions/question/show/1question show 1 Просмотр вопроса #1 /myquestions/category/show/allcategory show all Просмотр вопросов из всех категорий /myquestions/all/showall show - Просмотр списка всех категорий /myquestions/question/showformquestion showform - Вывод формы для написания вопроса

Изменим функции генерации и декодирования SEF-ссылок. Откройте файл /components/com_myquestions/router.phpи измените код функции MyQuestionsBuildRoute() следующим образом:

function MyQuestionsBuildRoute(&$query) { $segments = array(); if (isset($query['view'])) { $segments[] = $query['view']; unset($query['view']); } if (isset($query['task'])) { $segments[] = $query['task']; unset($query['task']); } if (isset($query['id'])) { $segments[] = $query['id']; unset($query['id']); } return $segments; }

В том же файле замените функцию MyQuestionsParseRoute() следующей:

function MyQuestionsParseRoute ($segments) { $vars = array(); $vars['view'] = $segments[0]; if (count($segments) > 1) { $vars['task'] = $segments[1]; if (count($segments) > 2) $vars['id'] = $segments[2]; } return $vars; }

Как видите, теперь мы предполагаем, что первый элемент в массиве segments - это view, второй - task, а третий - id.

Добавление контроллера к коду бэкенда

Бэкенд не нуждается в большом контроле над форматом вывода, поэтому его можно не переводить на архитектуру MVC. Добавим только контроллер, чтобы исключить выражение switch().

Создайте файл /administrator/components/com_myquestions/controller.php. В нем мы объявим класс QuestionController. В конструкторе этого контроллера регистрируются задачи, взятые из старого кода переключателя switch из файла admin.myquestions.php.

<?php defined('_JEXEC') or die('Restricted access'); jimport('joomla.application.component.controller'); class QuestionController extends JController { function __construct($default = array()) { parent::__construct($default); $this->registerTask('reply', 'replyToQuestion'); $this->registerTask('save', 'saveQuestion'); $this->registerTask('apply', 'saveQuestion'); $this->registerTask('remove', 'removeQuestions'); $this->registerTask('sendToExpert', 'send'); $this->registerTask('sendAnswer', 'send'); $this->registerTask('showCat', 'showCategories'); $this->registerTask('addCat', 'editCategory'); $this->registerTask('editCat', 'editCategory'); $this->registerTask('saveCat', 'saveCategory'); $this->registerTask('applyCat', 'saveCategory'); $this->registerTask('removeCat', 'removeCategories'); } } ?>

Все функции из файла admin.myquestions.phpперейдут в класс QuestionController в качестве методов практически без изменений, за исключением одного аспекта. Отказ от выражения switch ведет к невозможности передавать переменные непосредственно в методы класса контроллера. Поэтому необходимо либо добавлять в класс контроллера новые поля, либо получить переменные из переменных HTTP-запроса или других источников непосредственно в коде каждого метода. В нашем примере почти все методы используют значения переменных option и task. Теперь эти значения будут не передаваться как параметры, а извлекаться из HTTP-запроса с помощью функции JRequest(). Например, первые строки функции saveQuestion() примут вид:

function saveQuestion() { $option = JRequest::getVar('option'); $task = JRequest::getVar('task'); $row = $this->save(); ... }

Итак, перенесите в класс QuestionController функции replyToQuestion(), save(), saveQuestion() и др. Затем замените содержимое файла admin.myquestions.phpследующим кодом:

<?php defined('_JEXEC') or die('Restricted access'); require_once(JApplicationHelper::getPath('admin_html')); require_once(JPATH_COMPONENT.DS.'controller.php'); JTable::addIncludePath(JPATH_COMPONENT.DS.'tables'); $controller = new QuestionController(array('default_task' => 'showQuestions')); $controller->execute(JRequest::getVar('task')); $controller->redirect(); ?>

Как вы уже заметили, конструктор нашего контроллера в бэкенде имеет параметр default. При вызове конструктора мы передаем в него массив, который хранит значение default_task, равное showQuestions. Таким путем задано название задачи, которая будет выполнена по умолчанию.