laravel 通过 slug 而不是 id 搜索对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34484965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 12:54:19  来源:igfitidea点击:

Search object by slug and not by id

laravellaravel-5eloquentlaravel-routinglaravel-5.2

提问by Roxy Walsh

I'm a relative beginner with Laravel (using version 5.2.3) and have been working through tutorials on Laracasts and then doing a bit of my own experimenting.

我是 Laravel 的相对初学者(使用 5.2.3 版)并且一直在学习有关 Laracasts 的教程,然后做了一些我自己的实验。

I successfully set up a route that fetches an item from a table by its ID, as shown below

我成功设置了一个路由,通过它的 ID 从表中获取一个项目,如下所示

Route::get('/wiseweasel/{id}', 'WiseweaselController@singleArticle');

For simplicity, the controller simply dd's the article

为简单起见,控制器只是 dd 的文章

public function singleArticle($id)
{
  $article = ww_articles::find($id);
  dd($article);
}

This works absolutely fine - I visit eg /wiseweasel/2 and get the contents of the record with id2.

这绝对有效 - 我访问例如 /wiseweasel/2 并使用 id2 获取记录的内容。

So, I then wanted to use the slug field from the record instead of the id. Since I know the ID method was working, I've tried just modifying this route and controller (also tried creating anew, neither worked) So I now have:

因此,我想使用记录中的 slug 字段而不是 id。由于我知道 ID 方法正在工作,因此我尝试修改此路由和控制器(也尝试重新创建,但均无效)所以我现在有:

Route::get('/wiseweasel/{slug}', 'WiseweaselController@singleArticle');

and

public function singleArticle($slug)
{
  $article = ww_articles::find($slug);
  dd($article);
}

The slug for the second record is "secondarticle". So, visiting the url /wiseweasel/secondarticle, I would expect to see the same record as previously dd'd out. Instead, I end up with null.

第二个记录的 slug 是“secondarticle”。因此,访问 url /wiseweasel/secondarticle,我希望看到与之前 dd 相同的记录。相反,我最终得到了 null。

Even more oddly, using the original id route (/wiseweasel/2) still returns the record... when I have removed all trace of this from the routes and controller, so I would expect this to fail...

更奇怪的是,使用原始 id 路由 (/wiseweasel/2) 仍然返回记录......当我从路由和控制器中删除所有这些跟踪时,所以我希望这会失败......

This is making me wonder if this could be some odd caching issue? I've tried

这让我想知道这是否可能是一些奇怪的缓存问题?我试过了

php artisan route:clear

php工匠路线:清除

in case the route was being cached. I've also tried restarting both Apache and MySql (I'm using XAMMP for both).

以防路由被缓存。我还尝试重新启动 Apache 和 MySql(我都使用 XAMMP)。

Still no luck though... not sure if I've misunderstood how something works or what's going on... so if anyone has any suggestions as to what I might have done wrong, or anything to try, I would be very grateful! :)

仍然没有运气......不确定我是否误解了某些东西是如何工作的或发生了什么......所以如果有人对我可能做错了什么或尝试任何事情有任何建议,我将非常感激!:)

采纳答案by Marcin Nabia?ek

Laravel won't automatically know that for slugit should search record in different way.

Laravel 不会自动知道slug它应该以不同的方式搜索记录。

When you are using:

当您使用:

$article = ww_articles::find($slug);

you are telling Laravel - find record of www_articlesby ID. (no matter you call this id $slug).

你是在告诉 Laravel -www_articles按 ID查找记录。(不管你叫这个id $slug)。

To achieve what you want change:

要实现您想要的更改:

$article = ww_articles::find($slug);

into

进入

$article = ww_articles::where('slug', $slug)->first();

This will do the trick (for slugput the name of column in table in database). Of course remember that in this case slug should be unique in all records or you won't be able to get all the slugs.

这将起作用(用于slug将列名放在数据库中的表中)。当然请记住,在这种情况下,slug 在所有记录中应该是唯一的,否则您将无法获得所有 slug。

回答by lagbox

You also have the option of using Route Model Binding to take care of this and inject the resolved instance into your methods.

您还可以选择使用路由模型绑定来处理此问题并将解析的实例注入到您的方法中。

With the new implicit Route Model Binding you can tell the model what key it should use for route binding.

使用新的隐式路由模型绑定,您可以告诉模型应该使用什么键进行路由绑定。

// routes
Route::get('/wiseweasel/{article}', 'WiseweaselController@singleArticle');


// Article model
public function getRouteKeyName()
{
    return 'slug';
}

// controller
public function singleArticle(Article $article)
{
    dd($article);
}

Laravel Docs - Route Model Binding

Laravel 文档 - 路由模型绑定

回答by Sergio Guillen Mantilla

Maybe it's a bit late for the answer but there is another way to keep using find method and use slugas your table identifier. You have to set the protected $primaryKeyproperty to 'slug'in your model.

也许答案有点晚了,但还有另一种方法可以继续使用 find 方法并使用slug作为您的表标识符。您必须在模型中将受保护的$primaryKey属性设置为“slug”

class ww_articles extends Model
{
    protected $primaryKey = 'slug';
    ...
}

This will work because findmethod internally uses the getQualifiedKeyNamemethod from Model class which uses the $primaryKey property.

这将起作用,因为find方法在内部使用来自 Model 类的getQualifiedKeyName方法,该方法使用 $primaryKey 属性。

回答by Abbas Arif

Better use SCOPE, easy and convenient.

更好的使用SCOPE,简单方便。

public function scopeSlug($query, $slug)
{
    return $query->where("slug", $slug);
}

Now we can use it like this:

现在我们可以这样使用它:

$article = ww_articles::slug($slug)->first();

Applying Global Scopes

应用全局范围

回答by Bojan Kogoj

If you have both routes like this

如果你有这样的两条路线

Route::get('/wiseweasel/{id}', 'WiseweaselController@singleArticle');
Route::get('/wiseweasel/{slug}', 'WiseweaselController@singleArticle');

it will always use the first one. Obviously, there is no id 'secondarticle', so it returns null (although in this case it doesn't matter, they both point to the same method).

它将始终使用第一个。显然,没有 id 'secondarticle',因此它返回 null(尽管在这种情况下无关紧要,它们都指向相同的方法)。

The reason is route will search through possible routes till it finds a matching, which is always the one with {id}. Why? You're not telling Route that {id} must match an integer!

原因是 route 将搜索可能的路线,直到找到匹配的,它总是带有 {id} 的那个。为什么?你不是告诉 Route {id} 必须匹配一个整数!

You can make sure {id} is understood as an integer, however I suggest using urls like this is a better option

你可以确保 {id} 被理解为一个整数,但是我建议使用这样的 url 是一个更好的选择

/wiseweasel/{id}/{slug?}

Another suggestion. Do not use names such as xx_articles for a model, but Article instead. This way you can use the new implicit route binding. So using implicit route binding your url would look like this (assuming your model is called Article)

另一个建议。不要为模型使用诸如 xx_articles 之类的名称,而是使用文章。这样您就可以使用新的隐式路由绑定。因此,使用隐式路由绑定您的 url 将如下所示(假设您的模型称为文章)

Route::get('/wiseweasel/{article}', 'WiseweaselController@singleArticle');