Учитывая следующий код:
DB::table('users')->get();
Я хочу получить строку исходного SQL-запроса, которую построил бы построитель запросов, поэтому в этом примере это будут пользователи SELECT * FROM users
.
Как мне это сделать?
Чтобы вывести на экран последние запущенные запросы, вы можете использовать это
dd(DB::getQueryLog());
Я считаю, что самые последние запросы будут в нижней части массива.
У вас будет что-то вроде этого:
array(1) { [0]=> array(3) { ["query"]=> string(21) "select * from "users"" ["bindings"]=> array(0) { } ["time"]=> string(4) "0.92" } }
Согласно комментарию Джошуа ниже, теперь это отключено по умолчанию. Чтобы использовать его, вам необходимо включить его вручную, используя:
DB::enableQueryLog();
Используйте метод toSql()
в экземпляре QueryBuilder
.
DB::table('users')->toSql()
вернет:
выберите * из `users`
Это проще, чем подключение прослушивателя событий, а также позволяет проверить, как будет выглядеть запрос в любой момент, пока вы его создаете.
Вы можете прослушать событие «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" }
Если вы пытаетесь получить журнал с использованием 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 Manager, захватите экземпляр соединения и вызовите метод enableQueryLog
$capsule::connection()->enableQueryLog();
ИЗМЕНИТЬ СНОВА
Принимая во внимание фактический вопрос, вы могли бы сделать следующее, чтобы преобразовать текущий одиночный запрос, а не все предыдущие запросы:
$sql = $query->toSql(); $bindings = $query->getBindings();
Для получения строки запроса существует красноречивый метод.
toSql ()
в нашем случае,
DB::table('users')->toSql();
вернуть
select * from users
это точное решение, возвращающее строку запроса SQL. Надеюсь, что это полезно …
Если вы используете 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 \ красноречивый \ Builder
Осветить \ Database \ красноречивый \ Отношения \ HasMany
Осветить \ Database \ Query \ Builder
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();
Просто вы можете сделать следующее, используя toSql()
,
$query = DB::table('users')->get(); echo $query->toSql();
Если он не работает, вы можете настроить это из документации laravel .
Другой способ сделать это
DB::getQueryLog()
но если он возвращает пустой массив, то по умолчанию он отключен,
просто включите с помощью DB::enableQueryLog()
и он будет работать 🙂
для получения дополнительной информации посетите Github Issue, чтобы узнать больше об этом.
Надеюсь, поможет 🙂
$data = User::toSql(); echo $data; //this will retrun select * from users. //here User is model
Это функция, которую я поместил в базовый класс. Просто передайте объект построителя запроса в него, и строка 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; }
Если вы не используете 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('\'Ymd 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);
От laravel 5.2
и далее. вы можете использовать DB::listen
для выполнения исполняемых запросов.
DB::listen(function ($query) { // $query->sql // $query->bindings // $query->time });
Или, если вы хотите отладить один экземпляр Builder
вы можете использовать метод toSql
.
DB::table('posts')->toSql();
Для 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() { // } }
Источник
DB::enableQueryLog(); $queries = DB::getQueryLog();
вы можете использовать часовой механизм
Clockwork – это расширение Chrome для разработки PHP, расширяющее инструменты для разработчиков с новой панелью, предоставляющей всю информацию, полезную для отладки и профилирования ваших приложений PHP, включая информацию о запросе, заголовках, получаемых и отправляемых данных, куки, данные сеанса, запросы к базе данных, маршрутов, визуализации времени выполнения приложения и т. д.
но работает также в firefox
Вы можете использовать этот пакет для получения всех запросов, которые выполняются при загрузке вашей страницы
https://github.com/barryvdh/laravel-debugbar
Я создал несколько простых функций, чтобы получить 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 ], // ]
Вот решение, которое я использую:
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]); });
Пожалуйста, прочитайте комментарии в коде. Я знаю, это не идеально, но для моей повседневной отладки это нормально. Он пытается построить связанный запрос с большей или меньшей степенью надежности. Однако, не доверяйте этому полностью, двигатели базы данных избегают значений по-разному, которые эта короткая функция не реализует. Итак, внимательно прочтите результат.
композитор требует «barryvdh / laravel-debugbar»: «2.3. *"
вот увидишь