以单路径参数或其他方式斜杠以处理具有动态参数数量的菜单尾


8

根据Symfony文档,以下定义的路由应为/hello/bob和触发指定的控制器/hello/bob/bobby

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::Controller }
  requirements:
    _access: 'TRUE'
    names: .+

在一个请求的情况下/hello/bob/bobby{names}PARAM将是“鲍勃/巴比”(斜杠完整),这将是到控制器打破这种分解成多个变量或离开它作为一个单一的字符串。诀窍在于更改后的正则表达式(“。+”)用于过滤该{names}参数。

stackoverflow帖子还暗示可以使用自定义正则表达式来允许在路由参数中使用斜线(至少在Symfony 2中)。

如果我针对Drupal 8.0.0-beta15尝试此操作,它将无法正常工作,并且仅针对的请求触发指定的控制器/hello/bob。但是,我可以确认它曾经在以前的beta中起作用(我认为直到〜beta13为止)。

Drupal与Symfony路由组件集成的方式有什么改变可以解释这一点?也许还有另一种方法可以在路由参数中完成斜线的传递?我知道内核正在向Symfony 3.0迈进,但是我不确定这是否可以解释问题。

我也知道,路由订阅者可用于管理动态路由结构。但是,我正在处理的情况在基本路径的末尾需要几乎无限的组合/数量的动态参数(但是在我的控制器中解析起来很简单)。在/hello?names[]=bob&names[]=bobby这种情况下,我还尝试避免使用查询字符串(例如)。

主要是我对与Symfony文档的断开连接感到困惑,这似乎表明这应该可行。


补充笔记

张贴这个问题后,我发现在D8核心队列讨论:[讨论]删除自动传递额外的参数的:Y / N。似乎可以得出结论,“菜单尾”支持(本质上就是我所追求的)将在D8中被正式删除。讨论在3年前结束,因此我只能猜测,直到最近(〜beta13)才完全实现一些更通用的实现细节。这也许可以解释为什么我现在才注意到这一变化。

我猜想任何特定于Symfony的路由逻辑进一步剖析路由(以及特定于参数的正则表达式等)之前,Drupal(不是Symfony)现在正在基于原始斜杠分隔的请求生成404响应。如果是这种情况,则可以解释为什么上述技术停止工作。但是,我仍然想知道是否还有其他方法可以避免使用查询参数和自定义路由订阅者来满足这种需求。


根据我对Symfony的了解,我希望/ hello / {用户名}在/ hello / bob上匹配,但在/ hello / bob / smith上不匹配。如果需要其他参数,则必须像在stackoverflow.com/questions/11980175/…中那样为它们设置默认值。但也许我不明白这个问题。
cilefen

配置默认值可以按预期工作(即,可以将{names}设置为可选参数)。所以是的,我想我可以有一个像/hello/{arg1}/{arg2}/{arg3}/.../{argN}这样的路由路径,它可以使用0-N参数。但是,这对参数的数量设置了静态限制,并且感觉非常混乱。我的理解是应该可以通过在单个参数中使用斜杠分隔符来进行不同的操作,这是基于Symfony文档(symfony.com/doc/master/cookbook/routing/slash_in_parameter.html)以及以前使用较旧的Drupal的经验核心测试版。
rjacobs

1
目前还不清楚是什么path: /hello/{names},并username: .+有相互做。

@chx,对不起,我在发布问题后立即编辑了我的问题,以使其更加通用。在此过程中,我忘了更新yml代码段。我已经解决了。它应显示为“名称:。+”
rjacobs

我只是注意到我的最后一句话可能给人以我解决问题的印象。请注意,我的帖子中只有一个错字。问题/问题仍然如现在所说的那样。
rjacobs 2015/09/28

Answers:


9

您可以通过添加实现InboundPathProcessorInterface的类来更改路径

namespace Drupal\mymodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class HelloPathProcessor implements InboundPathProcessorInterface {

  public function processInbound($path, Request $request) {
    if (strpos($path, '/hello/') === 0) {
      $names = preg_replace('|^\/hello\/|', '', $path);
      $names = str_replace('/',':', $names);
      return "/hello/$names";
    }
    return $path;
  }

}

这样,路由器会将路径解释/hello/bob/bobby为,/hello/bob:bobby并且您将:在控制器中将参数分隔为(或与参数不冲突的任何其他字符)。

您还需要在mymodule.services.yml中将类注册为服务(确保优先级设置为高于200)

