Как получить построитель запросов для вывода его необработанного SQL-запроса в виде строки?

244

С учетом следующего кода:

DB::table('users')->get();

Я хочу получить необработанную строку запроса SQL, которую построил построитель запросов выше, поэтому в этом примере это будет SELECT * FROM users.

Как это сделать?

  • 9
    Laravel Eloquent ORM получает необработанный запрос: echo User::where('status', 1)->toSql();
Теги:
laravel-4

19 ответов

294
Лучший ответ

Чтобы выводить на экран последние запущенные запросы, вы можете использовать этот

dd(DB::getQueryLog());

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

У вас будет что-то вроде этого:

array(1) {
  [0]=>
  array(3) {
    ["query"]=>
    string(21) "select * from "users""
    ["bindings"]=>
    array(0) {
    }
    ["time"]=>
    string(4) "0.92"
  }
}

Как ниже комментарий Джошуа ниже, по умолчанию это отключено. Чтобы использовать его, вам необходимо включить его вручную, используя:

DB::enableQueryLog();
  • 0
    Есть ли в любом случае Laravel может вывести это в console.log браузера?
  • 1
    хм, я не уверен, но вы можете достичь желаемого с помощью пакета композитора stackoverflow.com/a/17339752/813181
Показать ещё 8 комментариев
421

Используйте метод toSql() для экземпляра QueryBuilder.

DB::table('users')->toSql() вернется:

выберите * из `users`

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

  • 6
    Я думаю, что это самый простой способ при использовании Eloquent вне Laravel.
  • 42
    это не показывает связанные значения
Показать ещё 10 комментариев
46

Вы можете прослушать событие "illuminate.query". Перед запросом добавьте следующий прослушиватель событий:

Event::listen('illuminate.query', function($query, $params, $time, $conn) 
{ 
    dd(array($query, $params, $time, $conn));
});

DB::table('users')->get();

Это напечатает что-то вроде:

array(4) {
  [0]=>
  string(21) "select * from "users""
  [1]=>
  array(0) {
  }
  [2]=>
  string(4) "0.94"
  [3]=>
  string(6) "sqlite"
}
  • 1
    Я получаю вызов неопределенного метода Illuminate \ Database \ Query \ Builder :: listen () в Laravel 4
  • 2
    Спасибо, это здорово. Следует отметить, что dd - это функция, которая создает Dump для заданной переменной и завершает выполнение скрипта, а также для импорта Event, включает use Illuminate\Support\Facades\Event;
Показать ещё 1 комментарий
31

Если вы пытаетесь получить журнал с использованием Illuminate без использования Laravel:

\Illuminate\Database\Capsule\Manager::getQueryLog();

Вы также можете выполнить быструю функцию:

function logger() {
    $queries = \Illuminate\Database\Capsule\Manager::getQueryLog();
    $formattedQueries = [];
    foreach( $queries as $query ) :
        $prep = $query['query'];
        foreach( $query['bindings'] as $binding ) :
            $prep = preg_replace("#\?#", is_numeric($binding) ? $binding : "'" . $binding . "'", $prep, 1);
        endforeach;
        $formattedQueries[] = $prep;
    endforeach;
    return $formattedQueries;
}

ИЗМЕНИТЬ

обновленные версии, похоже, отключили ведение журнала запросов по умолчанию (приведенное выше возвращает пустой массив). Чтобы вернуться назад, при инициализации диспетчера Capsule, захватите экземпляр соединения и вызовите метод enableQueryLog

$capsule::connection()->enableQueryLog();

ИЗМЕНИТЬ СНОВА

Принимая во внимание фактический вопрос, вы могли бы сделать следующее для преобразования текущего одиночного запроса вместо всех предыдущих запросов:

$sql = $query->toSql();
$bindings = $query->getBindings();
  • 0
    я получаю этот тип возврата из запроса "name = [{" name ":" rifat "}]" что мне нужно сделать, чтобы получить только "name = rifat"?
  • 0
    Я бы распечатал ваши привязки, похоже, что вы передаете массив вместо строки
Показать ещё 4 комментария
27

Существует метод в красноречиве для получения строки запроса.

toSql()

в нашем случае,

 DB::table('users')->toSql(); 

возврат

select * from users

- точное решение, возвращающее строку запроса SQL. Надеюсь, что это полезно...

  • 9
    как насчет привязки запроса? например, когда вы делаете ->where('foo', '=', 'bar') бар не будет отображаться в SQL
16

Если вы используете laravel 5.1 и MySQL, вы можете использовать эту функцию, созданную мной:

/*
 *  returns SQL with values in it
 */
