問題描述
我已經開發了一個基本的 MVC 框架作為 php 的學習項目——這實際上是它的第二個版本,我正在努力改進第一個版本所欠缺的兩個方面:
I've developed a basic MVC framework as a learning project in php--this is actually the second version of it, and I'm trying to improve two aspects that the first version fell short on:
- 請求路由:映射請求,例如/controller/action/[參數]
- 模塊:旨在擴展應用程序的嵌入式應用程序,例如一個內容管理系統.
- Request Routing: mapping requests, e.g. /controller/action/[params]
- Modules: drop-in applications designed to extend the application, e.g. a CMS.
我能夠接受一個請求并將其解析為不同的部分,例如控制器、動作、參數等.這些映射到相應的控制器類/文件,例如/foo/bar"->FooController::bar() -所有這些都在我的 RequestRouter 類中完成并封裝在一個請求對象.
I'm able to take a request and parse it into it's various pieces, e.g. controller, action, args, etc.. These map to corresponding controller classes/files, e.g. "/foo/bar" -> FooController::bar() - all of which is done in my RequestRouter class and encapsulated in a Request object.
- 我維護一個 Manifest 對象,其中包含對應用程序文件的分類引用(控制器、庫等).清單由我的自動加載程序方法使用.
- 由于清單被緩存,所以每當我添加新文件/類時都會重建它,這對于添加/刪除新模塊時也是如此.
Controller::methods() 渲染正確的視圖.
The Controller::methods() render the correct views fine.
然后是模塊,它們的組織方式就像核心結構一樣(/root/raspberry/vendors/core/module)
Then comes the modules, which are organized like the core is structured (/root/raspberry/vendors/core/module)
問題
我認為我目前遇到的問題是與模塊相關的路由/請求處理的組合:
The Problem
The issue that I think I'm having at the moment is a combination of Routing/Request Handling where modules are concerned:
- 如果我請求 project.dev/admin 它映射到AdminController::index() -- 這是正確的
- 然而,當我引用 project.dev/admin/editor 時,我仍然得到 AdminController::editor() 我真正想要的是 EditorController::index()
- If I request project.dev/admin it maps to the AdminController::index() -- this is correct
- However, when I reference project.dev/admin/editor I still get AdminController::editor() where what I really want is EditorController::index()
經過一些研究,我想我可以創建一個裝飾器,它實現一個前端控制器模式并包裝給定的控制器.裝飾器可以重新解析請求,使/editor 成為控制器并重新映射剩余的段 (/editor/action/args).
After some research, I figure I could create a Decorator, which implements a Front Controller pattern and wraps a given Controller. The decorator could re-parse the request to make /editor the controller and re-map the remaining segments (/editor/action/args).
所有這些似乎都可以正常工作,但我覺得我在流程的早期(RequestRouter)中遺漏了一些基本的東西.我在 SO 中研究了其他類似的問題,并閱讀了 HMVC,原則上它似乎可以回答我的問題,但它似乎更多的是接口驅動而不是框架驅動(如果這有意義?)我已經還研究了 Kohana 等其他框架,但我不太了解它們的模塊系統和路由到同一模塊中的多個控制器的工作原理.
All of this seems like it could work fine, but I feel like I'm missing something fundamental earlier in the flow (RequestRouter). I've research other similar questions here in SO, and read up on HMVC, and in principle it seems like it might answer my questions, but it seems more interface-driven than framework-driven (if that makes sense?) I've also looked at other frameworks like Kohana, but I'm not quite grasping how their module system and routing to multiple controllers in the same module work.
關于如何在不引入前端控制器或重新解析請求的情況下有效實現模塊系統的任何見解或建議,將不勝感激.或者,如果我應該以不同的方式重新構建我的模塊,我想了解如何做到這一點.
Any insights or suggestions on how to effectively implement a module system without introducing a Front Controller or re-parsing a request would be much appreciated. Alternately, if I should re-structure my modules in a different manner, I'd like to understand how to do that.
我的 RequestRouter 維護一個我預先定義的路由列表(包括它們的默認方法).使用這些預定義的路由,我可以訪問/admin/editor 并獲得 EditorController::index(),但我必須為每個控制器定義一個路由,并請求進入控制器中的控制器模塊.我不認為這是一個好的設計.這是我的路線示例:
My RequestRouter maintains a list of routes that I pre-defined (including their default methods). Using these pre-defined routes, I can access /admin/editor and get EditorController::index(), but I'd have to define a route for every controller and request that goes to controllers in the module. I don't think this is good design. Here's a sample of my routes:
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
)
)
這是我的請求對象的樣子:
This is what my Request object looks like:
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
)
這是應用程序文件系統:
This is the application file system:
http://s11.postimage.org/pujb2g9v7/Screen_shot1_2007.png2012_10_09_at_8_45_27_PM.png"
http://s11.postimage.org/pujb2g9v7/Screen_shot_2012_10_09_at_8_45_27_PM.png
推薦答案
該問題似乎是由過于簡化的路由機制引起的.我得到的印象是您正在使用簡單的 explode()
從 URL 收集參數.雖然這僅適用于基本示例,但當您嘗試使用更高級的路由方案時,設置將失敗.
The issue seems to be caused by over-simplified routing mechanism. The impression i get is that you are using simple explode()
to collect the parameters from URL. While this works just fin in basic examples, the setup will fail when you try to use a bit more advanced routing schemes.
與其在 /
上拆分字符串,不如將其與正則表達式模式進行匹配.基本上,您定義要匹配的模式列表,第一個匹配項用于填充 Request
實例.
Instead of splitting the string on /
, you should match it against regexp patterns. Basically, you define a list of patterns to match against and first match is used to populate the Request
instance.
在您的情況下會定義兩種模式:
In your situation would would have two patterns defined:
'#admin/(:?(:?/(?P
[^/.,;? ]+))?/(?P[^/.,;? ]+))?#' '#(:?(:?/(?P
[^/.,;? ]+))?/(?P[^/.,;? ]+))?#'
'#admin/(:?(:?/(?P<controller>[^/.,;? ]+))?/(?P<action>[^/.,;? ]+))?#'
'#(:?(:?/(?P<controller>[^/.,;? ]+))?/(?P<action>[^/.,;? ]+))?#'
如果第一個失敗,第二個會匹配.
If the first one fails, the second one would match.
P.S. 你應該知道控制器不應該渲染輸出.響應的生成是視圖實例的責任.視圖應該是包含表示邏輯的功能齊全的對象,可以組合來自多個模板的響應.
P.S. You should know that controllers are not supposed to render output. Generation of response is responsibility of view instances. Views should be fully functional objects which contain presentation logic and can compose a response from multiple templates.
這篇關于如何在 MVC 框架中有效地實現模塊,并在單個模塊中處理到多個控制器的路由?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!