簡體   English   中英

ZF3:如何根據方法和路由路由到特定的控制器/動作?

[英]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',
            ],
        ],
    ],
    //...
];

我正在努力實現的目標:

  • 如果路由/index/foo被請求並且被GET方法請求,那么它應該被路由到IndexController fooAction
  • 如果路由/index/foo被請求並且是通過POST方法請求的,那么它應該被路由到IndexController bar Action (注意這里是 barAction 而不是 fooAction)

如何做到這一點?

嘗試將文字更改為Zend\\Mvc\\Router\\Http\\Part路由,然后將HTTP路由作為CHILD路由放入!

參見此處https://docs.zendframework.com/zend-router/routing/#http-route-types

給自己和其他任何人的筆記,作為@ delboy1978uk答案的補充筆記。

我一直在尋找的答案是這樣的:

  • GET /index/foo => IndexController 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'
                    ],
                ],
            ]
        ],
    ],
    //...
];

我知道這是一個古老的話題,但我想分享我的答案給任何遇到這個問題並且正在與 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM