Почему не работает whereHas?

Есть таблица с товарами и таблица для отношений товары-подарки. Подарками являются те же товары:
Schema::create('products', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->boolean('is_gift')->default(false);
});

Schema::create('products_gifts', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('product_id');
    $table->integer('gift_id');
});

Модель:
class Product extends Model
{
    protected $table = 'products';

    public function gifts()
    {
        return $this->belongsToMany(static::class, 'products_gifts', 'product_id', 'gift_id');
    }
}

Таблица products:
5d2dc175a09bb235127483.png

Таблица products_gifts:
5d2dc1ce3d328675209782.png

Получим товары, которые не являются подарками (+ подарки в отношениях):
$products = Product::with('gifts')->where('is_gift', '=', false)->get()->toArray();

Всё ок, возвращаются три товара, с подарками, как и задумывалось.

Теперь нужно получить только те товары, у которых одним из подарков является "Первый товар-подарок", его id=4.

Что я делаю:
$products = Product::with('gifts')
    ->where('is_gift', '=', false)
    ->whereHas('gifts', function (Builder $query) {
        $query->where('id', '=', 4);
    })
    ->get();

Получается вот такой sql:
select *
from `products`
where `is_gift` = 0
    and exists(select *
        from `products` as `laravel_reserved_0`
        inner join `products_gifts` on `laravel_reserved_0`.`id` = `products_gifts`.`gift_id`
        where `products`.`id` = `products_gifts`.`product_id`
        and `id` = 4)

И вот такая ошибка:

SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous (SQL: select * from `products` where `is_gift` = 0 and exists (select * from `products` as `laravel_reserved_0` inner join `products_gifts` on `laravel_reserved_0`.`id` = `products_gifts`.`gift_id` where `products`.`id` = `products_gifts`.`product_id` and `id` = 4))


Если добавить 'laravel_reserved_0.' то работает:
$products = Product::with('gifts')
    ->where('is_gift', '=', false)
    ->whereHas('gifts', function (Builder $query) {
        $query->where('laravel_reserved_0.id', '=', 4);
    })
    ->get();

Но что-то мне подсказывает, что это решение так себе.

Я так понимаю мешает поле id в таблице products_gifts? К сожалению, структуру таблиц менять нельзя.

Что можно сделать?
  • Вопрос задан
  • 480 просмотров
Пригласить эксперта
Ответы на вопрос 3
select *
from `products`
where `is_gift` = 0
  and exists(select *
             from `products` as `laravel_reserved_0`
                    inner join `products_gifts` on `laravel_reserved_0`.`id` = `products_gifts`.`gift_id`
             where `products`.`id` = `products_gifts`.`product_id`
             and `laravel_reserved_0`.`id` = 4)
Последняя строка в запросе.
Ответ написан
@vism
Вместо whereHas, использовать whereExist, и этот код преобразованый в query builder
select * from `products` as `laravel_reserved_0` inner join `products_gifts` on `laravel_reserved_0`.`id` = `products_gifts`.`gift_id` where `products`.`id` = `products_gifts`.`product_id` and `laravel_reserved_0`.`id` = 4
Ответ написан
@krioz
belongsToMany(static::class
а не нужно ли здесь указывать класс гифтов, а не себя же?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы