Как эффективно реализовать модули в среде MVC и обрабатывать маршрутизацию на несколько контроллеров в одном модуле?

Я разработал базовую структуру MVC как учебный проект в php – на самом деле это вторая версия, и я пытаюсь улучшить два аспекта, которые первая версия не оправдала:

  • Запрос маршрутизации: запросы отображения, например / controller / action / [params]
  • Модули: выпадающие приложения, предназначенные для расширения приложения, например, CMS.

Вот где я сейчас:

  1. Я могу взять запрос и разобрать его на различные части, например, контроллер, действие, аргументы и т. Д. Они сопоставляются с соответствующими классами / файлами контроллера, например «/ foo / bar» -> FooController :: bar () – все это сделано в моем классе RequestRouter и инкапсулировано в объект Request.

    • Я поддерживаю объект манифеста, который содержит категоризированные ссылки (контроллеры, lib и т. Д.) Для файлов приложений. Этот манифест используется моим методом автозагрузчика.
    • Поскольку манифест кэшируется, он восстанавливается всякий раз, когда я добавляю новые файлы / классы, это верно, когда новые модули добавляются / удаляются.
  2. Controller :: methods () отлично отображает правильные представления.

  3. Затем идут модули, которые организованы так, как ядро ​​структурировано (/ root / raspberry / vendors / core / module)

Проблема

Проблема, на мой взгляд, в настоящий момент связана с комбинацией обработки маршрутизации / запроса, в которой находятся модули:

  • Если я запрашиваю project.dev/admin, он сопоставляется с AdminController :: index () – это правильно
  • Однако, когда я ссылаюсь на project.dev/admin/editor, я все еще получаю AdminController :: editor (), где я действительно хочу, это EditorController :: index ()

После некоторых исследований, я полагаю, я мог бы создать Decorator , который реализует шаблон Front Controller и обертывает данный контроллер. Декоратор может повторно разбить запрос на создание / редактирование контроллера и повторную карту оставшихся сегментов (/ editor / action / args).

Все это похоже на то, что это может работать нормально, но я чувствую, что мне не хватает чего-то фундаментального ранее в потоке (RequestRouter). Я исследую другие подобные вопросы здесь, в SO, и читаю на HMVC, и в принципе кажется, что он может ответить на мои вопросы, но он кажется более ориентированным на интерфейс, чем с каркасом (если это имеет смысл?) также посмотрел на другие структуры, такие как Kohana, но я не совсем понимаю, как их модульная система и маршрутизация на несколько контроллеров в одном модуле работают.

Любые идеи или предложения по эффективному внедрению модульной системы без введения Front Controller или повторного анализа запроса были бы высоко оценены. В качестве альтернативы, если я должен переструктурировать свои модули по-другому, я хотел бы понять, как это сделать.

Дополнительная информация:

Мой RequestRouter поддерживает список маршрутов, которые я предварительно определил (включая их методы по умолчанию). Используя эти заранее определенные маршруты, я могу получить доступ / admin / editor и получить EditorController :: index (), но мне нужно будет определить маршрут для каждого контроллера и запрос, который поступает на контроллеры в модуле. Я не думаю, что это хороший дизайн. Вот пример моих маршрутов:

Array ( [/foo] => Array ( [controller] => FooController [method] => bar [path] => /core ) [/admin] => Array ( [controller] => AdminController [method] => index [path] => /vendors/admin ) [/admin/editor] => Array ( [controller] => EditorController [method] => index [path] => /vendors/admin ) ) 

Это объект моего запроса выглядит так:

 Request Object ( [properties:Request:private] => Array ( [url] => /admin/editor [query] => [uri] => /admin/editor [controller] => admin [action] => editor [args] => [referrer] => Array ( [HTTP_REFERER] => [REMOTE_ADDR] => 127.0.0.1 [HTTP_VIA] => [HTTP_X_FORWARDED_FOR] => ) [get] => ) [request_status:Request:private] => 200 ) 

Это образец моего манифеста:

 [controller] => Array ( [icontroller] => /htdocs/raspberry/raspberry/core/controller/icontroller.class.php [index] => /htdocs/raspberry/raspberry/core/controller/index.php [serviceerror] => /htdocs/raspberry/raspberry/core/controller/serviceerror.controller.php [admin] => /htdocs/raspberry/raspberry/vendors/core/admin/controller/admin.controller.ph [composer] => /htdocs/raspberry/raspberry/vendors/core/admin/controller/composer.controller.php ) 

Это файловая система приложения:

http://img.ruphp.com/vendor/Screen_shot_2012-10-09_at_8.45.27_PM.png

Проблема, похоже, вызвана чрезмерно упрощенным механизмом маршрутизации. Создается впечатление, что вы используете простой explode() для сбора параметров из URL. Хотя это работает только в базовых примерах, установка завершится неудачно, когда вы попытаетесь использовать несколько более совершенные схемы маршрутизации.

Вместо того, чтобы разбивать строку на / , вы должны сопоставлять ее с шаблонами regexp. В основном, вы определяете список шаблонов для соответствия, и первое совпадение используется для заполнения экземпляра Request .

В вашей ситуации было бы определено два шаблона:

  • '#admin/(:?(:?/(?P<controller>[^/\.,;?\n]+))?/(?P<action>[^/\.,;?\n]+))?#'
  • '#(:?(:?/(?P<controller>[^/\.,;?\n]+))?/(?P<action>[^/\.,;?\n]+))?#'

Если первый не удастся, второй будет соответствовать.

PS Вы должны знать, что контроллеры не должны выводить вывод. Генерация ответа – это ответственность за просмотр экземпляров. Представления должны быть полностью функциональными объектами, которые содержат логику представления и могут составлять ответ от нескольких шаблонов.