Опубликован: 02.10.2012 | Доступ: свободный | Студентов: 1856 / 70 | Длительность: 11:55:00
Теги: joomla, mvc, php, xhtml, xml
Лекция 6:

Архитектура MVC в компонентах Joomla

< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Регистрация задачи

Регистрация задачи - это ее сопоставление какому-либо методу класса, производного от JController.

JController registerTask(string $task, string $method)
            

где

$task - задача;
$method - имя метода.

Пример в коде контроллера:

$this->registerTask('save', 'saveItem');
            
Стандартная реализация метода display()

О методе display() говорилось выше.

JController display(bool $cachable = false, array $urlparams = false)
            

где

$cachable - задает, кэшировать ли вывод представления;
$urlparams - массив пар "имя-значение" для URL, использующихся при кэшировании.
Получение ссылки на текущее представление
JView getView(string $name = '', string $type = '', string $prefix = '', array $config = array())
            

где

$name - имя представления. По умолчанию совпадает с именем контроллера;
$type - тип представления, который можно определить как $document->getType();
$prefix - префикс класса представления. По умолчанию <имя контроллера>View;
$config - массив параметров, которые будут переданы в конструктор представления, - имя представления, кодировка, путь к директории шаблонов и т.д.

Если класс <префикс><имя представления> не найдется в директориях, заданных по умолчанию, то будет произведен его поиск в файле <имя представления>/view.<тип представления>.php. Например, если в коде класса MyComponentController есть строка

$view = &$this->getView('Item', 'html');
            

то будет произведен поиск класса MyComponentViewItem в файле /components/com_<имя компонента>/views/Item/view.html.php.

Получение объекта-представителя модели
JModel getModel(string $name = '', string $prefix = '', array $config = array())
            

где

$name - имя модели. По умолчанию совпадает с именем контроллера;
$prefix - префикс класса модели. По умолчанию <имя контроллера>Model;
$config - массив параметров, которые будут переданы в конструктор модели.
Задание параметров для будущего перенаправления
JController setRedirect(string $url, string $msg=null, string $type=null)
            

где

$url - URL для перенаправления;
$msg - сообщение для пользователя;
$type - тип сообщения. По умолчанию - "message".

Например, в коде контроллера можно написать:

$this->setRedirect('index.php?option=com_mycomponent', 'Текст сообщения', 'notice');
            
Перенаправление браузера
bool redirect()
            

Метод возвращает false, если URL для перенаправления не был задан заранее.

Практика

Модели

Модель для списка всех категорий

В папке /components/com_myquestions создайте папку models, а в ней - файл all.php:

<?php
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.model');
class ModelMyQuestionsAll extends JModel
{
  var $_categories = null;
  function getList()
  {
    if (!$this->_categories)
    {  
      $query = "SELECT id, name, `desc` FROM #__myquestions_categories";
      $this->_categories = $this->_getList($query, 0, 0);
    }
    return $this->_categories;
  }
}
?>
            

Мы подключаем библиотеку моделей Joomla и объявляем класс ModelMyQuestionsAll как производный от класса JModel. В классе хранится список категорий _categories. Метод getList() проверяет, загружен ли список категорий. Если нет, то мы создаем запрос, чтобы выбрать из базы данных все категории вопросов, и получаем их с помощью метода _getList() класса JModel.

Модель для списка вопросов из какой-либо категории или из всех категорий

Создайте файл /components/com_myquestions/models/category.php:

<?php
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.model');
class ModelMyQuestionsCategory extends JModel
{
  var $_questions = null;
  var $_id = null;
  var $_name = null;
  function __construct()
  {
    parent::__construct();
    $id = JRequest::getVar('id','all');
    $this->_id = $id;
  }
  function getList()
  {
    if (!$this->_questions)
    {
      if ($this->isAllCat())
        $id_text = "";
      else
        $id_text = " id_cat={$this->_id} AND ";
      $query = "SELECT q.id, q.question, q.name, q.date, q.email, q.city, q.answer, c.id AS id_cat, 
      c.name AS name_cat FROM #__myquestions q, #__myquestions_categories c WHERE $id_text answer <> 
      '' AND (published = 1 OR (expiration_date <> '0000-00-00 00:00:00' AND expiration_date > NOW())) 
      AND q.id_cat=c.id";
      $this->_questions = $this->_getList($query, 0, 0);  
    }
    return $this->_questions;
  }
  function getCatName()
  {
    if (!$this->_name)
    {
      if (!$this->isAllCat())
      {
        $query = "SELECT name FROM #__myquestions_categories WHERE id = '" . $this->_id . "'";
        $this->_db->setQuery($query);
        $this->_name = $this->_db->loadResult();
      }
    }
    if (!$this->isAllCat())
      return $this->_name;
    else
      return JText::_('COM_MYQUESTIONS_ALL_QUESTIONS');
  }
  Function isAllCat()
  {
    if ($this->_id=='all')
      return true;
    return false;
  }
}
?>
            
