Avatar ·

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

Всем привет! Я новичок в Laravel и Eloquent, и у меня возникла проблема. Я использую Query Builder для построения запросов к базе данных, но мне нужно увидеть, какой именно SQL-запрос генерируется на выходе. Например, у меня есть такой код: ```php $users = DB::table('users') ->where('active', 1) ->where('age', '>', 18) ->orderBy('name') ->get(); ``` Я хочу увидеть полный SQL, который выполняется, чтобы отладить его или проверить, правильно ли строятся JOIN'ы. Пробовал использовать `dd()` и `toSql()`, но они почему-то не показывают связанные данные или подстановки. Может, есть какой-то метод, который выводит готовый запрос с подставленными значениями? Заранее спасибо за помощь! <<>>

Использование методов toSql() и getBindings()

Самый простой способ получить сырой SQL-запрос — это использовать метод toSql(), который возвращает строку запроса с плейсхолдерами вместо значений. Однако, чтобы увидеть полный запрос с подставленными значениями, нужно комбинировать его с методом getBindings().

Пример базового использования:

$query = DB::table('users')
    ->where('active', 1)
    ->where('age', '>', 18)
    ->orderBy('name');

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

// Вывод для отладки
echo $sql; // SELECT * FROM `users` WHERE `active` = ? AND `age` > ? ORDER BY `name`
print_r($bindings); // [1, 18]

Сборка полного запроса вручную

Чтобы получить строку с реальными значениями, можно написать небольшую вспомогательную функцию:

function getRawQuery($query) {
    $sql = $query->toSql();
    $bindings = $query->getBindings();
    
    // Заменяем плейсхолдеры на значения с экранированием
    foreach ($bindings as $binding) {
        $value = is_numeric($binding) ? $binding : "'" . $binding . "'";
        $sql = preg_replace('/\?/', $value, $sql, 1);
    }
    
    return $sql;
}

// Использование
$query = DB::table('users')
    ->where('active', 1)
    ->where('age', '>', 18)
    ->orderBy('name');

echo getRawQuery($query); 
// SELECT * FROM `users` WHERE `active` = 1 AND `age` > 18 ORDER BY `name`

Глобальный слушатель запросов для отладки

Если нужно логировать все запросы в приложении, используйте слушатель в методе boot() сервис-провайдера:

// В AppServiceProvider.php
public function boot()
{
    DB::listen(function ($query) {
        $sql = $query->sql;
        $bindings = $query->bindings;
        $time = $query->time;
        
        // Логируем в файл
        \Log::info('SQL: ' . $sql, [
            'bindings' => $bindings,
            'time' => $time . ' ms'
        ]);
    });
}

Расширенный метод с учетом всех плейсхолдеров

Для сложных запросов с массивами (например, whereIn) лучше использовать встроенный метод toRawSql() (доступен с Laravel 8.x):

// Laravel 8+ (если пакет установлен)
$query = DB::table('users')
    ->whereIn('id', [1, 2, 3])
    ->where('name', 'like', '%John%');

echo $query->toRawSql();
// SELECT * FROM `users` WHERE `id` IN (1, 2, 3) AND `name` LIKE '%John%'

Если toRawSql() недоступен, можно установить пакет laravel-query-builder-debug или использовать сторонние инструменты вроде Laravel Debugbar (рекомендую для разработки).

Важное замечание

Метод toSql() работает только для Query Builder, но не для коллекций Eloquent. Если вы используете модель, вызовите toSql() до get():

$query = User::where('active', 1);
echo $query->toSql(); // Работает

$users = $query->get();
// После get() $query уже выполнен, toSql() не сработает

Для быстрой отладки в контроллере можно использовать dd() с комбинацией методов:

dd(DB::table('users')
    ->where('active', 1)
    ->toSql(), 
    DB::table('users')
    ->where('active', 1)
    ->getBindings());
<<>>

Использование расширения Laravel Debugbar

Если вы часто отлаживаете SQL, рекомендую установить пакет barryvdh/laravel-debugbar. Он выводит панель отладки прямо в браузере, где отображаются все выполненные запросы, их время и полный SQL с подставленными значениями.

Установка через Composer:

composer require barryvdh/laravel-debugbar --dev

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

Альтернативный метод: использование макросов

Можно добавить макрос для Query Builder, чтобы получать сырой SQL в любом месте:

// В AppServiceProvider::boot()
DB::macro('toRawSql', function ($query) {
    $sql = $query->toSql();
    $bindings = $query->getBindings();
    
    foreach ($bindings as $binding) {
        $value = is_numeric($binding) ? $binding : "'" . $binding . "'";
        $sql = preg_replace('/\?/', $value, $sql, 1);
    }
    
    return $sql;
});

// Использование
$query = DB::table('users')->where('active', 1);
echo DB::toRawSql($query);

Этот подход удобен, если вы не хотите использовать внешние пакеты, но нуждаетесь в быстром доступе к сырому SQL.