В разделе "Первые папки и файлы. Добавление пунктов меню" предлагается создать две файла: - myquestions.php; - admin.myquestions.php с соответствуюшими адресами: - /components/com_myquestions/myquestions.php; - /administrator/components/com_myquestions/admin.myquestions.php; Так вот, при создании файла "admin.myquestions.php" В админке выдает ошибку - "Компонент не найден", а при переименовании его на "myquestions.php" в последующем шаге, в админке не выводятся кнопки редактирования. |
Архитектура MVC в компонентах Joomla
Цель лекции: Ознакомиться с основами применения архитектуры MVC при разработке компонентов.
Взаимодействие элементов архитектуры MVC в Joomla
MVC ("Model - View - Controller") - это набор паттернов проектирования, который предполагает разделение программного кода на три группы:
- модели (model) используются для хранения данных. В Joomla модели реализуются с помощью абстрактного класса JModel;
- представления (view) генерируют вывод для заданной информации с помощью шаблона. В Joomla реализуются с помощью абстрактного класса JView;
- контроллеры (controller) получают команды от пользователя и управляют моделями и представлениями для выполнения этих команд. В Joomla реализуются с помощью абстрактного класса JController.
Приблизительно схема взаимодействия этих групп в коде Joomla представлена на следующей диаграмме последовательности ( рис. 6.1 на основе иллюстрации из книги [4, p.246]).
В файле /components/com_<имя компонента>/<имя компонента>.php находится код для создания контроллера, например:
$controller = new MyComponentController(); $controller->execute(JRequest::getVar('task')); $controller->redirect();
В HTTP-запросе задается задача, представление и, при необходимости, другие данные. Метод execute() вызывает метод вашего контроллера, который называется так же, как и заданная задача. Если задача не указана, то ей будет присвоено значение "display", следовательно, будет выполнен метод display(). Для этой и всех остальных задач, которые должен выполнять ваш компонент, необходимо создать в классе контроллера одноименные методы. Наконец, метод redirect() перенаправляет пользователя к другому URL, если такой URL был задан в каком-либо методе при выполнении контроллера.
В простейшем случае класс контроллера описан в файле /components/com_<имя компонента>/controller.php, в более сложных случаях этих классов может быть несколько. Каждый из них должен быть производным от JController:
class MyComponentController extends JController { … function display() { … parent::display(); … } … }
Вы можете переопределить метод JController::display() в своем классе контроллера. Метод display() базового класса вызывает методы getView(), getModel(), а также метод display() заданного представления. getView() возвращает объект-представитель заданного представления, getModel() - заданной модели. По умолчанию используются те представление и модель, название которых совпадает с именем контроллера.
Далее нас будет интересовать работа метода display() заданного представления.
Каждый класс представления описан в файле /components/com_<имя компонента>/views/<имя представления>/view.html.php и является производным от JView. В этом классе может быть перегружен метод display(), чтобы вызвать метод класса модели для загрузки данных:
class MyComponentViewMyView extends JView { function display($tpl=null) { $model=&$this->getModel(); $list=$model->getList(); $this->assignRef('list', $list); parent::display($tpl); } }
Каждый класс модели описан в файле /components/com_<имя компонента>/models/<имя модели>.php и является производным от JModel. В этом классе может находиться метод для загрузки данных из базы данных или другого источника:
class ModelMyComponentMyModel extends JModel { var $_somelist = null; function getList() { if (!$this->_somelist) { $query = "SELECT * FROM #__mycomponent"; $this->_somelist = $this->_getList($query, 0, 0); } return $this->_somelist; } }
Итак, метод класса представления display() вызывает метод класса модели для загрузки данных и сохраняет результат в какой-либо переменной, которая затем с помощью метода JView::assignRef() связывается с текущим представлением. Наконец, вызывается метод базового класса JView::display(), который загружает файл заданного шаблона при помощи перехвата выходного потока.
Шаблон находится в папке /components/com_<имя компонента>/views/<имя представления>/tmpl. В его коде осуществляется вывод на экран переменных текущего представления. Например:
<table width="100%"> <?php foreach($this->list as $l) echo '<tr><td>'.$l->data.'</td></tr>'; ?> </table>
Так выглядит простейший вариант взаимодействия моделей, представлений и контроллеров.
Классы Joomla для реализации MVC
JModel
Одно из полей класса JModel - объект-представитель базы данных $_db. Таким образом, для выполнения запросов к базе данных в методах производных от JModel классов нужно обращаться непосредственно к этому полю, не получая новой ссылки на глобальный объект JDatabase:
$this->_db->setQuery($query); $this->_db->query();
Получение списка каких-либо объектов и количества записей
array _getList(string $query, int $limitstart=0, int $limit=0) int _getListCount(string $query)
где
Например:
$query = "SELECT * FROM #__mycomponent"; $list = $this->_getList($query, 0, 0); $count = $this->_getListCount($query);
JView
Joomla поддерживает возможность добавления нескольких моделей к одному представлению. В таком случае ссылки на объекты-представители моделей будут храниться в поле _models объекта JView. Для добавления модели используется метод
JModel setModel(object &$model, bool $default = false)
где
$model | - имя модели (т.е. имя соответствующего класса); |
$default | - назначить ли ее моделью по умолчанию. |
Метод возвращает добавленную модель.
Получение ссылки на объект-представитель одной из добавленных к представлению моделей
JModel getModel(string $name = null)
где $name - имя модели.
Например, добавим в коде контроллера к представлению SomeView модели Model1 и Model2:
$view = &$this->getView('SomeView', 'html'); $view->setModel($this->getModel('Model1'), true); $view->setModel($this->getModel('Model2'));
Получение данных из зарегистрированной модели или поля представления
mixed get(string $property, string $default = null)
где
$property | - название метода модели, который требуется вызвать, или поля представления. В первом случае будет вызван метод get<Название метода>() - обратите внимание на заглавную букву; |
$default | - если данные должны быть получены из модели, то $default - имя модели. Если требуется получить значение поля, то $default - значение, которое будет возвращено, если такое поле отсутствует. |
Например, если в модели, заданной для текущего представления по умолчанию, есть метод getValue(), то получить в классе представления возвращаемое им значение можно так:
$temp = &$this->get('value');
Связывание переменной с представлением
bool assignRef(string $key, mixed &$val)
где
$key | - имя поля объекта-представителя представления. Не может начинаться со знака подчеркивания; |
$val | - значение поля. |
Пример:
$view->assignRef('somevar', $someval);
Выполнение и отображение скрипта шаблона
void display(string $tpl = null) string loadTemplate(string $tpl = null)
где $tpl - имя файла шаблона. Конкретное имя файла зависит от значений имени и расширения макета, заданных в классе, по умолчанию это соответственно default и php. Если вы хотите изменить эти значения, используйте методы setLayout() и setLayoutExt(). Будет произведен поиск файла <имя макета>_<$tpl>.<расширение макета> или при $tpl=null <имя макета>.<расширение макета>.
display() выводит на экран результат работы скрипта шаблона, а loadTemplate() только возвращает этот результат. При ошибке display() возвращает объект Exception.
Например:
echo $view->loadTemplate('mytpl');
отобразит результат выполнения скрипта /components/com_<имя компонента>/views/<имя представления>/tmpl/default_mytpl.php.
JController
Выполнение задачи путем вызова одноименного метода производного класса
mixed execute(string $task)
где $task - имя задачи. Если такой задачи не найдется, будет выполнена задача "__default".
Метод возвращает значение, возвращаемое вызванным методом, или false в случае ошибки.
Например, код
$controller->execute('addItem');
приведет к вызову метода addItem() контроллера $controller.