Листинг .

В данном классе хранятся список вопросов _questions, id категории _id и название категории _name.

Конструктор класса вызывает конструктор родительского класса, затем получает из HTTP-запроса id категории и сохраняет его в поле _id. Если id категории не задан, то вместо него сохраняется значение all, т.к. в таком случае будут выводиться вопросы сразу из всех категорий.

Метод getCatName() возвращает либо название текущей категории, либо строку "Все вопросы", если категория не задана.

Метод isAllCat() возвращает true, если категория не задана, и false в противном случае.

Модель для одного вопроса

Создайте файл /components/com_myquestions/models/question.php:

<?php
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.model');
class ModelMyQuestionsQuestion extends JModel
{
  var $_question = null;
  var $_id = null;
  function __construct()
  {
    parent::__construct();
    $id = JRequest::getVar('id',0);
    $this->_id = $id;
  }
  function getQuestion()
  {
    if (!$this->_question)
    {
      $query = "SELECT q.id, q.question, q.name, q.date, q.email, q.city, q.answer, q.published, q.expiration_date, 
      c.id AS id_cat, c.name AS name_cat FROM #__myquestions q, #__myquestions_categories c WHERE q.id_cat=c.id AND 
      q.id = {$this->_id}";
      $this->_db->setQuery($query);
      $this->_question = $this->_db->loadObject();
      if ($this->_question->answer == '' || ($this->_question->published == 0 && ($this->
      _question->expiration_date == '0000-00-00 00:00:00' || strtotime($this->_question->expiration_date) <= time())))
      {
        JError::raiseError(404, JText::_(' COM_MYQUESTIONS_ERROR404'));
      }
    }
    return $this->_question;
  }
}
?>
            

Функция getQuestion() загружает одну запись с заданным id. Если после загрузки вопроса оказывается, что он является неопубликованным, то генерируется сообщение об ошибке 404.

Представления

Создайте в папке /components/com_myquestions подпапку views, а в ней - папки all, category и question. В каждой из них создайте по папке для шаблонов под названием tmpl.

Получившееся дерево папок показано на рис. 6.2.

Дерево папок MVC-компонента

Рис. 6.2. Дерево папок MVC-компонента
Просмотр списка всех категорий

Создайте файл /components/com_myquestions/views/all/view.html.php:

<?php
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.view');
class QuestionViewAll extends JView
{
  function display($tpl=null)
  {
    global $option;
    $model=&$this->getModel();
    $list=$model->getList();
    for ($i=0; $i<count($list); $i++)
    {
      $row=&$list[$i];
      $row->link=JRoute::_('index.php?option='.$option.'&id='.$row->id.'&view=category&task=show');
    }
    $this->assignRef('list', $list);
    parent::display($tpl);
  }
}
?>
            

Класс QuestionViewAll объявляется как производный от класса JView.

В методе display() мы получаем ссылку на ассоциированную с данным представлением модель и используем ее метод getList(), чтобы получить список категорий. К каждому элементу этого списка добавляем ссылку для просмотра данной категории. Связываем этот список с переменной list шаблона и вызываем метод JView::display() для отображения шаблона.

По умолчанию будет отображен шаблон default. Напишем его. Создайте файл /components/com_myquestions/views/all/tmpl/default.php:

<?php
defined('_JEXEC') or die('Restricted access');
global $option;
echo "<a href=\"".JRoute::_('index.php?option='.$option.'&view=question&task=showform')."\">".
JText::_('COM_MYQUESTIONS_ADD_QUESTION')."</a>";
?>
<br/>
<table width="100%">
  <?php
    foreach($this->list as $l)
      echo '<tr><td><p><a href="'.$l->link.'">'.$l->name.'</a></td><td>'.$l->desc.'</td></tr>';
  ?>
