按 slug 而不是按 id 搜索 object

Search object by slug and not by id

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

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

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

为简单起见,控制器简单地添加了文章

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

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

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

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

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

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

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

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

php artisan route:clear

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

虽然还是不走运……不确定我是否误解了某些东西的工作原理或正在发生的事情……所以如果有人对我可能做错了什么有任何建议,或者有什么可以尝试的,我将不胜感激! :)

如果你有这样的两条路线

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

它将始终使用第一个。很明显,没有id'secondarticle',所以它returnsnull(虽然在本例中无所谓,它们都指向同一个方法)。

原因是路由会搜索可能的路由,直到找到匹配项,该匹配项始终是带有 {id} 的匹配项。为什么?您没有告诉 Route {id} 必须匹配一个整数!

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

/wiseweasel/{id}/{slug?}

另一个建议。不要对模型使用 xx_articles 等名称,而应使用 Article。这样就可以使用新的implicit route binding了。所以使用隐式路由绑定你的 url 看起来像这样(假设你的模型被称为文章)

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

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

当您使用时:

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

你告诉 Laravel - 通过 ID 查找 www_articles 的记录。 (不管你叫这个id $slug)。

为了达到你想要的改变:

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

进入

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

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

您还可以选择使用路由模型绑定来解决这个问题,并将已解析的实例注入到您的方法中。

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

// 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

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

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

这会起作用,因为来自模型 class 的 find method internally uses the getQualifiedKeyName 方法使用 $primaryKey 属性.