首页 > 解决方案 > Laravel,简单而正确的关系方式

问题描述

我想用这个逻辑列出相关品牌的相关类别。

产品表

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('slug');
        $table->integer('brand_id')->unsigned();
        $table->foreign('brand_id')->references('id')->on('brands')->onDelete('cascade');
        $table->integer('category_id')->unsigned();
        $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
        $table->timestamps();
    });
}

网页.php

Route::get('{Brand}/{Category}/{Product}', 'ProductsController@show');
Route::get('{Brand}/{Category}', 'ProductsController@index');

例如,第一条路线;Samsung/phones 应列出所有带有以下代码部分的三星手机。还有其他方法可以使这些代码变得简单吗?并且此查询返回 null。我检查了查询是否获得了正确的列,但返回 null。

use App\Product;
use App\Brand;
use App\Category;

class ProductsController extends Controller
{
    public function index(Request $request)
    {   
        $category = $request->Category;
        $cat_id = Category::select('id')
                    ->where('slug',$category)
                    ->get();

        $brand = $request->Brand;
        $br_id = Brand::select('id')
                ->where('slug', $brand)
                ->get();

        $products = Product::select('id','name','slug')
                ->where('category_id', $cat_id)
                ->where('brand_id', $br_id)
                ->get();

        return view('products.index', compact('products'));
    }
}

产品.php

class Product extends Model
    {
        public function brands()
        {
            return $this->belongsTo('App\Brand');
        }

        public function categories()
        {
            return $this->belongsTo('App\Category');
        }
    }

分类.php

class Category extends Model
{

    public function brands()
    {
        return $this->belongsToMany('App\Brand');
    }

    public function products()
    {
        return $this->hasMany('App\Product');
    }
}

标签: laraveleloquent

解决方案


首先阅读有关 laravel 关系的文档: https ://laravel.com/docs/5.7/eloquent-relationships

您当前代码不起作用的原因是因为在您的路线中您要求提供参数:

Route::get('{Brand}/{Category}', 'ProductsController@index');

但是在 ProductsController 上的 index() 方法中,您没有包含这些参数。

 public function index(Request $request, Brand $brand, Category $category)

您的代码中的第二个问题是您根本没有使用您的关系。您当前的控制器只是进行了一个新的雄辩的查询。

使用您在类别模型中定义的方法获取给定类别的所有产品的示例:

public function index(Request $request, Brand $brand, Category $category)
{   

    $products = $category->products;

    return view('products.index', compact('products'));
}

使用给定品牌扩展此功能的示例:

public function index(Request $request, Brand $brand, Category $category)
{   

    $products = $category->products()->where('brand_id', $brand->id)->get();

    return view('products.index', compact('products'));
}

更新

如评论中所述,URL 参数是 slugs 而不是 ids,因此自动路由模型绑定将不起作用。带有蛞蝓的更新解决方案:

public function index(Request $request, $brand, $category)
{
    $categoryModel = Category::where('slug', $category)->firstOrFail();
    $brandModel = Brand::where('slug', $brand)->firstOrFail();   

    $products = $categoryModel->products()->where('brand_id', $brandModel->id)->get();

    return view('products.index', compact('products'));
}

进一步改进您的代码将是添加一个范围或辅助方法,以便您可以执行类似的操作Brand::FindBySlug($slug);


推荐阅读