Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Модели

Модель — класс, который получает данные из базы и отдаёт их представлению. В Joomla есть готовые базовые модели: для списка достаточно написать один запрос, а постраничный вывод модель сделает сама. Заменим записи, заданные в коде, настоящими записями из базы.

Таблица

Компоненту нужна своя таблица. Пока создадим её вручную: откройте phpMyAdmin и выполните запрос, заменив #__ приставкой таблиц вашего сайта (она видна в именах остальных таблиц):

CREATE TABLE `#__hello_posts` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `title` VARCHAR(255) NOT NULL,
    `body` TEXT NOT NULL,
    `published` TINYINT NOT NULL DEFAULT 1,
    `created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
INSERT INTO `#__hello_posts` (`title`, `body`) VALUES
('Первая запись', 'Текст первой записи'),
('Вторая запись', 'Текст второй записи');

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

Где лежат модели

components/com_hello/src/
├── Controller/DisplayController.php
├── Model/
│   ├── PostsModel.php           список записей
│   └── PostModel.php            одна запись
└── View/
    ├── Posts/HtmlView.php
    └── Post/HtmlView.php

Имя модели совпадает с именем представления: для view=posts Joomla сама создаёт PostsModel и передаёт её представлению.

Модель списка

// components/com_hello/src/Model/PostsModel.php
namespace My\Component\Hello\Site\Model;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\QueryInterface;
 
class PostsModel extends ListModel
{
    protected function getListQuery(): QueryInterface
    {
        $db = $this->getDatabase();
 
        return $db->getQuery(true)
            ->select($db->quoteName(['id', 'title', 'created']))
            ->from($db->quoteName('#__hello_posts'))
            ->where($db->quoteName('published') . ' = 1')
            ->order($db->quoteName('created') . ' DESC');
    }
}

Вы описываете только запрос. Методы getItems() (записи текущей страницы) и getPagination() (ссылки на страницы) уже есть в ListModel.

Вызов из представления

// components/com_hello/src/View/Posts/HtmlView.php
public function display($tpl = null): void
{
    $model = $this->getModel();
 
    $this->posts = $model->getItems();
    $this->pagination = $model->getPagination();
 
    parent::display($tpl);
}

Объявите в классе ещё одно свойство — public $pagination;. Теперь $this->posts — массив объектов, поэтому макет меняется:

<?php
// components/com_hello/tmpl/posts/default.php
 
defined('_JEXEC') or die;
 
use Joomla\CMS\Router\Route;
?>
<h1>Блог</h1>
 
<ul>
    <?php foreach ($this->posts as $post) : ?>
        <li>
            <a href="<?php echo Route::_('index.php?option=com_hello&view=post&id=' . (int) $post->id); ?>">
                <?php echo $this->escape($post->title); ?>
            </a>
        </li>
    <?php endforeach; ?>
</ul>
 
<?php echo $this->pagination->getListFooter(); ?>

Откройте index.php?option=com_hello&view=posts — выведены записи из базы, каждая со ссылкой.

Модель одной записи

// components/com_hello/src/Model/PostModel.php
namespace My\Component\Hello\Site\Model;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\ItemModel;
use Joomla\Database\ParameterType;
 
class PostModel extends ItemModel
{
    public function getItem($pk = null)
    {
        $id = (int) ($pk ?: Factory::getApplication()->getInput()->getInt('id'));
        $db = $this->getDatabase();
 
        $query = $db->getQuery(true)
            ->select('*')
            ->from($db->quoteName('#__hello_posts'))
            ->where($db->quoteName('id') . ' = :id')
            ->where($db->quoteName('published') . ' = 1')
            ->bind(':id', $id, ParameterType::INTEGER);
 
        $post = $db->setQuery($query)->loadObject();
 
        if (!$post) {
            throw new \Exception('Запись не найдена', 404);
        }
 
        return $post;
    }
}

Номер записи берётся из параметра id адреса. Если записи нет, исключение с кодом 404 покажет страницу «Не найдено».

Страница записи

// components/com_hello/src/View/Post/HtmlView.php
namespace My\Component\Hello\Site\View\Post;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
 
class HtmlView extends BaseHtmlView
{
    public $post;
 
    public function display($tpl = null): void
    {
        $this->post = $this->getModel()->getItem();
 
        parent::display($tpl);
    }
}
<?php
// components/com_hello/tmpl/post/default.php
 
defined('_JEXEC') or die;
?>
<h1><?php echo $this->escape($this->post->title); ?></h1>
 
<p><?php echo nl2br($this->escape($this->post->body)); ?></p>

Щёлкните по записи в списке — откроется страница index.php?option=com_hello&view=post&id=1 с заголовком и текстом.

Частая ошибка

Модель называют не так, как представление: представление posts, а модель PostListModel. Joomla ищет модель по имени представления, не находит, и $this->getModel() возвращает пустое значение — вызов getItems() заканчивается ошибкой. Для View\Posts модель должна называться PostsModel, для View\Post — PostModel.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.