</table>
<br/>
            

Доступ к переменной list осуществляется через $this, т.к. это поле текущего класса QuestionViewAll.

Просмотр списка вопросов из какой-либо категории или из всех категорий

Создайте файл /com_myquestions/views/category/view.html.php:

<?php
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.view');
class QuestionViewCategory extends JView
{
  function display($tpl=null)
  {
    global $option;
    $model=&$this->getModel();
    $list=$model->getList();
    $name_cat=$model->getCatName();
    $is_all_cat=$model->isAllCat();
    for ($i=0; $i<count($list); $i++)
    {
      $row=&$list[$i];
      $row->link=JRoute::_('index.php?option='.$option.'&id='.$row->id.'&view=question&task=show');
      if ($is_all_cat)
        $row->link_cat=JRoute::_('index.php?option='.$option.'&id='.$row->id_cat.'&view=category&task=show');
    }
    $this->assignRef('list', $list);
    $this->assignRef('name_cat', $name_cat);
    $this->assignRef('is_all_cat', $is_all_cat);
    parent::display($tpl);
  }
}
?>
            

Данный код в целом аналогичен коду метода QuestionViewAll::display(). Если выводится список вопросов сразу из всех категорий, то в name_cat будет храниться текст "Все вопросы", а к объекту-представителю каждого вопроса добавится ссылка на его категорию. Если же выводится содержимое одной категории, то в name_cat будет храниться ее название, а ссылок на категорию каждого вопроса выводиться не будет, т.к. все эти ссылки будут одинаковы и вести на страницу с текущим же списком.

Для создания шаблона по умолчанию создайте файл /components/com_myquestions/views/category/tmpl/default.php:

<?php
defined('_JEXEC') or die('Restricted access');
global $option;
echo "<a href=\"".JRoute::_('index.php?option='.$option.'&view=question&task=showform')."\">".JText::_('COM_MYQUESTIONS_ADD_QUESTION')."</a>";
?>
<H1><?=$this->name_cat?></H1>
<?php foreach($this->list as $l): ?>
  <table width="100%">
    <tr>
      <td width="25%"><i><?=$l->name?></i></td>
      <td width="25%"><i><u><?=$l->email?></u></i></td>
      <td width="25%"><i><?=JHTML::_('date', $l->date,
      JText::_('DATE_FORMAT_LC3'))?></i></td>
      <td width="25%"><i><?=$l->city?></i></td>
    </tr>
    <?php
      if ($this->is_all_cat == true)
      {
    ?>
    <tr>
      <td colspan="4"><a href="<?=$l->link_cat?>"><?=$l->name_cat?></a></td>      
    </tr>
    <?php
      }
    ?>
    <tr>
      <td colspan="4"><b><?=$l->question?></b></td>
    </tr>
    <tr>
      <td colspan="4"><?=$l->answer?></td>
    </tr>
    <tr>
      <td colspan="4"><a style="text-decoration: none;" title="<?=JText::_('COM_MYQUESTIONS_READMORE')?>" 
      alt="<?=JText::_('COM_MYQUESTIONS_READMORE')?>" href="<?=$l->link?>">---></a></td>
    </tr>
  </table>
  <br/>
<?php endforeach;?>
            

Данный шаблон аналогичен шаблону по умолчанию для представления all.

< Лекция 5 || Лекция 6: 123 || Лекция 7 >
Кирилл Гусаров
Кирилл Гусаров

В разделе "Первые папки и файлы. Добавление пунктов меню"

предлагается создать две файла:

- myquestions.php;

- admin.myquestions.php

с соответствуюшими адресами:

/components/com_myquestions/myquestions.php;

- /administrator/components/com_myquestions/admin.myquestions.php;

Так вот, при создании файла "admin.myquestions.php" В админке выдает ошибку - "Компонент не найден", а при переименовании его на  "myquestions.php" в последующем шаге, в админке не выводятся кнопки редактирования. 
Проверил кодировку, проверил правильность пути к файлам, пересохранил указанный код. Скажите что я делаю не так или в чем может быть причина?

Наталья Алмаева
Наталья Алмаева
Россия
Сергей Козлов
Сергей Козлов
Россия, Тюмень