Laravel предоставляет отличный конструктор запросов и ORM — Eloquent. Это позволяет писать запросы невероятно простым и понятным способом. Тем не менее, бывают случаи, когда вам нужно создать сложный запрос и увидеть, какой SQL в действительности сгенерируется.
В этом руководстве мы пройдёмся по некоторым способам получения этой информации, начиная с простых методов и заканчивая мощным пакетом.
Перед тем, как мы начнём, давайте построим запрос для вымышленного бага, который нам прислали:
Баг #22321
Проблема: Поиск пользователей выдаёт слишком много результатов
Как увидеть баг: Я ищу «John Doe [email protected]»
и получаю назад сотни результатов.
Пройдя в код, мы нашли ту часть, где, скорее всего, скрыта ошибка:
$results = User::where(function($q) use ($request) {
$q->orWhere('email', 'like', '%[email protected]%');
$q->orWhere('first_name', 'like', '%John%');
$q->orWhere('last_name', 'like', '%Doe%');
})->get();
Можете ли вы уже обнаружить проблему? Если нет, не переживайте, мы начнём отладку этого запроса и увидим, что на самом деле происходит.
Простая отладка запросов
Самый простой метод увидеть запрос, который генерируется — использовать методtoSql()
. Всё, что нам нужно сделать — заменить get()
на toSql()
и затем вывести результаты с помощью dd()
.
Вот обновлённый запрос:
$results = User::where(function($q) use ($request) {
$q->orWhere('email', 'like', '%[email protected]%');
$q->orWhere('first_name', 'like', '%John%');
$q->orWhere('last_name', 'like', '%Doe%');
})->toSql();
dd($results)
Запустив это в браузере, мы увидим следующий SQL:
select * from `users` where (`email` like ? or `first_name` like ? or `last_name` like ?)
Этот метод хорош для быстрого отображения SQL запросов. Тем не менее, он не отображает биндинги и показывает ?
на их месте. В некоторых случаях, в зависимости от сложности биндингов, этого вам будет достаточно для отладки запроса.
Прослушивание событий базы данных
Вторым способом является прослушивание событий объекта DB
. Для этого можно воспользоваться небольших хелпером ниже:
\DB::listen(function($sql) {
var_dump($sql);
});
Теперь, когда загрузится страница, вы получите тот же самый вывод, как и в предыдущем способе.
select * from `users` where (`email` like ? or `first_name` like ? or `last_name` like ?)
DB::listen
— более продвинутый способ, который принимает 2 дополнительных параметра для доступа к таймингу и биндингам:
\DB::listen(function($sql, $bindings, $time) {
var_dump($sql);
var_dump($bindings);
var_dump($time);
});
Это выведет нам:
string 'select * from `users` where (`email` like ? or `first_name` like ? or `last_name` like ?)' (length=89)
array (size=3)
0 => string '%[email protected]%' (length=18)
1 => string '%John%' (length=6)
2 => string '%Doe%' (length=5)
float 35.63
Как вы видите, этот способ предоставляет нам запрос, биндинги и время выполнения запроса.
Пакет Debugbar
Ещё одним способом отладки запросов является установка Laravel Debugbar. После установки вы сможете просмотреть все запросы в специальной вкладке панели браузера. Это достаточно мощный пакет, и он даёт большое кол-во информации о вашем приложении.
Заключение
Вы уже нашли ошибку? Вместо orWhere
нужно использовать where
. Финальный код с фиксом:
$results = User::where(function($q) use ($request) {
$q->where('email', 'like', '%[email protected]%');
$q->where('first_name', 'like', '%John%');
$q->where('last_name', 'like', '%Doe%');
})->get();
Что даст нам корректный запрос:
select * from `users` where (`email` like '%[email protected]%' and `first_name` like '%John%' and `last_name` like '%Doe%')
Удачной отладки!