Laravel - 如何使用Eloquent在FK上设置orderBy?

时间:2016-05-25 18:07:35

标签: eloquent laravel-5.2

我有产品型号,我有分类型号。我还有一个名为category_product的数据透视表。我想在我的CategoryController上设置orderBy

Product.php

public function category()
{
    return $this->belongsToMany(Category::class, 'category_product', 'category_id', 'product_id');
}

Category.php

public function products()
{
    return $this->hasMany(Product::class);
}

CategoryController.php

public function index()
{
    // works
    $categories = Category::where('parent_category_id', 0)->orderBy('name', 'asc')->get();

    // Unknown column 'category_product.sort_key'
    $categories = ProductCategory::where('parent_category_id', 0)->orderBy('category_product.sort_key', 'asc')->orderBy('name', 'asc')->get();


    return view('category.index', compact('categories'));
}

我的数据透视表如下所示:

product_id
category_id
sort_order

我遵循建议的表命名约定。我甚至传递了数据透视表名称是安全的。 - 我不确定如何在我的查询中包含数据透视表。

我也相信这是我无法正确访问列的原因。 例如:

Product.php

$this->categories->myColumn // Undefined property

我的迁移看起来像这样:

...
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('category_id')->references('id')->on('categories');

感谢您的任何建议!

修改

我按照建议更新了逻辑,但我仍然认为我还没有完成正确的连接。

Category.php

public function products()
{
    return $this->belongsToMany(Product::class, 'category_product', 'category_id', 'product_id')
        ->withPivot('sort_key');
}

Product.php

public function categories()
{
    return $this->belongsToMany(Category::class, 'category_product', 'category_id', 'product_id')
        ->withPivot('sort_key');
}

CategoryController.php

public function index()
{
    $categories = Category::where('parent_category_id', 0)
        ->orderBy('sort_order', 'asc')
        ->orderBy('name', 'asc')
        ->get();

    return view('category.index', compact('categories'));
}

Column not found: 1054 Unknown column 'sort_order' in 'order clause

如果我采取->orderBy('sort_order', 'asc')一切都很好。我也试过->orderBy('category_product.sort_order', 'asc')而没有运气。

1 个答案:

答案 0 :(得分:0)

首先,根据the documentation,多对多关系的倒数并不是很多,它属于很多。 Category.php文件的第3行应为:

return $this->belongsToMany(Product::class);

如果要在检索类别或产品模型时使用数据透视表中的sort_order列,则需要在产品和类别模型定义中包含withPivot()方法,如下所示: / p>

<强> Product.php

public function category()
{
    return $this->belongsToMany(Category::class, 'category_product', 'category_id', 'product_id')
    ->withPivot('sort_order');
}

<强> Category.php

public function products()
{
    return $this->belongsToMany(Category::class, 'category_product', 'category_id', 'product_id')
    ->withPivot('sort_order');
}

完成后,假设您想要获取ID为2的类别的所有产品。您可以在CategoryController中执行类似的操作:

<强> CategoryController.php

public function index()
{
    // Get all products for category with an id of 2
    $Products = Category::find(2)->products;

    // Assign the sort_table attribute to each Product model. Can be done
    // in the model definition by setting an accessor attribute. Setting
    // it here for expediency.

    foreach($Products as $Product) $Product->sort_order = $Product->pivot->sort_order;

    // Sort products in descending order using the sort_order column from
    // the pivot table.
    $SortedProducts = $Products->sortByDesc('sort_order');
}

对产品进行分类的最后一行是Collection Method。集合方法几乎总是比在模型中对排序顺序进行硬编码更强大,因为您可以流畅地创建许多方法的链,例如:

$SortedProducts = $Products->where('status', 'available')
                           ->sortBy('product_name');

您还可以使代码变得更加清晰,并且有可能避免在应用程序中稍后再进行数据库查询,只是为了以不同的方式对结果进行排序,从而使一切变得更快。

修改

当您调用Category::外观时,您告诉Laravel要做的是对您在类别模型中定义的表格进行查询。默认情况下,它与型号名称相同。考虑到这一点,除非您的sort_order表格中有categories,否则Laravel会抱怨它无法找到sort_order列。

但是,如果你做了这样的事情:

public function index()
{
    $Products = Category::find(2)->products;

    $products = $Products->toArray();

    var_dump($products);
}

...您会注意到pivot密钥以及sort_order子密钥。

简而言之,只有在实际使用数据透视表时,Laravel才会附加数据透视表的列,就像上面的示例一样。如果您想在不调用产品和类别模型中定义的多对多关系的情况下获取sort_order列,则可以使用简单的连接:

public function index()
{
    $categories = Category::where('parent_category_id', 0)
        ->join('category_product', 'categories.id', '=', category_product.category_id)
        ->orderBy('category_product.sort_order', 'asc')
        ->orderBy('name', 'asc')
        ->get();

    return view('category.index', compact('categories'));
}