update v1.0.7.9 R.C.

This is a Release Candidate. We are still testing.
This commit is contained in:
Sujit Prasad
2016-08-03 20:04:36 +05:30
parent 8b6b924d09
commit ffa56a43cb
3830 changed files with 181529 additions and 495353 deletions

View File

@@ -0,0 +1,4 @@
/vendor
composer.phar
composer.lock
.DS_Store

View File

@@ -0,0 +1,19 @@
Copyright (C) 2013-2014 Barry vd. Heuvel
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,86 @@
# Changelog for Laravel Debugbar
## 1.8.4 (2014-10-31)
- Add Redis/PDO storage options
## 1.8.3 (2014-11-23)
- Base EventCollector on TimeData Collector
## 1.8.2 (2014-11-18)
- Use XHR handler instead of jQuery handler
## 1.8.1 (2014-11-14)
- Fix compatability with Symfony 2.3 (Laravel 4.)
## 1.8.0 (2014-10-31)
- Fix L5 compatability
- add hints + explain options to QueryLogger
- update to Debugbar 1.10.x
- new ViewCollector layout with more information
## 1.7.7 (2014-09-15)
- Make it compatible with Laravel 5.0-dev
- Allow anonymous function as `enabled` setting (for IP checks etc)
- Escape query bindings, to prevent executing of scripts/html
## 1.7.6 (2014-09-12)
- Fix reflash bug
- Fix caching of debugbar assets
## 1.7.5 (2014-09-12)
- Reflash data for all debugbar requests
## 1.7.4 (2014-09-08)
- Rename assets routes to prevent Nginx conflicts
## 1.7.3 (2014-09-05)
- Add helper functions (debug(), add/start/stop_measure() and measure()
- Collect data on responses that are not redirect/ajax/html also.
## 1.7.2 (2014-09-04)
- Fix 4.0 compatibility (problem with Controller namespace)
- Give deprecation notice instead of publishing assets.
## 1.7.1 (2014-09-03)
- Deprecated `debugbar:publish` command in favor of AssetController
- Fixed issue with detecting absolute paths in Windows
## 1.7.0 (2014-09-03)
- Use AssetController instead of publishing assets to the public folder.
- Inline fonts + images to base64 Data-URI
- Use PSR-4 file structure
## 1.6.8 (2014-08-27)
- Change OpenHandler layout
- Add backtrace option for query origin
## 1.6.7 (2014-08-09)
- Add Twig extensions for better integration with rcrowe/TwigBridge
## 1.6.6 (2014-07-08)
- Check if Requests wantsJSON instead of only isXmlHttpRequest
- Make sure closure for timing is run, even when disabled
## 1.6.5 (2014-06-24)
- Add Laravel style
## 1.6.4 (2014-06-15)
- Work on non-UTF-8 handling

View File

@@ -0,0 +1,31 @@
{
"name": "barryvdh/laravel-debugbar",
"description": "PHP Debugbar integration for Laravel",
"keywords": ["laravel", "debugbar", "profiler", "debug", "webprofiler"],
"license": "MIT",
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/support": "5.1.*|5.2.*",
"symfony/finder": "~2.7|~3.0",
"maximebf/debugbar": "~1.11.0"
},
"autoload": {
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Debugbar Settings
|--------------------------------------------------------------------------
|
| Debugbar is enabled by default, when debug is set to true in app.php.
| You can override the value by setting enable to true or false instead of null.
|
*/
'enabled' => null,
/*
|--------------------------------------------------------------------------
| Storage settings
|--------------------------------------------------------------------------
|
| DebugBar stores data for session/ajax requests.
| You can disable this, so the debugbar stores data in headers/session,
| but this can cause problems with large data collectors.
| By default, file storage (in the storage folder) is used. Redis and PDO
| can also be used. For PDO, run the package migrations first.
|
*/
'storage' => array(
'enabled' => true,
'driver' => 'file', // redis, file, pdo, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '' // Instance of StorageInterface for custom driver
),
/*
|--------------------------------------------------------------------------
| Vendors
|--------------------------------------------------------------------------
|
| Vendor files are included by default, but can be set to false.
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
| and for js: jquery and and highlight.js
| So if you want syntax highlighting, set it to true.
| jQuery is set to not conflict with existing jQuery scripts.
|
*/
'include_vendors' => true,
/*
|--------------------------------------------------------------------------
| Capture Ajax Requests
|--------------------------------------------------------------------------
|
| 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.
|
*/
'capture_ajax' => true,
/*
|--------------------------------------------------------------------------
| Clockwork integration
|--------------------------------------------------------------------------
|
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
*/
'clockwork' => false,
/*
|--------------------------------------------------------------------------
| DataCollectors
|--------------------------------------------------------------------------
|
| Enable/disable DataCollectors
|
*/
'collectors' => array(
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
'memory' => true, // Memory usage
'exceptions' => true, // Exception displayer
'log' => true, // Logs from Monolog (merged in messages if enabled)
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'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
),
/*
|--------------------------------------------------------------------------
| Extra options
|--------------------------------------------------------------------------
|
| Configure some DataCollectors
|
*/
'options' => array(
'auth' => array(
'show_name' => false, // Also show the users name/email in the debugbar
),
'db' => array(
'with_params' => true, // Render SQL with the parameters substituted
'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' => array( // EXPERIMENTAL: Show EXPLAIN output on queries
'enabled' => false,
'types' => array('SELECT'), // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
),
'hints' => true, // Show hints for common mistakes
),
'mail' => array(
'full_log' => false
),
'views' => array(
'data' => false, //Note: Can slow down the application, because the data can be quite large..
),
'route' => array(
'label' => true // show complete route on bar
),
'logs' => array(
'file' => null
),
),
/*
|--------------------------------------------------------------------------
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| 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
|
*/
'inject' => true,
/*
|--------------------------------------------------------------------------
| DebugBar route prefix
|--------------------------------------------------------------------------
|
| Sometimes you want to set route prefix to be used by DebugBar to load
| its resources from. Usually the need comes from misconfigured web server or
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
*/
'route_prefix' => '_debugbar',
);

View File

@@ -0,0 +1,194 @@
## Laravel Debugbar
[![Packagist License](https://poser.pugx.org/barryvdh/laravel-debugbar/license.png)](http://choosealicense.com/licenses/mit/)
[![Latest Stable Version](https://poser.pugx.org/barryvdh/laravel-debugbar/version.png)](https://packagist.org/packages/barryvdh/laravel-debugbar)
[![Total Downloads](https://poser.pugx.org/barryvdh/laravel-debugbar/d/total.png)](https://packagist.org/packages/barryvdh/laravel-debugbar)
### For Laravel 4, please use the [1.8 branch](https://github.com/barryvdh/laravel-debugbar/tree/1.8)!
This is a package to integrate [PHP Debug Bar](http://phpdebugbar.com/) with Laravel 5.
It includes a ServiceProvider to register the debugbar and attach it to the output. You can publish assets and configure it through Laravel.
It bootstraps some Collectors to work with Laravel and implements a couple custom DataCollectors, specific for Laravel.
It is configured to display Redirects and (jQuery) Ajax Requests. (Shown in a dropdown)
Read [the documentation](http://phpdebugbar.com/docs/) for more configuration options.
![Screenshot](https://cloud.githubusercontent.com/assets/973269/4270452/740c8c8c-3ccb-11e4-8d9a-5a9e64f19351.png)
Note: Use the DebugBar only in development. It can slow the application down (because it has to gather data). So when experiencing slowness, try disabling some of the collectors.
This package includes some custom collectors:
- QueryCollector: Show all queries, including binding + timing
- RouteCollector: Show information about the current Route.
- ViewCollector: Show the currently loaded views. (Optionally: display the shared data)
- EventsCollector: Show all events
- LaravelCollector: Show the Laravel version and Environment. (disabled by default)
- SymfonyRequestCollector: replaces the RequestCollector with more information about the request/response
- LogsCollector: Show the latest log entries from the storage logs. (disabled by default)
- FilesCollector: Show the files that are included/required by PHP. (disabled by default)
- ConfigCollector: Display the values from the config files. (disabled by default)
Bootstraps the following collectors for Laravel:
- LogCollector: Show all Log messages
- SwiftMailCollector and SwiftLogCollector for Mail
And the default collectors:
- PhpInfoCollector
- MessagesCollector
- TimeDataCollector (With Booting and Application timing)
- MemoryCollector
- ExceptionsCollector
It also provides a Facade interface for easy logging Messages, Exceptions and Time
## Installation
Require this package with composer:
```
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:
```
Barryvdh\Debugbar\ServiceProvider::class,
```
If you want to use the facade to log messages, add this to your facades in app.php:
```
'Debugbar' => Barryvdh\Debugbar\Facade::class,
```
The profiler is enabled by default, if you have app.debug=true. You can override that in the config (`debugbar.enabled`). See more options in `config/debugbar.php`
You can also set in your config if you want to include/exclude the vendor files also (FontAwesome, Highlight.js and jQuery). If you already use them in your site, set it to false.
You can also only display the js of css vendors, by setting it to 'js' or 'css'. (Highlight.js requires both css + js, so set to `true` for syntax highlighting)
Copy the package config to your local config with the publish command:
```
php artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider"
```
### Lumen:
For Lumen, register a different Provider in `bootstrap/app.php`:
```
if (env('APP_DEBUG')) {
$app->register(Barryvdh\Debugbar\LumenServiceProvider::class);
}
```
To change the configuration, copy the file to your config folder and enable it:
```
$app->configure('debugbar');
```
## Usage
You can now add messages using the Facade (when added), using the PSR-3 levels (debug, info, notice, warning, error, critical, alert, emergency):
```php
Debugbar::info($object);
Debugbar::error('Error!');
Debugbar::warning('Watch out…');
Debugbar::addMessage('Another message', 'mylabel');
```
And start/stop timing:
```php
Debugbar::startMeasure('render','Time for rendering');
Debugbar::stopMeasure('render');
Debugbar::addMeasure('now', LARAVEL_START, microtime(true));
Debugbar::measure('My long operation', function() {
// Do something…
});
```
Or log exceptions:
```php
try {
throw new Exception('foobar');
} catch (Exception $e) {
Debugbar::addException($e);
}
```
There are also helper functions available for the most common calls:
```php
// All arguments will be dumped as a debug message
debug($var1, $someString, $intValue, $object);
start_measure('render','Time for rendering');
stop_measure('render');
add_measure('now', LARAVEL_START, microtime(true));
measure('My long operation', function() {
// Do something…
});
```
If you want you can add your own DataCollectors, through the Container or the Facade:
```php
Debugbar::addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages'));
//Or via the App container:
$debugbar = App::make('debugbar');
$debugbar->addCollector(new DebugBar\DataCollector\MessagesCollector('my_messages'));
```
By default, the Debugbar is injected just before `</body>`. If you want to inject the Debugbar yourself,
set the config option 'inject' to false and use the renderer yourself and follow http://phpdebugbar.com/docs/rendering.html
```php
$renderer = Debugbar::getJavascriptRenderer();
```
Note: Not using the auto-inject, will disable the Request information, because that is added After the response.
You can add the default_request datacollector in the config as alternative.
## Enabling/Disabling on run time
You can enable or disable the debugbar during run time.
```php
\Debugbar::enable();
\Debugbar::disable();
```
NB. Once enabled, the collectors are added (and could produce extra overhead), so if you want to use the debugbar in production, disable in the config and only enable when needed.
## Twig Integration
Laravel Debugbar comes with two Twig Extensions. These are tested with [rcrowe/TwigBridge](https://github.com/rcrowe/TwigBridge) 0.6.x
Add the following extensions to your TwigBridge config/extensions.php (or register the extensions manually)
```php
'Barryvdh\Debugbar\Twig\Extension\Debug',
'Barryvdh\Debugbar\Twig\Extension\Dump',
'Barryvdh\Debugbar\Twig\Extension\Stopwatch',
```
The Dump extension will replace the [dump function](http://twig.sensiolabs.org/doc/functions/dump.html) to output variables using the DataFormatter. The Debug extension adds a `debug()` function which passes variables to the Message Collector,
instead of showing it directly in the template. It dumps the arguments, or when empty; all context variables.
```
{{ debug() }}
{{ debug(user, categories) }}
```
The Stopwatch extension adds a [stopwatch tag](http://symfony.com/blog/new-in-symfony-2-4-a-stopwatch-tag-for-twig) similar to the one in Symfony/Silex Twigbridge.
```
{% stopwatch "foo" %}
…some things that gets timed
{% endstopwatch %}
```

View File

@@ -0,0 +1,30 @@
<?php namespace Barryvdh\Debugbar\Console;
use DebugBar\DebugBar;
use Illuminate\Console\Command;
class ClearCommand extends Command
{
protected $name = 'debugbar:clear';
protected $description = 'Clear the Debugbar Storage';
protected $debugbar;
public function __construct(DebugBar $debugbar)
{
$this->debugbar = $debugbar;
parent::__construct();
}
public function fire()
{
$this->debugbar->boot();
if ($storage = $this->debugbar->getStorage()) {
$storage->clear();
$this->info('Debugbar Storage cleared!');
} else {
$this->error('No Debugbar Storage found..');
}
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Barryvdh\Debugbar\Console;
use Illuminate\Console\Command;
/**
* Publish the Debugbar assets to the public directory
*
* @author Barry vd. Heuvel <barryvdh@gmail.com>
* @deprecated No longer needed because of the AssetController
*/
class PublishCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'debugbar:publish';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish the Debugbar assets';
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$this->info(
'NOTICE: Since laravel-debugbar 1.7.x, publishing assets is no longer necessary. The assets in public/packages/barryvdh/laravel-debugbar and maximebf/php-debugbar can be safely removed.'
);
}
}

View File

@@ -0,0 +1,58 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Illuminate\Http\Response;
class AssetController extends BaseController
{
/**
* Return the javascript for the Debugbar
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function js()
{
$renderer = $this->debugbar->getJavascriptRenderer();
$content = $renderer->dumpAssetsToString('js');
$response = new Response(
$content, 200, array(
'Content-Type' => 'text/javascript',
)
);
return $this->cacheResponse($response);
}
/**
* Return the stylesheets for the Debugbar
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function css()
{
$renderer = $this->debugbar->getJavascriptRenderer();
$content = $renderer->dumpAssetsToString('css');
$response = new Response(
$content, 200, array(
'Content-Type' => 'text/css',
)
);
return $this->cacheResponse($response);
}
/**
* Cache the response 1 year (31536000 sec)
*/
protected function cacheResponse(Response $response)
{
$response->setSharedMaxAge(31536000);
$response->setMaxAge(31536000);
$response->setExpires(new \DateTime('+1 year'));
return $response;
}
}

View File

@@ -0,0 +1,38 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Routing\Controller;
use Illuminate\Http\Request;
if (class_exists('Illuminate\Routing\Controller')) {
class BaseController extends Controller
{
protected $debugbar;
public function __construct(Request $request, LaravelDebugbar $debugbar)
{
$this->debugbar = $debugbar;
if ($request->hasSession()){
$request->session()->reflash();
}
}
}
} else {
class BaseController
{
protected $debugbar;
public function __construct(Request $request, LaravelDebugbar $debugbar)
{
$this->debugbar = $debugbar;
if ($request->hasSession()){
$request->session()->reflash();
}
}
}
}

View File

@@ -0,0 +1,59 @@
<?php namespace Barryvdh\Debugbar\Controllers;
use Barryvdh\Debugbar\Support\Clockwork\Converter;
use DebugBar\OpenHandler;
use Illuminate\Http\Response;
class OpenHandlerController extends BaseController
{
public function handle()
{
$debugbar = $this->debugbar;
if (!$debugbar->isEnabled()) {
$this->app->abort('500', 'Debugbar is not enabled');
}
$openHandler = new OpenHandler($debugbar);
$data = $openHandler->handle(null, false, false);
return new Response(
$data, 200, array(
'Content-Type' => 'application/json'
)
);
}
/**
* Return Clockwork output
*
* @param $id
* @return mixed
* @throws \DebugBar\DebugBarException
*/
public function clockwork($id)
{
$request = [
'op' => 'get',
'id' => $id,
];
$debugbar = $this->debugbar;
if (!$debugbar->isEnabled()) {
$this->app->abort('500', 'Debugbar is not enabled');
}
$openHandler = new OpenHandler($debugbar);
$data = $openHandler->handle($request, false, false);
// Convert to Clockwork
$converter = new Converter();
$output = $converter->convert(json_decode($data, true));
return response()->json($output);
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Contracts\Support\Arrayable;
/**
* Collector for Laravel's Auth provider
*/
class AuthCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Auth\AuthManager */
protected $auth;
/** @var bool */
protected $showName = false;
/**
* @param \Illuminate\Auth\AuthManager $auth
*/
public function __construct($auth)
{
$this->auth = $auth;
}
/**
* Set to show the users name/email
* @param bool $showName
*/
public function setShowName($showName)
{
$this->showName = (bool) $showName;
}
/**
* @{inheritDoc}
*/
public function collect()
{
try {
$user = $this->auth->user();
} catch (\Exception $e) {
$user = null;
}
return $this->getUserInformation($user);
}
/**
* Get displayed user information
* @param \Illuminate\Auth\UserInterface $user
* @return array
*/
protected function getUserInformation($user = null)
{
// Defaults
if (is_null($user)) {
return array(
'name' => 'Guest',
'user' => array('guest' => true),
);
}
// The default auth identifer is the ID number, which isn't all that
// useful. Try username and email.
$identifier = $user->getAuthIdentifier();
if (is_numeric($identifier)) {
try {
if ($user->username) {
$identifier = $user->username;
} elseif ($user->email) {
$identifier = $user->email;
}
} catch (\Exception $e) {
}
}
return array(
'name' => $identifier,
'user' => $user instanceof Arrayable ? $user->toArray() : $user,
);
}
/**
* @{inheritDoc}
*/
public function getName()
{
return 'auth';
}
/**
* @{inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
'auth' => array(
'icon' => 'lock',
'widget' => 'PhpDebugBar.Widgets.VariableListWidget',
'map' => 'auth.user',
'default' => '{}'
)
);
if ($this->showName) {
$widgets['auth.name'] = array(
'icon' => 'user',
'tooltip' => 'Auth status',
'map' => 'auth.name',
'default' => '',
);
}
return $widgets;
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
class EventCollector extends TimeDataCollector
{
/** @var Dispatcher */
protected $events;
/** @var ValueExporter */
protected $exporter;
public function __construct($requestStartTime = null)
{
parent::__construct($requestStartTime);
$this->exporter = new ValueExporter();
}
public function onWildcardEvent()
{
$name = $this->events->firing();
$time = microtime(true);
// Get the arguments passed to the event
$params = $this->prepareParams(func_get_args());
// Find all listeners for the current event
foreach ($this->events->getListeners($name) as $i => $listener) {
// Check if it's an object + method name
if (is_array($listener) && count($listener) > 1 && is_object($listener[0])) {
list($class, $method) = $listener;
// Skip this class itself
if ($class instanceof static) {
continue;
}
// Format the listener to readable format
$listener = get_class($class) . '@' . $method;
// Handle closures
} elseif ($listener instanceof \Closure) {
$reflector = new \ReflectionFunction($listener);
// Skip our own listeners
if ($reflector->getNamespaceName() == 'Barryvdh\Debugbar') {
continue;
}
// Format the closure to a readable format
$filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/');
$listener = $reflector->getName() . ' (' . $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine() . ')';
} else {
// Not sure if this is possible, but to prevent edge cases
$listener = $this->formatVar($listener);
}
$params['listeners.' . $i] = $listener;
}
$this->addMeasure($name, $time, $time, $params);
}
public function subscribe(Dispatcher $events)
{
$this->events = $events;
$events->listen('*', array($this, 'onWildcardEvent'));
}
protected function prepareParams($params)
{
$data = array();
foreach ($params as $key => $value) {
if (is_object($value) && Str::is('Illuminate\*\Events\*', get_class($value))) {
$value = $this->prepareParams(get_object_vars($value));
}
$data[$key] = htmlentities($this->exporter->exportValue($value), ENT_QUOTES, 'UTF-8', false);
}
return $data;
}
public function collect()
{
$data = parent::collect();
$data['nb_measures'] = count($data['measures']);
return $data;
}
public function getName()
{
return 'event';
}
public function getWidgets()
{
return array(
"events" => array(
"icon" => "tasks",
"widget" => "PhpDebugBar.Widgets.TimelineWidget",
"map" => "event",
"default" => "{}",
),
'events:badge' => array(
'map' => 'event.nb_measures',
'default' => 0,
),
);
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Contracts\Foundation\Application;
class FilesCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Contracts\Foundation\Application */
protected $app;
protected $basePath;
/**
* @param \Illuminate\Contracts\Foundation\Application $app
*/
public function __construct(Application $app = null)
{
$this->app = $app;
$this->basePath = base_path();
}
/**
* {@inheritDoc}
*/
public function collect()
{
$files = $this->getIncludedFiles();
$compiled = $this->getCompiledFiles();
$included = array();
$alreadyCompiled = array();
foreach ($files as $file) {
// Skip the files from Debugbar, they are only loaded for Debugging and confuse the output.
// Of course some files are stil always loaded (ServiceProvider, Facade etc)
if (strpos($file, 'vendor/maximebf/debugbar/src') !== false || strpos(
$file,
'vendor/barryvdh/laravel-debugbar/src'
) !== false
) {
continue;
} elseif (!in_array($file, $compiled)) {
$included[] = array(
'message' => "'" . $this->stripBasePath($file) . "',",
// Use PHP syntax so we can copy-paste to compile config file.
'is_string' => true,
);
} else {
$alreadyCompiled[] = array(
'message' => "* '" . $this->stripBasePath($file) . "',",
// Mark with *, so know they are compiled anyways.
'is_string' => true,
);
}
}
// First the included files, then those that are going to be compiled.
$messages = array_merge($included, $alreadyCompiled);
return array(
'messages' => $messages,
'count' => count($included),
);
}
/**
* Get the files included on load.
*
* @return array
*/
protected function getIncludedFiles()
{
return get_included_files();
}
/**
* Get the files that are going to be compiled, so they aren't as important.
*
* @return array
*/
protected function getCompiledFiles()
{
if ($this->app && class_exists('Illuminate\Foundation\Console\OptimizeCommand')) {
$reflector = new \ReflectionClass('Illuminate\Foundation\Console\OptimizeCommand');
$path = dirname($reflector->getFileName()) . '/Optimize/config.php';
if (file_exists($path)) {
$app = $this->app;
$core = require $path;
return array_merge($core, $app['config']['compile']);
}
}
return array();
}
/**
* Remove the basePath from the paths, so they are relative to the base
*
* @param $path
* @return string
*/
protected function stripBasePath($path)
{
return ltrim(str_replace($this->basePath, '', $path), '/');
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
$name = $this->getName();
return array(
"$name" => array(
"icon" => "files-o",
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
"map" => "$name.messages",
"default" => "{}"
),
"$name:badge" => array(
"map" => "$name.count",
"default" => "null"
)
);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'files';
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\MessagesCollector;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Auth\Authenticatable;
/**
* Collector for Laravel's Auth provider
*/
class GateCollector extends MessagesCollector
{
/**
* @param Gate $gate
*/
public function __construct(Gate $gate)
{
parent::__construct('gate');
if (method_exists($gate, 'after')) {
$gate->after([$this, 'addCheck']);
}
}
public function addCheck(Authenticatable $user, $ability, $result, $arguments = [])
{
$label = $result ? 'success' : 'error';
$this->addMessage([
'ability' => $ability,
'result' => $result,
'user' => $user->getAuthIdentifier(),
'arguments' => $arguments,
], $label, false);
}
}

View File

@@ -0,0 +1,143 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Config;
/**
* Based on Illuminate\Foundation\Console\RoutesCommand for Taylor Otwell
* https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Console/RoutesCommand.php
*
*/
class IlluminateRouteCollector extends DataCollector implements Renderable
{
/**
* The router instance.
*
* @var \Illuminate\Routing\Router
*/
protected $router;
public function __construct(Router $router)
{
$this->router = $router;
}
/**
* {@inheritDoc}
*/
public function collect()
{
$route = $this->router->current();
return $this->getRouteInformation($route);
}
/**
* Get the route information for a given route.
*
* @param \Illuminate\Routing\Route $route
* @return array
*/
protected function getRouteInformation($route)
{
if (!is_a($route, 'Illuminate\Routing\Route')) {
return array();
}
$uri = head($route->methods()) . ' ' . $route->uri();
$action = $route->getAction();
$result = array(
'uri' => $uri ?: '-',
);
$result = array_merge($result, $action);
if (isset($action['controller']) && strpos($action['controller'], '@') !== false) {
list($controller, $method) = explode('@', $action['controller']);
if(class_exists($controller) && method_exists($controller, $method)) {
$reflector = new \ReflectionMethod($controller, $method);
}
unset($result['uses']);
} elseif (isset($action['uses']) && $action['uses'] instanceof \Closure) {
$reflector = new \ReflectionFunction($action['uses']);
$result['uses'] = $this->formatVar($result['uses']);
}
if (isset($reflector)) {
$filename = ltrim(str_replace(base_path(), '', $reflector->getFileName()), '/');
$result['file'] = $filename . ':' . $reflector->getStartLine() . '-' . $reflector->getEndLine();
}
if ($middleware = $this->getMiddleware($route)) {
$result['middleware'] = $middleware;
}
return $result;
}
/**
* Get middleware
*
* @param \Illuminate\Routing\Route $route
* @return string
*/
protected function getMiddleware($route)
{
$middleware = array_keys($route->middleware());
return implode(', ', $middleware);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'route';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
"route" => array(
"icon" => "share",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "route",
"default" => "{}"
)
);
if (Config::get('debugbar.options.route.label', true)) {
$widgets['currentroute'] = array(
"icon" => "share",
"tooltip" => "Route",
"map" => "route.uri",
"default" => ""
);
}
return $widgets;
}
/**
* Display the route information on the console.
*
* @param array $routes
* @return void
*/
protected function displayRoutes(array $routes)
{
$this->table->setHeaders($this->headers)->setRows($routes);
$this->table->render($this->getOutput());
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Illuminate\Foundation\Application;
class LaravelCollector extends DataCollector implements Renderable
{
/** @var \Illuminate\Foundation\Application $app */
protected $app;
/**
* @param Application $app
*/
public function __construct(Application $app = null)
{
$this->app = $app;
}
/**
* {@inheritDoc}
*/
public function collect()
{
// Fallback if not injected
$app = $this->app ?: app();
return array(
"version" => $app::VERSION,
"environment" => $app->environment(),
"locale" => $app->getLocale(),
);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'laravel';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"version" => array(
"icon" => "github",
"tooltip" => "Version",
"map" => "laravel.version",
"default" => ""
),
"environment" => array(
"icon" => "desktop",
"tooltip" => "Environment",
"map" => "laravel.environment",
"default" => ""
),
"locale" => array(
"icon" => "flag",
"tooltip" => "Current locale",
"map" => "laravel.locale",
"default" => "",
),
);
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\MessagesCollector;
use Psr\Log\LogLevel;
use ReflectionClass;
class LogsCollector extends MessagesCollector
{
protected $lines = 124;
public function __construct($path = null, $name = 'logs')
{
parent::__construct($name);
$path = $path ?: $this->getLogsFile();
$this->getStorageLogs($path);
}
/**
* Get the path to the logs file
*
* @return string
*/
public function getLogsFile()
{
// default daily rotating logs (Laravel 5.0)
$path = storage_path() . '/logs/laravel-' . date('Y-m-d') . '.log';
// single file logs
if (!file_exists($path)) {
$path = storage_path() . '/logs/laravel.log';
}
return $path;
}
/**
* get logs apache in app/storage/logs
* only 24 last of current day
*
* @param string $path
*
* @return array
*/
public function getStorageLogs($path)
{
if (!file_exists($path)) {
return;
}
//Load the latest lines, guessing about 15x the number of log entries (for stack traces etc)
$file = implode("", $this->tailFile($path, $this->lines));
foreach ($this->getLogs($file) as $log) {
$this->addMessage($log['header'] . $log['stack'], $log['level'], false);
}
}
/**
* By Ain Tohvri (ain)
* http://tekkie.flashbit.net/php/tail-functionality-in-php
* @param string $file
* @param int $lines
* @return array
*/
protected function tailFile($file, $lines)
{
$handle = fopen($file, "r");
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = array();
while ($linecounter > 0) {
$t = " ";
while ($t != "\n") {
if (fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
$t = fgetc($handle);
$pos--;
}
$linecounter--;
if ($beginning) {
rewind($handle);
}
$text[$lines - $linecounter - 1] = fgets($handle);
if ($beginning) {
break;
}
}
fclose($handle);
return array_reverse($text);
}
/**
* Search a string for log entries
* Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand
*
* @param $file
* @return array
*/
public function getLogs($file)
{
$pattern = "/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\].*/";
$log_levels = $this->getLevels();
// There has GOT to be a better way of doing this...
preg_match_all($pattern, $file, $headings);
$log_data = preg_split($pattern, $file);
$log = array();
foreach ($headings as $h) {
for ($i = 0, $j = count($h); $i < $j; $i++) {
foreach ($log_levels as $ll) {
if (strpos(strtolower($h[$i]), strtolower('.' . $ll))) {
$log[] = array('level' => $ll, 'header' => $h[$i], 'stack' => $log_data[$i]);
}
}
}
}
$log = array_reverse($log);
return $log;
}
/**
* Get the log levels from psr/log.
* Based on https://github.com/mikemand/logviewer/blob/master/src/Kmd/Logviewer/Logviewer.php by mikemand
*
* @access public
* @return array
*/
public function getLevels()
{
$class = new ReflectionClass(new LogLevel());
return $class->getConstants();
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
/**
* Collector for Laravel's Auth provider
*/
class MultiAuthCollector extends AuthCollector
{
/** @var array $guards */
protected $guards;
/**
* @param \Illuminate\Auth\AuthManager $auth
* @param array $guards
*/
public function __construct($auth, $guards)
{
parent::__construct($auth);
$this->guards = $guards;
}
/**
* @{inheritDoc}
*/
public function collect()
{
$data = [];
$names = '';
foreach($this->guards as $guardName) {
$user = $this->auth->guard($guardName)->user();
$data['guards'][$guardName] = $this->getUserInformation($user);
if(!is_null($user)) {
$names .= $guardName . ": " . $data['guards'][$guardName]['name'] . ', ';
}
}
foreach ($data['guards'] as $key => $var) {
if (!is_string($data['guards'][$key])) {
$data['guards'][$key] = $this->formatVar($var);
}
}
$data['names'] = rtrim($names, ', ');
return $data;
}
/**
* @{inheritDoc}
*/
public function getWidgets()
{
$widgets = array(
"auth" => array(
"icon" => "lock",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "auth.guards",
"default" => "{}"
)
);
if ($this->showName) {
$widgets['auth.name'] = array(
'icon' => 'user',
'tooltip' => 'Auth status',
'map' => 'auth.names',
'default' => '',
);
}
return $widgets;
}
}

View File

@@ -0,0 +1,354 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\PDO\PDOCollector;
use DebugBar\DataCollector\TimeDataCollector;
/**
* Collects data about SQL statements executed with PDO
*/
class QueryCollector extends PDOCollector
{
protected $timeCollector;
protected $queries = array();
protected $renderSqlWithParams = false;
protected $findSource = false;
protected $explainQuery = false;
protected $explainTypes = array('SELECT'); // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+
protected $showHints = false;
/**
* @param TimeDataCollector $timeCollector
*/
public function __construct(TimeDataCollector $timeCollector = null)
{
$this->timeCollector = $timeCollector;
}
/**
* Renders the SQL of traced statements with params embedded
*
* @param boolean $enabled
* @param string $quotationChar NOT USED
*/
public function setRenderSqlWithParams($enabled = true, $quotationChar = "'")
{
$this->renderSqlWithParams = $enabled;
}
/**
* Show or hide the hints in the parameters
*
* @param boolean $enabled
*/
public function setShowHints($enabled = true)
{
$this->showHints = $enabled;
}
/**
* Enable/disable finding the source
*
* @param bool $value
*/
public function setFindSource($value = true)
{
$this->findSource = (bool) $value;
}
/**
* Enable/disable the EXPLAIN queries
*
* @param bool $enabled
* @param array|null $types Array of types to explain queries (select/insert/update/delete)
*/
public function setExplainSource($enabled, $types)
{
$this->explainQuery = $enabled;
if($types){
$this->explainTypes = $types;
}
}
/**
*
* @param string $query
* @param array $bindings
* @param float $time
* @param \Illuminate\Database\Connection $connection
*/
public function addQuery($query, $bindings, $time, $connection)
{
$explainResults = array();
$time = $time / 1000;
$endTime = microtime(true);
$startTime = $endTime - $time;
$hints = $this->performQueryAnalysis($query);
$pdo = $connection->getPdo();
$bindings = $connection->prepareBindings($bindings);
// Run EXPLAIN on this query (if needed)
if ($this->explainQuery && preg_match('/^('.implode($this->explainTypes).') /i', $query)) {
$statement = $pdo->prepare('EXPLAIN ' . $query);
$statement->execute($bindings);
$explainResults = $statement->fetchAll(\PDO::FETCH_CLASS);
}
$bindings = $this->checkBindings($bindings);
if (!empty($bindings) && $this->renderSqlWithParams) {
foreach ($bindings as $binding) {
$query = preg_replace('/\?/', $pdo->quote($binding), $query, 1);
}
}
$source = null;
if ($this->findSource) {
try {
$source = $this->findSource();
} catch (\Exception $e) {
}
}
$this->queries[] = array(
'query' => $query,
'bindings' => $this->escapeBindings($bindings),
'time' => $time,
'source' => $source,
'explain' => $explainResults,
'connection' => $connection->getDatabaseName(),
'hints' => $this->showHints ? $hints : null,
);
if ($this->timeCollector !== null) {
$this->timeCollector->addMeasure($query, $startTime, $endTime);
}
}
/**
* 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()
*
* Perform simple regex analysis on the code
*
* @package xplain (https://github.com/rap2hpoutre/mysql-xplain-xplain)
* @author e-doceo
* @copyright 2014
* @version $Id$
* @access public
* @param string $query
* @return string
*/
protected function performQueryAnalysis($query)
{
$hints = array();
if (preg_match('/^\\s*SELECT\\s*`?[a-zA-Z0-9]*`?\\.?\\*/i', $query)) {
$hints[] = 'Use <code>SELECT *</code> only if you need all columns from table';
}
if (preg_match('/ORDER BY RAND()/i', $query)) {
$hints[] = '<code>ORDER BY RAND()</code> is slow, try to avoid if you can.
You can <a href="http://stackoverflow.com/questions/2663710/how-does-mysqls-order-by-rand-work" target="_blank">read this</a>
or <a href="http://stackoverflow.com/questions/1244555/how-can-i-optimize-mysqls-order-by-rand-function" target="_blank">this</a>';
}
if (strpos($query, '!=') !== false) {
$hints[] = 'The <code>!=</code> operator is not standard. Use the <code>&lt;&gt;</code> operator to test for inequality instead.';
}
if (stripos($query, 'WHERE') === false && preg_match('/^(SELECT) /i', $query)) {
$hints[] = 'The <code>SELECT</code> statement has no <code>WHERE</code> clause and could examine many more rows than intended';
}
if (preg_match('/LIMIT\\s/i', $query) && stripos($query, 'ORDER BY') === false) {
$hints[] = '<code>LIMIT</code> without <code>ORDER BY</code> causes non-deterministic results, depending on the query execution plan';
}
if (preg_match('/LIKE\\s[\'"](%.*?)[\'"]/i', $query, $matches)) {
$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);
}
/**
* Use a backtrace to search for the origin of the query.
*/
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) {
return 'Template file';
} else {
$file = $trace['file'];
$line = isset($trace['line']) ? $trace['line'] : '?';
}
return $this->normalizeFilename($file) . ':' . $line;
} elseif (isset($trace['function']) && $trace['function'] == 'Illuminate\Routing\{closure}') {
return 'Route binding';
}
}
}
/**
* Get the filename/line from a Twig template trace
*
* @param array $trace
* @return array The file and line
*/
protected function getTwigInfo($trace)
{
$file = $trace['object']->getTemplateName();
if (isset($trace['line'])) {
foreach ($trace['object']->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
return array($file, $templateLine);
}
}
}
return array($file, -1);
}
/**
* Shorten the path by removing the relative links and base dir
*
* @param string $path
* @return string
*/
protected function normalizeFilename($path)
{
if (file_exists($path)) {
$path = realpath($path);
}
return str_replace(base_path(), '', $path);
}
/**
* Reset the queries.
*/
public function reset()
{
$this->queries = array();
}
/**
* {@inheritDoc}
*/
public function collect()
{
$totalTime = 0;
$queries = $this->queries;
$statements = array();
foreach ($queries as $query) {
$totalTime += $query['time'];
$bindings = $query['bindings'];
if($query['hints']){
$bindings['hints'] = $query['hints'];
}
$statements[] = array(
'sql' => $this->formatSql($query['query']),
'params' => (object) $bindings,
'duration' => $query['time'],
'duration_str' => $this->formatDuration($query['time']),
'stmt_id' => $query['source'],
'connection' => $query['connection'],
);
//Add the results from the explain as new rows
foreach($query['explain'] as $explain){
$statements[] = array(
'sql' => ' - EXPLAIN #' . $explain->id . ': `' . $explain->table . '` (' . $explain->select_type . ')',
'params' => $explain,
'row_count' => $explain->rows,
'stmt_id' => $explain->id,
);
}
}
$data = array(
'nb_statements' => count($queries),
'nb_failed_statements' => 0,
'accumulated_duration' => $totalTime,
'accumulated_duration_str' => $this->formatDuration($totalTime),
'statements' => $statements
);
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}
*/
public function getName()
{
return 'queries';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"queries" => array(
"icon" => "inbox",
"widget" => "PhpDebugBar.Widgets.SQLQueriesWidget",
"map" => "queries",
"default" => "[]"
),
"queries:badge" => array(
"map" => "queries.nb_statements",
"default" => 0
)
);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
class SessionCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SessionCollector
*
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($session)
{
$this->session = $session;
}
/**
* {@inheritdoc}
*/
public function collect()
{
$data = array();
foreach ($this->session->all() as $key => $value) {
$data[$key] = is_string($value) ? $value : $this->formatVar($value);
}
return $data;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'session';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"session" => array(
"icon" => "archive",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "session",
"default" => "{}"
)
);
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
use Symfony\Component\HttpFoundation\Response;
/**
*
* Based on \Symfony\Component\HttpKernel\DataCollector\RequestDataCollector by Fabien Potencier <fabien@symfony.com>
*
*/
class SymfonyRequestCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Request $request */
protected $request;
/** @var \Symfony\Component\HttpFoundation\Request $response */
protected $response;
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SymfonyRequestCollector
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Request $response
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($request, $response, $session = null)
{
$this->request = $request;
$this->response = $response;
$this->session = $session;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'request';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return array(
"request" => array(
"icon" => "tags",
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
"map" => "request",
"default" => "{}"
)
);
}
/**
* {@inheritdoc}
*/
public function collect()
{
$request = $this->request;
$response = $this->response;
$responseHeaders = $response->headers->all();
$cookies = array();
foreach ($response->headers->getCookies() as $cookie) {
$cookies[] = $this->getCookieHeader(
$cookie->getName(),
$cookie->getValue(),
$cookie->getExpiresTime(),
$cookie->getPath(),
$cookie->getDomain(),
$cookie->isSecure(),
$cookie->isHttpOnly()
);
}
if (count($cookies) > 0) {
$responseHeaders['Set-Cookie'] = $cookies;
}
$statusCode = $response->getStatusCode();
$data = array(
'format' => $request->getRequestFormat(),
'content_type' => $response->headers->get('Content-Type') ? $response->headers->get(
'Content-Type'
) : 'text/html',
'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '',
'status_code' => $statusCode,
'request_query' => $request->query->all(),
'request_request' => $request->request->all(),
'request_headers' => $request->headers->all(),
'request_server' => $request->server->all(),
'request_cookies' => $request->cookies->all(),
'response_headers' => $responseHeaders,
'path_info' => $request->getPathInfo(),
);
if ($this->session) {
$sessionAttributes = array();
foreach ($this->session->all() as $key => $value) {
$sessionAttributes[$key] = $value;
}
$data['session_attributes'] = $sessionAttributes;
}
foreach ($data['request_server'] as $key => $value) {
if (str_is('*_KEY', $key) || str_is('*_PASSWORD', $key)
|| str_is('*_SECRET', $key) || str_is('*_PW', $key)) {
$data['request_server'][$key] = '******';
}
}
if (isset($data['request_headers']['php-auth-pw'])) {
$data['request_headers']['php-auth-pw'] = '******';
}
if (isset($data['request_server']['PHP_AUTH_PW'])) {
$data['request_server']['PHP_AUTH_PW'] = '******';
}
foreach ($data as $key => $var) {
if (!is_string($data[$key])) {
$data[$key] = $this->formatVar($var);
}
}
return $data;
}
private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly)
{
$cookie = sprintf('%s=%s', $name, urlencode($value));
if (0 !== $expires) {
if (is_numeric($expires)) {
$expires = (int) $expires;
} elseif ($expires instanceof \DateTime) {
$expires = $expires->getTimestamp();
} else {
$expires = strtotime($expires);
if (false === $expires || -1 == $expires) {
throw new \InvalidArgumentException(
sprintf('The "expires" cookie parameter is not valid.', $expires)
);
}
}
$cookie .= '; expires=' . substr(
\DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'),
0,
-5
);
}
if ($domain) {
$cookie .= '; domain=' . $domain;
}
$cookie .= '; path=' . $path;
if ($secure) {
$cookie .= '; secure';
}
if ($httponly) {
$cookie .= '; httponly';
}
return $cookie;
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace Barryvdh\Debugbar\DataCollector;
use DebugBar\Bridge\Twig\TwigCollector;
use Illuminate\View\View;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
class ViewCollector extends TwigCollector
{
protected $templates = array();
protected $collect_data;
/**
* Create a ViewCollector
*
* @param bool $collectData Collects view data when tru
*/
public function __construct($collectData = true)
{
$this->collect_data = $collectData;
$this->name = 'views';
$this->templates = array();
$this->exporter = new ValueExporter();
}
public function getName()
{
return 'views';
}
public function getWidgets()
{
return array(
'views' => array(
'icon' => 'leaf',
'widget' => 'PhpDebugBar.Widgets.TemplatesWidget',
'map' => 'views',
'default' => '[]'
),
'views:badge' => array(
'map' => 'views.nb_templates',
'default' => 0
)
);
}
/**
* Add a View instance to the Collector
*
* @param \Illuminate\View\View $view
*/
public function addView(View $view)
{
$name = $view->getName();
$path = $view->getPath();
if (!is_object($path)) {
if ($path) {
$path = ltrim(str_replace(base_path(), '', realpath($path)), '/');
}
if (substr($path, -10) == '.blade.php') {
$type = 'blade';
} else {
$type = pathinfo($path, PATHINFO_EXTENSION);
}
} else {
$type = get_class($view);
$path = '';
}
if (!$this->collect_data) {
$params = array_keys($view->getData());
} else {
$data = array();
foreach ($view->getData() as $key => $value) {
$data[$key] = $this->exporter->exportValue($value);
}
$params = $data;
}
$this->templates[] = array(
'name' => $path ? sprintf('%s (%s)', $name, $path) : $name,
'param_count' => count($params),
'params' => $params,
'type' => $type,
);
}
public function collect()
{
$templates = $this->templates;
return array(
'nb_templates' => count($templates),
'templates' => $templates,
);
}
}

View File

@@ -0,0 +1,12 @@
<?php namespace Barryvdh\Debugbar;
class Facade extends \Illuminate\Support\Facades\Facade
{
/**
* {@inheritDoc}
*/
protected static function getFacadeAccessor()
{
return 'debugbar';
}
}

View File

@@ -0,0 +1,122 @@
<?php namespace Barryvdh\Debugbar;
use DebugBar\DebugBar;
use DebugBar\JavascriptRenderer as BaseJavascriptRenderer;
use Illuminate\Routing\UrlGenerator;
/**
* {@inheritdoc}
*/
class JavascriptRenderer extends BaseJavascriptRenderer
{
// Use XHR handler by default, instead of jQuery
protected $ajaxHandlerBindToJquery = false;
protected $ajaxHandlerBindToXHR = true;
public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null)
{
parent::__construct($debugBar, $baseUrl, $basePath);
$this->cssFiles['laravel'] = __DIR__ . '/Resources/laravel-debugbar.css';
$this->cssVendors['fontawesome'] = __DIR__ . '/Resources/vendor/font-awesome/style.css';
}
/**
* Set the URL Generator
*
* @param \Illuminate\Routing\UrlGenerator $url
* @deprecated
*/
public function setUrlGenerator($url)
{
}
/**
* {@inheritdoc}
*/
public function renderHead()
{
$cssRoute = route('debugbar.assets.css', [
'v' => $this->getModifiedTime('css')
]);
$jsRoute = route('debugbar.assets.js', [
'v' => $this->getModifiedTime('js')
]);
$html = "<link rel='stylesheet' type='text/css' href='{$cssRoute}'>";
$html .= "<script type='text/javascript' src='{$jsRoute}'></script>";
if ($this->isJqueryNoConflictEnabled()) {
$html .= '<script type="text/javascript">jQuery.noConflict(true);</script>' . "\n";
}
return $html;
}
/**
* Get the last modified time of any assets.
*
* @param string $type 'js' or 'css'
* @return int
*/
protected function getModifiedTime($type)
{
$files = $this->getAssets($type);
$latest = 0;
foreach ($files as $file) {
$mtime = filemtime($file);
if ($mtime > $latest) {
$latest = $mtime;
}
}
return $latest;
}
/**
* Return assets as a string
*
* @param string $type 'js' or 'css'
* @return string
*/
public function dumpAssetsToString($type)
{
$files = $this->getAssets($type);
$content = '';
foreach ($files as $file) {
$content .= file_get_contents($file) . "\n";
}
return $content;
}
/**
* Makes a URI relative to another
*
* @param string|array $uri
* @param string $root
* @return string
*/
protected function makeUriRelativeTo($uri, $root)
{
if (!$root) {
return $uri;
}
if (is_array($uri)) {
$uris = array();
foreach ($uri as $u) {
$uris[] = $this->makeUriRelativeTo($u, $root);
}
return $uris;
}
if (substr($uri, 0, 1) === '/' || preg_match('/^([a-zA-Z]+:\/\/|[a-zA-Z]:\/|[a-zA-Z]:\\\)/', $uri)) {
return $uri;
}
return rtrim($root, '/') . "/$uri";
}
}

View File

@@ -0,0 +1,880 @@
<?php namespace Barryvdh\Debugbar;
use Barryvdh\Debugbar\DataCollector\AuthCollector;
use Barryvdh\Debugbar\DataCollector\EventCollector;
use Barryvdh\Debugbar\DataCollector\FilesCollector;
use Barryvdh\Debugbar\DataCollector\GateCollector;
use Barryvdh\Debugbar\DataCollector\LaravelCollector;
use Barryvdh\Debugbar\DataCollector\LogsCollector;
use Barryvdh\Debugbar\DataCollector\MultiAuthCollector;
use Barryvdh\Debugbar\DataCollector\QueryCollector;
use Barryvdh\Debugbar\DataCollector\SessionCollector;
use Barryvdh\Debugbar\DataCollector\SymfonyRequestCollector;
use Barryvdh\Debugbar\DataCollector\ViewCollector;
use Barryvdh\Debugbar\Storage\FilesystemStorage;
use DebugBar\Bridge\MonologCollector;
use DebugBar\Bridge\SwiftMailer\SwiftLogCollector;
use DebugBar\Bridge\SwiftMailer\SwiftMailCollector;
use DebugBar\DataCollector\ConfigCollector;
use DebugBar\DataCollector\ExceptionsCollector;
use DebugBar\DataCollector\MemoryCollector;
use DebugBar\DataCollector\MessagesCollector;
use DebugBar\DataCollector\PhpInfoCollector;
use DebugBar\DataCollector\RequestDataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use Barryvdh\Debugbar\Support\Clockwork\ClockworkCollector;
use DebugBar\DebugBar;
use DebugBar\Storage\PdoStorage;
use DebugBar\Storage\RedisStorage;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Session\SessionManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Debug bar subclass which adds all without Request and with LaravelCollector.
* Rest is added in Service Provider
*
* @method void emergency($message)
* @method void alert($message)
* @method void critical($message)
* @method void error($message)
* @method void warning($message)
* @method void notice($message)
* @method void info($message)
* @method void debug($message)
* @method void log($message)
*/
class LaravelDebugbar extends DebugBar
{
/**
* The Laravel application instance.
*
* @var \Illuminate\Foundation\Application
*/
protected $app;
/**
* Normalized Laravel Version
*
* @var string
*/
protected $version;
/**
* True when booted.
*
* @var bool
*/
protected $booted = false;
/**
* True when enabled, false disabled an null for still unknown
*
* @var bool
*/
protected $enabled = null;
/**
* True when this is a Lumen application
*
* @var bool
*/
protected $is_lumen = false;
/**
* @param Application $app
*/
public function __construct($app = null)
{
if (!$app) {
$app = app(); //Fallback when $app is not given
}
$this->app = $app;
$this->version = $app->version();
$this->is_lumen = str_contains($this->version, 'Lumen');
}
/**
* Enable the Debugbar and boot, if not already booted.
*/
public function enable()
{
$this->enabled = true;
if (!$this->booted) {
$this->boot();
}
}
/**
* Boot the debugbar (add collectors, renderer and listener)
*/
public function boot()
{
if ($this->booted) {
return;
}
/** @var \Barryvdh\Debugbar\LaravelDebugbar $debugbar */
$debugbar = $this;
/** @var Application $app */
$app = $this->app;
$this->selectStorage($debugbar);
if ($this->shouldCollect('phpinfo', true)) {
$this->addCollector(new PhpInfoCollector());
}
if ($this->shouldCollect('messages', true)) {
$this->addCollector(new MessagesCollector());
}
if ($this->shouldCollect('time', true)) {
$this->addCollector(new TimeDataCollector());
if ( ! $this->isLumen()) {
$this->app->booted(
function () use ($debugbar) {
$startTime = $this->app['request']->server('REQUEST_TIME_FLOAT');
if ($startTime) {
$debugbar['time']->addMeasure('Booting', $startTime, microtime(true));
}
}
);
}
$debugbar->startMeasure('application', 'Application');
}
if ($this->shouldCollect('memory', true)) {
$this->addCollector(new MemoryCollector());
}
if ($this->shouldCollect('exceptions', true)) {
try {
$exceptionCollector = new ExceptionsCollector();
$exceptionCollector->setChainExceptions(
$this->app['config']->get('debugbar.options.exceptions.chain', true)
);
$this->addCollector($exceptionCollector);
} catch (\Exception $e) {
}
}
if ($this->shouldCollect('laravel', false)) {
$this->addCollector(new LaravelCollector($this->app));
}
if ($this->shouldCollect('default_request', false)) {
$this->addCollector(new RequestDataCollector());
}
if ($this->shouldCollect('events', false) && isset($this->app['events'])) {
try {
$startTime = $this->app['request']->server('REQUEST_TIME_FLOAT');
$eventCollector = new EventCollector($startTime);
$this->addCollector($eventCollector);
$this->app['events']->subscribe($eventCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add EventCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->shouldCollect('views', true) && isset($this->app['events'])) {
try {
$collectData = $this->app['config']->get('debugbar.options.views.data', true);
$this->addCollector(new ViewCollector($collectData));
$this->app['events']->listen(
'composing:*',
function ($view) use ($debugbar) {
$debugbar['views']->addView($view);
}
);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ViewCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if (!$this->isLumen() && $this->shouldCollect('route')) {
try {
$this->addCollector($this->app->make('Barryvdh\Debugbar\DataCollector\IlluminateRouteCollector'));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add RouteCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if (!$this->isLumen() && $this->shouldCollect('log', true)) {
try {
if ($this->hasCollector('messages')) {
$logger = new MessagesCollector('log');
$this['messages']->aggregate($logger);
$this->app['log']->listen(
function ($level, $message, $context) use ($logger) {
try {
$logMessage = (string) $message;
if (mb_check_encoding($logMessage, 'UTF-8')) {
$logMessage .= (!empty($context) ? ' ' . json_encode($context) : '');
} else {
$logMessage = "[INVALID UTF-8 DATA]";
}
} catch (\Exception $e) {
$logMessage = "[Exception: " . $e->getMessage() . "]";
}
$logger->addMessage(
'[' . date('H:i:s') . '] ' . "LOG.$level: " . $logMessage,
$level,
false
);
}
);
} else {
$this->addCollector(new MonologCollector($this->app['log']->getMonolog()));
}
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add LogsCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('db', true) && isset($this->app['db'])) {
$db = $this->app['db'];
if ($debugbar->hasCollector('time') && $this->app['config']->get(
'debugbar.options.db.timeline',
false
)
) {
$timeCollector = $debugbar->getCollector('time');
} else {
$timeCollector = null;
}
$queryCollector = new QueryCollector($timeCollector);
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);
}
if ($this->app['config']->get('debugbar.options.db.explain.enabled')) {
$types = $this->app['config']->get('debugbar.options.db.explain.types');
$queryCollector->setExplainSource(true, $types);
}
if ($this->app['config']->get('debugbar.options.db.hints', true)) {
$queryCollector->setShowHints(true);
}
$this->addCollector($queryCollector);
try {
$db->listen(
function ($query, $bindings = null, $time = null, $connectionName = null) use ($db, $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 ( $query instanceof \Illuminate\Database\Events\QueryExecuted ) {
$bindings = $query->bindings;
$time = $query->time;
$connection = $query->connection;
$query = $query->sql;
} else {
$connection = $db->connection($connectionName);
}
$queryCollector->addQuery((string) $query, $bindings, $time, $connection);
}
);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add listen to Queries for Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->shouldCollect('mail', true) && class_exists('Illuminate\Mail\MailServiceProvider')) {
try {
$mailer = $this->app['mailer']->getSwiftMailer();
$this->addCollector(new SwiftMailCollector($mailer));
if ($this->app['config']->get('debugbar.options.mail.full_log') && $this->hasCollector(
'messages'
)
) {
$this['messages']->aggregate(new SwiftLogCollector($mailer));
}
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add MailCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('logs', false)) {
try {
$file = $this->app['config']->get('debugbar.options.logs.file');
$this->addCollector(new LogsCollector($file));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add LogsCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('files', false)) {
$this->addCollector(new FilesCollector($app));
}
if ($this->shouldCollect('auth', false)) {
try {
if($this->checkVersion('5.2')) {
// fix for compatibility with Laravel 5.2.*
$guards = array_keys($this->app['config']->get('auth.guards'));
$authCollector = new MultiAuthCollector($app['auth'], $guards);
} else {
$authCollector = new AuthCollector($app['auth']);
}
$authCollector->setShowName(
$this->app['config']->get('debugbar.options.auth.show_name')
);
$this->addCollector($authCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add AuthCollector to Laravel Debugbar: ' . $e->getMessage(), $e->getCode(), $e
)
);
}
}
if ($this->shouldCollect('gate', false)) {
try {
$gateCollector = $this->app->make('Barryvdh\Debugbar\DataCollector\GateCollector');
$this->addCollector($gateCollector);
} catch (\Exception $e){
// No Gate collector
}
}
$renderer = $this->getJavascriptRenderer();
$renderer->setIncludeVendors($this->app['config']->get('debugbar.include_vendors', true));
$renderer->setBindAjaxHandlerToXHR($app['config']->get('debugbar.capture_ajax', true));
$this->booted = true;
}
public function shouldCollect($name, $default = false)
{
return $this->app['config']->get('debugbar.collectors.' . $name, $default);
}
/**
* Starts a measure
*
* @param string $name Internal name, used to stop the measure
* @param string $label Public name
*/
public function startMeasure($name, $label = null)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->startMeasure($name, $label);
}
}
/**
* Stops a measure
*
* @param string $name
*/
public function stopMeasure($name)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
try {
$collector->stopMeasure($name);
} catch (\Exception $e) {
// $this->addException($e);
}
}
}
/**
* Adds an exception to be profiled in the debug bar
*
* @param Exception $e
*/
public function addException(Exception $e)
{
if ($this->hasCollector('exceptions')) {
/** @var \DebugBar\DataCollector\ExceptionsCollector $collector */
$collector = $this->getCollector('exceptions');
$collector->addException($e);
}
}
/**
* Returns a JavascriptRenderer for this instance
*
* @param string $baseUrl
* @param string $basePathng
* @return JavascriptRenderer
*/
public function getJavascriptRenderer($baseUrl = null, $basePath = null)
{
if ($this->jsRenderer === null) {
$this->jsRenderer = new JavascriptRenderer($this, $baseUrl, $basePath);
}
return $this->jsRenderer;
}
/**
* Modify the response and inject the debugbar (or data in headers)
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return \Symfony\Component\HttpFoundation\Response
*/
public function modifyResponse(Request $request, Response $response)
{
$app = $this->app;
if ($app->runningInConsole() || !$this->isEnabled() || $this->isDebugbarRequest()) {
return $response;
}
// Show the Http Response Exception in the Debugbar, when available
if (isset($response->exception)) {
$this->addException($response->exception);
}
if ($this->shouldCollect('config', false)) {
try {
$configCollector = new ConfigCollector();
$configCollector->setData($app['config']->all());
$this->addCollector($configCollector);
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ConfigCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($this->app->bound(SessionManager::class)){
/** @var \Illuminate\Session\SessionManager $sessionManager */
$sessionManager = $app->make(SessionManager::class);
$httpDriver = new SymfonyHttpDriver($sessionManager, $response);
$this->setHttpDriver($httpDriver);
if ($this->shouldCollect('session') && ! $this->hasCollector('session')) {
try {
$this->addCollector(new SessionCollector($sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add SessionCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
} else {
$sessionManager = null;
}
if ($this->shouldCollect('symfony_request', true) && !$this->hasCollector('request')) {
try {
$this->addCollector(new SymfonyRequestCollector($request, $response, $sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add SymfonyRequestCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
}
if ($app['config']->get('debugbar.clockwork') && ! $this->hasCollector('clockwork')) {
try {
$this->addCollector(new ClockworkCollector($request, $response, $sessionManager));
} catch (\Exception $e) {
$this->addException(
new Exception(
'Cannot add ClockworkCollector to Laravel Debugbar: ' . $e->getMessage(),
$e->getCode(),
$e
)
);
}
$this->addClockworkHeaders($response);
}
if ($response->isRedirection()) {
try {
$this->stackData();
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif (
$this->isJsonRequest($request) &&
$app['config']->get('debugbar.capture_ajax', true)
) {
try {
$this->sendDataInHeaders(true);
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif (
($response->headers->has('Content-Type') &&
strpos($response->headers->get('Content-Type'), 'html') === false)
|| $request->getRequestFormat() !== 'html'
) {
try {
// Just collect + store data, don't inject it.
$this->collect();
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
} elseif ($app['config']->get('debugbar.inject', true)) {
try {
$this->injectDebugbar($response);
} catch (\Exception $e) {
$app['log']->error('Debugbar exception: ' . $e->getMessage());
}
}
return $response;
}
/**
* Check if the Debugbar is enabled
* @return boolean
*/
public function isEnabled()
{
if ($this->enabled === null) {
$this->enabled = value($this->app['config']->get('debugbar.enabled'));
}
return $this->enabled;
}
/**
* Check if this is a request to the Debugbar OpenHandler
*
* @return bool
*/
protected function isDebugbarRequest()
{
return $this->app['request']->segment(1) == '_debugbar';
}
/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return bool
*/
protected function isJsonRequest(Request $request)
{
// If XmlHttpRequest, return true
if ($request->isXmlHttpRequest()) {
return true;
}
// Check if the request wants Json
$acceptable = $request->getAcceptableContentTypes();
return (isset($acceptable[0]) && $acceptable[0] == 'application/json');
}
/**
* Collects the data from the collectors
*
* @return array
*/
public function collect()
{
/** @var Request $request */
$request = $this->app['request'];
$this->data = array(
'__meta' => array(
'id' => $this->getCurrentRequestId(),
'datetime' => date('Y-m-d H:i:s'),
'utime' => microtime(true),
'method' => $request->getMethod(),
'uri' => $request->getRequestUri(),
'ip' => $request->getClientIp()
)
);
foreach ($this->collectors as $name => $collector) {
$this->data[$name] = $collector->collect();
}
// Remove all invalid (non UTF-8) characters
array_walk_recursive(
$this->data,
function (&$item) {
if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) {
$item = mb_convert_encoding($item, 'UTF-8', 'UTF-8');
}
}
);
if ($this->storage !== null) {
$this->storage->save($this->getCurrentRequestId(), $this->data);
}
return $this->data;
}
/**
* Injects the web debug toolbar into the given Response.
*
* @param \Symfony\Component\HttpFoundation\Response $response A Response instance
* Based on https://github.com/symfony/WebProfilerBundle/blob/master/EventListener/WebDebugToolbarListener.php
*/
public function injectDebugbar(Response $response)
{
$content = $response->getContent();
$renderer = $this->getJavascriptRenderer();
if ($this->getStorage()) {
$openHandlerUrl = route('debugbar.openhandler');
$renderer->setOpenHandlerUrl($openHandlerUrl);
}
$renderedContent = $renderer->renderHead() . $renderer->render();
$pos = strripos($content, '</body>');
if (false !== $pos) {
$content = substr($content, 0, $pos) . $renderedContent . substr($content, $pos);
} else {
$content = $content . $renderedContent;
}
$response->setContent($content);
}
/**
* Disable the Debugbar
*/
public function disable()
{
$this->enabled = false;
}
/**
* Adds a measure
*
* @param string $label
* @param float $start
* @param float $end
*/
public function addMeasure($label, $start, $end)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->addMeasure($label, $start, $end);
}
}
/**
* Utility function to measure the execution of a Closure
*
* @param string $label
* @param \Closure $closure
*/
public function measure($label, \Closure $closure)
{
if ($this->hasCollector('time')) {
/** @var \DebugBar\DataCollector\TimeDataCollector $collector */
$collector = $this->getCollector('time');
$collector->measure($label, $closure);
} else {
$closure();
}
}
/**
* Collect data in a CLI request
*
* @return array
*/
public function collectConsole()
{
if (!$this->isEnabled()) {
return;
}
$this->data = array(
'__meta' => array(
'id' => $this->getCurrentRequestId(),
'datetime' => date('Y-m-d H:i:s'),
'utime' => microtime(true),
'method' => 'CLI',
'uri' => isset($_SERVER['argv']) ? implode(' ', $_SERVER['argv']) : null,
'ip' => isset($_SERVER['SSH_CLIENT']) ? $_SERVER['SSH_CLIENT'] : null
)
);
foreach ($this->collectors as $name => $collector) {
$this->data[$name] = $collector->collect();
}
// Remove all invalid (non UTF-8) characters
array_walk_recursive(
$this->data,
function (&$item) {
if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) {
$item = mb_convert_encoding($item, 'UTF-8', 'UTF-8');
}
}
);
if ($this->storage !== null) {
$this->storage->save($this->getCurrentRequestId(), $this->data);
}
return $this->data;
}
/**
* Magic calls for adding messages
*
* @param string $method
* @param array $args
* @return mixed|void
*/
public function __call($method, $args)
{
$messageLevels = array('emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug', 'log');
if (in_array($method, $messageLevels)) {
foreach($args as $arg) {
$this->addMessage($arg, $method);
}
}
}
/**
* Adds a message to the MessagesCollector
*
* A message can be anything from an object to a string
*
* @param mixed $message
* @param string $label
*/
public function addMessage($message, $label = 'info')
{
if ($this->hasCollector('messages')) {
/** @var \DebugBar\DataCollector\MessagesCollector $collector */
$collector = $this->getCollector('messages');
$collector->addMessage($message, $label);
}
}
/**
* Check the version of Laravel
*
* @param string $version
* @param string $operator (default: '>=')
* @return boolean
*/
protected function checkVersion($version, $operator = ">=")
{
return version_compare($this->version, $version, $operator);
}
protected function isLumen()
{
return $this->is_lumen;
}
/**
* @param DebugBar $debugbar
*/
protected function selectStorage(DebugBar $debugbar)
{
$config = $this->app['config'];
if ($config->get('debugbar.storage.enabled')) {
$driver = $config->get('debugbar.storage.driver', 'file');
switch ($driver) {
case 'pdo':
$connection = $config->get('debugbar.storage.connection');
$table = $this->app['db']->getTablePrefix() . 'phpdebugbar';
$pdo = $this->app['db']->connection($connection)->getPdo();
$storage = new PdoStorage($pdo, $table);
break;
case 'redis':
$connection = $config->get('debugbar.storage.connection');
$storage = new RedisStorage($this->app['redis']->connection($connection));
break;
case 'custom':
$class = $config->get('debugbar.storage.provider');
$storage = $this->app->make($class);
break;
case 'file':
default:
$path = $config->get('debugbar.storage.path');
$storage = new FilesystemStorage($this->app['files'], $path);
break;
}
$debugbar->setStorage($storage);
}
}
protected function addClockworkHeaders(Response $response)
{
$prefix = $this->app['config']->get('debugbar.route_prefix');
$response->headers->set('X-Clockwork-Id', $this->getCurrentRequestId(), true);
$response->headers->set('X-Clockwork-Version', 1, true);
$response->headers->set('X-Clockwork-Path', $prefix .'/clockwork/', true);
}
}

View File

@@ -0,0 +1,57 @@
<?php namespace Barryvdh\Debugbar;
use Laravel\Lumen\Application;
class LumenServiceProvider extends ServiceProvider
{
/** @var Application */
protected $app;
/**
* Get the active router.
*
* @return Application
*/
protected function getRouter()
{
return $this->app;
}
/**
* Get the config path
*
* @return string
*/
protected function getConfigPath()
{
return base_path('config/debugbar.php');
}
/**
* Register the Debugbar Middleware
*
* @param string $middleware
*/
protected function registerMiddleware($middleware)
{
$this->app->middleware([$middleware]);
}
/**
* Check the App Debug status
*/
protected function checkAppDebug()
{
return env('APP_DEBUG');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('debugbar', 'command.debugbar.clear');
}
}

View File

@@ -0,0 +1,83 @@
<?php namespace Barryvdh\Debugbar\Middleware;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
class Debugbar
{
/**
* The App container
*
* @var Container
*/
protected $container;
/**
* The DebugBar instance
*
* @var LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new middleware instance.
*
* @param Container $container
* @param LaravelDebugbar $debugbar
*/
public function __construct(Container $container, LaravelDebugbar $debugbar)
{
$this->container = $container;
$this->debugbar = $debugbar;
}
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
try {
/** @var \Illuminate\Http\Response $response */
$response = $next($request);
} catch (Exception $e) {
$response = $this->handleException($request, $e);
}
// Modify the response to add the Debugbar
$this->debugbar->modifyResponse($request, $response);
return $response;
}
/**
* Handle the given exception.
*
* (Copy from Illuminate\Routing\Pipeline by Taylor Otwell)
*
* @param $passable
* @param Exception $e
* @return mixed
* @throws Exception
*/
protected function handleException($passable, Exception $e)
{
if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) {
throw $e;
}
$handler = $this->container->make(ExceptionHandler::class);
$handler->report($e);
return $handler->render($passable, $e);
}
}

View File

@@ -0,0 +1,248 @@
div.phpdebugbar {
font-size: 13px;
font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
}
div.phpdebugbar-resize-handle {
border-bottom-color: #ddd;
}
div.phpdebugbar-closed,
div.phpdebugbar-minimized {
border-top-color: #ddd;
}
a.phpdebugbar-restore-btn {
border-right-color: #ddd !important;
}
div.phpdebugbar code, div.phpdebugbar pre {
background: none;
font-family: monospace;
font-size: 1em;
border: 0;
padding: 0;
}
div.phpdebugbar-body {
border-top: none;
}
div.phpdebugbar-header {
min-height: 30px;
line-height: 20px;
padding-left: 39px;
}
div.phpdebugbar-header,
a.phpdebugbar-restore-btn,
div.phpdebugbar-openhandler .phpdebugbar-openhandler-header {
background: #f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIcAAACHCAYAAAA850oKAAAMfElEQVR42u2dC5RVZRXH7zwQGRTEqUEDxMdEQSggWAYjomlKGOAyylJBs5AhYVgIKYQ5hrgIfPVQwXgYQ4lppTApqxdiZGqAYy8cHIyKfCGi9lCPqO3N3VOX6d57vn3u9zrn7LvWfy3E4dzvfPs35+xvf3vvL5NhfoLxw4eC5oKaQW2gN0HvirxTANpBdpqHdsuY+MCFu4AaQNtl0mOtp0EzQFW6wJgEek4mNlFCe14MKosKxeGgn8hEJlpo32ouGLWgZ2TyUiG0cy0HjOdl0lL3mumn8iqRJ0Z6nyDVxeBYJ5OUaj2Q10mFv5wok5NKvQ36d85/T8wXx3hWJirRQgC2glaBrgKNJf+yghg4GnQdvV4OyYVjukxeoiE4FlSuuCDpDxqT+xcS+UwZBJy9Eplsf/VP4xAUgWOOGMAbCH4LuhM0Gx/t5AeUZVx94MtXimFSDkEROAaA3hKjGYVhOWgC6BgvIQgBZLEY0YgeBr3XIzt3B50KmgZaBtpM+TiohYUCYN1kW96IBjiCoJxiGOeB5oPuB+1UGO/VhS54gRhTuwZaAAF/sUeA6kG3g35Dr7Ko0dKz8n1JGWijGFSrlmqEoBL0IdD5oAWgtYpPA672gPrmG8BA0D4xqja9AzotAgi9QaNBXwY1gVooJ9TWuHE11TnfwG4So2rV30A9FID4OOgh0F5Pxr1EnFM7WqMAR71v4y400AvFoNp1UQgcnUBb4gAHOqebxKBa9RpGQkMAeX8JKw07cNBAB4lzql2b2vMnisz7RO/hoIF+UwyqXV9R8D+a4gAHhltfEINqFe5jnRQy74dSqam/cEhuqTFhclXXkHkfZjm2EQkOcU4dRU/hZ2Z5DQcNcjDF3cWoejVW4Rdzvddw0EBvFWNq127QESHzXuOqAhG/fLgiHD1AL4pBtevBsAQgCq2/4wKOzYy09c+LMY3ocoW5/7oLOPAPlyrCUUb5AmJQvXo9LDGIwuuPuYADYxndFAEZIs6pET2Rd5v8wLk/jsLwVuFALRbn1LkWKcz9Z13AEYT2aDiwVcNLYkw3yUHwMytsw4FqZjw9vijGdJMchIXOoFbbcKDOZmQ4PybGdJYcNCQw3OYzHxzb0DNWBGSYi/W3JAfZ6Y6QKfA/ZjBeL0vEkM6SgzC00GwbjldUK7XEOTWqXyskB73HVOOdjI6aC/jZyWJIY5qnMP+nm4g9ZUKqnwYznNPNYkhjyUEfVrDBAptw7C8EZjw9PiLOqdHkoEMUKuIesQkH6jMMQL4jhjSmOxTm/2jyF63B8RdQF0U40Dl6WQxpTOMUbDDBJhyoaxhPjyliRKPJQUcq2OAOm3Bg57o+4pzGJjmoCvQnW3Cg7mI8PU4WIxrVNAUbnAB6wxYcqDoGICvEiMb0hkrXIPiZqczrYq3MMqqV7sOFYysjpbDGo3YCSVRLWHIQ2eG+Itd4KgeG3vn+MXdQX2A8Pb4kRjSqxYrbG7tyYFhC3YGOUDEgd0CYUthdEY4KSn8TQ5pLDjpdwQ7HKsGgAQ7UjYzrf1SMaFS7VDoHRW1EFmVAmFL4AXFOncc8fgyamddfcAgH6gHGd/QEvSoGLUkYqV5NQcb+gY1OyCUOeDTje+RMF57QeVxKK4m+rloel3IDrYyUQtw1fFKMXjA9AqPKN4PODRy3xKYVzqcyGm5sJuNL6wSE/waxsCEwHpt1dth2vAUYDgqyPdExJ+Tx9sQhHXCgL1HDGMiqFMLwKrVSmEO/IJ0zjj8whoNB44PsqdT/0hE+j5xrkDLnFGNB94IaqISgwgMYutJ+CwJxBagRdEOx7kEZjcGYIYyBNiQMhj+DvovRY9AHPTk+o5KCX2fSCqexgB4yDcf+lELV5RUN/A8xhgHHfjvVrfb2BIZy6sA0i8oVcF/rr0H2LJ3GEO0yDQc3pfDUmICwjyr78BE8Dj35jCcfrG0Osm2x8RW2p8D48WSFa0PgmE9lmEbhQFKrGDf3PQ9hwMSmDTShZwQhXf8sw4CnKUyiV9guxj1tUHh6fIP6hBiDA9XIuNkjbfabKKC99Bi+kvaBDvIIhmqMN9ArbHuJPuEKBUB+YBoOpO8oxgTMtAwDnghxN7ZaCrItvMs9ggGr5z9Br7AWzaUeL1PrqI5A4C/F57A3HD2ZbjMJB+pupldt0jnF7KaVoEtAtRmPPhR8GgX6WpDt9Wr6lM4nyGH9NBZK4TZ+x0UExT9aTMKBGsmYpFEal9QYov82OseRchjMwlBBnQnwZOmfkX9j+zVarzBOPL3hHxnDlJYzJm5NxNQBbGCHx16eYyyvoTQg8Fy2aZSut9eT0P3xCuM+P2N4IJMZk9gLaQ25Hp5F8nOso8H2SJyVkUUYsOrsUtpef97T5fkflQrVDA/iRdWUQhrL7DxO1P30nsRa3EoPYaihnExM1N0Ro0DeUtdwoG5iTHQn8pYx3Dsw8PBo7yB7zMhY0C2g38c87H+eazj2qSTB+voh7x2DYdeDHg2S1YN1b9Gwg6VBPBojGCopGDYP9MtSq8Zi0j2o0gUcL1HyCLZm6OcpDGUUDJtBkdLXEg5DPs03DQc+bv9OS0uMQC7qEImb4osPgcEw0GU0zt2SmbbfdqN0wvE65QK0p7pdqRC7P8ERDO+jRN2VlMUtqYr561+qo8LxCqWUYXRvRMcNKsoyCoNjuo2sKEqQPZcipdvE8Mpae8DTXdcGFb27JysAcpIBGKro6bWIsrilN5mO9g45f/k0aDno4qgbVBQdDINjVqnb4rRhVUfXezhwfIpiAjPjB7VP9ASdG1S0/RsGyCkRUuBOJLDWF8qWFmnTNiNJTtQ07qshcFyl2oSOrtmjSBqcyIyWmXIIxyg8Pc5kXrNeDGZXJjOa5obAgUvgnszI5e/EaDGHg4w5sgMMC6jabRMFy3BFsYZ5zdPEaMmAowvoW7Q/sZM24PJlbg1lXvdeMVzM4KA4x2BKGG6mxByltHnm9xzTMYVe5CEctEcxhVLaS9mj+CTze68T43kGR84exZ1UwKSzUUklYxxdyW8RI7qCw/IexdQIwTYxoi04aI/irJw9CptZT5hv2o3p4zwiRjQIB+1RXEOdZlzvUVzPfHrI6ZSG4fBpQLgK6cMERNpYpgQOVBMTjp4pTe1LJRz4mhjGBGS2GDMdcKA2Rsjv2C4GTQccqHFMQM4Rg6YHjlZu+SMlAolhUwAH6nImHP0t9LgQODzRbk4hNgFysxg2HXCgFjLhOIyirWLgFMCBgbG+TEAuE+OmAw7U6gjZ6lvFwOmA490IgbERYuDIQqf+wTjBsTFCMtL3xdCsPirrqWXV4Tb7c+jSeCYcvaQAKrS6/heUzVfjqnmLLmGIvBMTkLkCwf/tXf0qyHY47Om67ZO5Ql/1tk3PCBT7W1Y1YKonZ/LidpPYLegwJiDjUwoEdlW6ImC0G487HKhFEe7zpykBYgvVIh+no94kjhPwJtavMO9zQIHCqiQIW15eHTAOgk4yHKh7ItzrLQkCAss5sKG+uWPDYj5BdSnbd8EOyXiq0vEZG5+Yw7E5YHYoDLKH9MUNiIXcmmKBI6uJEfZdtnh+T1hNeCPo5MBle87AzZkfOoVlkVXMex7u4X08S10JhgeO+7VSpeMl+Ie2BDw9GiNMgA8nY6P/gwcBnBI4Pk6MgoXYH+4+Km7bjn+5LgFw4P5Jrwj1Li5OxsZjQvD4jY8Fjk+qplcsNsRZnmcu1mYoYJKEpd2qCJMz3dLYcOKbQKO5e0OGoBhE9dDFjh+dgz84NEEbStycD+wz9qSh8WDzmjXUpaCzB0D0CbItyFX7qg1u/4dPJQSQTREmrU5zSuMPg+zJTVUeANGdlu4bmAXnrbkXaUhQ5HCCZef0LfLbLuJmyhsCojNtNN5D2wyl7XwH2eZuzyUEDtyeP9iwc/o2beT9L2vKLRBltOJZSg6v3tAAtXNKytNjboQJnqqYJJM/a8oNFLiZiMeL7TQaVCT61iUEDlza9o7w29dUIElmBitJxiwQ2JdtpqHs+uawyNiOhAByV4SJryD/60e0xD/KEyAOBU0KsqdYm2rF1Rb6igyy7SNfSAggIzMx/QTZY1TH0HLYdN9VjHfUqg6sNiFPkBbXUcgIrzY8mfLWwN7Zc20B93wdesUkwQepjwEU/UDXOtjnQvtWl0LyhTFf5u7xYbmZZ25rKHz/uKMd4Em6bqQLOWpxjaTe5gkQ2Hn5Aiw1dJTP2kr1Kl1N3eBQ8uTX0WMwDvkg6OEPcgQEroDwcMLVgfphAbpC+W1kJ7TXidyx/wdIVCWo/YcgUwAAAABJRU5ErkJggg==) no-repeat 5px 3px;
}
a.phpdebugbar-close-btn {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAADDSURBVDhPxZCxCsIwFEUzuGdwCvQD7BIIcehUXDqVfGM/wsG/iG4ifkzMlRuSPLo4eeFBue8c6Iv6b4wxW557Hs0KnWa3seqDxTiOyVqbhmF4UND4Rofdruyce3rvE6bIRSo9GOI1McbLPM/vVm4l7MAQr0kpHaQsJTDE+6zrepym6SVFdNgR69M+hBTLzWCI10gJvydvBkO8ZlmWayvhJnkzGOI1+fBTCOHWPkT7YNiBId4HizxnCKy+r81uX/otSn0A7dioI/vYX+8AAAAASUVORK5CYII=) no-repeat 9px 6px;
color : #555;
}
a.phpdebugbar-open-btn {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAOCAYAAADJ7fe0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfdCgYULwwNKp3GAAAAGHRFWHRTb2Z0d2FyZQBwYWludC5uZXQgNC4wLjOM5pdQAAAA1UlEQVQ4T2OgKpCUlOQH4vdA/B8Jv4dKEwYgDdLS0v8NDQ3/GxsbwzGIj2YoGEO1oQJkjcRgqDZUAJKwsrJ6/v//fwdiMFQbKgAZkpGR0QR0ajy60wlgRJhBXSGhpqb2CNnZhHBkZORcqBEMDFBX2BsYGGBVjAv39vZaQ41gYIC6Ygs2hbiwr6/vdqA+DqgR4CiW19bWxqoYF87Ly4uFaocAZWXlydgU4sJ2dna3ga4QgGqHAC0trY/YFOPCKSkpDVCtCAA01QaIsaYJHFgCqpVagIEBACGlF2c3r4ViAAAAAElFTkSuQmCC) no-repeat 8px 6px;
}
div.phpdebugbar-header,
div.phpdebugbar-openhandler-header {
background-size: 21px auto;
background-position: 9px center;
}
a.phpdebugbar-restore-btn {
background-size: 20px;
width: 16px;
border-right-color: #ccc;
}
div.phpdebugbar-header > div > * {
font-size: 13px;
}
div.phpdebugbar-header .phpdebugbar-tab {
padding: 5px 6px;
}
div.phpdebugbar .phpdebugbar-header select {
padding: 1px 0;
}
dl.phpdebugbar-widgets-kvlist dt {
width: 200px;
min-height: 20px;
padding: 7px 5px;
line-height: 20px;
}
dl.phpdebugbar-widgets-kvlist dd {
min-height: 20px;
margin-left: 210px;
padding: 7px 5px;
line-height: 20px;
}
ul.phpdebugbar-widgets-timeline .phpdebugbar-widgets-measure {
height: 25px;
line-height: 25px;
border: none;
}
ul.phpdebugbar-widgets-timeline li:nth-child(even) {
background-color: #f9f9f9;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-value {
height: 15px;
background-color: #f4645f;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label,
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-collector {
top: 0px;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter {
background-color: #f4645f;
}
a.phpdebugbar-tab:hover,
span.phpdebugbar-indicator:hover,
a.phpdebugbar-indicator:hover,
a.phpdebugbar-close-btn:hover,
a.phpdebugbar-open-btn:hover {
background-color: #ebebeb;
transition: background-color .25s linear 0s, color .25s linear 0s;
}
a.phpdebugbar-tab.phpdebugbar-active {
background: #f4645f;
color: #fff;
}
a.phpdebugbar-tab.phpdebugbar-active span.phpdebugbar-badge {
background-color: white;
color: #f4645f;
}
a.phpdebugbar-tab span.phpdebugbar-badge {
vertical-align: 0px;
padding: 2px 6px;
background: #f4645f;
font-size: 12px;
color: #fff;
border-radius: 10px;
}
div.phpdebugbar-openhandler .phpdebugbar-openhandler-header {
background-size: 20px;
}
div.phpdebugbar-openhandler a {
color: #555;
}
div.phpdebugbar-openhandler table {
table-layout: fixed;
}
div.phpdebugbar-openhandler table td,
div.phpdebugbar-openhandler table th {
text-align: left;
}
div.phpdebugbar-openhandler table td a {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.phpdebugbar-indicator span.phpdebugbar-tooltip {
top: -36px;
border: none;
border-radius: 5px;
background: #f5f5f5;
font-size: 12px;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter {
margin: 0;
padding: 5px 8px;
border-radius: 0;
font-size: 12px;
transition: background-color .25s linear 0s, color .25s linear 0s;
}
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar a.phpdebugbar-widgets-filter:hover {
background-color: #ad4844;
color: #fff;
}
.phpdebugbar-widgets-toolbar > .fa {
width: 25px;
font-size: 15px;
color: #555;
text-align: center;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item {
padding: 5px 10px;
border: none;
font-family: inherit;
overflow: visible;
display: flex;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-sql {
flex: 1 1 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-duration {
flex: 0 0 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-database {
flex: 0 0 auto;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item .phpdebugbar-widgets-params {
flex: 1 1 auto;
order: -1;
width: auto;
max-width: 200px;
}
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item:nth-child(even) {
background-color: #f9f9f9;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error:before {
font-size: 12px;
color: #e74c3c;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-warning:before {
font-size: 12px;
color: #f1c40f;
}
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-error {
color: #e74c3c;
}
.phpdebugbar-widgets-value.phpdebugbar-widgets-warning {
color: #f1c40f;
}
div.phpdebugbar-widgets-sqlqueries .phpdebugbar-widgets-status {
background: none !important;
font-family: inherit !important;
font-weight: 400 !important;
}

View File

@@ -0,0 +1,5 @@
# Font Squirrel Font-face Generator Configuration File
# Upload this file to the generator to recreate the settings
# you used to create these fonts.
{"mode":"expert","formats":["woff"],"tt_instructor":"keep","fallback":"none","fallback_custom":"100","options_subset":"none","subset_custom":"","subset_custom_range":"","subset_ot_features":"all","subset_ot_features_list":"","base64":"Y","css_stylesheet":"style.css","filename_suffix":"","emsquare":"2048","spacing_adjustment":"0","rememberme":"Y"}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,174 @@
<?php namespace Barryvdh\Debugbar;
use Illuminate\Routing\Router;
use Illuminate\Session\SessionManager;
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$configPath = __DIR__ . '/../config/debugbar.php';
$this->mergeConfigFrom($configPath, 'debugbar');
$this->app->alias(
'DebugBar\DataFormatter\DataFormatter',
'DebugBar\DataFormatter\DataFormatterInterface'
);
$this->app->singleton('debugbar', function ($app) {
$debugbar = new LaravelDebugbar($app);
if ($app->bound(SessionManager::class)) {
$sessionManager = $app->make(SessionManager::class);
$httpDriver = new SymfonyHttpDriver($sessionManager);
$debugbar->setHttpDriver($httpDriver);
}
return $debugbar;
}
);
$this->app->alias('debugbar', 'Barryvdh\Debugbar\LaravelDebugbar');
$this->app['command.debugbar.clear'] = $this->app->share(
function ($app) {
return new Console\ClearCommand($app['debugbar']);
}
);
$this->commands(array('command.debugbar.clear'));
}
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$app = $this->app;
$configPath = __DIR__ . '/../config/debugbar.php';
$this->publishes([$configPath => $this->getConfigPath()], 'config');
// If enabled is null, set from the app.debug value
$enabled = $this->app['config']->get('debugbar.enabled');
if (is_null($enabled)) {
$enabled = $this->checkAppDebug();
}
if (! $enabled) {
return;
}
$routeConfig = [
'namespace' => 'Barryvdh\Debugbar\Controllers',
'prefix' => $this->app['config']->get('debugbar.route_prefix'),
];
$this->getRouter()->group($routeConfig, function($router) {
$router->get('open', [
'uses' => 'OpenHandlerController@handle',
'as' => 'debugbar.openhandler',
]);
$router->get('clockwork/{id}', [
'uses' => 'OpenHandlerController@clockwork',
'as' => 'debugbar.clockwork',
]);
$router->get('assets/stylesheets', [
'uses' => 'AssetController@css',
'as' => 'debugbar.assets.css',
]);
$router->get('assets/javascript', [
'uses' => 'AssetController@js',
'as' => 'debugbar.assets.js',
]);
});
if ($app->runningInConsole() || $app->environment('testing')) {
return;
}
/** @var LaravelDebugbar $debugbar */
$debugbar = $this->app['debugbar'];
$debugbar->enable();
$debugbar->boot();
$this->registerMiddleware('Barryvdh\Debugbar\Middleware\Debugbar');
}
/**
* Get the active router.
*
* @return Router
*/
protected function getRouter()
{
return $this->app['router'];
}
/**
* Get the config path
*
* @return string
*/
protected function getConfigPath()
{
return config_path('debugbar.php');
}
/**
* Publish the config file
*
* @param string $configPath
*/
protected function publishConfig($configPath)
{
$this->publishes([$configPath => config_path('debugbar.php')], 'config');
}
/**
* Register the Debugbar Middleware
*
* @param string $middleware
*/
protected function registerMiddleware($middleware)
{
$kernel = $this->app['Illuminate\Contracts\Http\Kernel'];
$kernel->pushMiddleware($middleware);
}
/**
* Check the App Debug status
*/
protected function checkAppDebug()
{
return $this->app['config']->get('app.debug');
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('debugbar', 'command.debugbar.clear');
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Barryvdh\Debugbar\Storage;
use DebugBar\Storage\StorageInterface;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
/**
* Stores collected data into files
*/
class FilesystemStorage implements StorageInterface
{
protected $dirname;
protected $files;
protected $gc_lifetime = 24; // Hours to keep collected data;
protected $gc_probability = 5; // Probability of GC being run on a save request. (5/100)
/**
* @param \Illuminate\Filesystem\Filesystem $files The filesystem
* @param string $dirname Directories where to store files
*/
public function __construct($files, $dirname)
{
$this->files = $files;
$this->dirname = rtrim($dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
/**
* {@inheritDoc}
*/
public function save($id, $data)
{
if (!$this->files->isDirectory($this->dirname)) {
if ($this->files->makeDirectory($this->dirname, 0777, true)) {
$this->files->put($this->dirname . '.gitignore', "*\n!.gitignore");
} else {
throw new \Exception("Cannot create directory '$this->dirname'..");
}
}
try {
$this->files->put($this->makeFilename($id), json_encode($data));
} catch (\Exception $e) {
//TODO; error handling
}
// Randomly check if we should collect old files
if (rand(1, 100) <= $this->gc_probability) {
$this->garbageCollect();
}
}
/**
* Create the filename for the data, based on the id.
*
* @param $id
* @return string
*/
public function makeFilename($id)
{
return $this->dirname . basename($id) . ".json";
}
/**
* Delete files older then a certain age (gc_lifetime)
*/
protected function garbageCollect()
{
foreach (Finder::create()->files()->name('*.json')->date('< ' . $this->gc_lifetime . ' hour ago')->in(
$this->dirname
) as $file) {
$this->files->delete($file->getRealPath());
}
}
/**
* {@inheritDoc}
*/
public function get($id)
{
return json_decode($this->files->get($this->makeFilename($id)), true);
}
/**
* {@inheritDoc}
*/
public function find(array $filters = array(), $max = 20, $offset = 0)
{
// Sort by modified time, newest first
$sort = function (\SplFileInfo $a, \SplFileInfo $b) {
return strcmp($b->getMTime(), $a->getMTime());
};
// Loop through .json files, filter the metadata and stop when max is found.
$i = 0;
$results = array();
foreach (Finder::create()->files()->name('*.json')->in($this->dirname)->sort($sort) as $file) {
if ($i++ < $offset && empty($filters)) {
$results[] = null;
continue;
}
$data = json_decode($file->getContents(), true);
$meta = $data['__meta'];
unset($data);
if ($this->filter($meta, $filters)) {
$results[] = $meta;
}
if (count($results) >= ($max + $offset)) {
break;
}
}
return array_slice($results, $offset, $max);
}
/**
* Filter the metadata for matches.
*
* @param $meta
* @param $filters
* @return bool
*/
protected function filter($meta, $filters)
{
foreach ($filters as $key => $value) {
if (!isset($meta[$key]) || fnmatch($value, $meta[$key]) === false) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
public function clear()
{
foreach (Finder::create()->files()->name('*.json')->in($this->dirname) as $file) {
$this->files->delete($file->getRealPath());
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Barryvdh\Debugbar\Support\Clockwork;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use DebugBar\DataCollector\Renderable;
use Symfony\Component\HttpFoundation\Response;
/**
*
* Based on \Symfony\Component\HttpKernel\DataCollector\RequestDataCollector by Fabien Potencier <fabien@symfony.com>
*
*/
class ClockworkCollector extends DataCollector implements DataCollectorInterface, Renderable
{
/** @var \Symfony\Component\HttpFoundation\Request $request */
protected $request;
/** @var \Symfony\Component\HttpFoundation\Request $response */
protected $response;
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
protected $session;
/**
* Create a new SymfonyRequestCollector
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Request $response
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
*/
public function __construct($request, $response, $session = null)
{
$this->request = $request;
$this->response = $response;
$this->session = $session;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'clockwork';
}
/**
* {@inheritDoc}
*/
public function getWidgets()
{
return null;
}
/**
* {@inheritdoc}
*/
public function collect()
{
$request = $this->request;
$response = $this->response;
$data = array(
'getData' => $request->query->all(),
'postData' => $request->request->all(),
'headers' => $request->headers->all(),
'cookies' => $request->cookies->all(),
'uri' => $request->getRequestUri(),
'method' => $request->getMethod(),
'responseStatus' => $response->getStatusCode(),
);
if ($this->session) {
$sessionAttributes = array();
foreach ($this->session->all() as $key => $value) {
$sessionAttributes[$key] = $value;
}
$data['sessionData'] = $sessionAttributes;
}
if (isset($data['postData']['php-auth-pw'])) {
$data['postData']['php-auth-pw'] = '******';
}
if (isset($data['postData']['PHP_AUTH_PW'])) {
$data['postData']['PHP_AUTH_PW'] = '******';
}
return $data;
}
}

View File

@@ -0,0 +1,135 @@
<?php namespace Barryvdh\Debugbar\Support\Clockwork;
class Converter {
/**
* Convert the phpdebugbar data to Clockwork format.
*
* @param array $data
* @return array
*/
public function convert($data)
{
$meta = $data['__meta'];
// Default output
$output = [
'id' => $meta['id'],
'method' => $meta['method'],
'uri' => $meta['uri'],
'time' => $meta['utime'],
'headers' => [],
'cookies' => [],
'emailsData' => [],
'getData' => [],
'log' => [],
'postData' => [],
'sessionData' => [],
'timelineData' => [],
'viewsData' => [],
'controller' => null,
'responseTime' => null,
'responseStatus' => null,
'responseDuration' => 0,
];
if (isset($data['clockwork'])) {
$output = array_merge($output, $data['clockwork']);
}
if (isset($data['time'])) {
$time = $data['time'];
$output['time'] = $time['start'];
$output['responseTime'] = $time['end'];
$output['responseDuration'] = $time['duration'] * 1000;
foreach($time['measures'] as $measure) {
$output['timelineData'][] = [
'data' => [],
'description' => $measure['label'],
'duration' => $measure['duration'] * 1000,
'end' => $measure['end'],
'start' => $measure['start'],
'relative_start' => $measure['start'] - $time['start'],
];
}
}
if (isset($data['route'])) {
$route = $data['route'];
$controller = null;
if (isset($route['controller'])) {
$controller = $route['controller'];
} elseif (isset($route['uses'])) {
$controller = $route['uses'];
}
$output['controller'] = $controller;
list($method, $uri) = explode(' ', $route['uri'], 2);
$output['routes'][] = [
'action' => $controller,
'after' => isset($route['after']) ? $route['after'] : null,
'before' => isset($route['before']) ? $route['before'] : null,
'method' => $method,
'name' => isset($route['as']) ? $route['as'] : null,
'uri' => $uri,
];
}
if (isset($data['messages'])) {
foreach($data['messages']['messages'] as $message) {
$output['log'][] = [
'message' => $message['message'],
'time' => $message['time'],
'level' => $message['label'],
];
}
}
if (isset($data['queries'])) {
$queries = $data['queries'];
foreach($queries['statements'] as $statement){
$output['databaseQueries'][] = [
'query' => $statement['sql'],
'bindings' => $statement['params'],
'duration' => $statement['duration'] * 1000,
'connection' => $statement['connection']
];
}
$output['databaseDuration'] = $queries['accumulated_duration'] * 1000;
}
if (isset($data['views'])) {
foreach ($data['views']['templates'] as $view) {
$output['viewsData'][] = [
'description' => 'Rendering a view',
'duration' => 0,
'end' => 0,
'start' => 0,
'data' => [
'name' => $view['name'],
'data' => $view['params'],
],
];
}
}
if (isset($data['swiftmailer_mails'])) {
foreach($data['swiftmailer_mails']['mails'] as $mail) {
$output['emailsData'][] = [
'data' => [
'to' => $mail['to'],
'subject' => $mail['subject'],
'headers' => isset($mail['headers']) ? explode("\n", $mail['headers']) : null,
],
];
}
}
return $output;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Barryvdh\Debugbar;
use DebugBar\HttpDriverInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* HTTP driver for Symfony Request/Session
*/
class SymfonyHttpDriver implements HttpDriverInterface
{
/** @var \Symfony\Component\HttpFoundation\Session\Session */
protected $session;
/** @var \Symfony\Component\HttpFoundation\Response */
protected $response;
public function __construct($session, $response = null)
{
$this->session = $session;
$this->response = $response;
}
/**
* {@inheritDoc}
*/
public function setHeaders(array $headers)
{
if (!is_null($this->response)) {
$this->response->headers->add($headers);
}
}
/**
* {@inheritDoc}
*/
public function isSessionStarted()
{
if (!$this->session->isStarted()) {
$this->session->start();
}
return $this->session->isStarted();
}
/**
* {@inheritDoc}
*/
public function setSessionValue($name, $value)
{
$this->session->set($name, $value);
}
/**
* {@inheritDoc}
*/
public function hasSessionValue($name)
{
return $this->session->has($name);
}
/**
* {@inheritDoc}
*/
public function getSessionValue($name)
{
return $this->session->get($name);
}
/**
* {@inheritDoc}
*/
public function deleteSessionValue($name)
{
$this->session->remove($name);
}
}

View File

@@ -0,0 +1,88 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use Illuminate\Foundation\Application;
use Twig_Environment;
use Twig_Extension;
use Twig_SimpleFunction;
/**
* Access Laravels auth class in your Twig templates.
*/
class Debug extends Twig_Extension
{
/**
* @var \Barryvdh\Debugbar\LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new auth extension.
*
* @param \Illuminate\Foundation\Application $app
*/
public function __construct(Application $app)
{
if ($app->bound('debugbar')) {
$this->debugbar = $app['debugbar'];
} else {
$this->debugbar = null;
}
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'Laravel_Debugbar_Debug';
}
/**
* {@inheritDoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction(
'debug', [$this, 'debug'], array('needs_context' => true, 'needs_environment' => true)
),
);
}
/**
* Based on Twig_Extension_Debug / twig_var_dump
* (c) 2011 Fabien Potencier
*
* @param Twig_Environment $env
* @param $context
*/
public function debug(Twig_Environment $env, $context)
{
if (!$env->isDebug() || !$this->debugbar) {
return;
}
$count = func_num_args();
if (2 === $count) {
$data = array();
foreach ($context as $key => $value) {
if (is_object($value)) {
if (method_exists($value, 'toArray')) {
$data[$key] = $value->toArray();
} else {
$data[$key] = "Object (" . get_class($value) . ")";
}
} else {
$data[$key] = $value;
}
}
$this->debugbar->addMessage($data);
} else {
for ($i = 2; $i < $count; $i++) {
$this->debugbar->addMessage(func_get_arg($i));
}
}
return;
}
}

View File

@@ -0,0 +1,84 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use DebugBar\DataFormatter\DataFormatterInterface;
use Twig_Environment;
use Twig_Extension;
use Twig_SimpleFunction;
/**
* Dump variables using the DataFormatter
*/
class Dump extends Twig_Extension
{
/**
* @var \DebugBar\DataFormatter\DataFormatter
*/
protected $formatter;
/**
* Create a new auth extension.
*
* @param \DebugBar\DataFormatter\DataFormatterInterface $formatter
*/
public function __construct(DataFormatterInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'Laravel_Debugbar_Dump';
}
/**
* {@inheritDoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction(
'dump', [$this, 'dump'], array('is_safe' => ['html'], 'needs_context' => true, 'needs_environment' => true)
),
);
}
/**
* Based on Twig_Extension_Debug / twig_var_dump
* (c) 2011 Fabien Potencier
*
* @param Twig_Environment $env
* @param $context
*
* @return string
*/
public function dump(Twig_Environment $env, $context)
{
$output = '';
$count = func_num_args();
if (2 === $count) {
$data = array();
foreach ($context as $key => $value) {
if (is_object($value)) {
if (method_exists($value, 'toArray')) {
$data[$key] = $value->toArray();
} else {
$data[$key] = "Object (" . get_class($value) . ")";
}
} else {
$data[$key] = $value;
}
}
$output .= $this->formatter->formatVar($data);
} else {
for ($i = 2; $i < $count; $i++) {
$output .= $this->formatter->formatVar(func_get_arg($i));
}
}
return '<pre>'.$output.'</pre>';
}
}

View File

@@ -0,0 +1,56 @@
<?php namespace Barryvdh\Debugbar\Twig\Extension;
use Barryvdh\Debugbar\Twig\TokenParser\StopwatchTokenParser;
use Illuminate\Foundation\Application;
use Twig_Extension;
/**
* Access Laravels auth class in your Twig templates.
* Based on Symfony\Bridge\Twig\Extension\StopwatchExtension
*/
class Stopwatch extends Twig_Extension
{
/**
* @var \Barryvdh\Debugbar\LaravelDebugbar
*/
protected $debugbar;
/**
* Create a new auth extension.
*
* @param \Illuminate\Foundation\Application $app
*/
public function __construct(Application $app)
{
if ($app->bound('debugbar')) {
$this->debugbar = $app['debugbar'];
} else {
$this->debugbar = null;
}
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'stopwatch';
}
public function getTokenParsers()
{
return array(
/*
* {% stopwatch foo %}
* Some stuff which will be recorded on the timeline
* {% endstopwatch %}
*/
new StopwatchTokenParser($this->debugbar !== null),
);
}
public function getDebugbar()
{
return $this->debugbar;
}
}

View File

@@ -0,0 +1,37 @@
<?php namespace Barryvdh\Debugbar\Twig\Node;
/**
* Represents a stopwatch node. Based on Symfony\Bridge\Twig\Node\StopwatchNode
*
* @author Wouter J <wouter@wouterj.nl>
*/
class StopwatchNode extends \Twig_Node
{
public function __construct(
\Twig_NodeInterface $name,
$body,
\Twig_Node_Expression_AssignName $var,
$lineno = 0,
$tag = null
) {
parent::__construct(array('body' => $body, 'name' => $name, 'var' => $var), array(), $lineno, $tag);
}
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('var'))
->raw(' = ')
->subcompile($this->getNode('name'))
->write(";\n")
->write("\$this->env->getExtension('stopwatch')->getDebugbar()->startMeasure(")
->subcompile($this->getNode('var'))
->raw(");\n")
->subcompile($this->getNode('body'))
->write("\$this->env->getExtension('stopwatch')->getDebugbar()->stopMeasure(")
->subcompile($this->getNode('var'))
->raw(");\n");
}
}

View File

@@ -0,0 +1,55 @@
<?php namespace Barryvdh\Debugbar\Twig\TokenParser;
use Barryvdh\Debugbar\Twig\Node\StopwatchNode;
/**
* Token Parser for the stopwatch tag. Based on Symfony\Bridge\Twig\TokenParser\StopwatchTokenParser;
*
* @author Wouter J <wouter@wouterj.nl>
*/
class StopwatchTokenParser extends \Twig_TokenParser
{
protected $debugbarAvailable;
public function __construct($debugbarAvailable)
{
$this->debugbarAvailable = $debugbarAvailable;
}
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
// {% stopwatch 'bar' %}
$name = $this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
// {% endstopwatch %}
$body = $this->parser->subparse(array($this, 'decideStopwatchEnd'), true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
if ($this->debugbarAvailable) {
return new StopwatchNode(
$name,
$body,
new \Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()),
$lineno,
$this->getTag()
);
}
return $body;
}
public function getTag()
{
return 'stopwatch';
}
public function decideStopwatchEnd(\Twig_Token $token)
{
return $token->test('endstopwatch');
}
}

View File

@@ -0,0 +1,81 @@
<?php
if (!function_exists('debugbar')) {
/**
* Get the Debugbar instance
*
* @return \Barryvdh\Debugbar\LaravelDebugbar
*/
function debugbar()
{
return app('debugbar');
}
}
if (!function_exists('debug')) {
/**
* Adds one or more messages to the MessagesCollector
*
* @param mixed ...$value
* @return string
*/
function debug($value)
{
$debugbar = app('debugbar');
foreach (func_get_args() as $value) {
$debugbar->addMessage($value, 'debug');
}
}
}
if (!function_exists('start_measure')) {
/**
* Starts a measure
*
* @param string $name Internal name, used to stop the measure
* @param string $label Public name
*/
function start_measure($name, $label = null)
{
app('debugbar')->startMeasure($name, $label);
}
}
if (!function_exists('stop_measure')) {
/**
* Stop a measure
*
* @param string $name Internal name, used to stop the measure
*/
function stop_measure($name)
{
app('debugbar')->stopMeasure($name);
}
}
if (!function_exists('add_measure')) {
/**
* Adds a measure
*
* @param string $label
* @param float $start
* @param float $end
*/
function add_measure($label, $start, $end)
{
app('debugbar')->addMeasure($label, $start, $end);
}
}
if (!function_exists('measure')) {
/**
* Utility function to measure the execution of a Closure
*
* @param string $label
* @param \Closure $closure
*/
function measure($label, \Closure $closure)
{
app('debugbar')->measure($label, $closure);
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePhpdebugbarStorageTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('phpdebugbar', function (Blueprint $table) {
$table->string('id');
$table->longText('data');
$table->string('meta_utime');
$table->dateTime('meta_datetime');
$table->string('meta_uri');
$table->string('meta_ip');
$table->string('meta_method');
$table->primary('id');
$table->index('meta_utime');
$table->index('meta_datetime');
$table->index('meta_uri');
$table->index('meta_ip');
$table->index('meta_method');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('phpdebugbar');
}
}