Я разрабатываю приложение на Laravel 5.5 и сталкиваюсь с проблемой с конкретной областью запросов. У меня есть следующая структура таблицы (некоторые поля опущены):
orders
---------
id
parent_id
status
parent_id
ссылается на id
из той же таблицы. У меня есть эта область запроса для фильтрации записей, у которых нет детей:
public function scopeNoChildren(Builder $query): Builder
{
return $query->select('orders.*')
->leftJoin('orders AS children', function ($join) {
$join->on('orders.id', '=', 'children.parent_id')
->where('children.status', self::STATUS_COMPLETED);
})
->where('children.id', null);
}
Этот объем отлично работает при использовании в одиночку. Однако, если я попытаюсь объединить его с любым другим условием, он выдает исключение SQL:
Order::where('status', Order::STATUS_COMPLETED)
->noChildren()
->get();
Приводит к следующему:
SQLSTATE [23000]: Нарушение ограничения целостности: 1052 Столбец "статус" в том месте, где предложение неоднозначно
Я нашел два способа избежать этой ошибки:
Решение # 1: префикс всех других условий с именем таблицы
Выполнение чего-то подобного:
Order::where('orders.status', Order::STATUS_COMPLETED)
->noChildren()
->get();
Но я не думаю, что это хороший подход, так как не ясно, что имя таблицы требуется в случае, если другой разработчик или даже сам попытается снова использовать эту область в будущем. Вероятно, они в конечном итоге выяснят это, но это не кажется хорошей практикой.
Решение №2: используйте подзапрос
Я могу хранить двусмысленные столбцы в подзапросе. Тем не менее, в этом случае и по мере роста таблицы производительность ухудшится.
Это стратегия, которую я использую. Потому что это не требует каких-либо изменений в других областях и условиях. По крайней мере, не так, как я применяю это сейчас.
public function scopeNoChildren(Builder $query): Builder
{
$subQueryChildren = self::select('id', 'parent_id')
->completed();
$sqlChildren = DB::raw(sprintf(
'(%s) AS children',
$subQueryChildren->toSql()
));
return $query->select('orders.*')
->leftJoin($sqlChildren, function ($join) use ($subQueryChildren) {
$join->on('orders.id', '=', 'children.parent_id')
->addBinding($subQueryChildren->getBindings());
})->where('children.id', null);
}
Идеальное решение
Я думаю, что отличное решение для использования запросов без префикса с именем таблицы, не полагаясь на подзапросы.
Вот почему я спрашиваю: есть ли способ, чтобы имя таблицы автоматически добавлялось к методам запросов Eloquent?