Давно новостей не было, но они всё же были, просто писать было лень ![]()
В общем просили контроллеры, теперь они есть. Ну правда в таком виде как я это вижу, возможно у кого-то есть что добавить))
Как раньше писался модуль?
Входная точка модуля выглядела обычно примерно так:
defined('_IN_JOHNCMS') || die('Error: restricted access');
/** @var Tools $tools */
$tools = di(Tools::class);
/** @var User $user */
$user = di(User::class);
/** @var Render $view */
$view = di(Render::class);
/** @var NavChain $nav_chain */
$nav_chain = di(NavChain::class);
/** @var Request $request */
$request = di(Request::class);
// Регистрируем Namespace для шаблонов модуля
$view->addFolder('reg', __DIR__ . '/templates/');
// Register the module languages domain and folder
/** @var Translator $translator */
$translator = di(Translator::class);
$translator->addTranslationDomain('registration', __DIR__ . '/locale');
$nav_chain->add(__('Registration'));Неприлично много однотипного кода, да ещё и комментарии перед каждым получением зависимостей. Их конечно можно опустить, но тогда в IDE не будет работать автокомплит, а он хорошо экономит время и позволяет "изучать классы" без чтения документации. Так же в каждом модуле ещё надо самостоятельно указывать откуда брать шаблоны и переводы.
Дальше надо было писать какую-то логику определения страницы, которую нужно отдать пользователю. Из-за этого не всегда было очевидно какие страницы есть в модуле и где искать код, который отвечает за неё. Ну и так же нужно было самостоятельно получать параметры из маршрута.
Теперь с контроллерами всё стало несколько проще и избавляет нас от многого дублирующегося кода.
Давайте посмотрим на примере...
Есть маршрут:
$map->addRoute(['GET', 'POST'], '/news/add_vote/{article_id:\d+}/{type_vote:\d}/', [News\Controllers\VoteController::class, 'add']);Этот маршрут отвечает за голосование за новость. Чтобы учесть голос нам нужен идентификатор новости и тип голоса (положительный или отрицательный).
Под этот маршрут будет попадать ссылка site.com/news/add_vote/100/1/ Если пользователь перейдет по такой ссылке он проголосует положительно за новость с идентификатором 100.
Из настроек маршрута сразу понятно что принимает он и какой класс и метод класса отвечает за обработку его. (А в IDE можно сразу перейти к классу через CTRL + click). Даже если у вас нет IDE, из пути всё равно понятно где искать класс. Класс расположен в модуле news в папке Controllers и называется VoteController.php
Посмотрим на метод и класс: VoteController.php
Этот класс избавлен от всех рутинных объявлений переменных.
Если в классе задано название модуля так: protected $module_name = 'news'; то шаблонизатор, а так же переводы будут настроены автоматически.
Посмотрим на метод add
public function add(User $user, int $article_id, bool $type_vote = false): voidВ этом методе ожидается пользователь, идентификатор статьи и тип голоса.
Что происходит когда выполняется этот метод?
По сути этот код равнозначен следующему:
/** @var User $user */
$user = di(User::class);
$route = di('route');
$article_id = (int) $route['article_id'];
$type_vote = (bool) $route['type_vote'];Благодаря автокомплиту описать метод можно очень быстро, а в комментарии /** @var User $user */ нет необходимости т.к. IDE и так понимает что в переменной $user уже содержится объект текущего пользователя.
Переменные $article_id и $type_vote будут внедрены автоматически если в настройках маршрута есть описание параметров с такими же названиями. Так же эти переменные будут автоматически приведены к тому типу, который указан в сигнатуре метода. В данном случае в методе указано что $article_id это int (число), а $type_vote это bool. К этим значениям они и будут приведены.
Всё это ещё будет более детально в примерах описано в документации после выхода новой версии движка.