MVC в Joomla: практические правила для компонентов 5.x
В Joomla MVC — не просто три папки с моделями, видами и контроллерами. Разбираем, где держать запросы и бизнес-логику, как выбирать между legacy-структурой и современным компонентом для Joomla 5.x.

Компонент Joomla 5.x можно собрать по MVC и при этом получить код, который трудно тестировать и опасно расширять. На практике проблемы начинаются не с самого паттерна, а с неверных границ: SQL попадает во view, контроллер превращается в сервисный слой, а шаблон начинает менять данные. Ниже — рабочая схема для компонентов Joomla 4/5, критерии выбора структуры и ошибки, которые дороже всего исправлять после запуска.
Что в Joomla считается MVC
В компоненте Joomla запрос проходит через несколько уровней. Контроллер принимает действие пользователя, модель получает и изменяет данные, view готовит набор данных для отображения, а layout выводит HTML. Это не жёсткая изоляция как в учебной реализации MVC: Joomla добавляет диспетчеризацию компонента, menu item, состояния модели, layout и фабрику MVC.
Типичный маршрут выглядит так: пункт меню вызывает компонент, компонент выбирает контроллер, контроллер — задачу, задача обращается к модели, а view передаёт данные в layout. Значения view, task и layout приходят из запроса и конфигурации пункта меню, поэтому их нельзя считать доверенными данными.
Хороший MVC-компонент Joomla не прячет всю логику по разным папкам. Он делает понятным, кто отвечает за изменение данных, кто — за их получение, а кто — только за вывод.
Состояние модели1 — это набор фильтров, сортировки и пагинации, который модель сохраняет между вызовами. В Joomla оно обычно используется, чтобы список одинаково работал для запроса, количества записей и постраничной навигации.
Три практических подхода
Выбор структуры зависит от версии Joomla и срока жизни компонента. Для нового проекта на Joomla 5.x обычно не стоит копировать старый компонент Joomla 3 без адаптации: такая экономия проявится при обновлении, тестировании и подключении зависимостей.
| Подход | Когда выбирать | Цена решения |
|---|---|---|
| Legacy MVC | Поддержка существующего расширения Joomla 3 или старого компонента | Проще быстро внести локальную правку, но сложнее перейти на namespace, сервис-провайдер и современную загрузку классов |
| Namespace MVC Joomla 4/5 | Новый компонент или активная миграция на Joomla 5.x | Нужно настроить структуру расширения, services provider и соглашения именования |
| MVC плюс отдельный сервисный слой | Сложные правила, внешние API, расчёты, очереди и повторное использование логики | Появляются дополнительные классы и тесты, зато контроллеры и модели не разрастаются |
Legacy MVC: только для поддержки
В старой структуре разработчик часто работает с файлами вроде controller.php, models/, views/ и tmpl/. Это нормально, если задача — исправить конкретную ошибку в работающем расширении. Плохо превращать такой компонент в основу нового продукта: без аккуратной миграции смешиваются старый загрузчик классов, глобальные имена и современная контейнерная конфигурация.
Namespace MVC: базовый вариант для Joomla 5.x
В современном компоненте классы получают namespace, а загрузка и создание MVC-объектов проходят через конфигурацию расширения. Для сайта и административной части используются разные пространства имён и контексты. Это уменьшает риск конфликта классов и упрощает переход к зависимостям Joomla.
Практическое правило: сначала определите публичную и административную части компонента, затем названия view и моделей. Не начинайте с копирования папок. Сначала проверьте, как компонент подключается через services provider и как Joomla создаёт его MVCFactory.
MVC плюс сервисный слой
Если модель одновременно строит сложный SQL-запрос, вызывает платёжный API, проверяет права и отправляет уведомление, проблема уже не в размере файла. У модели слишком много причин для изменения. Вынесите предметное действие в отдельный сервис, а модель оставьте координатором чтения или сохранения данных.
Такой сервис не должен напрямую зависеть от HTML-layout. Он может вернуть результат или выбросить исключение, а контроллер решит, какое сообщение показать и куда перенаправить пользователя. Внешний API, ключи и URL храните в конфигурации, а не в PHP-файле компонента.
Где держать код
- Контроллер. Проверяйте входные параметры, права доступа, токен формы и выбирайте действие. Не помещайте сюда длинный SQL и расчёты. Если после проверки контроллер сам собирает несколько зависимостей и обрабатывает десятки условий, пора выделить сервис.
- Модель. Сюда относится получение и изменение данных компонента. Для списков используйте
ListModel, состояние модели и единый запрос, который учитывает фильтры. Для записи данных проверяйте права и входные значения до сохранения. - View. View получает данные модели и подготавливает их для layout. Она не должна решать, можно ли удалить запись, менять таблицу базы или вызывать удалённый API.
- Layout. Layout выводит данные. Экранируйте значения перед HTML-выводом и не рассчитывайте, что данные из модели уже безопасны только потому, что пришли из базы.
- Сервис. Вынесите сюда повторяемые операции: расчёт цены, синхронизацию с API, импорт, сложную проверку перехода состояния. Сервис можно вызвать из нескольких задач и тестировать без рендера страницы.
Как выглядит модель списка
Ниже — фрагмент для namespace-компонента Joomla 5.x. Он показывает границу модели: модель строит запрос, а layout не знает, как устроена таблица. Имена таблицы и полей замените на свои.
<?php
namespace Joomla\Component\Example\Site\Model;
use Joomla\CMS\MVC\Model\ListModel;
class ItemsModel extends ListModel
{
protected function getListQuery()
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select([
$db->quoteName('a.id'),
$db->quoteName('a.title'),
$db->quoteName('a.created')
])
->from($db->quoteName('#__example_items', 'a'))
->where($db->quoteName('a.published') . ' = 1')
->order($db->quoteName('a.created') . ' DESC');
return $query;
}
}Фрагмент опирается на API Joomla 5.x: ListModel, getDatabase() и объект построителя запроса. Если вы поддерживаете Joomla 3, не переносите этот код механически: в старых версиях отличаются загрузка классов, структура расширения и часть соглашений MVC.
Что чаще всего ломается
SQL в layout
Такой код трудно переиспользовать для RSS, JSON-ответа и административного списка. Перенесите запрос в модель, а фильтры передавайте через состояние модели. Инвалидация кеша после изменения данных — отдельная задача, её не стоит прятать в шаблоне.
Данные из запроса без фильтрации
Параметры сортировки, идентификаторы и поисковая строка должны проходить проверку. Для имени поля нельзя просто подставлять пользовательскую строку в SQL: используйте белый список допустимых полей и направлений сортировки.
Проверка доступа только в меню
Скрытый пункт меню не защищает задачу контроллера. Пользователь может обратиться к URL напрямую. Проверяйте ACL и право на конкретное действие в контроллере или сервисе перед чтением закрытых данных и особенно перед изменением или удалением.
Смешение site и administrator
Публичная часть и админка могут использовать похожие названия view, но у них разные права, шаблоны и сценарии. Явно разделяйте namespace, контроллеры и модели. Если модель нужна в обоих контекстах, вынесите общую работу с данными в отдельный класс, а не подключайте файл из соседней части вручную.
Толстая модель
Модель на тысячу строк не становится архитектурой только потому, что лежит в папке Model. Разделите чтение списка, изменение сущности и интеграции. Критерий простой: если класс нельзя проверить без базы, HTTP-запроса и рендера страницы, часть его логики стоит вынести.
Когда какой подход выбирать
Для нового компонента на Joomla 5.x выбирайте namespace MVC и сразу закладывайте сервисный слой для нетривиальных операций. Для небольшого каталога достаточно модели списка, формы, контроллера и layout. Для миграции старого расширения сначала зафиксируйте поведение тестами или ручным чек-листом, затем переносите один сценарий за раз.
Не пытайтесь переписать весь компонент ради самого факта перехода на MVC. Если legacy-код стабилен и меняется редко, безопаснее ограничить миграцию участками, которые требуют новых функций Joomla или ломаются при обновлении. Цена полной переделки — не только часы разработки, но и повторная проверка прав, маршрутов, форм и совместимости с шаблоном.
Что сделать дальше
Возьмите один пользовательский сценарий — например, фильтрацию списка и открытие карточки — и нарисуйте его путь от menu item до layout. Затем проверьте пять точек: где проверяются права, где строится SQL, где экранируется вывод, где обрабатывается ошибка и можно ли вызвать тот же сервис из другой задачи. После этого включите журналирование ошибок на тестовом сайте и отдельно проверьте прямые URL к административным задачам. Такой аудит быстрее показывает реальные проблемы MVC, чем механическое сравнение названий папок.
1 Состояние модели — сохранённые параметры фильтра, сортировки и страницы списка, которые Joomla использует при построении запроса и пагинации.
Prompt-инженер: Идеальные запросы для Midjourney, ChatGPT и других моделей.
Спросить за 15 ₽Источники: Joomla Manual: Building Extensions — Components, Joomla Documentation: Developing an MVC Component
Частые вопросы
Нужно ли использовать MVC для каждого расширения Joomla?
Чем MVC в Joomla 5.x отличается от структуры Joomla 3?
Можно ли писать SQL прямо в контроллере?
Где проверять права на удаление записи?
Что делать, если код написан под Joomla 3?
Почему модель работает, но список показывает неправильную пагинацию?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.