限制与 Laravel 的多态多对多关系中的相关记录

2022-08-31 01:12:33

我正在使用Laravel 5.1,我需要使用多态多对多关系来限制我正在提取的相关记录的数量。

我想做的是按parent_id获取类别列表。对于每个类别,我只想拉四个帖子。

我已经使用下面的代码,但它会导致一堆额外的查询。如果可能的话,我只想点击数据库一次。如果可能的话,我想使用Laravel/Eloquent框架,但对这一点上可行的方法持开放态度。

@foreach ($categories as $category)
  @if ($category->posts->count() > 0)
    <h2>{{ $category->name }}</h2>
    <a href="/style/{{ $category->slug }}">See more</a>

    {-- This part is the wonky part --}

    @foreach ($category->posts()->take(4)->get() as $post)

      {{ $post->body }}

    @endforeach

  @endif
@endforeach

后控制器

public function index(Category $category)
{
  $categories = $category->with('posts')
      ->whereParentId(2)
      ->get();

  return view('posts.index')->with(compact('categories'));
}

数据库

posts
    id - integer
    body - string

categories
    id - integer
    name - string
    parent_id - integer

categorizables
    category_id - integer
    categorizable_id - integer
    categorizable_type - string

岗位模型

<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    public function categories()
    {
        return $this->morphToMany('App\Category', 'categorizable');
    }

类别模型

<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
    public function category()
    {
        return $this->belongsTo('App\Category', 'parent_id');
    }
    public function subcategories()
    {
        return $this->hasMany('App\Category', 'parent_id')->orderBy('order', 'asc');
    }
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'categorizable');
    }

我在网上看到了很多指向此的链接,但没有一个真正对我有用。

我尝试过这个解决方案,没有任何运气。

$categories = $category->with('posts')
->whereParentId(2)
->posts()
->take(4)
->get();

我已经在SoftOnTheSofa上研究了Jarek的这个解决方案,但它是一种hasMany关系,说实话,有点超出了我的sql技能,让我根据我的需求进行调整。

编辑

我为此设置添加了一个github存储库,如果它对任何人都有用的话。


答案 1

编辑类别模型

public function fourPosts() {
    // This is your relation object
    return $this->morphedByMany('App\Post', 'categorizable')
    // We will join the same instance of it and will add a temporary incrementing
    // Number to each post
    ->leftJoin(\DB::raw('(' . $this->morphedByMany('App\Post', 'categorizable')->select(\DB::raw('*,@post_rank := IF(@current_category = category_id, @post_rank + 1, 1) AS post_rank, @current_category := category_id'))
    ->whereRaw("categorizable_type = 'App\\\\Post'")
    ->orderBy('category_id', 'ASC')->toSql() . ') as joined'), function($query) {
        $query->on('posts.id', '=', 'joined.id');
    // And at the end we will get only posts with post rank of 4 or below
    })->where('post_rank', '<=', 4);
}

然后在您的控制器中,您获得的所有类别都与此

$categories = Category::whereParentId(1)->with('fourPosts')->get();

将只有四个帖子。要测试此操作(请记住,现在您将使用方法加载帖子,因此您必须使用此属性访问四个帖子):fourPosts

foreach ($categories as $category) {
    echo 'Category ' . $category->id . ' has ' . count($category->fourPosts) . ' posts<br/>';
}

简而言之,您将一个子查询添加到morph对象,该子查询允许我们为类别中的每个帖子分配临时递增编号。然后,您可以获取具有此临时数字的行小于或等于 4 :)


答案 2

这对你有用吗?

$categories = $category->with(['posts' => function($query)
    {
        $query->take(4);
    })
    ->whereParentId(2)
    ->get();

推荐