Laravel version update

Laravel version update
This commit is contained in:
Manish Verma
2018-08-06 18:48:58 +05:30
parent d143048413
commit 126fbb0255
13678 changed files with 1031482 additions and 778530 deletions

View File

@@ -11,7 +11,7 @@
],
"require": {
"php": ">=5.5.9",
"illuminate/support": "5.1.*|5.2.*|5.3.*",
"illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*",
"symfony/finder": "~2.7|~3.0",
"maximebf/debugbar": "~1.13.0"
},
@@ -22,10 +22,5 @@
"files": [
"src/helpers.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
}
}

View File

@@ -12,7 +12,7 @@ return [
|
*/
'enabled' => null,
'enabled' => env('DEBUGBAR_ENABLED', null),
/*
|--------------------------------------------------------------------------
@@ -58,10 +58,23 @@ return [
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
| you can use this option to disable sending the data through the headers.
|
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
*/
'capture_ajax' => true,
'add_ajax_timing' => false,
/*
|--------------------------------------------------------------------------
| Custom Error Handler for Deprecated warnings
|--------------------------------------------------------------------------
|
| When enabled, the Debugbar shows deprecated warnings for Symfony components
| in the Messages tab.
|
*/
'error_handler' => false,
/*
|--------------------------------------------------------------------------
| Clockwork integration
@@ -92,17 +105,17 @@ return [
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'auth' => true, // Display Laravel authentication status
'gate' => true, // Display Laravel Gate checks
'session' => true, // Display session data
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'laravel' => false, // Laravel version and environment
'events' => false, // All events fired
'default_request' => false, // Regular or special Symfony request logger
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'logs' => false, // Add the latest log messages
'files' => false, // Show the included files
'config' => false, // Display config settings
'auth' => false, // Display Laravel authentication status
'gate' => false, // Display Laravel Gate checks
'session' => true, // Display session data
],
/*
@@ -116,13 +129,13 @@ return [
'options' => [
'auth' => [
'show_name' => false, // Also show the users name/email in the debugbar
'show_name' => true, // Also show the users name/email in the debugbar
],
'db' => [
'with_params' => true, // Render SQL with the parameters substituted
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
'timeline' => false, // Add the queries to the timeline
'backtrace' => false, // EXPERIMENTAL: Use a backtrace to find the origin of the query in your files.
'explain' => [ // EXPERIMENTAL: Show EXPLAIN output on queries
'explain' => [ // Show EXPLAIN output on queries
'enabled' => false,
'types' => ['SELECT'], // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+
],
@@ -147,7 +160,7 @@ return [
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| Usually, the debugbar is added just before <body>, by listening to the
| Usually, the debugbar is added just before </body>, by listening to the
| Response after the App is done. If you disable this, you have to add them
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
@@ -167,4 +180,13 @@ return [
*/
'route_prefix' => '_debugbar',
/*
|--------------------------------------------------------------------------
| DebugBar route domain
|--------------------------------------------------------------------------
|
| By default DebugBar route served from the same domain that request served.
| To override default domain, specify it as a non-empty value.
*/
'route_domain' => null,
];

View File

@@ -48,6 +48,7 @@ composer require barryvdh/laravel-debugbar
```
After updating composer, add the ServiceProvider to the providers array in config/app.php
> If you use a catch-all/fallback route, make sure you load the Debugbar ServiceProvider before your own App ServiceProviders.
### Laravel 5.x:
@@ -116,7 +117,7 @@ Or log exceptions:
try {
throw new Exception('foobar');
} catch (Exception $e) {
Debugbar::addException($e);
Debugbar::addThrowable($e);
}
```

View File