function getSql($model)
{
    $replace = function ($sql, $bindings)
    {
        $needle = '?';
        foreach ($bindings as $replace){
            $pos = strpos($sql, $needle);
            if ($pos !== false) {
                if (gettype($replace) === "string") {
                     $replace = ' "'.addslashes($replace).'" ';
                }
                $sql = substr_replace($sql, $replace, $pos, strlen($needle));
            }
        }
        return $sql;
    };
    $sql = $replace($model->toSql(), $model->getBindings());

    return $sql;
}

В качестве входного параметра вы можете использовать любой из этих

Осветите\Database\Eloquent\Builder

Осветите\Database\Eloquent\Отношения\HasMany

Осветите\Database\Query\Builder

  • 0
    Ответ улучшен, чтобы включить все замечания, сделанные в комментариях. Большое спасибо.
12

DB::QueryLog() работает только после выполнения запроса $builder->get(). если вы хотите получить запрос перед выполнением запроса, вы можете использовать метод $builder->toSql(). это пример того, как получить sql и связать его:

    $query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
    $query = vsprintf($query, $builder->getBindings());
    dump($query);

    $result = $builder->get();
  • 2
    Это, безусловно, лучший ответ, простой и прямой к сути. Спасибо :)
  • 3
    В качестве однострочника: $query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
6
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
  • 0
    Это гораздо точнее, контролируется и отвечает потребностям вопроса.
  • 0
    Спасибо за ваш комментарий.
Показать ещё 1 комментарий
6

Первый способ:

Просто вы можете сделать следующее, используя метод toSql(),

$query = DB::table('users')->get();

echo $query->toSql();

Если он не работает, вы можете настроить вещь из документации laravel.

Второй способ:

Другой способ сделать это -

DB::getQueryLog()

но если он возвращает пустой массив, то по умолчанию он отключен в этом,

просто включится с DB::enableQueryLog(), и он будет работать:)

для получения дополнительной информации посетите Github Issue, чтобы узнать больше об этом.

Надеюсь, это поможет:)

4

Это функция, которую я поместил в базовый класс. Просто передайте объект построителя запроса в него, и будет возвращена строка SQL.

function getSQL($builder) {
  $sql = $builder->toSql();
  foreach ( $builder->getBindings() as $binding ) {
    $value = is_numeric($binding) ? $binding : "'".$binding."'";
    $sql = preg_replace('/\?/', $value, $sql, 1);
  }
  return $sql;
}
2

Чтобы просмотреть запрос Laravel Выполненный запрос, используйте журнал запросов laravel

DB::enableQueryLog();

$queries = DB::getQueryLog();
2

Для laravel 5.5.X

