[英]ZF3: How to route to specific controller/action based on method and route?
In my module's module.config.php
, I have something like this:在我的模块的
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',
],
],
],
//...
];
What I'm trying to achieve:我正在努力实现的目标:
How to achieve that?如何做到这一点?
Try changing the literal to a Zend\\Mvc\\Router\\Http\\Part
route, and then putting the HTTP routes in as CHILD routes! 尝试将文字更改为
Zend\\Mvc\\Router\\Http\\Part
路由,然后将HTTP路由作为CHILD路由放入!
See here https://docs.zendframework.com/zend-router/routing/#http-route-types 参见此处https://docs.zendframework.com/zend-router/routing/#http-route-types
A note to myself and anyone else looking, as additional note to @delboy1978uk's answer. 给自己和其他任何人的笔记,作为@ delboy1978uk答案的补充笔记。
The answer I was looking for is something like this: 我一直在寻找的答案是这样的:
/index/foo
=> IndexController fooAction /index/foo
=> IndexController fooAction /index/foo
=> IndexController barAction /index/foo
=> IndexController barAction So the code in module.config.php
file can be like this: 所以
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'
],
],
]
],
],
//...
];
I know this is an old topic but I wanted to share my answer for anyone who comes across this and is struggling with zend or Laminas (I use Laminas) and the routing of method based AND localized routes.我知道这是一个古老的话题,但我想分享我的答案给任何遇到这个问题并且正在与 zend 或 Laminas(我使用 Laminas)以及基于方法和本地化路由的路由苦苦挣扎的人。 Basically you should be able to just replace "Laminas" by "Zend" for the namespaces.
基本上,您应该能够将名称空间的“Laminas”替换为“Zend”。 The code base is very similar.
代码库非常相似。
First of all: I was not able to use @evilReiko's solution because 'may_terminate' => false,
always threw an exception for me.首先:我无法使用@evilReiko 的解决方案,因为
'may_terminate' => false,
总是为我抛出异常。 When I set it to true
the child routes were ignored ... obviously :D当我将其设置为
true
,子路由被忽略了......显然:D
But the note helped me to understand some stuff going on.但是这张便条帮助我了解了一些正在发生的事情。 I decided to just implement a custom class which handles both: URL localization and method/action routing.
我决定只实现一个自定义类,它同时处理:URL 本地化和方法/操作路由。
I created a new folder Classes
and added a new file MethodSegment
into modules/Application
.我创建了一个新文件夹
Classes
并在modules/Application
添加了一个新文件MethodSegment
。 So the file path would be modules/Application/Classes/MethodSegment.php
.所以文件路径将是
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;
}
}
Basically I copied the code from the Laminas Method class and enhanced it so I can pass an array of actions.基本上,我从 Laminas Method 类中复制了代码并对其进行了增强,以便我可以传递一系列操作。
You can use the MethodSegment like so:您可以像这样使用 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
],
],
],
],
[...]
Hope this helps anyone, IMO the child route approach is very clunky.希望这对任何人都有帮助,IMO 子路线方法非常笨拙。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.