首页 > 解决方案 > Laravel Eloquent 返回值取决于关系的值

问题描述

我正在尝试根据列的值从表中返回数据。让我解释。

我有 3 张桌子。books,genres和一个数据透视表来关联这两个表的值。

  1. books
  2. genres
  3. book_genre

存在many-to-many关系,因为 abook可以包含 differentgenres并且 agenre可以与 different 相关联books

关系

Book Model

class Book extends Model
{
    use HasFactory;

    /**
     * @inheritdoc
     *
     * @var string[]
     */
    protected $fillable = [
        'title',
        'language',
        'thumbnail',
        'active'
    ];

    /**
     * @inheritdoc
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new ExcludeBookWhenInactiveRelations());
    }

    /**
     * Genders relationship
     *
     * @return BelongsToMany
     */
    public function genres()
    {
        return $this->belongsToMany(Genre::class);
    }
}

Genre Model

class Genre extends Model
{
    use HasFactory;

    /**
     * @inheritdoc
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'active'
    ];

    /**
     * Books relationship
     *
     * @return BelongsToMany
     */
    public function books()
    {
        return $this->belongsToMany(Book::class);
    }
}

现在,我正在尝试global scope在我的Book模型中创建一个,因此在查询时,它只返回未被禁用books的。genres也就是说,如果在我的genre表中,我将activea 的属性更改genre为 false 并且genre与 a 相关联book,那么它不应该向我显示book.

这是Global Scope我正在创建的:

class ExcludeBookWhenInactiveRelations implements Scope
{
    /**
     * @inheritdoc
     *
     * @param Builder $builder
     * @param Model $model
     * @return Builder|void
     */
    public function apply(Builder $builder, Model $model)
    {
        return $builder->whereHas('genres', function ($query) {
            return $query->where('active', true);
        });
    }
}

发生的情况是,当我将 a 的active属性值更改为genrefalse,它不会显示genere在集合中,但如果它book有 2genres并且其中一个将active属性保留在 中true,那么它会跟随我返回book,以及我'我想做的是如果book至少有 1 个genderdisabled (false),那么它不会在集合中显示它。

你能帮我解决我的问题吗?非常感谢您提前。

标签: laraveleloquent

解决方案


您雄辩的设置正在创建此查询。

select * from books where exists (select * from genres inner join book_genre on genres.id = book_genre.genre_id where books.id = book_genre.book_id and active = 1)

在这里,如果书只有一种活跃的流派,它将被选中。这是错误的。现在您需要另一个没有太大区别的查询。

select * from books where not exists (select * from genres inner join book_genre on genres.id = book_genre.genre_id where books.id = book_genre.book_id and active = 0) 

在这里,如果书籍只有一种不活跃的流派,它将不会从最终记录中被选中。

@leo95batista 雄辩地提供了这个查询。

class ExcludeBookWhenInactiveRelation implements Scope
{
    /**
     * @inheritdoc
     *
     * @param Builder $builder
     * @param Model $model
     * @return Builder|void
     */
    public function apply(Builder $builder, Model $model)
    {
        return $builder->whereDoesntHave('genres', function (Builder $query) {
            return $query->where('active', false);
        });
    }
}

推荐阅读