我知道这是一个老话题,但我想与遇到此问题并正在努力处理 zend 或 Laminas(我使用 Laminas)以及基于方法和本地化路由的路由的任何人分享我的答案。基本上你应该能够用“Zend”替换命名空间的“Laminas”。代码库非常相似。
首先:我无法使用@evilReiko 的解决方案,因为'may_terminate' => false,
总是为我抛出异常。当我将它设置true
为子路由时被忽略了......显然:D
但这张纸条帮助我理解了一些正在发生的事情。我决定只实现一个自定义类来处理:URL 本地化和方法/动作路由。
我创建了一个新文件夹Classes
并将一个新文件添加MethodSegment
到modules/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 子路线方法非常笨拙。