Laravel 5.6 - 使用默认控制器进行路径模型绑定

时间:2018-04-05 21:48:44

标签: php laravel binding controller routes

我正在使用Laravel构建购物应用程序,其中每个产品的URL必须保持简洁。

而不是使用以下永久链接结构:(这是常见但不利的)

www.example.com/products/{product-slug}

我想使用这个永久链接结构:

www.example.com/{product-slug}

为了实现这一点,我在路由文件中使用隐式路由模型绑定:

Route::get( '{product}', function ( App\Product $product ) {

   return view( 'product' ); // this works, but is not what I want

});

我正在覆盖Product模型中的查找行为:

class Product extends Model
{

   public function getRouteKeyName()
   {
      return 'slug'; // use the 'product.slug' column for look ups within the database
   }

}

现在,根据Laravel的文件:

  

Laravel自动解析路径或控制器操作中定义的Eloquent模型,其类型提示的变量名称与路径段名称匹配。   (View Source)

所以我知道Laravel会将{product}变量与我数据库中存储的产品相匹配,如果找不到,则返回404响应。

这对我来说都很有意义......

...然而

每个产品页面都是唯一的,因此在路径与{product}匹配后,需要将{product}对象传递给控制器​​以进行进一步处理。

那么如果我想保持隐式模型绑定,如何将此路由传递给控制器​​?

2 个答案:

答案 0 :(得分:3)

将路线指向控制器功能。

这将是您的路线(我将控制器命名为ProductController并将其指向show功能,但您可以根据自己的喜好重命名两者:

Route::get( '{product}', 'ProductController@show');

这将在你的ProductController中:

public function show(Request $request, \App\Product $product)
{
    // Do stuff with $product

    // Return view and pass it the $product variable
    return view('product', compact('product'));
}

答案 1 :(得分:0)

要回答我自己的问题,我想我找到了一个很好的解决方案,结合了我的初步方法和devk's响应:

Arjun's Blog的想法。

事实证明,您还可以通过将Eloquent模型作为依赖项传递来在控制器中执行隐式模型绑定:

/* App/Http/Controllers/ProductController.php */

/**
* Get the Product object.
*
* @param App\Models\Product
*/
public function show( Product $product )
{
   return view( 'product', compact( 'product' ) );
}

即使我们现在使用控制器引用模型,Laravel仍会自动解析模型。实际上,在文档中明确定义了这种行为:

  

Laravel自动解析路线或中定义的Eloquent模型   控制器操作,其类型提示的变量名称与路径匹配   段名称。   (View Source)

第一次读这篇文章时,我一定错过了这些词......

现在,为了设置{product-slug}路线(按照我想要的方式),您必须设置模型和路线定义,如下所示:

/* App/Models/Product.php */

class Product extends Model
{
   /**
    * Get the route key for the model.
    *
    * @return string
    */
   public function getRouteKeyName()
   {
      return 'slug';
   }
}

如前所述,覆盖getRouteKeyName()方法将使Laravel使用数据库中的slug列而不是id列(默认值)来搜索产品。< / p>

/* routes/web.php */

Route::get( '{product}', 'ProductController@show' );

在我们的路线文件中,我们仍然将参数命名为{product}(而不是{product-slug}),因为参数的名称必须与Eloquent模型的名称相匹配。

使用此配置,请求:

www.example.com/{product-slug}

如果提供的{product-slug}与数据库中存储的/匹配,

将返回产品页面。如果找不到产品,则会返回404 Not Found响应。

但是,因为我们将此路由绑定到基本路径{{1}},这意味着客户端请求的每个URL都将通过此配置传递。

要避免此问题,请确保路由定义在路由文件中的顺序正确(从最高优先级到最低优先级),并在发生冲突时使用验证。