简体   繁体   English

路由中间的可选参数

[英]Optional parameter in the middle of a route

Is there any way to add an optional parameter in the middle of a route ?有没有办法在路由中间添加一个可选参数?

Example routes:示例路线:

/things/entities/
/things/1/entities/

I tried this, but it does not work:我试过这个,但它不起作用:

get('things/{id?}/entities', 'MyController@doSomething');

I know I can do this...我知道我可以做到这一点...

get('things/entities', 'MyController@doSomething');
get('things/{id}/entities', 'MyController@doSomething');

... but my question is: Can I add an optional parameter in the middle of a route? ...但我的问题是:我可以在路由中间添加一个可选参数吗?

No. Optional parameters need to go to the end of the route, otherwise Router wouldn't know how to match URLs to routes.不可以。可选参数需要放在路由的末尾,否则 Router 不知道如何将 URL 与路由匹配。 What you implemented already is the correct way of doing that:您已经实施的是正确的做法:

get('things/entities', 'MyController@doSomething');
get('things/{id}/entities', 'MyController@doSomething');

You could try doing it with one route:你可以尝试用一条路线来做:

get('things/{id}/entities', 'MyController@doSomething');

and pass * or 0 if you want to fetch entities for all things, but I'd call it a hack.并传递* 或 0如果你想为所有东西获取实体,但我称之为黑客。

There are some other hacks that could allow you to use one route for that, but it will increase the complexity of your code and it's really not worth it.还有一些其他的 hack 可以让您为此使用一种路线,但这会增加您的代码的复杂性,这真的不值得。

The "correct" answer for this question is;这个问题的“正确”答案是; No, you can't and shouldn't use an optional parameter unless it's at the end of the route/url.不,您不能也不应该使用可选参数,除非它位于路由/url 的末尾。

But, if you absolutely need to have an optional parameter in the middle of a route, there is a way to achieve that.但是,如果您绝对需要在路由中间有一个可选参数,那么有一种方法可以实现这一点。 It's not a solution I would recommend, but here you go:这不是我推荐的解决方案,但您可以这样做:

routes/web.php : routes/web.php

// Notice the missing slash
Route::get('/test/{id?}entities', 'Pages\TestController@first')
    ->where('id', '([0-9/]+)?')
    ->name('first');

Route::get('/test/entities', 'Pages\TestController@second')
    ->name('second');

app/Http/Controllers/Pages/TestController.php : app/Http/Controllers/Pages/TestController.php

<?php

namespace App\Http\Controllers\Pages;

use App\Http\Controllers\Controller;

class TestController extends Controller
{
    public function first($id = null)
    {
        // If $id is not null, it will have a trailing slash
        $id = rtrim($id, '/');

        return 'First route with: ' . $id;
    }

    public function second()
    {
        return 'Second route';
    }
}

resources/views/test.blade.php : resources/views/test.blade.php

<!-- Notice the trailing slash on id -->
<!-- Will output http://myapp.test/test/123/entities -->
<a href="{{ route('first', ['id' => '123/']) }}">
    First route
</a>

<!-- Will output http://myapp.test/test/entities -->
<a href="{{ route('second') }}">
    Second route
</a>

Both links will trigger the first -method in TestController .两个链接都将触发TestControllerfirst方法。 The second -method will never be triggered. second方法永远不会被触发。

This solution works in Laravel 6.3, not sure about other versions.此解决方案适用于 Laravel 6.3,不确定其他版本。 And once again, this solution is not good practice.再一次,这个解决方案不是好的做法。

Having the optional parameter in the middle of the route definition like that, will only work when the parameter is present.像这样在路由定义的中间有可选参数,只有当参数存在时才会起作用。 Consider the following:考虑以下:

  • when accessing the path things/1/entities , the id parameter will correctly get the value of 1 .当访问路径things/1/entitiesid参数将正确获得1的值。
  • when accessing the path things/entities , because Laravel uses regular expressions that match from left to right, the entities part of the path will be considered to be the value of the id parameter (so in this case $id = 'entitites'; ).当访问路径things/entities ,因为 Laravel 使用从左到右匹配的正则表达式,路径的entities部分将被认为是id参数的值(所以在这种情况下$id = 'entitites'; ) . This means that the router will not actually be able to match the full route, because the id was matched and it now expects to have a trailing /entities string as well (so the route that would match would need to be things/entities/entities , which is of course not what we're after).这意味着路由器实际上无法匹配完整的路由,因为id已匹配,现在它也希望有一个尾随/entities字符串(因此匹配的路由需要是things/entities/entities ,这当然不是我们所追求的)。

So you'll have to go with the separate route definition approach.因此,您必须采用单独的路由定义方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM