Avatar ·

Как получить сырой SQL-запрос из Query Builder в Laravel в виде строки?

Всем привет. Я новичок в Laravel и пытаюсь отладить один сложный запрос с использованием Query Builder. Мне нужно увидеть, какой именно SQL-запрос генерирует Eloquent, чтобы проверить, правильно ли строятся JOIN'ы и WHERE'ы. Проблема в том, что я использую `DB::table('users')->select(...)->where(...)->get()`, и всё работает, но я хочу увидеть итоговый SQL перед выполнением, чтобы убедиться, что он корректен. Например, у меня есть такой код: ```php $users = DB::table('users') ->join('orders', 'users.id', '=', 'orders.user_id') ->where('users.active', 1) ->whereIn('orders.status', ['pending', 'processing']) ->orderBy('users.created_at', 'desc') ->get(); ``` Я пробовал использовать `->toSql()`, но он возвращает запрос с плейсхолдерами `?` вместо реальных значений (например, `WHERE users.active = ?`). А мне нужен именно готовый SQL с подставленными значениями, чтобы скопировать его и выполнить в phpMyAdmin или HeidiSQL для проверки. Подскажите, есть ли способ получить полный SQL-запрос со всеми параметрами? Или хотя бы способ увидеть, какие значения подставляются вместо вопросительных знаков? Заранее спасибо! P.S. Laravel 10, PHP 8.2. <<>>

Способы получения полного SQL-запроса в Laravel

Вы столкнулись с типичной ситуацией при отладке запросов. К сожалению, встроенный метод toSql() действительно возвращает только запрос с плейсхолдерами. Однако существует несколько проверенных способов получить готовый SQL со всеми значениями.

Способ 1: Использование макроса для Query Builder (рекомендуется)

Добавьте этот макрос в AppServiceProvider::boot():

use Illuminate\Support\Facades\DB;
use Illuminate\Database\Query\Builder;

// В методе boot() вашего AppServiceProvider
Builder::macro('toRawSql', function() {
    $sql = $this->toSql();
    $bindings = $this->getBindings();
    
    foreach ($bindings as $binding) {
        $value = is_numeric($binding) ? $binding : "'" . $binding . "'";
        $sql = preg_replace('/\?/', $value, $sql, 1);
    }
    
    return $sql;
});

Теперь вы можете использовать:

$query = DB::table('users')
    ->join('orders', 'users.id', '=', 'orders.user_id')
    ->where('users.active', 1)
    ->whereIn('orders.status', ['pending', 'processing'])
    ->orderBy('users.created_at', 'desc');

dd($query->toRawSql()); // Выведет готовый SQL

Способ 2: Встроенная функция для Eloquent моделей

Если вы работаете с Eloquent, можно использовать комбинацию методов:

$users = User::join('orders', 'users.id', '=', 'orders.user_id')
    ->where('users.active', 1)
    ->whereIn('orders.status', ['pending', 'processing'])
    ->orderBy('users.created_at', 'desc');

// Получаем SQL с плейсхолдерами
$sql = $users->toSql();
// Получаем массив bindings
$bindings = $users->getBindings();

// Форматируем для вывода
dump([
    'sql' => $sql,
    'bindings' => $bindings
]);

Способ 3: Использование Laravel Debugbar

Самый удобный способ для разработки — установить пакет barryvdh/laravel-debugbar:

composer require barryvdh/laravel-debugbar --dev

После установки на каждой странице будет отображаться панель с выполненными SQL-запросами, их временем выполнения и полным текстом запроса с подставленными значениями.

Способ 4: Логирование всех запросов

Включите логирование запросов в глобальном масштабе:

// В AppServiceProvider::boot()
DB::listen(function ($query) {
    $sql = $query->sql;
    $bindings = $query->bindings;
    
    // Логирование в файл
    \Log::info('SQL: ' . $sql, $bindings);
    
    // Или вывод в консоль (если используете artisan tinker)
    // dump($sql, $bindings);
});

Способ 5: Использование artisan tinker для отладки

В консоли выполните:

php artisan tinker

// Затем введите запрос
> $query = DB::table('users')->where('id', 1);
> $query->dd(); // dump and die — покажет SQL и bindings

Метод dd() — это встроенная возможность Laravel, которая выводит отладочную информацию и прекращает выполнение.

Рекомендация

Для быстрой отладки используйте макрос toRawSql() из первого способа. Для постоянного мониторинга — установите Debugbar. Метод dd() хорош для разовых проверок в tinker или контроллерах.

Важно: никогда не используйте эти методы в production-окружении, так как они могут раскрыть структуру базы данных и чувствительные данные.

<<>>

Альтернативный подход: использование пакета spatie/laravel-sql-commenter

Если вам нужно не просто увидеть SQL, а понять, какой код его сгенерировал, рекомендую пакет от Spatie. Он добавляет комментарии к SQL-запросам с указанием файла и строки вызова.

composer require spatie/laravel-sql-commenter

После установки в логах MySQL вы увидите:

/* App\Http\Controllers\UserController::index:25 */
SELECT * FROM `users` WHERE `active` = 1

Это особенно полезно, когда в проекте много запросов и нужно быстро найти проблемный участок кода.

Ещё один способ: метод dump()

В Laravel 8+ появился метод dump() для Query Builder, который выводит запрос с bindings, но не прекращает выполнение:

$users = DB::table('users')
    ->where('active', 1)
    ->dump() // Выведет SQL и bindings
    ->get(); // Продолжит выполнение

Это удобно, когда нужно отладить цепочку запросов, не прерывая их выполнение.