[英]ZF3: How to route to specific controller/action based on method and route?
在我的模块的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',
],
],
],
//...
];
我正在努力实现的目标:
如何做到这一点?
尝试将文字更改为Zend\\Mvc\\Router\\Http\\Part
路由,然后将HTTP路由作为CHILD路由放入!
参见此处https://docs.zendframework.com/zend-router/routing/#http-route-types
给自己和其他任何人的笔记,作为@ delboy1978uk答案的补充笔记。
我一直在寻找的答案是这样的:
/index/foo
=> IndexController fooAction /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'
],
],
]
],
],
//...
];
我知道这是一个古老的话题,但我想分享我的答案给任何遇到这个问题并且正在与 zend 或 Laminas(我使用 Laminas)以及基于方法和本地化路由的路由苦苦挣扎的人。 基本上,您应该能够将名称空间的“Laminas”替换为“Zend”。 代码库非常相似。
首先:我无法使用@evilReiko 的解决方案,因为'may_terminate' => false,
总是为我抛出异常。 当我将其设置为true
,子路由被忽略了......显然:D
但是这张便条帮助我了解了一些正在发生的事情。 我决定只实现一个自定义类,它同时处理:URL 本地化和方法/操作路由。
我创建了一个新文件夹Classes
并在modules/Application
添加了一个新文件MethodSegment
。 所以文件路径将是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 子路线方法非常笨拙。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.