Laravel按关联表排序

13

我在项目中有产品和类别模型。 产品属于类别。由于产品具有外键category_id,因此可以轻松地对输出进行排序:

$products = Product::orderBy('category_id', 'asc')->get();

但是我真正想要的是按类别名称对产品进行排序,所以我尝试了:

$products = Product::with(['categories' => function($q){
            $q->orderBy('name', 'asc')->first();
        }]);

但是它没有任何输出。作为一个测试,我返回了 return Product::with('categories')->first(); 它可以正常输出...

下面是 Eloquent 关联关系。

Product

class Product extends Model
{
    protected $fillable = [
        'name',
        'description',
        'price',
        'category_id',
    ];

    protected $hidden = [
        'created_at',
        'updated_at',
    ];

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

分类:

class Category extends Model
{
    protected $fillable = [
        'name'
    ];

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

视图部分:

@foreach ($products as $product)
                <tr>

                    <td>{!! $product->categories->name !!}</td>
                    <td>
                        @if(!empty($product->picture))
                            Yes
                        @else
                            No
                        @endif
                    </td>
                    <td>{!! $product->name !!}</td>
                    <td>{!! $product->description !!}</td>
                    <td>{!! $product->price !!}</td>
                    <td>
                        <a href="{{ url('/product/'.$product->id.'/edit') }}">
                            <i class="fa fa-fw fa-pencil text-warning"></i>
                        </a>
                        <a href="" data-href="{{route('product.destroyMe', $product->id)}}"
                           data-toggle="modal" data-target="#confirm-delete">
                            <i class="fa fa-fw fa-times text-danger"></i>
                        </a>
                    </td>
                </tr>
            @endforeach
4个回答

9
我没有测试过,但我认为这应该有效。
// Get all the products
$products = \App\Product::all();

// Add Closure function to the sortBy method, to sort by the name of the category
$products->sortBy(function($product) { 
  return $product->categories()->name;
});

这也应该可以工作:
 $products = Product::with('categories')->get()
   ->sortBy(function($product) { 
       return $product->categories->name;
  })

那行不通,也没有逻辑意义。产品只能有一个类别。我已经在Tinker中测试了我的关系,它们按照预期工作。模型不应该是问题所在。 - Norgul
它不应该影响结果,但我认为对于一对多的关系来说,这只是违反了惯例。 - geckob
更新了答案。 - geckob
你的答案差不多可以解决问题...按照以下方式更新它:$products = Product::with('categories')->get()->sortBy(function($product) { return $product->categories->name; }); - Norgul
@Norgul: 已更新您的代码。但我认为它应该是可用的。在测试之前我还没有删除它。如果有用请点赞。 - geckob
显示剩余5条评论

8
您可以使用join(),请尝试下面的代码。
$query = new Product; //new object
//$query = Product::where('id','!=',0);
$query = $query->join('categories', 'categories.id','=','products.categories.id');
$query = $query->select('categories.name as cat_name','products.*');
$query = $query->orderBy('cat_name','asc');
$record = $query->get();

为什么需要新产品?我需要所有现有的产品。 - Norgul
使用 new 可以创建 'Product' 类的新对象。因此,如果您可以附加一些额外的 where 子句,则还可以将第一行替换为第二行。 - DsRaj
如果有一些产品不属于任何类别,请使用 leftjoin 而不是 join - Christopher K.
这是唯一对我有效的解决方案,只需要进行一些简单的调整,例如使用左连接而不是连接等。 - John Smith

3
你可以简单地向Eloquent急切加载提供函数,从而处理相关表如何被查询的方式。
$product = Product::with(['categories' => function ($q) {
  $q->orderBy('name', 'asc');
}])->find($productId);

-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接