services:
  mymodule.path_processor:
    class: Drupal\mymodule\PathProcessor\HelloPathProcessor
    tags:
      - { name: path_processor_inbound, priority: 250 }

是的,这很好,我想这与用于路径别名的机制相同吗?如果走这条路线,我假设路由器路径将保持不变(/ hello / {names}),那么“名称”仍可以作为单个路线参数来处理。因此,如果以编程方式生成使用此路由的URL,仍然必须使用自定义分隔符(bob:bobby)来构造名称,但是系统仍将与更“友好”的URL输入(bob / bobby)兼容吗?
rjacobs

1

您可以执行以下操作来检索路径参数:在这种情况下,我想将/ rest /之后的所有内容检索为字符串数组。

您的yourmodule.routing.yml文件应如下所示。

yourmodule.rest:
  path: /rest/{path_parms}
  defaults:
    _controller: 'Drupal\yourmodule\Controller\YourController::response'
    _title: 'Rest API Title'
  requirements:
    path_params: '^[^\?]*$'
    _permission: 'access content'

或在path \ to \ yourmodule \ src \ Routing \ RouteProvider.php中

/**
 * @file
 * Contains \Drupal\yourmodule\Routing\RouteProvider.
 */

namespace Drupal\yourmodule\Routing;

use Symfony\Component\Routing\Route;

/**
 * Defines dynamic routes.
 */
class RouteProvider
{
    /**
     * Returns all your module routes.
     *
     * @return RouteCollection
     */
    public function routes()
    {
        $routes = [];

        // This route leads to the JS REST controller
        $routes['yourmodule.rest'] = new Route(
            '/rest/{path_params}',
            [
              '_controller' => '\Drupal\yourmodule\Controller\YourController::response',
              '_title' => 'REST API Title',
            ],
            [
              'path_params' => '^[^\?]*$',
              '_permission' => 'access content',
            ]
        );

        \Drupal::service('router.builder')->setRebuildNeeded();

        return $routes;
    }
}

接下来,如下所示将Path处理器添加到模块中。路径\到\您的模块\ src \ PathProcessor \ YourModulePathProcessor.php

namespace Drupal\yourmodule\PathProcessor;

use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class YourModulePathProcessor implements InboundPathProcessorInterface {

    public function processInbound($path, Request $request) {
        // If a path begins with `/rest`
        if (strpos($path, '/rest/') === 0) {
            // Transform the rest of the path after `/rest`
            $names = preg_replace('|^\/rest\/|', '', $path);
            $names = str_replace('/',':', $names);

            return "/rest/$names";
        }

        return $path;
    }
}

最后,在您的控制器中,执行以下操作:path \ to \ yourmodule \ src \ Controller \ YourController.php

namespace Drupal\yourmodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller routines for test_api routes.
 */
class YourController extends ControllerBase {

    /**
     * Callback for `rest/{path_params}` API method.
     */
    public function response(Request $request) {
        $params = explode(':', $request->attributes->get('path_params'));

        // The rest of your logic goes here ...
    }

}

它不适用于drupal 8.7.9
Ekta Puri

真?您是否找到了替代品?
GuruKay

尚未,如果您有任何解决方案,请分享
Ekta Puri

抱歉,我花了很长时间,我更新了我的帖子,以显示我最终为获得路径参数所做的事情。就我自己而言,我的自定义REST API需要它。
GuruKay

0

替代解决方案:

创建一个接收json数组的route参数。


mymodule.routing.yml

_hello:
  path:     /hello/{names}
  defaults: { _controller: \Drupal\mymodule\Controller\Main::index }
  requirements:
    _access: 'TRUE'

\ Drupal \ mymodule \ Controller \ Main

public function index($names_json) {
  $names = Json::decode($names_json);
  // Do something with $names
}

是的,将多个参数编码为一个路由参数无疑是一种选择。我假设您是在暗示“名称”参数是直接编码/序列化的正式php数组?如果是这样,是否会为JSON的路径组件提供更多合适的编码选项?请注意,与编码技术无关,这也将使用户友好的路径变得少得多(人工输入的潜在问题,但不一定是程序化路径生成的问题)。
rjacobs

当然,您可以使用所需的任何编码技术。我更喜欢JSON,因为它在大多数语言中都非常标准地带有编码器(/ decoder)。这会使路径变得不那么用户友好。如果路径暴露在外面,那么我认为在查询中传递名称(name [] = Ben&name [] = George)更具可读性。
2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.