@@ -19,9 +19,17 @@ class ClearCommand extends Command
public function fire()
{
$this->debugbar->boot();
if ($storage = $this->debugbar->getStorage()) {
$storage->clear();
try
{
$storage->clear();
} catch(\InvalidArgumentException $e) {
// hide InvalidArgumentException if storage location does not exist
if(strpos($e->getMessage(), 'does not exist') === false) {
throw $e;
}
}
$this->info('Debugbar Storage cleared!');
} else {
$this->error('No Debugbar Storage found..');

View File

@@ -21,13 +21,18 @@ class EventCollector extends TimeDataCollector
$this->exporter = new ValueExporter();
}
public function onWildcardEvent()
public function onWildcardEvent($name = null, $data = [])
{
$name = $this->events->firing();
$time = microtime(true);
// Pre-Laravel 5.4, using 'firing' to get the current event name.
if (method_exists($this->events, 'firing')) {
$name = $this->events->firing();
// Get the arguments passed to the event
$params = $this->prepareParams(func_get_args());
// Get the arguments passed to the event
$data = func_get_args();
}
$params = $this->prepareParams($data);
$time = microtime(true);
// Find all listeners for the current event
foreach ($this->events->getListeners($name) as $i => $listener) {

View File

@@ -5,18 +5,22 @@ namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\MessagesCollector;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Auth\Authenticatable;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
/**
* Collector for Laravel's Auth provider
*/
class GateCollector extends MessagesCollector
{
/** @var ValueExporter */
protected $exporter;
/**
* @param Gate $gate
*/
public function __construct(Gate $gate)
{
parent::__construct('gate');
$this->exporter = new ValueExporter();
if (method_exists($gate, 'after')) {
$gate->after([$this, 'addCheck']);
@@ -31,7 +35,7 @@ class GateCollector extends MessagesCollector
'ability' => $ability,
'result' => $result,
'user' => $user->getAuthIdentifier(),
'arguments' => $arguments,
'arguments' => $this->exporter->exportValue($arguments),
], $label, false);
}
}

View File

@@ -91,9 +91,7 @@ class IlluminateRouteCollector extends DataCollector implements Renderable
*/
protected function getMiddleware($route)
{
$middleware = array_keys($route->middleware());
return implode(', ', $middleware);
return implode(', ', $route->middleware());
}
/**

View File

@@ -2,6 +2,10 @@
namespace Barryvdh\Debugbar\DataCollector;
use Illuminate\Auth\SessionGuard;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\Str;
/**
* Collector for Laravel's Auth provider
*/
@@ -30,8 +34,14 @@ class MultiAuthCollector extends AuthCollector
$names = '';
foreach($this->guards as $guardName) {
$user = $this->auth->guard($guardName)->user();
try {
$user = $this->resolveUser($this->auth->guard($guardName));
} catch (\Exception $e) {
continue;
}
$data['guards'][$guardName] = $this->getUserInformation($user);
if(!is_null($user)) {
$names .= $guardName . ": " . $data['guards'][$guardName]['name'] . ', ';
}
@@ -47,7 +57,26 @@ class MultiAuthCollector extends AuthCollector
return $data;
}
private function resolveUser(Guard $guard)
{
// if we're logging in using remember token
// then we must resolve user „manually”
// to prevent csrf token regeneration
$recaller = $guard instanceof SessionGuard
? $guard->getRequest()->cookies->get($guard->getRecallerName())
: null;
if (is_string($recaller) && Str::contains($recaller, '|')) {
$segments = explode('|', $recaller);
if (count($segments) == 2 && trim($segments[0]) !== '' && trim($segments[1]) !== '') {
return $guard->getProvider()->retrieveByToken($segments[0], $segments[1]);
}
}
return $guard->user();
}
/**
* @{inheritDoc}
*/

View File

@@ -14,6 +14,7 @@ class QueryCollector extends PDOCollector
protected $queries = [];
protected $renderSqlWithParams = false;
protected $findSource = false;
protected $middleware = [];
protected $explainQuery = false;
protected $explainTypes = ['SELECT']; // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+
protected $showHints = false;
@@ -52,10 +53,12 @@ class QueryCollector extends PDOCollector
* Enable/disable finding the source
*
* @param bool $value
* @param array $middleware
*/
public function setFindSource($value = true)
public function setFindSource($value, array $middleware)
{
$this->findSource = (bool) $value;
$this->middleware = $middleware;
}
/**
@@ -97,7 +100,7 @@ class QueryCollector extends PDOCollector
$explainResults = $statement->fetchAll(\PDO::FETCH_CLASS);
}
$bindings = $this->checkBindings($bindings);
$bindings = $this->getDataFormatter()->checkBindings($bindings);
if (!empty($bindings) && $this->renderSqlWithParams) {
foreach ($bindings as $key => $binding) {
// This regex matches placeholders only, not the question marks,
@@ -110,7 +113,8 @@ class QueryCollector extends PDOCollector
}
}
$source = null;
$source = [];
if ($this->findSource) {
try {
$source = $this->findSource();
@@ -120,7 +124,8 @@ class QueryCollector extends PDOCollector
$this->queries[] = [
'query' => $query,
'bindings' => $this->escapeBindings($bindings),
'type' => 'query',
'bindings' => $this->getDataFormatter()->escapeBindings($bindings),
'time' => $time,
'source' => $source,
'explain' => $explainResults,
@@ -133,36 +138,6 @@ class QueryCollector extends PDOCollector
}
}
/**
* Check bindings for illegal (non UTF-8) strings, like Binary data.
*
* @param $bindings
* @return mixed
*/
protected function checkBindings($bindings)
{
foreach ($bindings as &$binding) {
if (is_string($binding) && !mb_check_encoding($binding, 'UTF-8')) {
$binding = '[BINARY DATA]';
}
}
return $bindings;
}
/**
* Make the bindings safe for outputting.
*
* @param array $bindings
* @return array
*/
protected function escapeBindings($bindings)
{
foreach ($bindings as &$binding) {
$binding = htmlentities($binding, ENT_QUOTES, 'UTF-8', false);
}
return $bindings;
}
/**
* Explainer::performQueryAnalysis()
*
@@ -200,39 +175,105 @@ class QueryCollector extends PDOCollector
$hints[] = 'An argument has a leading wildcard character: <code>' . $matches[1]. '</code>.
The predicate with this argument is not sargable and cannot use an index if one exists.';
}
return implode("<br />", $hints);
return $hints;
}
/**
* Use a backtrace to search for the origin of the query.
* Use a backtrace to search for the origins of the query.
*
* @return array
*/
protected function findSource()
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($traces as $trace) {
if (isset($trace['class']) && isset($trace['file']) && strpos(
$trace['file'],
DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR
) === false
) {
if (isset($trace['object']) && is_a($trace['object'], 'Twig_Template')) {
list($file, $line) = $this->getTwigInfo($trace);
} elseif (strpos($trace['file'], storage_path()) !== false) {
$hash = pathinfo($trace['file'], PATHINFO_FILENAME);
$line = isset($trace['line']) ? $trace['line'] : '?';
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
if ($name = $this->findViewFromHash($hash)) {
return 'view::' . $name . ':' . $line;
}
return 'view::' . $hash . ':' . $line;
} else {
$file = $trace['file'];
$line = isset($trace['line']) ? $trace['line'] : '?';
$sources = [];
foreach ($stack as $index => $trace) {
$sources[] = $this->parseTrace($index, $trace);
}
return array_filter($sources);
}
/**
* Parse a trace element from the backtrace stack.
*
* @param int $index
* @param array $trace
* @return object|bool
*/
protected function parseTrace($index, array $trace)
{
$frame = (object) [
'index' => $index,
'namespace' => null,
'name' => null,
'line' => isset($trace['line']) ? $trace['line'] : '?',
];
if (isset($trace['function']) && $trace['function'] == 'substituteBindings') {
$frame->name = 'Route binding';
return $frame;
}
if (isset($trace['class']) && isset($trace['file']) && strpos(
$trace['file'],
DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'laravel' . DIRECTORY_SEPARATOR . 'framework'
) === false && strpos(
$trace['file'],
DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'barryvdh' . DIRECTORY_SEPARATOR . 'laravel-debugbar'
) === false
) {
$file = $trace['file'];
if (isset($trace['object']) && is_a($trace['object'], 'Twig_Template')) {
list($file, $frame->line) = $this->getTwigInfo($trace);
} elseif (strpos($file, storage_path()) !== false) {
$hash = pathinfo($file, PATHINFO_FILENAME);
if (! $frame->name = $this->findViewFromHash($hash)) {
$frame->name = $hash;
}
return $this->normalizeFilename($file) . ':' . $line;
} elseif (isset($trace['function']) && $trace['function'] == 'Illuminate\Routing\{closure}') {
return 'Route binding';
$frame->namespace = 'view';
return $frame;
} elseif (strpos($file, 'Middleware') !== false) {
$frame->name = $this->findMiddlewareFromFile($file);
if ($frame->name) {
$frame->namespace = 'middleware';
} else {
$frame->name = $this->normalizeFilename($file);
}
return $frame;
}
$frame->name = $this->normalizeFilename($file);
return $frame;
}
return false;
}
/**
* Find the middleware alias from the file.
*
* @param string $file
* @return string|null
*/
protected function findMiddlewareFromFile($file)
{
$filename = pathinfo($file, PATHINFO_FILENAME);
foreach ($this->middleware as $alias => $class) {
if (strpos($class, $filename) !== false) {
return $alias;
}
}
}
@@ -298,6 +339,35 @@ class QueryCollector extends PDOCollector
return str_replace(base_path(), '', $path);
}
/**
* Collect a database transaction event.
* @param string $event
* @param \Illuminate\Database\Connection $connection
* @return array
*/
public function collectTransactionEvent($event, $connection)
{
$source = [];
if ($this->findSource) {
try {
$source = $this->findSource();
} catch (\Exception $e) {
}
}
$this->queries[] = [
'query' => $event,
'type' => 'transaction',
'bindings' => [],
'time' => 0,
'source' => $source,
'explain' => [],
'connection' => $connection->getDatabaseName(),
'hints' => null,
];
}
/**
* Reset the queries.
*/
@@ -318,17 +388,16 @@ class QueryCollector extends PDOCollector
foreach ($queries as $query) {
$totalTime += $query['time'];
$bindings = $query['bindings'];
if($query['hints']){
$bindings['hints'] = $query['hints'];
}
$statements[] = [
'sql' => $this->formatSql($query['query']),
'params' => (object) $bindings,
'sql' => $this->getDataFormatter()->formatSql($query['query']),
'type' => $query['type'],
'params' => [],
'bindings' => $query['bindings'],
'hints' => $query['hints'],
'backtrace' => array_values($query['source']),
'duration' => $query['time'],
'duration_str' => $this->formatDuration($query['time']),
'stmt_id' => $query['source'],
'duration_str' => ($query['type'] == 'transaction') ? '' : $this->formatDuration($query['time']),
'stmt_id' => $this->getDataFormatter()->formatSource(reset($query['source'])),
'connection' => $query['connection'],
];
@@ -336,6 +405,7 @@ class QueryCollector extends PDOCollector
foreach($query['explain'] as $explain){
$statements[] = [
'sql' => ' - EXPLAIN #' . $explain->id . ': `' . $explain->table . '` (' . $explain->select_type . ')',
'type' => 'explain',
'params' => $explain,
'row_count' => $explain->rows,
'stmt_id' => $explain->id,
@@ -343,8 +413,12 @@ class QueryCollector extends PDOCollector
}
}
$nb_statements = array_filter($queries, function ($query) {
return $query['type'] == 'query';
});
$data = [
'nb_statements' => count($queries),
'nb_statements' => count($nb_statements),
'nb_failed_statements' => 0,
'accumulated_duration' => $totalTime,
'accumulated_duration_str' => $this->formatDuration($totalTime),
@@ -353,17 +427,6 @@ class QueryCollector extends PDOCollector
return $data;
}
/**
* Removes extra spaces at the beginning and end of the SQL query and its lines.
*
* @param string $sql
* @return string
*/
protected function formatSql($sql)
{
return trim(preg_replace("/\s*\n\s*/", "\n", $sql));
}
/**
* {@inheritDoc}
*/
@@ -379,8 +442,8 @@ class QueryCollector extends PDOCollector
{
return [
"queries" => [
"icon" => "inbox",
"widget" => "PhpDebugBar.Widgets.SQLQueriesWidget",
"icon" => "database",
"widget" => "PhpDebugBar.Widgets.LaravelSQLQueriesWidget",
"map" => "queries",
"default" => "[]"
],

View File

@@ -8,13 +8,13 @@ use DebugBar\DataCollector\Renderable;
class SessionCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface|\Illuminate\Contracts\Session\Session $session */
protected $session;
/**
* Create a new SessionCollector
*
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface|\Illuminate\Contracts\Session\Session $session
*/
public function __construct($session)
{

View File

@@ -0,0 +1,76 @@
<?php
namespace Barryvdh\Debugbar\DataFormatter;
use DebugBar\DataFormatter\DataFormatter;
class QueryFormatter extends DataFormatter
{
/**
* Removes extra spaces at the beginning and end of the SQL query and its lines.
*
* @param string $sql
* @return string
*/
public function formatSql($sql)
{
return trim(preg_replace("/\s*\n\s*/", "\n", $sql));
}
/**
* Check bindings for illegal (non UTF-8) strings, like Binary data.
*
* @param $bindings
* @return mixed
*/
public function checkBindings($bindings)
{
foreach ($bindings as &$binding) {
if (is_string($binding) && !mb_check_encoding($binding, 'UTF-8')) {
$binding = '[BINARY DATA]';
}
}
return $bindings;
}
/**
* Make the bindings safe for outputting.
*
* @param array $bindings
* @return array
*/
public function escapeBindings($bindings)
{
foreach ($bindings as &$binding) {
$binding = htmlentities($binding, ENT_QUOTES, 'UTF-8', false);
}
return $bindings;
}
/**
* Format a source object.
*
* @param object|null $source If the backtrace is disabled, the $source will be null.
* @return string
*/
public function formatSource($source)
{
if (! is_object($source)) {
return '';
}
$parts = [];
if ($source->namespace) {
$parts['namespace'] = $source->namespace . '::';
}
$parts['name'] = $source->name;
$parts['line'] = ':' . $source->line;
return implode($parts);
}
}

View File

@@ -19,6 +19,7 @@ class JavascriptRenderer extends BaseJavascriptRenderer
$this->cssFiles['laravel'] = __DIR__ . '/Resources/laravel-debugbar.css';
$this->cssVendors['fontawesome'] = __DIR__ . '/Resources/vendor/font-awesome/style.css';
$this->jsFiles['laravel-sql'] = __DIR__ . '/Resources/sqlqueries/widget.js';
}
/**
@@ -43,7 +44,10 @@ class JavascriptRenderer extends BaseJavascriptRenderer
$jsRoute = route('debugbar.assets.js', [
'v' => $this->getModifiedTime('js')
]);
]);
$cssRoute = preg_replace('/\Ahttps?:/', '', $cssRoute);
$jsRoute = preg_replace('/\Ahttps?:/', '', $jsRoute);
$html = "<link rel='stylesheet' type='text/css' property='stylesheet' href='{$cssRoute}'>";
$html .= "<script type='text/javascript' src='{$jsRoute}'></script>";

View File

@@ -22,6 +22,7 @@ use DebugBar\DataCollector\MessagesCollector;
use DebugBar\DataCollector\PhpInfoCollector;
use DebugBar\DataCollector\RequestDataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use Barryvdh\Debugbar\DataFormatter\QueryFormatter;
use Barryvdh\Debugbar\Support\Clockwork\ClockworkCollector;
use DebugBar\DebugBar;
use DebugBar\Storage\PdoStorage;
@@ -123,6 +124,11 @@ class LaravelDebugbar extends DebugBar
/** @var Application $app */
$app = $this->app;
// Set custom error handler
if ($app['config']->get('debugbar.error_handler' , false)) {
set_error_handler([$this, 'handleError']);
}
$this->selectStorage($debugbar);
@@ -198,7 +204,10 @@ class LaravelDebugbar extends DebugBar
$this->addCollector(new ViewCollector($collectData));
$this->app['events']->listen(
'composing:*',
function ($view) use ($debugbar) {
function ($view, $data = []) use ($debugbar) {
if ($data) {
$view = $data[0]; // For Laravel >= 5.4
}
$debugbar['views']->addView($view);
}
);
@@ -231,7 +240,16 @@ class LaravelDebugbar extends DebugBar
$logger = new MessagesCollector('log');
$this['messages']->aggregate($logger);
$this->app['log']->listen(
function ($level, $message, $context) use ($logger) {
function ($level, $message = null, $context = null) use ($logger) {
// Laravel 5.4 changed how the global log listeners are called. We must account for
// the first argument being an "event object", where arguments are passed
// via object properties, instead of individual arguments.
if ($level instanceof \Illuminate\Log\Events\MessageLogged) {
$message = $level->message;
$context = $level->context;
$level = $level->level;
}
try {
$logMessage = (string) $message;
if (mb_check_encoding($logMessage, 'UTF-8')) {
@@ -274,12 +292,15 @@ class LaravelDebugbar extends DebugBar
}
$queryCollector = new QueryCollector($timeCollector);
$queryCollector->setDataFormatter(new QueryFormatter());
if ($this->app['config']->get('debugbar.options.db.with_params')) {
$queryCollector->setRenderSqlWithParams(true);
}
if ($this->app['config']->get('debugbar.options.db.backtrace')) {
$queryCollector->setFindSource(true);
$middleware = ! $this->is_lumen ? $this->app['router']->getMiddleware() : [];
$queryCollector->setFindSource(true, $middleware);
}
if ($this->app['config']->get('debugbar.options.db.explain.enabled')) {
@@ -321,6 +342,61 @@ class LaravelDebugbar extends DebugBar
)
);
}
try {
$db->getEventDispatcher()->listen([
\Illuminate\Database\Events\TransactionBeginning::class,
'connection.*.beganTransaction',
], function ($transaction) use ($queryCollector) {
// Laravel 5.2 changed the way some core events worked. We must account for
// the first argument being an "event object", where arguments are passed
// via object properties, instead of individual arguments.
if($transaction instanceof \Illuminate\Database\Events\TransactionBeginning) {
$connection = $transaction->connection;
} else {
$connection = $transaction;
}
$queryCollector->collectTransactionEvent('Begin Transaction', $connection);
});
$db->getEventDispatcher()->listen([
\Illuminate\Database\Events\TransactionCommitted::class,
'connection.*.committed',
], function ($transaction) use ($queryCollector) {
if($transaction instanceof \Illuminate\Database\Events\TransactionCommitted) {
$connection = $transaction->connection;
} else {
$connection = $transaction;
}
$queryCollector->collectTransactionEvent('Commit Transaction', $connection);
});
$db->getEventDispatcher()->listen([
\Illuminate\Database\Events\TransactionRolledBack::class,
'connection.*.rollingBack',
], function ($transaction) use ($queryCollector) {
if($transaction instanceof \Illuminate\Database\Events\TransactionRolledBack) {
$connection = $transaction->connection;
} else {
$connection = $transaction;
}
$queryCollector->collectTransactionEvent('Rollback Transaction', $connection);
});
} catch (\Exception $e) {
$this->addThrowable(
new Exception(
'Cannot add listen transactions to Queries for Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->shouldCollect('mail', true) && class_exists('Illuminate\Mail\MailServiceProvider')) {
@@ -402,6 +478,25 @@ class LaravelDebugbar extends DebugBar
return $this->app['config']->get('debugbar.collectors.' . $name, $default);
}
/**
* Handle silenced errors
*
* @param $level
* @param $message
* @param string $file
* @param int $line
* @param array $context
* @throws \ErrorException
*/
public function handleError($level, $message, $file = '', $line = 0, $context = [])
{
if (error_reporting() & $level) {
throw new \ErrorException($message, 0, $level, $file, $line);
} else {
$this->addMessage($message, 'deprecation');
}
}
/**
* Starts a measure
*
@@ -577,6 +672,11 @@ class LaravelDebugbar extends DebugBar
) {
try {
$this->sendDataInHeaders(true);
if ($app['config']->get('debugbar.add_ajax_timing', false)) {
$this->addServerTimingHeaders($response);
}
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
@@ -584,6 +684,7 @@ class LaravelDebugbar extends DebugBar
($response->headers->has('Content-Type') &&
strpos($response->headers->get('Content-Type'), 'html') === false)
|| $request->getRequestFormat() !== 'html'
|| $response->getContent() === false
) {
try {
// Just collect + store data, don't inject it.
@@ -599,6 +700,8 @@ class LaravelDebugbar extends DebugBar
}
}
return $response;
}
@@ -866,7 +969,11 @@ class LaravelDebugbar extends DebugBar
break;
case 'redis':
$connection = $config->get('debugbar.storage.connection');
$storage = new RedisStorage($this->app['redis']->connection($connection));
$client = $this->app['redis']->connection($connection);
if (is_a($client, 'Illuminate\Redis\Connections\PredisConnection', false)) {
$client = $client->client();
}
$storage = new RedisStorage($client);
break;
case 'custom':
$class = $config->get('debugbar.storage.provider');
@@ -890,4 +997,24 @@ class LaravelDebugbar extends DebugBar
$response->headers->set('X-Clockwork-Version', 1, true);
$response->headers->set('X-Clockwork-Path', $prefix .'/clockwork/', true);
}
/**
* Add Server-Timing headers for the TimeData collector
*
* @see https://www.w3.org/TR/server-timing/
* @param Response $response
*/
protected function addServerTimingHeaders(Response $response)
{
if ($this->hasCollector('time')) {
$collector = $this->getCollector('time');
$headers = [];
foreach ($collector->collect()['measures'] as $k => $m) {
$headers[] = sprintf('%d=%F; "%s"', $k, $m['duration'], str_replace('"', "'", $m['label']));
}
$response->headers->set('Server-Timing', $headers, false);
}
}
}

View File

@@ -1,6 +1,8 @@
div.phpdebugbar {
font-size: 13px;
font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
direction: ltr;
text-align: left;
}
div.phpdebugbar-resize-handle {
@@ -198,25 +200,40 @@ ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item {
font-family: inherit;
overflow: visible;
display: flex;
flex-wrap: wrap;
}
.phpdebugbar-widgets-sql.phpdebugbar-widgets-name {
font-weight: bold;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-sql {
flex: 1 1 auto;
flex: 1;
margin-right: 5px;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-duration {
flex: 0 0 auto;
/*flex: 0 0 auto;*/
margin-left: auto;
margin-right: 5px;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-database {
flex: 0 0 auto;
/*flex: 0 0 auto;*/
margin-left: auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-stmt-id {
/*flex: 0 0 auto;*/
margin-left: auto;
margin-right: 5px;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-params {
background-color: rgba(255, 255, 255, .5);
flex: 1 1 auto;
order: -1;
width: auto;
max-width: 200px;
margin: 10px 100% 10px 0;
max-width: 100%;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(even) {
@@ -241,8 +258,39 @@ div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugb
color: #f1c40f;
}
div.phpdebugbar-widgets-sqlqueries {
line-height: 20px;
}
div.phpdebugbar-widgets-sqlqueries .phpdebugbar-widgets-status {
background: none !important;
font-family: inherit !important;
font-weight: 400 !important;
}
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params th,
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td {
padding: 5px 10px;
}
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-name {
text-align: right;
vertical-align: top;
white-space: nowrap;
}
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td.phpdebugbar-widgets-value {
text-align: left;
}
ul.phpdebugbar-widgets-list ul.phpdebugbar-widgets-table-list {
text-align: left;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-table-list-item {
/*padding: 5px 10px;*/
}
.phpdebugbar-text-muted {
color: #888;
}

View File

@@ -0,0 +1,225 @@
(function($) {
var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-');
/**
* Widget for the displaying sql queries
*
* Options:
* - data
*/
var LaravelSQLQueriesWidget = PhpDebugBar.Widgets.LaravelSQLQueriesWidget = PhpDebugBar.Widget.extend({
className: csscls('sqlqueries'),
onFilterClick: function(el) {
$(el).toggleClass(csscls('excluded'));
var excludedLabels = [];
this.$toolbar.find(csscls('.filter') + csscls('.excluded')).each(function() {
excludedLabels.push(this.rel);
});
this.$list.$el.find("li[connection=" + $(el).attr("rel") + "]").toggle();
this.set('exclude', excludedLabels);
},
render: function() {
this.$status = $('<div />').addClass(csscls('status')).appendTo(this.$el);
this.$toolbar = $('<div></div>').addClass(csscls('toolbar')).appendTo(this.$el);
var filters = [], self = this;
this.$list = new PhpDebugBar.Widgets.ListWidget({ itemRenderer: function(li, stmt) {
if (stmt.type === 'transaction') {
$('<strong />').addClass(csscls('sql')).addClass(csscls('name')).text(stmt.sql).appendTo(li);
} else {
$('<code />').addClass(csscls('sql')).html(PhpDebugBar.Widgets.highlight(stmt.sql, 'sql')).appendTo(li);
}
if (stmt.duration_str) {
$('<span title="Duration" />').addClass(csscls('duration')).text(stmt.duration_str).appendTo(li);
}
if (stmt.memory_str) {
$('<span title="Memory usage" />').addClass(csscls('memory')).text(stmt.memory_str).appendTo(li);
}
if (typeof(stmt.row_count) != 'undefined') {
$('<span title="Row count" />').addClass(csscls('row-count')).text(stmt.row_count).appendTo(li);
}
if (typeof(stmt.stmt_id) != 'undefined' && stmt.stmt_id) {
$('<span title="Prepared statement ID" />').addClass(csscls('stmt-id')).text(stmt.stmt_id).appendTo(li);
}
if (stmt.connection) {
$('<span title="Connection" />').addClass(csscls('database')).text(stmt.connection).appendTo(li);
li.attr("connection",stmt.connection);
if ( $.inArray(stmt.connection, filters) == -1 ) {
filters.push(stmt.connection);
$('<a />')
.addClass(csscls('filter'))
.text(stmt.connection)
.attr('rel', stmt.connection)
.on('click', function() { self.onFilterClick(this); })
.appendTo(self.$toolbar);
if (filters.length>1) {
self.$toolbar.show();
self.$list.$el.css("margin-bottom","20px");
}
}
}
if (typeof(stmt.is_success) != 'undefined' && !stmt.is_success) {
li.addClass(csscls('error'));
li.append($('<span />').addClass(csscls('error')).text("[" + stmt.error_code + "] " + stmt.error_message));
}
var table = $('<table><tr><th colspan="2">Metadata</th></tr></table>').addClass(csscls('params')).appendTo(li);
if (stmt.bindings && stmt.bindings.length) {
table.append(function () {
var icon = 'thumb-tack';
var $icon = '<i class="phpdebugbar-fa phpdebugbar-fa-' + icon + ' phpdebugbar-text-muted"></i>';
var $name = $('<td />').addClass(csscls('name')).html('Bindings ' + $icon);
var $value = $('<td />').addClass(csscls('value'));
var $span = $('<span />').addClass('phpdebugbar-text-muted');
var index = 0;
var $bindings = new PhpDebugBar.Widgets.ListWidget({ itemRenderer: function(li, binding) {
var $index = $span.clone().text(index++ + '.');
li.append($index, '&nbsp;', binding).removeClass(csscls('list-item')).addClass(csscls('table-list-item'));
}});
$bindings.set('data', stmt.bindings);
$bindings.$el
.removeClass(csscls('list'))
.addClass(csscls('table-list'))
.appendTo($value);
return $('<tr />').append($name, $value);
});
}
if (stmt.hints && stmt.hints.length) {
table.append(function () {
var icon = 'question-circle';
var $icon = '<i class="phpdebugbar-fa phpdebugbar-fa-' + icon + ' phpdebugbar-text-muted"></i>';
var $name = $('<td />').addClass(csscls('name')).html('Hints ' + $icon);
var $value = $('<td />').addClass(csscls('value'));
var $hints = new PhpDebugBar.Widgets.ListWidget({ itemRenderer: function(li, hint) {
li.append(hint).removeClass(csscls('list-item')).addClass(csscls('table-list-item'));
}});
$hints.set('data', stmt.hints);
$hints.$el
.removeClass(csscls('list'))
.addClass(csscls('table-list'))
.appendTo($value);
return $('<tr />').append($name, $value);
});
}
if (stmt.backtrace && stmt.backtrace.length) {
table.append(function () {
var icon = 'list-ul';
var $icon = '<i class="phpdebugbar-fa phpdebugbar-fa-' + icon + ' phpdebugbar-text-muted"></i>';
var $name = $('<td />').addClass(csscls('name')).html('Backtrace ' + $icon);
var $value = $('<td />').addClass(csscls('value'));
var $span = $('<span />').addClass('phpdebugbar-text-muted');
var $backtrace = new PhpDebugBar.Widgets.ListWidget({ itemRenderer: function(li, source) {
var $parts = [
$span.clone().text(source.index + '.'),
'&nbsp;',
];
if (source.namespace) {
$parts.push(source.namespace + '::');
}
$parts.push(source.name);
$parts.push($span.clone().text(':' + source.line));
li.append($parts).removeClass(csscls('list-item')).addClass(csscls('table-list-item'));
}});
$backtrace.set('data', stmt.backtrace);
$backtrace.$el
.removeClass(csscls('list'))
.addClass(csscls('table-list'))
.appendTo($value);
return $('<tr />').append($name, $value);
});
}
if (stmt.params && !$.isEmptyObject(stmt.params)) {
for (var key in stmt.params) {
if (typeof stmt.params[key] !== 'function') {
table.append('<tr><td class="' + csscls('name') + '">' + key + '</td><td class="' + csscls('value') +
'">' + stmt.params[key] + '</td></tr>');
}
}
}
li.css('cursor', 'pointer').click(function() {
if (table.is(':visible')) {
table.hide();
} else {
table.show();
}
});
}});
this.$list.$el.appendTo(this.$el);
this.bindAttr('data', function(data) {
this.$list.set('data', data.statements);
this.$status.empty();
var stmt;
// Search for duplicate statements.
for (var sql = {}, duplicate = 0, i = 0; i < data.statements.length; i++) {
if(data.statements[i].type === 'query') {
stmt = data.statements[i].sql;
if (data.statements[i].bindings && data.statements[i].bindings.length) {
stmt += JSON.stringify(data.statements[i].bindings);
}
sql[stmt] = sql[stmt] || { keys: [] };
sql[stmt].keys.push(i);
}
}
// Add classes to all duplicate SQL statements.
for (stmt in sql) {
if (sql[stmt].keys.length > 1) {
duplicate += sql[stmt].keys.length;
for (i = 0; i < sql[stmt].keys.length; i++) {
this.$list.$el.find('.' + csscls('list-item')).eq(sql[stmt].keys[i])
.addClass(csscls('sql-duplicate'))
.addClass(csscls('sql-duplicate-'+duplicate));
}
}
}
var t = $('<span />').text(data.nb_statements + " statements were executed").appendTo(this.$status);
if (data.nb_failed_statements) {
t.append(", " + data.nb_failed_statements + " of which failed");
}
if (duplicate) {
t.append(", " + duplicate + " of which were duplicated");
t.append(", " + (data.nb_statements - duplicate) + " unique");
}
if (data.accumulated_duration_str) {
this.$status.append($('<span title="Accumulated duration" />').addClass(csscls('duration')).text(data.accumulated_duration_str));
}
if (data.memory_usage_str) {
this.$status.append($('<span title="Memory usage" />').addClass(csscls('memory')).text(data.memory_usage_str));
}
});
}
});
})(PhpDebugBar.$);

View File

@@ -42,7 +42,7 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider
$this->app->alias('debugbar', 'Barryvdh\Debugbar\LaravelDebugbar');
$this->app['command.debugbar.clear'] = $this->app->share(
$this->app->singleton('command.debugbar.clear',
function ($app) {
return new Console\ClearCommand($app['debugbar']);
}
@@ -77,6 +77,7 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider
$routeConfig = [
'namespace' => 'Barryvdh\Debugbar\Controllers',
'prefix' => $this->app['config']->get('debugbar.route_prefix'),
'domain' => $this->app['config']->get('debugbar.route_domain'),
];
$this->getRouter()->group($routeConfig, function($router) {

View File

@@ -11,7 +11,7 @@ use Symfony\Component\HttpFoundation\Session\Session;
*/
class SymfonyHttpDriver implements HttpDriverInterface
{
/** @var \Symfony\Component\HttpFoundation\Session\Session */
/** @var \Symfony\Component\HttpFoundation\Session\Session|\Illuminate\Contracts\Session\Session|\Illuminate\Session\SessionManager */
protected $session;
/** @var \Symfony\Component\HttpFoundation\Response */
protected $response;
@@ -48,6 +48,13 @@ class SymfonyHttpDriver implements HttpDriverInterface
*/
public function setSessionValue($name, $value)
{
// In Laravel 5.4 the session changed to use their own custom implementation
// instead of the one from Symfony. One of the changes was the set method
// that was changed to put. Here we check if we are using the new one.
if (method_exists($this->session, 'driver') && $this->session->driver() instanceof \Illuminate\Contracts\Session\Session) {
$this->session->put($name, $value);
return;
}
$this->session->set($name, $value);
}