Encodera

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

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

Оглавление

Таблицы и сохранение данных

Чтобы создать или изменить запись из панели, нужны три готовых класса Joomla. Table представляет одну строку таблицы и умеет её загружать и сохранять. AdminModel проверяет данные формы и передаёт их в Table. FormController обрабатывает кнопки «Сохранить» и «Закрыть». От вас — по короткому наследнику каждого.

Файлы

administrator/components/com_hello/
├── forms/
│   └── post.xml                         описание формы
├── src/
│   ├── Controller/PostController.php
│   ├── Model/PostModel.php
│   ├── Table/PostTable.php
│   └── View/Post/HtmlView.php
└── tmpl/
    └── post/
        └── edit.php

Создайте их вручную и добавьте строку <folder>forms</folder> в раздел files внутри administration манифеста.

Класс таблицы

// administrator/components/com_hello/src/Table/PostTable.php
namespace My\Component\Hello\Administrator\Table;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;
 
class PostTable extends Table
{
    public function __construct(DatabaseDriver $db)
    {
        parent::__construct('#__hello_posts', 'id', $db);
    }
}

Конструктор называет таблицу и её первичный ключ. Столбцы Joomla узнаёт сама. У объекта появляются методы load($id), bind($data), check(), store() и delete($id). Метод check() можно переопределить, чтобы проверить данные перед записью.

Описание формы

<?xml version="1.0" encoding="UTF-8"?>
<!-- administrator/components/com_hello/forms/post.xml -->
<form>
    <fieldset name="details">
        <field name="id" type="hidden" />
        <field name="title" type="text" label="Заголовок" required="true" />
        <field name="body" type="textarea" label="Текст" rows="8" />
    </fieldset>
</form>

Имена полей совпадают со столбцами таблицы. Формам посвящён следующий урок.

Модель

// administrator/components/com_hello/src/Model/PostModel.php
namespace My\Component\Hello\Administrator\Model;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\AdminModel;
 
class PostModel extends AdminModel
{
    public function getForm($data = [], $loadData = true)
    {
        return $this->loadForm('com_hello.post', 'post', ['control' => 'jform', 'load_data' => $loadData]);
    }
 
    protected function loadFormData()
    {
        $data = Factory::getApplication()->getUserState('com_hello.edit.post.data', []);
 
        return $data ?: $this->getItem();
    }
}

getForm() загружает файл forms/post.xml. loadFormData() возвращает данные для полей: сначала те, что пользователь уже вводил, но не смог сохранить из-за ошибки, иначе — запись из базы. Методы getItem() и save() уже есть в AdminModel; класс таблицы PostTable он находит по своему имени.

Контроллер

// administrator/components/com_hello/src/Controller/PostController.php
namespace My\Component\Hello\Administrator\Controller;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\Controller\FormController;
 
class PostController extends FormController
{
}

Класс пуст: действия add, edit, save, apply и cancel унаследованы.

Экран редактирования

// administrator/components/com_hello/src/View/Post/HtmlView.php
namespace My\Component\Hello\Administrator\View\Post;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
 
class HtmlView extends BaseHtmlView
{
    public $form;
    public $item;
 
    public function display($tpl = null): void
    {
        $model = $this->getModel();
 
        $this->form = $model->getForm();
        $this->item = $model->getItem();
 
        ToolbarHelper::title($this->item->id ? 'Изменить запись' : 'Новая запись');
        ToolbarHelper::apply('post.apply');
        ToolbarHelper::save('post.save');
        ToolbarHelper::cancel('post.cancel');
 
        parent::display($tpl);
    }
}
<?php
// administrator/components/com_hello/tmpl/post/edit.php
 
defined('_JEXEC') or die;
 
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
 
Factory::getApplication()->getDocument()->getWebAssetManager()
    ->useScript('keepalive')
    ->useScript('form.validate');
?>
<form action="<?php echo Route::_('index.php?option=com_hello&layout=edit&id=' . (int) $this->item->id); ?>"
      method="post" name="adminForm" id="adminForm" class="form-validate">
 
    <?php echo $this->form->renderFieldset('details'); ?>
 
    <input type="hidden" name="task" value="">
    <?php echo HTMLHelper::_('form.token'); ?>
</form>

renderFieldset('details') выводит все поля группы с подписями.

Результат

Откройте «Компоненты → Hello» и нажмите «Создать». Появится форма с полями «Заголовок» и «Текст». Введите данные, нажмите «Сохранить и закрыть» — вы вернётесь к списку с сообщением об успехе и новой строкой. Щелчок по заголовку открывает ту же форму с данными записи.

Что происходит при сохранении

  1. Кнопка отправляет форму с task=post.save.
  2. FormController проверяет токен и права пользователя.
  3. AdminModel проверяет данные по описанию формы.
  4. PostTable выполняет bind(), check() и store().
  5. Контроллер перенаправляет на список — представление posts.

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

Свои действия, меняющие данные, пишут без проверки токена. Такое действие можно вызвать ссылкой с чужого сайта: браузер вошедшего администратора сам приложит его cookie. В готовых контроллерах проверка уже есть, а в собственных методах первой строкой ставьте $this->checkToken(); — и не забывайте HTMLHelper::_('form.token') в форме.

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

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