Всем привет! Разрабатываю проект на YII2 и нужна ваша помощь в понимании архитектуры модулей и маршрутизации.
Есть Yii2-Advanced приложение. В нем я хотел бы реализовать модульную структуру, что бы можно было урезать и расширять функционал (собственно этого все хотят). Нужно сделать сайт, с кучей однотипных страниц и страниц, на которых будет размещен дополнительный функционал.
Допустим у нас есть модуль Pages который отвечает, за работу со всеми страницами на сайте. Он формирует древо страниц и их URL-ы (в зависимости от вложенности и alias-ов которые придумал админ), и подключает к ним шаблоны и контент. И допустим в панели администратора мы создаем следующую структуру страниц:
- Главная (alias: /home)
- О компании (alias: /about)
- Новости (alias: /news)
- Контакты (alias: /contact)
В БД в таблице Page у нас появляются 4 записи
id | alias | name
---------------------------------
1 | /home | Главная
2 | /about | О компании
3 | /news | Новости
4 | /contact | Контакты
Пока страниц всего 4 можно сделать отдельные action в SiteController, но представим, что у нас много страниц и этот вариант не подходит.
Создаем PageController и изменяем маршрутизатор так, что бы он сначала искал страницы в БД по нашему alias и если нашел страницу с таким URL то отсылал на PageController::actionPage(), где бы мы доставали нужную страницу из базы, определяли ее шаблон, вставляли контент и выводили все это дело на фронт. А если нет, то искал controller/action в зависимости от URL-rules и выполнял его логику.
Но на странице Новости у нас должен работать модуль новостей, которые хранятся в отдельной таблице news, т.к. их может быть не одна сотня или этого модуля может не быть вообще. И у модуля news есть свой контроллер, который обеспечивает сортировку новостей по тегам, датам и любой другой функционал. К примеру NewsController::actionFindByTag() или NewsController::actionMostPopular().
И вот тут у меня возникает головная боль с маршрутами. Можно зашить дополнительное поле action, в таблицу template, которая отвечает за шаблоны страниц и чекать URL по нему. То есть если у страницы есть шаблон и его action != null
тогда уходим НЕ на PageController::actionPage(), а подставляем значение action и уходим по нему.
Теперь вроде все в порядке, пользователь набирает в адресе sitename.ru/news мы ищем эту страницу в БД, находим у нее template.action который равен news/index и уходим на NewsController::actionIndex(). И вот тут и таится проблема. Если админ изменит alias страницы Новости, например на /events, то по запросу sitename.ru/events он все равно попадет
на NewsController::actionIndex(), что нам и надо, но вот если он на странице новостей кликнет на "Показать популярные", которая должна вести на NewsController::actionMostPopular(), то единственный способ это указать контроллер и action напрямую, как news/most-popular. Соответственно происходит необоснованное изменение адресов с /events на /news/most-popular.
Резюмируя этот огромный вопрос. Не могу понять, как организовать модули с их логикой, рядом с обычными страницами без логики, и при этом что бы в панели администратора Админ мог изменять alias-ы страниц, их вложенность и прочее. Но функционал модулей сохранялся бы.
Заранее спасибо!
UPD:
Пока сошлись на том, что нужно определять принадлежность модуля к странице и как-то парсить URL в UrlManager::ParseRequest().
Хочу выразить огромное спасибо
Дмитрию Елисееву, за помощь, он предложил следующий вариант парсинга URL:
В parseRequest:
- Ищем /city/events/most-popular. Не нашлось.
- Ищем /city/events. Нашлось. Тип "news". Запускаем рекурсию:
$r = clone $request;
$r->setPathInfo('news/most-popular');
return $manager->parseRequest($r);
Пока не знаю подойдет ли этот метод, но буду пробовать его. Отпишусь здесь, когда проверю. Если у кого-то есть идеи, то буду очень признателен, за помощь.