Когда мне сказали, что нужно написать компонент для Joomla, я вздрогнул. Последний раз я работал с Joomla 2.5, и воспоминания были болезненные: JModelLegacy, глобальные переменные, HTML в PHP-файлах. Но Joomla 4+ изменилась кардинально — и я решил подойти к компоненту так, как подобает в 2026 году: чистый MVC, PSR-4 автозагрузка, DI-контейнер и нормальное разделение ответственности.
Архитектура MVC в Joomla
Joomla реализует классический MVC с небольшими нюансами. Модель (Model) работает с данными — через Table-классы или напрямую с JDatabase. Вид (View) отвечает за рендеринг — он получает данные от модели и передаёт их в шаблон. Контроллер (Controller) определяет, какое действие выполнить, и диспетчеризирует запрос.
В отличие от Laravel или Symfony, где роутинг конфигурируется отдельно, в Joomla он строится на соглашениях: URL /index.php?option=com_mycomp&view=items&id=42 автоматически вызывает контроллер, который загружает вид items и передаёт ему ID 42.
Структура директорий
Вот структура нашего компонента com_tasktracker:
com_tasktracker/
├── tasktracker.xml # Манифест компонента
├── src/
│ ├── Controller/
│ │ ├── DisplayController.php
│ │ └── TaskController.php
│ ├── Model/
│ │ ├── TasksModel.php
│ │ └── TaskModel.php
│ ├── View/
│ │ └── Tasks/
│ │ └── HtmlView.php
│ ├── Table/
│ │ └── TaskTable.php
│ └── Extension/
│ └── TasktrackerComponent.php
├── tmpl/
│ └── tasks/
│ └── default.php # Шаблон
└── sql/
└── install.mysql.utf8.sql
Joomla 4+ поддерживает PSR-4 автозагрузку из папки src/ — namespace автоматически мапится по имени компонента.
Контроллер
Базовый контроллер обрабатывает задачу display по умолчанию:
app->getIdentity()->authorise('core.view', 'com_tasktracker')) {
throw new \Exception('Доступ запрещён', 403);
}
return parent::display($cachable, $urlparams);
}
}
Модель и Table
Модель получает данные через Table-класс, который инкапсулирует работу с конкретной таблицей базы данных:
getDatabase();
$query = $db->getQuery(true);
$query->select($this->getState('list.select', 't.*'))
->from($db->quoteName('#__tasktracker_tasks', 't'))
->where($db->quoteName('t.state') . ' = 1')
->order($db->quoteName('t.created') . ' DESC');
// Фильтр по статусу
$status = $this->getState('filter.status');
if ($status) {
$query->where($db->quoteName('t.status') . ' = :status')
->bind(':status', $status);
}
return $query;
}
}
Обратите внимание: мы не используем JModelLegacy — это устаревший класс из Joomla 3. Вместо него ListModel и ItemModel из нового пространства имён Joomla\CMS\MVC\Model. Параметры запроса биндятся через bind() — это защищает от SQL-инъекций без ручного экранирования.
Вид и шаблон
Вид получает данные от модели и передаёт их в шаблон. В Joomla 4 шаблоны по-прежнему PHP-файлы, но мы используем Layout-систему для переиспользования:
items = $this->get('Items');
$this->pagination = $this->get('Pagination');
// Проверяем, что данные загружены
if (count($this->items) === 0) {
$this->app->enqueueMessage('Задачи не найдены', 'info');
}
parent::display($tpl);
}
}
Маршрутизация
В Joomla 4 добавили поддержку SEF-роутинга через файл services/provider.php. Мы настроили ЧПУ так:
registerView($tasks);
$task = new RouterViewConfiguration('task');
$task->setKey('id')->setParent($tasks, 'catid');
$this->registerView($task);
parent::__construct($app, $menu);
}
}
Теперь URL /tasks/42-my-task автоматически резолвится в контроллер и вид.
Сравнение с современными PHP-фреймворками
Честно говоря, после Laravel и Symfony подход Joomla ощущается архаично. Нет middleware-концепции, DI-контейнер есть, но его использование опционально и мало кто им пользуется. Шаблоны — это PHP без шаблонизатора (Twig не интегрирован из коробки, хотя есть плагины). Роутинг завязан на имя компонента и view.
Но у Joomla есть преимущество: её админка, ACL, мультиязычность и экосистема расширений работают из коробки. Если вам нужно добавить кастомную функциональность к существующему Joomla-сайту — писать компонент гораздо логичнее, чем поднимать отдельное Laravel-приложение рядом.
Мой совет: если проект на Joomla — пишите компонент по правилам платформы, но используйте современные классы (CMS\MVC\* вместо Legacy), PSR-4 автозагрузку и биндите параметры запросов. Это не Symfony, но и не тот ужас, который был в Joomla 2.5.
Пока нет комментариев
Будьте первым, кто оставит комментарий к этой статье