【问题标题】:Zend Framework 3 - route based on query stringZend Framework 3 - 基于查询字符串的路由
【发布时间】:2019-04-09 16:49:05
【问题描述】:

在 Zend Framework 3 中,是否可以根据 URL 是否包含查询字符串来路由到控制器?

例如,我有这两个网址:

/users
/users?name=Bob

我希望第一条路由调用UsersController,第二条路由调用NameController

这可能吗?

【问题讨论】:

    标签: php routes zend-framework3


    【解决方案1】:

    我的评论正在变成答案。所以,给你。

    下次请务必关注How to Ask


    请阅读ZF3 docs on Router 和可能的RFC 3986 Chapter 3 - Syntax Components,其中显示了什么是路径和什么是查询。

    来自RFC 3986 Chapter 3 - Syntax Components

    以下是两个示例 URI 及其组成部分:

         foo://example.com:8042/over/there?name=ferret#nose
         \_/   \______________/\_________/ \_________/ \__/
          |           |            |            |        |
       scheme     authority       path        query   fragment
          |   _____________________|__
         / \ /                        \
         urn:example:animal:ferret:nose
    

    ZF3 路由配置通常是在路径上的配置。 (几乎所有常见框架也是如此。) 是的,变量可以是路径的一部分。因此,它们在路由配置中进行配置。框架路由的高级配置通常还允许对方案和权限进行更改/要求。

    “查询”和“片段”部分不是路由配置的一部分。

    如果你想做某事,例如捕获一个“名称”键/值对并相应地进行路由,您将不得不在路径上创建一个“捕获器”(或任何名称)并自己确定重定向。

    例如,您可以执行this answer 之类的操作。如果您的控制器实例扩展了默认的 Zend Framework AbstractActionController 类,那么您应该有可用的 forward plugin。来自文档:

    Forward 返回调度请求的控制器的结果; 由开发人员决定如何处理(如果有的话) 那些结果。一项建议是将它们汇总到任何回报中 来自调用控制器的值。

    举个例子:

     $foo = $this->forward()->dispatch('foo', ['action' => 'process']);
     return [
         'somekey' => $somevalue,
         'foo'     => $foo,
     ];
    

    当然,您可以立即退货。

    另一个选项是redirect plugin(相同的链接)。

    return $this->redirect()->toRoute('login-success');
    

    有了这一切,您可以执行以下操作:

    $name = $this->params()->fromQuery('name', null);
    
    if ($name) {
        // dispatch
    
        if ($dispatchResult) {
            // return special
        }
    } 
    
    // redirect
    

    您重定向到路由名称的位置(即配置的路径)

    【讨论】:

    • 感谢您提供有关 forward()redirect() 插件的信息。
    【解决方案2】:

    作为 rkeet mentioned,查询字符串不是路由的一部分。因此,我们只是在路由配置数组中添加了一个三元组:

    'users' => [ 
        'type'    => Literal::class,
        'options' => [ 
            'route'    => '/users',
            'defaults' => [
                'controller' => isset($_GET['name'])
                              ? NameController::class
                              : UsersController::class,
                'action'     => 'index',
            ],   
        ],   
        'may_terminate' => true,
    ],
    

    这是不言自明的,但基本上调度的控制器取决于查询字符串中是否设置了值。

    我们决定不使用forward() 插件,因为我们不想多余地实例化一个额外的控制器。

    【讨论】:

    • 虽然这可行,但它打破了单一路线上单一动作的模式。在 ZF 中明确完成的事情。我强烈建议不要这样做,因为它创造了一些魔力,你今天就知道,但一年后会让人头疼。再说一次,会工作......
    【解决方案3】:

    即使 rkeet 的 answer 在技术上是正确的,我也会避免使用该解决方案,因为它将单个 HTTP 请求转换为两个(初始 GET 和转发/重定向)。

    我会配置路由路径以获得两条不同的路由:

    'router' => [
        'routes' => [
            'users' => [
                'type' => Literal::class,
                'options' => [
                    'route' => '/users',
                    'defaults' => [
                        'controller' => UsersController::class,
                        'action' => 'index'
                    ],
                    'may_terminate' => true,
                    'child_routes' => [
                        'name' => [ // This is the subroute name
                            'type' => Segment::class,
                            'options' => [
                                'route' => '/:name', // Option 1
                                // 'route' => '/name/:name', // Option 2
                                'defaults' => [
                                    'controller' => NameController::class,
                                    'action' => 'index'
                                ],
                                'constraints' => [
                                    'name' => '[a-zA-Z]+',
                                ]
                            ]
                        ]
                    ]
                ]
            ]
        ]
    ]
    

    通过此配置,您可以访问以下网址

    /users
    /users/Bob (option 1)
    /users/name/Bob (option 2)
    

    【讨论】:

    • 我们最初实际上使用了这种路由结构。但是,:name 参数通常包含不适合 URL 的字符,例如斜杠。所以,:name 参数必须是一个查询参数,而不是一个路由段。
    • 问题不是关于“路径”部分的路由配置(如我的回答所示),而是查询部分(在完整 URL 中的 ? 之后)。您的答案显示了基本的路由配置设置,正如我已经链接的the docs 中所解释的那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    相关资源
    最近更新 更多