代码之家  ›  专栏  ›  技术社区  ›  CodyEakins

Laravel 5.6-路由模型与默认控制器绑定

  •  1
  • CodyEakins  · 技术社区  · 7 年前

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

    而不是使用以下permalink结构:(这是常见的,但不太合适)

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

    我想使用此permalink结构:

    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自动解析路由或控制器操作中定义的雄辩模型,这些操作的类型提示变量名称与路由段名称匹配。 (View Source)

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

    这一切对我来说都很有意义。。。


    然而

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

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

    2 回复  |  直到 7 年前
        1
  •  3
  •   DevK    7 年前

    指向控制器功能的路径。

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

    为了回答我自己的问题,我想我已经找到了一个很好的解决方案,它将我最初的方法和 devk's 答复:

    贷项至 Arjun's Blog 为了这个想法。

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

    /* 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自动解析routes中定义的雄辩模型 或 控制器操作 其类型提示的变量名称与路由匹配 段名称。 (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' );
    

    在routes文件中,我们仍然将参数命名为 {product} (而不是 {产品段塞} )因为参数的名称必须与雄辩模型的名称匹配。


    使用此配置,在以下位置发出请求:

    www.example.com/{product-slug}

    如果提供了 {产品段塞} 匹配存储在数据库中的一个。如果未找到产品,将返回404 not found响应。

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

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