【问题标题】:Laravel 5.6 - Route Model Binding with a Default ControllerLaravel 5.6 - 使用默认控制器绑定路由模型
【发布时间】:2018-09-15 20:21:59
【问题描述】:

我正在使用 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} 对象传递给控制器​​进行进一步处理。

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

【问题讨论】:

    标签: php laravel binding controller routes


    【解决方案1】:

    为了回答我自己的问题,我想我找到了一个很好的解决方案,它结合了我最初的方法和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 列(这是默认值)来搜索产品。

    /* routes/web.php */
    
    Route::get( '{product}', 'ProductController@show' );
    

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


    使用此配置,请求:

    www.example.com/{product-slug}

    如果提供的{product-slug} 与存储在数据库中的匹配,将返回一个产品页面。如果未找到产品,则会返回 404 Not Found 响应。

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

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

    【讨论】:

    • 接受别人的答案、复制它并将其标记为答案通常被认为是一种不礼貌的行为(这样你就可以通过回答问题而不是他来获得代表提升)
    • 对控制器中类型提示变量名称需要匹配命名路由参数的事实的引用是我缺少的位。我很高兴这个答案在这里。
    【解决方案2】:

    将路由指向控制器功能。

    这将是您的路线(我将控制器命名为 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'));
    }
    

    【讨论】:

    • 应用内的其他页面页面呢? www.example.com/login 页面也会被意外匹配并传递给此控制器。我该如何避免这个缺点?
    • 一般来说,我建议在你的路由中添加一个前缀,如products/{product}。但如果您将login 路由放在{product} 路由之前(上方),它也会起作用。
    猜你喜欢
    • 2018-12-17
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 2019-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    相关资源
    最近更新 更多