【问题标题】:Laravel Route: Multiple Route Group With Prefix and Route Model BindingLaravel Route:具有前缀和路由模型绑定的多个路由组
【发布时间】:2021-01-05 00:44:04
【问题描述】:

你好SO的好人!

我有一个关于 Laravel Route 的问题,我无法解决。

在 User.php 模型中我使用 getRouteKeyName() 函数

public function getRouteKeyName()
{
    return 'user_name';
}

还有在 Post.php 模型中

public function getRouteKeyName()
{
    return 'uuid';
}

在users表中,1条记录

|----------------------------|
| id | ... | user_name | ... |
| 1  |-----|  @simple  |-----|

在帖子表中

|------------------------------------|
| id | ... | uuid              | ... |
| 1  |-----| abcd-123-efg-456  |-----|

在路由中(web.php)

// for post (key: uuid)
Route::group(['prefix' => '{post}'], function () {
    Route::get('/', function (Post $post) {
        return $post;
    });
});

// for users (key: user_name)
Route::group(['prefix' => '{user}'], function () {
    Route::get('/', function (User $user) {
        return $user;
    });
});

假设我们访问 url:www.example.test/@simple/

在调试栏中,我看到查询:

select * from posts where uuid = '@simple' 限制 1

我的尝试

[#1] 我将 where 子句放在帖子和用户的路由组中

Route::group([
    'prefix' => '{post}',
    'where' => [
        'post' => '^[a-zA-Z0-9-]{36}$' // I'm not Regex professional
    ]
], function () {
    Route::get('/', function (Post $post) {
        return $post;
    });
});

Route::group([
    'prefix' => '{user}',
    'where' => [
        'user' => '^(@)[a-zA-Z0-9]$' // I'm not Regex professional
    ]
], function () {
    Route::get('/', function (User $user) {
        return $user;
    });
});

所以让我们再次访问该网址:www.example.test/@simple

我得到了什么,404

[#2] 我删除了 User 和 post 模型中的 getRouteKeyname

重新访问网址:www.example.test/@simple,仍然得到 404

[#3]我试着把路由模型绑定列名

Route::group([
    'prefix' => '{post:uuid}', // This is what I changed
], function () {
    Route::get('/', function (Post $post) {
        return $post;
    });
});

Route::group([
    'prefix' => '{user:user_name}', // This is what I changed
], function () {
    Route::get('/', function (User $user) {
        return $user;
    });
});

不过,查询结果还是一样的:> select * from posts where uuid = '@simple' limit 1

我想要达到的目标

假设我们访问 url:www.example.test/@simple

获取user_name@simple 的用户,如果用户不存在,则返回404

帖子也一样

我们访问网址:www.example.test/abcd-1234-efgh-5678

获取uuidabcd-1234-efgh-5678 的帖子,如果不存在则为 404

问题:

[#1] 如何告诉 Laravel Route:我有 2 个具有不同模型绑定的 Route 组?对不起,如果这个问题有点令人困惑,因为我的英语不是很好

[#2] 我是否在 Laravel 中实现了路由组和路由模型绑定的最佳实践?

提前致谢!

【问题讨论】:

    标签: laravel laravel-routing


    【解决方案1】:

    你打算得到什么结果? 如果您正在做我认为您正在做的事情(试图查看帖子中的内容),您需要返回类似 $post->content 的内容(将内容替换为您想要获取的列),您甚至可能想要一个视图并使输出更好,加上使用控制器进行更多处理。

    路由模型绑定可以参考this,table:column和getRouteKeyName这两种方法都可以,但是第一个不会改变默认列,如果使用{user}对于另一个路由,它仍然会使用 ID 列,但是,第二个会更改默认值,如果您将 {user} 用于另一个路由,它将使用您指定的列。

    此外,您应该使用 user/{user:user_name}post/{post:uuid} 之类的东西,而不仅仅是 {user:username}{post:uuid},正如您所说,它不会知道您使用的是哪条路线。 uri 必须不同。

    路由按照您放置它们的顺序进行评估,这意味着带有{post:uuid} 的第二条路由将覆盖带有{user:username} 的路由,因为它们具有相同类型的uri,也就是说,它们都包含1 个通配符并且什么都没有别的。要解决这个问题,您只需通过添加静态部分来使它们的 uri 不同,例如,在 {post:uuid} 之前添加 post/ 和/或在 {user:user_name} 之前添加 user/,如下例所示:

    Route::group([
        'prefix' => 'post/{post:uuid}',
    ], function () {
        Route::get('/', function (Post $post) {
            return $post;
        });
    });
    
    Route::group([
        'prefix' => 'user/{user:user_name}',
    ], function () {
        Route::get('/', function (User $user) {
            return $user;
        });
    });
    

    为了清楚起见,您的 2 个路由具有相同的 uri 1 个通配符,没有其他任何内容,因此,与此 uri 一起出现的最后一个将覆盖具有相同 uri 的所有先前路由。这意味着在此之前具有相同 uri 的所有先前路由将被视为不存在,并且当您转到具有 /[insert something here] 格式的 uri 的路径时,它适合具有 1 个通配符的格式,并且只会转到您指定的最后一个,即用于帖子的那个。

    由于用户的路由是在帖子路由之前声明的,并且他们共享相同的 uri,因此只会使用帖子路由。即使您尝试查找用户,它仍然使用发布的路由,如果不存在与您提供的用户名相同的 uuid 的“帖子”,即使确实存在这样的用户,它仍然会返回错误用户名。

    此外,如果只有 1 条路线,则不需要路线组,但如果将来要向组中添加更多路线,它会更具可读性和方便性。

    【讨论】:

    • 您好,我使用 2 个路由组,一个用于发布,另一个是用户所以每当我访问这样的 URL 时:.../@user_name,它会获取一个用户而且,当我像这样访问 URl :.../abcd-1234-efgh-5678,它获取了一个我知道我可以使用控制器的帖子,它只是简化了我想要告诉的内容,实际代码使用控制器
    • 对不起,我不太明白现在什么不起作用 Idk 如果您正在简化路线的路径或什么,但是 {user:user_name} 之前的部分和 { 之前的部分post:uuid} 不能相同。
    • Route::group([ 'prefix' => 'post/{post:uuid}', ], function () { Route::get('/', function (Post $post) { return $post; }); }); Route::group([ 'prefix' => 'user/{user:user_name}', ], function () { Route::get('/', function (User $user) { return $user; }); }); 这样的事情就可以了。模式必须不同,否则它不会知道您使用的是哪条路线
    【解决方案2】:

    据我了解您的问题,以下是您需要进行的更改,它会起作用, 路线/web.php

    Route::group([
        'prefix' => 'post/{post:uuid}'
    ], function () {
        Route::get('/', function (Post $post) {
            return $post;
        });
    });
    
    Route::group([
        'prefix' => 'user/{user:user_name}'
    ], function () {
        Route::get('/', function (User $user) {
            return $user;
        });
    });
    

    您在上面使用的正则表达式只是过滤 {argument} 并检查 {argument} 是否基本上是字母数字,在上述两种情况下它的工作方式相同,除了在 user_name 中它还允许'-'

    【讨论】:

      猜你喜欢
      • 2017-09-11
      • 2015-07-12
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 2017-10-07
      • 2021-05-24
      • 1970-01-01
      • 2016-06-04
      相关资源
      最近更新 更多