0

在我的模块中module.config.php,我有这样的东西:

namespace Application;

return [
    //...
    // myroute1 will route to IndexController fooAction if the route is matching '/index/foo' but regardless of request method
    'myroute1' => [
        'type' => Zend\Router\Http\Literal::class,
        'options' => [
            'route'    => '/index/foo',
            'defaults' => [
                'controller' => Controller\IndexController::class,
                'action'     => 'foo',
            ],
        ],
    ],

    // myroute2 will route to IndexController fooAction if the route is request method is GET but regardless of requested route
    'myroute2' => [
        'type'    => Zend\Router\Http\Method::class,
        'options' => [
            'verb'     => 'get',
            'defaults' => [
                'controller'    => Controller\IndexController::class,
                'action'        => 'foo',
            ],
        ],
    ],
    //...
];

我想要达到的目标:

  • 如果路由/index/foo被请求并且被GET方法请求,那么它应该被路由到IndexController fooAction
  • 如果路由/index/foo被请求并且被POST方法请求,那么它应该被路由到IndexController bar Action(注意这里是 barAction 而不是 fooAction)

如何做到这一点?

4

3 回答 3

2

给我自己和其他任何人的便条,作为@delboy1978uk 答案的补充说明。

我正在寻找的答案是这样的:

  • GET /index/foo=> 索引控制器 fooAction
  • POST /index/foo=> IndexController barAction

所以module.config.php文件中的代码可以是这样的:

return [
    //...
    'myroute1' => [// The parent route will match the route "/index/foo"
        'type' => Zend\Router\Http\Literal::class,
        'options' => [
            'route'    => '/index/foo',
            'defaults' => [
                'controller' => Controller\IndexController::class,
                'action'     => 'foo',
            ],
        ],
        'may_terminate' => false,
        'child_routes' => [
            'myroute1get' => [// This child route will match GET request
                'type' => Method::class,
                'options' => [
                    'verb' => 'get',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'foo'
                    ],
                ],
            ],
            'myroute1post' => [// This child route will match POST request
                'type' => Method::class,
                'options' => [
                    'verb' => 'post',
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => 'bar'
                    ],
                ],
            ]
        ],
    ],
    //...
];
于 2017-09-13T14:16:17.390 回答
2

尝试将文字更改为Zend\Mvc\Router\Http\Part路由,然后将 HTTP 路由作为 CHILD 路由!

见这里https://docs.zendframework.com/zend-router/routing/#http-route-types

于 2017-09-12T14:05:29.480 回答
0

我知道这是一个老话题,但我想与遇到此问题并正在努力处理 zend 或 Laminas(我使用 Laminas)以及基于方法和本地化路由的路由的任何人分享我的答案。基本上你应该能够用“Zend”替换命名空间的“Laminas”。代码库非常相似。

首先:我无法使用@evilReiko 的解决方案,因为'may_terminate' => false,总是为我抛出异常。当我将它设置true为子路由时被忽略了......显然:D

但这张纸条帮助我理解了一些正在发生的事情。我决定只实现一个自定义类来处理:URL 本地化和方法/动作路由。

我创建了一个新文件夹Classes并将一个新文件添加MethodSegmentmodules/Application. 所以文件路径是modules/Application/Classes/MethodSegment.php.

<?php

namespace Application\Classes;

use Laminas\Router\Exception;
use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\RequestInterface as Request;
use Laminas\Router\Http\RouteMatch;
use Traversable;
    
/**
 * Method route.
 */
class MethodSegment extends \Laminas\Router\Http\Segment
{
    /**
     * associative array [method => action]
     *
     * @var array
     */
    protected $methodActions;

    /**
     * Default values - accessing $defaults from parent class Segment
     *
     * @var array
     */
    protected $defaults;

    /**
     * Create a new method route
     *
     * @param  string $route
     * @param  array  $constraints
     * @param  array  $defaults
     */
    public function __construct($route, array $constraints = [], array $defaults = [])
    {
        if(is_array($defaults['action']))
        {
            $this->methodActions = $defaults['action'];
            $defaults['action'] = array_values($defaults['action'])[0];
        }

        parent::__construct($route, $constraints, $defaults);
    }

    /**
     * factory(): defined by RouteInterface interface.
     *
     * @see    \Laminas\Router\RouteInterface::factory()
     *
     * @param  array|Traversable $options
     * @return Method
     * @throws Exception\InvalidArgumentException
     */
    public static function factory($options = [])
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (! is_array($options)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects an array or Traversable set of options',
                __METHOD__
            ));
        }

        if (! isset($options['defaults'])) {
            $options['defaults'] = [];
        }

        return new static($options['route'] ?? null, $options['constraints'] ?? [], $options['defaults']);
    }

    /**
     * match(): defined by RouteInterface interface.
     *
     * @see    \Laminas\Router\RouteInterface::match()
     *
     * @return RouteMatch|null
     */
    public function match(Request $request, $pathOffset = null, array $options = [])
    {
        if (! method_exists($request, 'getMethod')) {
            return null;
        }

        $requestVerb = strtolower($request->getMethod());
        $verb = array_keys($this->methodActions);

        if (in_array($requestVerb, $verb)) {
            $this->defaults['action'] = $this->methodActions[$requestVerb];
            return parent::match($request, $pathOffset, $options);
        }

        return null;
    }
}

基本上,我从 Laminas Method 类中复制了代码并对其进行了增强,因此我可以传递一系列动作。

您可以像这样使用 MethodSegment:

use App\Routing\MethodSegment;
return [
    'router' => [
        'routes' => [
            'home' => [
                'type'    => MethodSegment::class,
                'options' => [
                    'route'    => /[:language/],
                    'constraints' => [...],
                    'defaults' => [
                        'controller' => Controller\IndexController::class,
                        'action'     => [
                            'get' => 'index',
                            'post' => 'postIndex', // e.g. form
                        ],
                    ],
                ],
            ],
      [...]

希望这对任何人都有帮助,IMO 子路线方法非常笨拙。

于 2021-11-01T19:25:46.453 回答