4

我已经开发了一个基本的 MVC 框架作为 php 中的一个学习项目——这实际上是它的第二个版本,我正在尝试改进第一个版本不足的两个方面:

  • 请求路由:映射请求,例如 /controller/action/[params]
  • 模块:旨在扩展应用程序的插入式应用程序,例如 CMS。

这就是我现在所处的位置:

  1. 我能够接受一个请求并将其解析为各个部分,例如控制器、动作、参数等。这些映射到相应的控制器类/文件,例如“/foo/bar”-> FooController::bar() - 所有这些都在我的 RequestRouter 类中完成并封装在 Request 对象中。

    • 我维护一个 Manifest 对象,其中包含对应用程序文件的分类引用(控制器、lib 等)。清单由我的自动加载器方法使用。
    • 由于清单已缓存,因此每当我添加新文件/类时都会重新构建它,这适用于添加/删除新模块时。
  2. Controller::methods() 可以很好地呈现正确的视图。

  3. 然后是模块,它们的组织方式就像核心结构一样(/root/raspberry/vendors/core/module)

问题

我认为我目前遇到的问题是涉及模块的路由/请求处理的组合:

  • 如果我请求 project.dev/admin 它映射到 AdminController::index() - 这是正确的
  • 但是,当我引用 project.dev/admin/editor 时,我仍然得到AdminController::editor()我真正想要的是EditorController::index()

经过一番研究,我想我可以创建一个装饰器,它实现了一个前端控制器模式并包装了一个给定的控制器。装饰器可以重新解析请求以使 /editor 成为控制器并重新映射剩余的段(/editor/action/args)。

所有这一切似乎都可以正常工作,但我觉得我在流程的早期缺少一些基本的东西(RequestRouter)。我在 SO 中研究了其他类似的问题,并阅读了 HMVC,原则上它似乎可以回答我的问题,但它似乎比框架驱动更接口驱动(如果这有意义?)我已经还查看了其他框架,例如 Kohana,但我不太了解它们的模块系统和路由到同一模块中的多个控制器的工作原理。

任何关于如何在不引入前端控制器或重新解析请求的情况下有效实施模块系统的见解或建议将不胜感激。或者,如果我应该以不同的方式重新构建我的模块,我想了解如何做到这一点。

附加信息:

我的 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 对象的样子:

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://s11.postimage.org/pujb2g9v7/Screen_shot_2012_10_09_at_8_45_27_PM.png

4

1 回答 1

3

该问题似乎是由过度简化的路由机制引起的。我得到的印象是您使用简单explode()的方法从 URL 收集参数。虽然这仅在基本示例中有效,但当您尝试使用更高级的路由方案时,设置将失败。

/您应该将其与正则表达式模式匹配,而不是在 上拆分字符串。基本上,您定义要匹配的模式列表,第一个匹配用于填充Request实例。

在您的情况下,将定义两种模式:

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

如果第一个失败,第二个将匹配。

PS你应该知道控制器不应该渲染输出。响应的生成是视图实例的责任。视图应该是功能齐全的对象,其中包含表示逻辑并且可以从多个模板组成响应。

于 2012-10-10T02:09:44.453 回答