在Laravel 4中记录SQL查询已经有几个问题。但是我已经尝试了几乎所有方法,但它仍然没有按照我想要的方式工作。
这是我的情况
- 在我的 php 视图文件中,我向服务器发出 AJAX 请求
接收 AJAX 请求并运行 RAW 参数化的 Postgres SQL 查询(例如
DB::select('select * from my_table where id=?', array(1((
如果我使用
Event::listen('illuminate.query', function($sql)
{
Log::error($sql);
});
我只是得到"从id=my_table中选择*?"作为日志消息,而没有实际填充ID值。
如果我使用
$queries = DB::getQueryLog();
$last_query = end($queries);
Log::error(print_r($last_query, true));
我仍然没有填充 ID 的最终 SQL 查询。
最后,如果我使用像 https://github.com/loic-sharma/profiler 这样的日志记录工具 - 它不会显示任何内容,因为我正在发出 AJAX 请求。
我用尽了我的选择吗?还有别的办法吗?
这是我目前用于记录 sql 查询的内容。您应该能够将其放入主路由文件中,然后将"log"=> true添加到数据库配置中。
if (Config::get('database.log', false))
{
Event::listen('illuminate.query', function($query, $bindings, $time, $name)
{
$data = compact('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'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
Log::info($query, $data);
});
}
感谢 Jeemusu 回答有关将绑定插入准备好的语句的一点。
您应该能够通过传递 $bindings
作为 Event 函数的第二个参数来找到绑定。
Event::listen('illuminate.query', function($sql, $bindings, $time){
echo $sql; // select * from my_table where id=?
print_r($bindings); // Array ( [0] => 4 )
echo $time; // 0.58
// To get the full sql query with bindings inserted
$sql = str_replace(array('%', '?'), array('%%', '%s'), $sql);
$full_sql = vsprintf($sql, $bindings);
});
在 Laravel 3.x 中,我认为事件侦听器被称为laravel.query
继续@Collin詹姆斯的回答。
如果您只想记录到 sql 的单独文件,则可以执行以下操作:
if (Config::get('database.log', false)) {
Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
$data = compact('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'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
$query = vsprintf($query, $bindings);
$log = new Logger('sql');
$log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Y-m-d') . '.log', Logger::INFO));
// add records to the log
$log->addInfo($query, $data);
});
}
在文件顶部显示以下内容:
use Monolog'Logger;
use Monolog'Handler'StreamHandler;
这会将您的所有查询记录到名为 sql-YYYY-mm-dd.log
in storage/logs/
的文件中。
虽然接受的答案是正确的,但这个答案解释了在使用jQuery发出Ajax请求时如何更新loic-sharma分析器。使用这种方法不需要读取文件日志。
步骤 1
第一个问题是在每个 Ajax 请求时将更新的探查器数据发送到客户端。这可以使用Laravel应用程序的"之后"事件来解决。
应用/过滤器.php:
App::after(function($request, $response)
{
// If it's a JsonResponse and the profiler is enabled, include it in the response.
if($response instanceof 'Illuminate'Http'JsonResponse && Profiler::isEnabled()) {
$profiler = Profiler::getFacadeRoot();
$profilerJson = json_encode($profiler->render());
$content = substr($response->getContent(), 0, -1) . ',"profiler":' . $profilerJson . '}';
$response->setContent($content);
}
});
App::after
过滤器将在每次Laravel请求时运行。上面闭包的第一行确保仅当响应类型为 JsonResponse 并且启用了探查器时,它才会继续。如果是这种情况,请呈现探查器并将 HTML 追加到 JSON 对象。
注意:此代码假定返回的 JSON 是一个对象。所以数组会失败:Response::json(array(1,2,3))
.
步骤 2
现在更新的探查器 HTML 已发送到客户端,我们必须使用 javascript 使用新的探查器 HTML 更新 DOM。每次客户端收到 JSON 响应时都应发生这种情况。jQuery提供了全局Ajax事件处理程序,这是实现这一目标的完美选择。
$(document).ajaxSuccess(function(event, request, settings) {
try {
json = jQuery.parseJSON(request.responseText);
if(json.profiler) {
renderProfiler(json.profiler);
}
} catch(error) {
// Its not JSON.
return;
}
});
下面是将旧探查器替换为新探查器的方法:
renderProfiler = function(data) {
// Remove previous
$anbu = $('.anbu');
$anbu.prev().remove(); // Removes <style> tag of profiler
$anbu.next().next().remove(); // Removes the inline script tag of profiler
$anbu.next().remove(); // Removes jQuery script tag by the profiler
$anbu.remove(); // Removes the <div> tag of profiler
$(document.body).append(data);
};
使用它
现在,它就像返回响应一样简单,如下所示:
return Response::json(array(
'user' => Auth::user()
));
Laravel将附加分析器HTML。javascript将捕获JSON响应并更新DOM。您将在网页上拥有SQL查询和计时。
注意
在测试代码时,可能会有一两个错误。这也不是我这样做的。我没有在 json 响应中发送 HTML,而是使用探查器中的实际数据扩展对象。在客户端,我使用胡须模板渲染分析器。
虽然这个问题最初是针对Laravel 4的,但我仍然通过谷歌来到这里,但我使用的是Laravel 5。
有新的方法可以使用中间件记录Laravel 5中的所有查询,但是如果您更喜欢相同的方法,这里是Collin James提供的相同代码,但适用于Laravel 5
if (Config::get('database.log', false))
{
Event::listen('Illuminate'Database'Events'QueryExecuted', function($query)
{
$bindings = $query->bindings;
$time = $query->time;
$name = $query->connection->getName();
$data = compact('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'";
}
}
// Insert bindings into query
$query = str_replace(array('%', '?'), array('%%', '%s'), $query->sql);
$query = vsprintf($query, $bindings);
Log::info($query, $data);
});
}
这就是我一直在使用的东西:
DB::listen(function ($query, $bindings, $time, $connection) {
$fullQuery = vsprintf(str_replace(array('%', '?'), array('%%', '%s'), $query), $bindings);
$result = $connection . ' (' . $time . '): ' . $fullQuery;
dump($result);
// You can of course log the $result
});