Если вы хотите получить каждый запрос SQL, выполняемый вашим приложением, вы можете использовать метод listen. Этот метод полезен для ведения журнала запросов или отладки. Вы можете зарегистрировать свой прослушиватель запросов у поставщика услуг:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        DB::listen(function ($query) {
            // $query->sql
            // $query->bindings
            // $query->time
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Источник

2

Из laravel 5.2 и далее. вы можете использовать DB::listen для выполнения выполненных запросов.

DB::listen(function ($query) {
    // $query->sql
    // $query->bindings
    // $query->time
});

Или, если вы хотите отладить один экземпляр Builder, вы можете использовать метод toSql.

DB::table('posts')->toSql(); 
  • 1
    Функция прослушивания полезна, объявите ее перед выполнением запроса и выведите sql & bindings в методе. Несовершенный, но работает быстрее / проще, чем другие ответы.
2

Если вы не используете Laravel, а используете пакет Eloquent, тогда:

use \Illuminate\Database\Capsule\Manager as Capsule;
use \Illuminate\Events\Dispatcher;
use \Illuminate\Container\Container;

$capsule = new Capsule;

$capsule->addConnection([
    // connection details
]);
// Set the event dispatcher used by Eloquent models... (optional)
$capsule->setEventDispatcher(new Dispatcher(new Container));

// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();

// Setup the Eloquent ORM...(optional unless you've used setEventDispatcher())
$capsule->bootEloquent();

// Listen for Query Events for Debug
$events = new Dispatcher;
$events->listen('illuminate.query', function($query, $bindings, $time, $name)
{
    // Format binding data for sql insertion
    foreach ($bindings as $i => $binding) {
        if ($binding instanceof \DateTime) {
            $bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
        } else if (is_string($binding)) {
            $bindings[$i] = "'$binding'";`enter code here`
        }
    }

    // Insert bindings into query
    $query = str_replace(array('%', '?'), array('%%', '%s'), $query);
    $query = vsprintf($query, $bindings);

    // Debug SQL queries
    echo 'SQL: [' . $query . ']';
});

$capsule->setEventDispatcher($events);
1

вы можете использовать clockwork

Clockwork - это расширение Chrome для разработки PHP, расширяющее инструменты для разработчиков с новой панелью, предоставляющей всю информацию, полезную для отладки и профилирования ваших приложений PHP, включая информацию о запросе, заголовках, получении и отправке данных, куки, данные сеанса, запросов к базе данных, маршрутов, визуализации времени выполнения приложений и т.д.

но работает также в firefox

0

композитор требует "barryvdh/laravel-debugbar": "2.3. *"

вы увидите Изображение 780

0

Вот решение, которое я использую:

DB::listen(function ($sql, $bindings, $time) {
    $bound = preg_replace_callback("/\?/", function($matches) use ($bindings) {
        static $localBindings;
        if (!isset($localBindings)) {
            $localBindings = $bindings;
        }
        $val = array_shift($localBindings);

        switch (gettype($val)) {
            case "boolean":
                $val = ($val === TRUE) ? 1 : 0;  // mysql doesn't support BOOL data types, ints are widely used
                // $val = ($val === TRUE) ? "'t'" : "'f'";   // todo: use this line instead of the above for postgres and others
                break;

            case "NULL":
                $val = "NULL";
                break;

            case "string":
            case "object":
                $val = "'". addslashes($val). "'";   // correct escaping would depend on the RDBMS
                break;
        }
        return $val;
    }, $sql);
    array_map(function($x) { 
        (new \Illuminate\Support\Debug\Dumper)->dump($x); 
    }, [$sql, $bindings, $bound]);
});

Пожалуйста, прочитайте комментарии в коде. Я знаю, это не идеально, но для моей повседневной отладки это нормально. Он пытается построить связанный запрос с большей или меньшей степенью надежности. Однако, не доверяйте этому полностью, двигатели базы данных избегают значений по-разному, которые эта короткая функция не реализует. Итак, внимательно прочтите результат.

0

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

/**
 * getSql
 *
 * Usage:
 * getSql( DB::table("users") )
 * 
 * Get the current SQL and bindings
 * 
 * @param  mixed  $query  Relation / Eloquent Builder / Query Builder
 * @return array          Array with sql and bindings or else false
 */
function getSql($query)
{
    if( $query instanceof Illuminate\Database\Eloquent\Relations\Relation )
    {
        $query = $query->getBaseQuery();
    }

    if( $query instanceof Illuminate\Database\Eloquent\Builder )
    {
        $query = $query->getQuery();
    }

    if( $query instanceof Illuminate\Database\Query\Builder )
    {
        return [ 'query' => $query->toSql(), 'bindings' => $query->getBindings() ];
    }

    return false;
}

/**
 * logQuery
 *
 * Get the SQL from a query in a closure
 *
 * Usage:
 * logQueries(function() {
 *     return User::first()->applications;
 * });
 * 
 * @param  closure $callback              function to call some queries in
 * @return Illuminate\Support\Collection  Collection of queries
 */
function logQueries(closure $callback) 
{
    // check if query logging is enabled
    $logging = DB::logging();

    // Get number of queries
    $numberOfQueries = count(DB::getQueryLog());

    // if logging not enabled, temporarily enable it
    if( !$logging ) DB::enableQueryLog();

    $query = $callback();

    $lastQuery = getSql($query);

    // Get querylog
    $queries = new Illuminate\Support\Collection( DB::getQueryLog() );

    // calculate the number of queries done in callback
    $queryCount = $queries->count() - $numberOfQueries;

    // Get last queries
    $lastQueries = $queries->take(-$queryCount);

    // disable query logging
    if( !$logging ) DB::disableQueryLog();

    // if callback returns a builder object, return the sql and bindings of it
    if( $lastQuery )
    {
        $lastQueries->push($lastQuery);
    }

    return $lastQueries;
}

Использование:

getSql( DB::table('users') );
// returns 
// [
//     "sql" => "select * from `users`",
//     "bindings" => [],
// ]

getSql( $project->rooms() );
// returns
// [
//     "sql" => "select * from `rooms` where `rooms`.`project_id` = ? and `rooms`.`project_id` is not null",
//     "bindings" => [ 7 ],
// ]
0

Вы можете использовать этот пакет для получения всех запросов, которые выполняются при загрузке вашей страницы.

https://github.com/barryvdh/laravel-debugbar

Ещё вопросы

Сообщество Overcoder
Наверх
Меню