mirror of
https://github.com/maximebf/php-debugbar.git
synced 2025-01-16 21:08:34 +01:00
huge refactoring, comments and docs
This commit is contained in:
parent
2d4d840d21
commit
836050cea5
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (C) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
|
||||||
|
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.
|
84
README.md
84
README.md
@ -1,3 +1,83 @@
|
|||||||
# Debug bar for PHP
|
# PHP Debug Bar
|
||||||
|
|
||||||
Displays a debug bar in the browser with information from php
|
Displays a debug bar in the browser with information from php.
|
||||||
|
No more `var_dump()` in your code!
|
||||||
|
|
||||||
|
![Screenshot](docs/screenshot.png)
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
|
||||||
|
- Generic debug bar with no other dependencies
|
||||||
|
- Easy to integrate with any project
|
||||||
|
- Clean, fast and easy to use interface
|
||||||
|
- Handles AJAX request
|
||||||
|
- Includes generic data collectors and collectors for well known libraries
|
||||||
|
- The client side bar is 100% coded in javascript
|
||||||
|
- Easily create your own collectors and their associated view in the bar
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The easiest way to install DebugBar is using [Composer](https://github.com/composer/composer)
|
||||||
|
with the following requirement:
|
||||||
|
|
||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"maximebf/debugbar": ">=1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Alternatively, you can [download the archive](https://github.com/maximebf/php-debugbar/zipball/master)
|
||||||
|
and add the src/ folder to PHP's include path:
|
||||||
|
|
||||||
|
set_include_path('/path/to/src' . PATH_SEPARATOR . get_include_path());
|
||||||
|
|
||||||
|
DebugBar does not provide an autoloader but follows the [PSR-0 convention](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md).
|
||||||
|
You can use the following snippet to autoload ConsoleKit classes:
|
||||||
|
|
||||||
|
spl_autoload_register(function($className) {
|
||||||
|
if (substr($className, 0, 8) === 'DebugBar') {
|
||||||
|
$filename = str_replace('\\', DIRECTORY_SEPARATOR, trim($className, '\\')) . '.php';
|
||||||
|
require_once $filename;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
DebugBar is very easy to use and you can add it to any of your projets in no time.
|
||||||
|
The easiest way is using the `render()` functions
|
||||||
|
|
||||||
|
<?php
|
||||||
|
use DebugBar\StandardDebugBar;
|
||||||
|
use DebugBar\Renderer\JavascriptRenderer;
|
||||||
|
|
||||||
|
$debugbar = new StandardDebugBar();
|
||||||
|
$debugbarRenderer = $debugbar->getJavascriptRenderer();
|
||||||
|
|
||||||
|
$debugbar["messages"]->addMessage("hello world!");
|
||||||
|
?>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<?php echo $debugbarRenderer->renderHead() ?>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
...
|
||||||
|
<?php echo $debugbarRenderer->render() ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
The DebugBar uses DataCollectors to collect data from your PHP code. Some of them are
|
||||||
|
automated but others are manual. Use the `DebugBar` like an array where keys are the
|
||||||
|
collector names. In our previous example, we add a message to the `MessagesCollector`:
|
||||||
|
|
||||||
|
$debugbar["messages"]->addMessage("hello world!");
|
||||||
|
|
||||||
|
`StandardDebugBar` activates all bundled collectors:
|
||||||
|
|
||||||
|
- `MemoryCollector` (*memory*)
|
||||||
|
- `MessagesCollector` (*messages*)
|
||||||
|
- `PhpInfoCollector` (*php*)
|
||||||
|
- `RequestDataCollector` (*request*)
|
||||||
|
- `TimeDataCollector` (*time*)
|
||||||
|
|
||||||
|
Learn more about DebugBar in the [docs](http://maximebf.github.io/php-debugbar).
|
||||||
|
19
composer.json
Normal file
19
composer.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "maximebf/debugbar",
|
||||||
|
"description": "Debug bar in the browser for php application",
|
||||||
|
"keywords": ["debug"],
|
||||||
|
"homepage": "https://github.com/maximebf/php-debugbar",
|
||||||
|
"type": "library",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [{
|
||||||
|
"name": "Maxime Bouroumeau-Fuseau",
|
||||||
|
"email": "maxime.bouroumeau@gmail.com",
|
||||||
|
"homepage": "http://maximebf.com"
|
||||||
|
}],
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {"DebugBar": "src/"}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@
|
|||||||
include '../tests/bootstrap.php';
|
include '../tests/bootstrap.php';
|
||||||
|
|
||||||
use DebugBar\StandardDebugBar;
|
use DebugBar\StandardDebugBar;
|
||||||
use DebugBar\Renderer\JavascriptRenderer;
|
|
||||||
|
|
||||||
$debugbar = new StandardDebugBar();
|
$debugbar = new StandardDebugBar();
|
||||||
$debugbarRenderer = new JavascriptRenderer($debugbar, '../web/');
|
$debugbarRenderer = $debugbar->getJavascriptRenderer()->setBaseUrl('../web');
|
||||||
|
@ -20,7 +20,7 @@ $debugbar['time']->startMeasure('render');
|
|||||||
?>
|
?>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<?php echo $debugbarRenderer->renderIncludes() ?>
|
<?php echo $debugbarRenderer->renderHead() ?>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
$('.ajax').click(function() {
|
$('.ajax').click(function() {
|
||||||
@ -39,8 +39,7 @@ $debugbar['time']->startMeasure('render');
|
|||||||
<p><a href="demo_ajax_exception.php" class="ajax">load ajax content with exception</a></p>
|
<p><a href="demo_ajax_exception.php" class="ajax">load ajax content with exception</a></p>
|
||||||
<?php
|
<?php
|
||||||
usleep(100);
|
usleep(100);
|
||||||
$debugbar->collect();
|
echo $debugbarRenderer->render();
|
||||||
echo $debugbarRenderer->renderToolbar();
|
|
||||||
?>
|
?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -6,6 +6,5 @@ $debugbar['messages']->addMessage('hello from ajax');
|
|||||||
?>
|
?>
|
||||||
hello from AJAX
|
hello from AJAX
|
||||||
<?php
|
<?php
|
||||||
$debugbar->collect();
|
echo $debugbarRenderer->render(false);
|
||||||
echo $debugbarRenderer->renderAjaxToolbar();
|
|
||||||
?>
|
?>
|
||||||
|
@ -11,6 +11,5 @@ try {
|
|||||||
?>
|
?>
|
||||||
error from AJAX
|
error from AJAX
|
||||||
<?php
|
<?php
|
||||||
$debugbar->collect();
|
echo $debugbarRenderer->render(false);
|
||||||
echo $debugbarRenderer->renderAjaxToolbar();
|
|
||||||
?>
|
?>
|
||||||
|
80
docs/data_collectors.md
Normal file
80
docs/data_collectors.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Collecting Data
|
||||||
|
|
||||||
|
## Using collectors
|
||||||
|
|
||||||
|
Collectors can be added to your debug bar using `addCollector()`.
|
||||||
|
|
||||||
|
$debugbar = new DebugBar();
|
||||||
|
$debugbar->addCollector(new DataCollector\RequestDataCollector());
|
||||||
|
|
||||||
|
Each collector as a unique name as defined by its `getName()` method. You can
|
||||||
|
access collectors using `getCollector($name)`.
|
||||||
|
|
||||||
|
$debugbar->addCollector(new DataCollector\MessagesCollector());
|
||||||
|
$debugbar->getCollector('messages')->addMessage("foobar");
|
||||||
|
// or:
|
||||||
|
$debugbar['messages']->addMessage("foobar");
|
||||||
|
|
||||||
|
Data will be collected from them when the debug bar is rendered. You can however
|
||||||
|
collect the data earlier using `collect()`.
|
||||||
|
|
||||||
|
$debugbar->collect();
|
||||||
|
|
||||||
|
## Creating collectors
|
||||||
|
|
||||||
|
Collectors must implement the `DebugBar\DataCollector\DataCollectorInterface`. They
|
||||||
|
may subclass `DebugBar\DataCollector\DataCollector` which provides utility methods.
|
||||||
|
|
||||||
|
Collectors must provide a `getName()` function returning their unique name and a
|
||||||
|
`collect()` function returning some json-encodable data. The latter will be called at the
|
||||||
|
same time the `DebugBar::collect()` method is called.
|
||||||
|
|
||||||
|
class MyDataCollector extends DebugBar\DataCollector\DataCollector
|
||||||
|
{
|
||||||
|
public function collect()
|
||||||
|
{
|
||||||
|
return array("uniqid" => uniqid());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'mycollector';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$debugbar->addCollector(new MyDataCollector());
|
||||||
|
|
||||||
|
This however won't show anything in the debug bar as no information are provided
|
||||||
|
on how to display these data. You could do that manually as you'll see in later chapter
|
||||||
|
or implement the `DebugBar\DataSource\Renderable` interface.
|
||||||
|
|
||||||
|
To implement it, you must define a `getWidgets()` function which returns an array
|
||||||
|
of key/value pairs where key are control names and values control options as defined
|
||||||
|
in `JavascriptRenderer::addControl($name, $options)` (see Rendering chapter).
|
||||||
|
|
||||||
|
class MyDataCollector extends DebugBar\DataCollector\DataCollector implements DebugBar\DataCollector\Renderable
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
|
||||||
|
public function getWidgets()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"mycollector" => array(
|
||||||
|
"icon" => "cogs",
|
||||||
|
"tooltip" => "uniqid()",
|
||||||
|
"map" => "uniqid",
|
||||||
|
"default" => "''"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
This will have the result of adding a new indicator to the debug bar.
|
||||||
|
|
||||||
|
## Included collectors
|
||||||
|
|
||||||
|
- `MemoryCollector` (*memory*)
|
||||||
|
- `MessagesCollector` (*messages*)
|
||||||
|
- `PhpInfoCollector` (*php*)
|
||||||
|
- `RequestDataCollector` (*request*)
|
||||||
|
- `TimeDataCollector` (*time*)
|
120
docs/javascript_bar.md
Normal file
120
docs/javascript_bar.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Javascript Bar
|
||||||
|
|
||||||
|
The default client side implementation of the debug bar is made
|
||||||
|
entirely in Javascript and is located in the *debugbar.js* file.
|
||||||
|
|
||||||
|
It adds a bottom-anchored bar which can have tabs and indicators.
|
||||||
|
The bar can be in an open or close state. When open, the tab panel is
|
||||||
|
visible.
|
||||||
|
An indicator is a piece of information displayed in the always-visible
|
||||||
|
part of the bar.
|
||||||
|
|
||||||
|
The bar handles multiple datasets by displaying a select box
|
||||||
|
which allows you to switch between them.
|
||||||
|
|
||||||
|
The state of the bar (height, visibilty, active panel) can be saved
|
||||||
|
between requests (enabled in the standard bar).
|
||||||
|
|
||||||
|
Each panel is composed of a widget which is used to display the
|
||||||
|
data from a data collector. Some common widgets are provided in
|
||||||
|
the *widgets.js* file.
|
||||||
|
|
||||||
|
The `PhpDebugBar` namespace is used for all objects and the only
|
||||||
|
dependencies are *jQuery*, *jquery-drag* and *FontAwesome* (css).
|
||||||
|
|
||||||
|
The main class is `PhpDebugBar.DebugBar`. It provides the infrastructure
|
||||||
|
to manage tabs, indicators and datasets.
|
||||||
|
|
||||||
|
When initialized, the `DebugBar` class adds itself to the `<body>` of the
|
||||||
|
page. It is empty by default.
|
||||||
|
|
||||||
|
## Tabs and indicators
|
||||||
|
|
||||||
|
Controls (ie. tabs and indicators) are uniquely named. You can check if
|
||||||
|
a control exists using `isControl(name)`.
|
||||||
|
|
||||||
|
Tabs can be added using the `createTab(name, widget, title)` function.
|
||||||
|
The third argument is optional and will be computed from the name if not
|
||||||
|
provided.
|
||||||
|
|
||||||
|
var debugbar = new PhpDebugBar.DebugBar();
|
||||||
|
debugbar.createTab("messages", new PhpDebugBar.Widgets.MessagesWidget());
|
||||||
|
|
||||||
|
Indicators can be added using `createIndicator(name, icon, tooltip, position)`.
|
||||||
|
Only `name` is required in this case. `icon` should be the name of a FontAwesome
|
||||||
|
icon. `position` can either by *right* (default) or *left*.
|
||||||
|
|
||||||
|
debugbar.createIndicator("time", "cogs", "Request duration");
|
||||||
|
|
||||||
|
You may have noticed that the data to use inside these controls is not
|
||||||
|
specified at the moment. Although it could be specified when initialized, it
|
||||||
|
is better to use data mapping to support dynamically changing the data set.
|
||||||
|
|
||||||
|
## Data mapping
|
||||||
|
|
||||||
|
To enable dynamically changing the data sets, we need to specify which values
|
||||||
|
should be feed into which controls. This can be done using `setDataMap(map)`
|
||||||
|
which takes as argument an object where properties are control names. Values
|
||||||
|
should be arrays where the first item is the property from the data set and
|
||||||
|
the second a default value.
|
||||||
|
|
||||||
|
debugbar.setDataMap({
|
||||||
|
"messages": ["messages", []],
|
||||||
|
"time": ["time.duration_str", "0ms"]
|
||||||
|
});
|
||||||
|
|
||||||
|
You can notice that nested properties can also be accessed using the dot
|
||||||
|
notation.
|
||||||
|
|
||||||
|
In this mapping, `data["messages"]` will be fed to the *messages* tab
|
||||||
|
and `data["time"]["duration_str"]` will be fed to the *time* indicator.
|
||||||
|
|
||||||
|
Note: you can append mapping info using `addDataMap(map)`
|
||||||
|
|
||||||
|
## Datasets
|
||||||
|
|
||||||
|
Although you shouldn't have to do anything regarding managing datasets,
|
||||||
|
it is interesting to know a few functions related to them.
|
||||||
|
|
||||||
|
`addDataSet(data, id)` adds a dataset to the bar. The select box that
|
||||||
|
allows to swtich between sets is only displayed if more than one are added.
|
||||||
|
`id` is optional and will be auto-generated if not specified.
|
||||||
|
|
||||||
|
`showDataSet(id)` allows you to switch to a specific dataset.
|
||||||
|
|
||||||
|
## Widgets
|
||||||
|
|
||||||
|
A widget is a javascript object which must contain at least an `element`
|
||||||
|
property. `element`'s value will be appended to the tab panel.
|
||||||
|
|
||||||
|
Widgets should provide a `setData()` function so they can be used with
|
||||||
|
the data mapper.
|
||||||
|
|
||||||
|
var MyWidget = function() {
|
||||||
|
this.element = $('<div class="mywidget" />');
|
||||||
|
};
|
||||||
|
|
||||||
|
MyWidget.prototype.setData = function(text) {
|
||||||
|
this.element.text(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
debugbar.createTab("mytab", new MyWidget());
|
||||||
|
debugbar.addDataMap({"mytab": ["mydata", ""]});
|
||||||
|
|
||||||
|
Widgets for bundled data collectors are included as well as more generic
|
||||||
|
widgets that you can build on top of. They are located in *widgets.js* in
|
||||||
|
the `PhpDebugBar.Widgets` namespace.
|
||||||
|
|
||||||
|
Generic widgets:
|
||||||
|
|
||||||
|
- `ListWidget`: renders an array as a UL list
|
||||||
|
- `KVListWidget`: renders a hash as a DL list
|
||||||
|
- `VariablesListWidget`: an extension of `KVListWidget` to display a list of variables
|
||||||
|
- `IFrameWidget`: renders an iframe
|
||||||
|
|
||||||
|
Data collectors related widgets:
|
||||||
|
|
||||||
|
- `MessagesWidget`: for the `MessagesCollector`
|
||||||
|
- `TimelineWidget`: for the `TimeDataCollector`
|
10
docs/manifest.json
Normal file
10
docs/manifest.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"title": "PHP Debug Bar",
|
||||||
|
"home": "../README.md",
|
||||||
|
"files": [
|
||||||
|
"../README.md",
|
||||||
|
"data_collectors.md",
|
||||||
|
"rendering.md",
|
||||||
|
"javascript_bar.md"
|
||||||
|
]
|
||||||
|
}
|
117
docs/rendering.md
Normal file
117
docs/rendering.md
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# Rendering
|
||||||
|
|
||||||
|
Rendering is performed using the `DebugBar\JavascriptRenderer̀ class. It contains
|
||||||
|
all the useful functions to included the needed assets and generate a debug bar.
|
||||||
|
|
||||||
|
$renderer = $debugbar->getJavascriptRenderer();
|
||||||
|
|
||||||
|
## Assets
|
||||||
|
|
||||||
|
The debug bar relies on some css and javascript files which needs to be included
|
||||||
|
into your webpage. This can be done in two ways:
|
||||||
|
|
||||||
|
- Using `JavascriptRenderer::renderHead()` which will returns a string with
|
||||||
|
the needed script and link tags
|
||||||
|
- Using [Assetic](https://github.com/kriswallsmith/assetic) and
|
||||||
|
`JavascriptRenderer::getAsseticCollection()`
|
||||||
|
|
||||||
|
I would recommend using the second method as Assetic is a very powerful asset
|
||||||
|
manager but the first method is provided to quickly integrate the debug bar
|
||||||
|
into any projets.
|
||||||
|
|
||||||
|
You can define the base url of your assets using `setBaseUrl()`. This is needed
|
||||||
|
in 99% of cases. If you are using Assetic, you may have to change the base path
|
||||||
|
of the assets if you moved the folder. This can be done using `setBasePath()`.
|
||||||
|
|
||||||
|
Using `renderHead()`:
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
...
|
||||||
|
<?php echo $renderer->renderHead() ?>
|
||||||
|
...
|
||||||
|
</head>
|
||||||
|
...
|
||||||
|
</html>
|
||||||
|
|
||||||
|
Using Assetic:
|
||||||
|
|
||||||
|
list($cssCollection, $jsCollection) = $renderer->getAsseticCollection();
|
||||||
|
|
||||||
|
Note that you can only use the debug bar assets and manage the dependencies by yourself
|
||||||
|
using `$renderer->setIncludeVendors(false)`.
|
||||||
|
|
||||||
|
## The javascript object
|
||||||
|
|
||||||
|
The renderer will generate all the needed code for your debug bar. This means
|
||||||
|
initializing the DebugBar js object, adding tabs and indicators, defining a data map, etc...
|
||||||
|
|
||||||
|
Data collectors can provide their own controls when implementing the
|
||||||
|
`DebugBar\DataCollector\Renderable` interface as explained in the Collecting Data chapter.
|
||||||
|
|
||||||
|
Thus in almost all cases, you should only have to use `render()` right away:
|
||||||
|
|
||||||
|
<html>
|
||||||
|
...
|
||||||
|
<body>
|
||||||
|
<?php echo $renderer->render() ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
This will print the initilization code for the toolbar and the dataset for the request.
|
||||||
|
When you are performing AJAX requests, you do not want to initialize a new toolbar but
|
||||||
|
add the dataset to the existing one. You can disable initialization using ̀false` as
|
||||||
|
the first argument of ̀render()`.
|
||||||
|
|
||||||
|
<p>my ajax content</p>
|
||||||
|
<?php echo $renderer->render(false) ?>
|
||||||
|
|
||||||
|
### Controlling object initialization
|
||||||
|
|
||||||
|
You can further control the initialization of the javascript object using `setInitialization()`.
|
||||||
|
It takes a bitwise value made out of the constants ̀INITIALIZE_CONSTRUCTOR` and `INITIALIZE_CONTROLS`.
|
||||||
|
The first one controls whether to initialize the variable (ie. `var debugbar = new DebugBar()`). The
|
||||||
|
second one whether to initialize all the controls (ie. adding tab and indicators as well as data mapping).
|
||||||
|
|
||||||
|
You can also control the class name of the object using `setJavascriptClass()` and the name of
|
||||||
|
the instance variable using `setVariableName()`.
|
||||||
|
|
||||||
|
Let's say you have subclassed `PhpDebugBar.DebugBar` in javascript to do your own initilization.
|
||||||
|
Your new object is called `MyDebugBar`.
|
||||||
|
|
||||||
|
$renderer->setJavascriptClass("MyDebugBar");
|
||||||
|
$renderer->setInitialization(JavascriptRenderer::INITIALIZE_CONSTRUCTOR);
|
||||||
|
// ...
|
||||||
|
echo $renderer->render();
|
||||||
|
|
||||||
|
This has the result of printing:
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var phpdebugbar = new MyDebugBar();
|
||||||
|
phpdebugbar.addDataSet({ ... });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
Using `setInitialization(0)` will only render the addDataSet part.
|
||||||
|
|
||||||
|
### Defining controls
|
||||||
|
|
||||||
|
Controls can be manually added to the debug bar using `addControl($name, $options)`. You should read
|
||||||
|
the Javascript bar chapter before this section.
|
||||||
|
|
||||||
|
`$name` will be the name of your control and `$options` is a key/value pair array with these
|
||||||
|
possible values:
|
||||||
|
|
||||||
|
- *icon*: icon name
|
||||||
|
- *tooltip*: string
|
||||||
|
- *widget*: widget class name
|
||||||
|
- *map*: a property name from the data to map the control to
|
||||||
|
- *default*: a js string, default value of the data map
|
||||||
|
|
||||||
|
At least *icon* or *widget* are needed. If *widget* is specified, a tab will be created, otherwise
|
||||||
|
an indicator.
|
||||||
|
|
||||||
|
$renderer->addControl('messages', array(
|
||||||
|
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
|
||||||
|
"map" => "messages",
|
||||||
|
"default" => "[]"
|
||||||
|
));
|
BIN
docs/screenshot.png
Normal file
BIN
docs/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -1,9 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for data collectors
|
||||||
|
*/
|
||||||
abstract class DataCollector implements DataCollectorInterface
|
abstract class DataCollector implements DataCollectorInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Transforms a PHP variable to a string representation
|
||||||
|
*
|
||||||
|
* @param mixed $var
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function varToString($var)
|
public function varToString($var)
|
||||||
{
|
{
|
||||||
return print_r($var, true);
|
return print_r($var, true);
|
||||||
|
@ -1,10 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataCollector Interface
|
||||||
|
*/
|
||||||
interface DataCollectorInterface
|
interface DataCollectorInterface
|
||||||
{
|
{
|
||||||
function getName();
|
/**
|
||||||
|
* Called by the DebugBar when data needs to be collected
|
||||||
|
*
|
||||||
|
* @return array Collected data
|
||||||
|
*/
|
||||||
function collect();
|
function collect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique name of the collector
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getName();
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
class DependencyCollector extends DataCollector
|
class DependencyCollector extends DataCollector
|
||||||
{
|
{
|
||||||
public function getName()
|
/**
|
||||||
{
|
* {@inheritDoc}
|
||||||
return 'dependency';
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'dependency';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,47 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
class MemoryCollector extends DataCollector
|
/**
|
||||||
|
* Collects info about memory usage
|
||||||
|
*/
|
||||||
|
class MemoryCollector extends DataCollector implements Renderable
|
||||||
{
|
{
|
||||||
protected $peakUsage = 0;
|
protected $peakUsage = 0;
|
||||||
|
|
||||||
public function getName()
|
/**
|
||||||
{
|
* Returns the peak memory usage
|
||||||
return 'memory';
|
*
|
||||||
}
|
* @return integer
|
||||||
|
*/
|
||||||
public function getPeakUsage()
|
public function getPeakUsage()
|
||||||
{
|
{
|
||||||
return $this->peakUsage;
|
return $this->peakUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the peak memory usage value
|
||||||
|
*/
|
||||||
public function updatePeakUsage()
|
public function updatePeakUsage()
|
||||||
{
|
{
|
||||||
$this->peakUsage = memory_get_peak_usage(true);
|
$this->peakUsage = memory_get_peak_usage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a size in bytes to a human readable string
|
||||||
|
*
|
||||||
|
* @param string $size
|
||||||
|
* @param integer $precision
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toReadableString($size, $precision = 2)
|
public function toReadableString($size, $precision = 2)
|
||||||
{
|
{
|
||||||
$base = log($size) / log(1024);
|
$base = log($size) / log(1024);
|
||||||
@ -28,6 +49,9 @@ class MemoryCollector extends DataCollector
|
|||||||
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$this->updatePeakUsage();
|
$this->updatePeakUsage();
|
||||||
@ -36,4 +60,27 @@ class MemoryCollector extends DataCollector
|
|||||||
'peak_usage_str' => $this->toReadableString($this->peakUsage)
|
'peak_usage_str' => $this->toReadableString($this->peakUsage)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'memory';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getWidgets()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"memory" => array(
|
||||||
|
"icon" => "cogs",
|
||||||
|
"tooltip" => "Memory Usage",
|
||||||
|
"map" => "peak_usage_str",
|
||||||
|
"default" => "'0B'"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
class MessagesCollector extends DataCollector
|
/**
|
||||||
|
* Provides a way to log messages
|
||||||
|
*/
|
||||||
|
class MessagesCollector extends DataCollector implements Renderable
|
||||||
{
|
{
|
||||||
protected $messages = array();
|
protected $messages = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message
|
||||||
|
*
|
||||||
|
* A message can be anything from an object to a string
|
||||||
|
*
|
||||||
|
* @param mixed $message
|
||||||
|
* @param string $label
|
||||||
|
*/
|
||||||
public function addMessage($message, $label = 'info')
|
public function addMessage($message, $label = 'info')
|
||||||
{
|
{
|
||||||
$this->messages[] = array(
|
$this->messages[] = array(
|
||||||
@ -18,18 +37,43 @@ class MessagesCollector extends DataCollector
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all messages
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getMessages()
|
public function getMessages()
|
||||||
{
|
{
|
||||||
return $this->messages;
|
return $this->messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function collect()
|
||||||
|
{
|
||||||
|
return $this->messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return 'messages';
|
return 'messages';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function collect()
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getWidgets()
|
||||||
{
|
{
|
||||||
return $this->messages;
|
return array(
|
||||||
|
"messages" => array(
|
||||||
|
"widget" => "PhpDebugBar.Widgets.MessagesWidget",
|
||||||
|
"map" => "messages",
|
||||||
|
"default" => "[]"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects info about PHP
|
||||||
|
*/
|
||||||
class PhpInfoCollector extends DataCollector
|
class PhpInfoCollector extends DataCollector
|
||||||
{
|
{
|
||||||
public function getName()
|
/**
|
||||||
{
|
* {@inheritDoc}
|
||||||
return 'php';
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'version' => PHP_VERSION
|
'version' => PHP_VERSION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'php';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
25
src/DebugBar/DataCollector/Renderable.php
Normal file
25
src/DebugBar/DataCollector/Renderable.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a DataCollector is renderable using JavascriptRenderer
|
||||||
|
*/
|
||||||
|
interface Renderable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns a hash where keys are control names and their values
|
||||||
|
* an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getWidgets();
|
||||||
|
}
|
@ -1,14 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
class RequestDataCollector extends DataCollector
|
/**
|
||||||
|
* Collects info about the current request
|
||||||
|
*/
|
||||||
|
class RequestDataCollector extends DataCollector implements Renderable
|
||||||
{
|
{
|
||||||
public function getName()
|
/**
|
||||||
{
|
* {@inheritDoc}
|
||||||
return 'request';
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
public function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$vars = array('_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER');
|
$vars = array('_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER');
|
||||||
@ -22,4 +31,26 @@ class RequestDataCollector extends DataCollector
|
|||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'request';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getWidgets()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"request" => array(
|
||||||
|
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
|
||||||
|
"map" => "request",
|
||||||
|
"default" => "{}"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar\DataCollector;
|
namespace DebugBar\DataCollector;
|
||||||
|
|
||||||
class TimeCollector extends DataCollector
|
/**
|
||||||
|
* Collects info about the request duration as well as providing
|
||||||
|
* a way to log duration of any operations
|
||||||
|
*/
|
||||||
|
class TimeDataCollector extends DataCollector implements Renderable
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $requestStartTime;
|
protected $requestStartTime;
|
||||||
|
|
||||||
protected $requestEndTime;
|
protected $requestEndTime;
|
||||||
|
|
||||||
protected $measures = array();
|
protected $measures = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param float $requestStartTime
|
||||||
|
*/
|
||||||
public function __construct($requestStartTime = null)
|
public function __construct($requestStartTime = null)
|
||||||
{
|
{
|
||||||
if ($requestStartTime === null) {
|
if ($requestStartTime === null) {
|
||||||
@ -23,6 +37,12 @@ class TimeCollector extends DataCollector
|
|||||||
$this->requestStartTime = $requestStartTime;
|
$this->requestStartTime = $requestStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a measure
|
||||||
|
*
|
||||||
|
* @param string $name Internal name, used to stop the measure
|
||||||
|
* @param string $label Public name
|
||||||
|
*/
|
||||||
public function startMeasure($name, $label = null)
|
public function startMeasure($name, $label = null)
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
@ -33,6 +53,11 @@ class TimeCollector extends DataCollector
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a measure
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
public function stopMeasure($name)
|
public function stopMeasure($name)
|
||||||
{
|
{
|
||||||
$end = microtime(true);
|
$end = microtime(true);
|
||||||
@ -42,16 +67,54 @@ class TimeCollector extends DataCollector
|
|||||||
$this->measures[$name]['duration_str'] = $this->toReadableString($this->measures[$name]['duration']);
|
$this->measures[$name]['duration_str'] = $this->toReadableString($this->measures[$name]['duration']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to measure the execution of a Closure
|
||||||
|
*
|
||||||
|
* @param Closure $closure
|
||||||
|
*/
|
||||||
|
public function measure(\Closure $closure)
|
||||||
|
{
|
||||||
|
$name = spl_object_hash($closure);
|
||||||
|
$this->startMeasure($name, $closure);
|
||||||
|
$closure();
|
||||||
|
$this->stopMeasure($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all measures
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getMeasures()
|
||||||
|
{
|
||||||
|
return $this->measures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the request start time
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
public function getRequestStartTime()
|
public function getRequestStartTime()
|
||||||
{
|
{
|
||||||
return $this->requestStartTime;
|
return $this->requestStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the request end time
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
public function getRequestEndTime()
|
public function getRequestEndTime()
|
||||||
{
|
{
|
||||||
return $this->requestEndTime;
|
return $this->requestEndTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the duration of a request
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
public function getRequestDuration()
|
public function getRequestDuration()
|
||||||
{
|
{
|
||||||
if ($this->requestEndTime !== null) {
|
if ($this->requestEndTime !== null) {
|
||||||
@ -60,21 +123,20 @@ class TimeCollector extends DataCollector
|
|||||||
return microtime(true) - $this->requestStartTime;
|
return microtime(true) - $this->requestStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMeasures()
|
/**
|
||||||
{
|
* Transforms a duration in seconds in a readable string
|
||||||
return $this->measures;
|
*
|
||||||
}
|
* @param float $value
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toReadableString($value)
|
public function toReadableString($value)
|
||||||
{
|
{
|
||||||
return round($value / 1000) . 'ms';
|
return round($value * 1000) . 'ms';
|
||||||
}
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'time';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function collect()
|
public function collect()
|
||||||
{
|
{
|
||||||
$this->requestEndTime = microtime(true);
|
$this->requestEndTime = microtime(true);
|
||||||
@ -92,4 +154,32 @@ class TimeCollector extends DataCollector
|
|||||||
'measures' => array_values($this->measures)
|
'measures' => array_values($this->measures)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'time';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getWidgets()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
"time" => array(
|
||||||
|
"icon" => "time",
|
||||||
|
"tooltip" => "Request Duration",
|
||||||
|
"map" => "time.duration_str",
|
||||||
|
"default" => "'0ms'"
|
||||||
|
),
|
||||||
|
"timeline" => array(
|
||||||
|
"widget" => "PhpDebugBar.Widgets.TimelineWidget",
|
||||||
|
"map" => "time",
|
||||||
|
"default" => "{}"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,28 +1,69 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar;
|
namespace DebugBar;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
use DebugBar\DataCollector\DataCollector;
|
use DebugBar\DataCollector\DataCollector;
|
||||||
use DebugBar\Renderer\Renderer;
|
|
||||||
use DebugBar\Renderer\JavascriptRenderer;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main DebugBar object
|
||||||
|
*
|
||||||
|
* Mananges data collectors. DebugBar provides an array-like access
|
||||||
|
* to collectors by name.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* $debugbar = new DebugBar();
|
||||||
|
* $debugbar->addCollector(new DataCollector\MessagesCollector());
|
||||||
|
* $debugbar['messages']->addMessage("foobar");
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
class DebugBar implements ArrayAccess
|
class DebugBar implements ArrayAccess
|
||||||
{
|
{
|
||||||
protected $collectors = array();
|
protected $collectors = array();
|
||||||
|
|
||||||
protected $data;
|
protected $data;
|
||||||
|
|
||||||
|
protected $jsRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a data collector
|
||||||
|
*
|
||||||
|
* @param DataCollector $collector
|
||||||
|
*/
|
||||||
public function addCollector(DataCollector $collector)
|
public function addCollector(DataCollector $collector)
|
||||||
{
|
{
|
||||||
|
if (isset($this->collectors[$collector->getName()])) {
|
||||||
|
throw new DebugBarException("'$name' is already a registered collector");
|
||||||
|
}
|
||||||
$this->collectors[$collector->getName()] = $collector;
|
$this->collectors[$collector->getName()] = $collector;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a data collector has been added
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
public function hasCollector($name)
|
public function hasCollector($name)
|
||||||
{
|
{
|
||||||
return isset($this->collectors[$name]);
|
return isset($this->collectors[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data collector
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return DataCollector
|
||||||
|
*/
|
||||||
public function getCollector($name)
|
public function getCollector($name)
|
||||||
{
|
{
|
||||||
if (!isset($this->collectors[$name])) {
|
if (!isset($this->collectors[$name])) {
|
||||||
@ -31,11 +72,61 @@ class DebugBar implements ArrayAccess
|
|||||||
return $this->collectors[$name];
|
return $this->collectors[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all data collectors
|
||||||
|
*
|
||||||
|
* @return array[DataCollector]
|
||||||
|
*/
|
||||||
public function getCollectors()
|
public function getCollectors()
|
||||||
{
|
{
|
||||||
return $this->collectors;
|
return $this->collectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the data from the collectors
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function collect()
|
||||||
|
{
|
||||||
|
$this->data = array();
|
||||||
|
foreach ($this->collectors as $name => $collector) {
|
||||||
|
$this->data[$name] = $collector->collect();
|
||||||
|
}
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns collected data
|
||||||
|
*
|
||||||
|
* Will collect the data if none have been collected yet
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
if ($this->data === null) {
|
||||||
|
$this->collect();
|
||||||
|
}
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a JavascriptRenderer for this instance
|
||||||
|
*
|
||||||
|
* @return JavascriptRenderer
|
||||||
|
*/
|
||||||
|
public function getJavascriptRenderer()
|
||||||
|
{
|
||||||
|
if ($this->jsRenderer === null) {
|
||||||
|
$this->jsRenderer = new JavascriptRenderer($this);
|
||||||
|
}
|
||||||
|
return $this->jsRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
// ArrayAccess implementation
|
||||||
|
|
||||||
public function offsetSet($key, $value)
|
public function offsetSet($key, $value)
|
||||||
{
|
{
|
||||||
throw new DebugBarException("DebugBar[] is read-only");
|
throw new DebugBarException("DebugBar[] is read-only");
|
||||||
@ -55,18 +146,4 @@ class DebugBar implements ArrayAccess
|
|||||||
{
|
{
|
||||||
throw new DebugBarException("DebugBar[] is read-only");
|
throw new DebugBarException("DebugBar[] is read-only");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function collect()
|
|
||||||
{
|
|
||||||
$this->data = array();
|
|
||||||
foreach ($this->collectors as $name => $collector) {
|
|
||||||
$this->data[$name] = $collector->collect();
|
|
||||||
}
|
|
||||||
return $this->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getData()
|
|
||||||
{
|
|
||||||
return $this->data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar;
|
namespace DebugBar;
|
||||||
|
|
||||||
|
407
src/DebugBar/JavascriptRenderer.php
Normal file
407
src/DebugBar/JavascriptRenderer.php
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace DebugBar;
|
||||||
|
|
||||||
|
use DebugBar\DataCollector\Renderable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the debug bar using the client side javascript implementation
|
||||||
|
*
|
||||||
|
* Generates all the needed initialization code of controls
|
||||||
|
*/
|
||||||
|
class JavascriptRenderer
|
||||||
|
{
|
||||||
|
const INITIALIZE_CONSTRUCTOR = 2;
|
||||||
|
|
||||||
|
const INITIALIZE_CONTROLS = 4;
|
||||||
|
|
||||||
|
protected $debugBar;
|
||||||
|
|
||||||
|
protected $baseUrl;
|
||||||
|
|
||||||
|
protected $basePath;
|
||||||
|
|
||||||
|
protected $cssVendors = array('vendor/font-awesome/css/font-awesome.css');
|
||||||
|
|
||||||
|
protected $jsVendors = array('vendor/jquery-1.8.3.min.js', 'vendor/jquery.event.drag-2.2.js');
|
||||||
|
|
||||||
|
protected $includeVendors = true;
|
||||||
|
|
||||||
|
protected $cssFiles = array('debugbar.css');
|
||||||
|
|
||||||
|
protected $jsFiles = array('debugbar.js', 'widgets.js');
|
||||||
|
|
||||||
|
protected $javascriptClass = 'PhpDebugBar.DebugBar';
|
||||||
|
|
||||||
|
protected $variableName = 'phpdebugbar';
|
||||||
|
|
||||||
|
protected $initialization;
|
||||||
|
|
||||||
|
protected $controls = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DebugBar $debugBar
|
||||||
|
* @param string $baseUrl
|
||||||
|
* @param string $basePath
|
||||||
|
*/
|
||||||
|
public function __construct(DebugBar $debugBar, $baseUrl = '/debugbar', $basePath = null)
|
||||||
|
{
|
||||||
|
$this->debugBar = $debugBar;
|
||||||
|
$this->baseUrl = $baseUrl;
|
||||||
|
|
||||||
|
if ($basePath === null) {
|
||||||
|
$basePath = __DIR__ . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array('..', '..', '..', 'web'));
|
||||||
|
}
|
||||||
|
$this->basePath = $basePath;
|
||||||
|
|
||||||
|
// bitwise operations cannot be done in class definition :(
|
||||||
|
$this->initialization = self::INITIALIZE_CONSTRUCTOR | self::INITIALIZE_CONTROLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the path which assets are relative to
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public function setBasePath($path)
|
||||||
|
{
|
||||||
|
$this->basePath = $path;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path which assets are relative to
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBasePath()
|
||||||
|
{
|
||||||
|
return $this->basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the base URL from which assets will be served
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
*/
|
||||||
|
public function setBaseUrl($url)
|
||||||
|
{
|
||||||
|
$this->baseUrl = $url;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base URL from which assets will be served
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBaseUrl()
|
||||||
|
{
|
||||||
|
return $this->baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to include vendor assets
|
||||||
|
*
|
||||||
|
* @param boolean $enabled
|
||||||
|
*/
|
||||||
|
public function setIncludeVendors($enabled = true)
|
||||||
|
{
|
||||||
|
$this->includeVendors = $enabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if vendors assets are included
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function areVendorsIncluded()
|
||||||
|
{
|
||||||
|
return $this->includeVendors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the javascript class name
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
*/
|
||||||
|
public function setJavascriptClass($className)
|
||||||
|
{
|
||||||
|
$this->javascriptClass = $className;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the javascript class name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getJavascriptClass()
|
||||||
|
{
|
||||||
|
return $this->javascriptClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the variable name of the class instance
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function setVariableName($name)
|
||||||
|
{
|
||||||
|
$this->variableName = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the variable name of the class instance
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getVariableName()
|
||||||
|
{
|
||||||
|
return $this->variableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets what should be initialized
|
||||||
|
*
|
||||||
|
* - INITIALIZE_CONSTRUCTOR: only initializes the instance
|
||||||
|
* - INITIALIZE_CONTROLS: initializes the controls and data mapping
|
||||||
|
* - INITIALIZE_CONSTRUCTOR | INITIALIZE_CONTROLS: initialize everything (default)
|
||||||
|
*
|
||||||
|
* @param integer $init
|
||||||
|
*/
|
||||||
|
public function setInitialization($init)
|
||||||
|
{
|
||||||
|
$this->initialization = $init;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns what should be initialized
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getInitialization()
|
||||||
|
{
|
||||||
|
return $this->initialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a control to initialize
|
||||||
|
*
|
||||||
|
* Possible options:
|
||||||
|
* - icon: icon name
|
||||||
|
* - tooltip: string
|
||||||
|
* - widget: widget class name
|
||||||
|
* - map: a property name from the data to map the control to
|
||||||
|
* - default: a js string, default value of the data map
|
||||||
|
*
|
||||||
|
* "icon" or "widget" are at least needed
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function addControl($name, $options)
|
||||||
|
{
|
||||||
|
if (!isset($options['icon']) || !isset($options['widget'])) {
|
||||||
|
throw new DebugBarException("Missing 'icon' or 'widget' option for control '$name'");
|
||||||
|
}
|
||||||
|
$this->controls[$name] = $options;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of asset files
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getAssetFiles()
|
||||||
|
{
|
||||||
|
$cssFiles = $this->cssFiles;
|
||||||
|
$jsFiles = $this->jsFiles;
|
||||||
|
|
||||||
|
if ($this->includeVendors) {
|
||||||
|
$cssFiles = array_merge($this->cssVendors, $cssFiles);
|
||||||
|
$jsFiles = array_merge($this->jsVendors, $jsFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($cssFiles, $jsFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a tuple where the both items are Assetic AssetCollection,
|
||||||
|
* the first one being css files and the second js files
|
||||||
|
*
|
||||||
|
* @return array or \Assetic\Asset\AssetCollection
|
||||||
|
*/
|
||||||
|
public function getAsseticCollection()
|
||||||
|
{
|
||||||
|
list($cssFiles, $jsFiles) = $this->getAssetFiles();
|
||||||
|
return array(
|
||||||
|
$this->createAsseticCollection($cssFiles),
|
||||||
|
$this->createAsseticCollection($jsFiles)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Assetic AssetCollection with the given files.
|
||||||
|
* Filenames will be converted to absolute path using
|
||||||
|
* the base path.
|
||||||
|
*
|
||||||
|
* @param array $files
|
||||||
|
* @return \Assetic\Asset\AssetCollection
|
||||||
|
*/
|
||||||
|
protected function createAsseticCollection($files)
|
||||||
|
{
|
||||||
|
$assets = array();
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$assets[] = new \Assetic\Asset\FileAsset($this->makeUriRelativeTo($file, $this->basePath));
|
||||||
|
}
|
||||||
|
return new \Assetic\Asset\AssetCollection($assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the html to include needed assets
|
||||||
|
*
|
||||||
|
* Only useful if Assetic is not used
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function renderHead()
|
||||||
|
{
|
||||||
|
list($cssFiles, $jsFiles) = $this->getAssetFiles();
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
foreach ($cssFiles as $file) {
|
||||||
|
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n",
|
||||||
|
$this->makeUriRelativeTo($file, $this->baseUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($jsFiles as $file) {
|
||||||
|
$html .= sprintf('<script type"text/javascript" src="%s"></script>' . "\n",
|
||||||
|
$this->makeUriRelativeTo($file, $this->baseUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a URI relative to another
|
||||||
|
*
|
||||||
|
* @param string $uri
|
||||||
|
* @param string $root
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function makeUriRelativeTo($uri, $root)
|
||||||
|
{
|
||||||
|
if (substr($uri, 0, 1) === '/' || preg_match('/^([a-z]+:\/\/|[a-zA-Z]:\/)/', $uri)) {
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
return rtrim($root, '/') . "/$uri";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the code needed to display the debug bar
|
||||||
|
*
|
||||||
|
* AJAX request should not render the initialization code.
|
||||||
|
*
|
||||||
|
* @param boolean $initialize Whether to render the de bug bar initialization code
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function render($initialize = true)
|
||||||
|
{
|
||||||
|
$js = '';
|
||||||
|
|
||||||
|
if ($initialize) {
|
||||||
|
$js = $this->getJsInitializationCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
$js .= sprintf("%s.addDataSet(%s);\n", $this->variableName, json_encode($this->debugBar->getData()));
|
||||||
|
return "<script type=\"text/javascript\">\n$js\n</script>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the js code needed to initialize the debug bar
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getJsInitializationCode()
|
||||||
|
{
|
||||||
|
$js = '';
|
||||||
|
|
||||||
|
if (($this->initialization & self::INITIALIZE_CONSTRUCTOR) === self::INITIALIZE_CONSTRUCTOR) {
|
||||||
|
$js = sprintf("var %s = new %s();\n", $this->variableName, $this->javascriptClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->initialization & self::INITIALIZE_CONTROLS) === self::INITIALIZE_CONTROLS) {
|
||||||
|
$js .= $this->getJsControlsDefinitionCode($this->variableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $js;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the js code needed to initialized the controls and data mapping of the debug bar
|
||||||
|
*
|
||||||
|
* Controls can be defined by collectors themselves or using {@see addControl()}
|
||||||
|
*
|
||||||
|
* @param string $varname Debug bar's variable name
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getJsControlsDefinitionCode($varname)
|
||||||
|
{
|
||||||
|
$js = '';
|
||||||
|
$dataMap = array();
|
||||||
|
$controls = $this->controls;
|
||||||
|
|
||||||
|
// finds controls provided by collectors
|
||||||
|
foreach ($this->debugBar->getCollectors() as $collector) {
|
||||||
|
if ($collector instanceof Renderable) {
|
||||||
|
$controls = array_merge($controls, $collector->getWidgets());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($controls as $name => $options) {
|
||||||
|
if (isset($options['widget'])) {
|
||||||
|
$js .= sprintf("%s.createTab(\"%s\", new %s());\n",
|
||||||
|
$varname,
|
||||||
|
$name,
|
||||||
|
$options['widget']
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$js .= sprintf("%s.createIndicator(\"%s\", \"%s\", \"%s\");\n",
|
||||||
|
$varname,
|
||||||
|
$name,
|
||||||
|
isset($options['icon']) ? $options['icon'] : 'null',
|
||||||
|
isset($options['tooltip']) ? $options['tooltip'] : 'null'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($options['map']) && isset($options['default'])) {
|
||||||
|
$dataMap[$name] = array($options['map'], $options['default']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates the data mapping object
|
||||||
|
$mapJson = array();
|
||||||
|
foreach ($dataMap as $name => $values) {
|
||||||
|
$mapJson[] = sprintf('"%s": ["%s", %s]', $name, $values[0], $values[1]);
|
||||||
|
}
|
||||||
|
$js .= sprintf("%s.setDataMap({\n%s\n});\n", $varname, implode(",\n", $mapJson));
|
||||||
|
|
||||||
|
// activate state restauration
|
||||||
|
$js .= sprintf("%s.restoreState();\n", $varname);
|
||||||
|
|
||||||
|
return $js;
|
||||||
|
}
|
||||||
|
}
|
@ -1,159 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DebugBar\Renderer;
|
|
||||||
|
|
||||||
use DebugBar\DebugBar;
|
|
||||||
|
|
||||||
class JavascriptRenderer
|
|
||||||
{
|
|
||||||
protected $baseUrl = '/';
|
|
||||||
|
|
||||||
protected $cssVendors = array('vendor/font-awesome/css/font-awesome.css');
|
|
||||||
|
|
||||||
protected $jsVendors = array('vendor/jquery-1.8.3.min.js', 'vendor/jquery.event.drag-2.2.js');
|
|
||||||
|
|
||||||
protected $cssFiles = array('debugbar.css');
|
|
||||||
|
|
||||||
protected $jsFiles = array('debugbar.js', 'widgets.js');
|
|
||||||
|
|
||||||
protected $includeVendors = true;
|
|
||||||
|
|
||||||
protected $includeFiles = true;
|
|
||||||
|
|
||||||
protected $toolbarFile = 'standard-debugbar.js';
|
|
||||||
|
|
||||||
protected $toolbarClass = 'StandardPhpDebugBar';
|
|
||||||
|
|
||||||
protected $toolbarVariableName = 'phpdebugbar';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \DebugBar\DebugBar $debugBar
|
|
||||||
* @param string $baseUrl
|
|
||||||
*
|
|
||||||
* @Inject(debugBar="debugBar", baseUrl="$[debugBarRenderer][baseUrl]")
|
|
||||||
*/
|
|
||||||
public function __construct(DebugBar $debugBar, $baseUrl = '/')
|
|
||||||
{
|
|
||||||
$this->debugBar = $debugBar;
|
|
||||||
$this->setBaseUrl($baseUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBaseUrl($url)
|
|
||||||
{
|
|
||||||
$this->baseUrl = $url;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBaseUrl()
|
|
||||||
{
|
|
||||||
return $this->baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setIncludeVendors($enabled = true)
|
|
||||||
{
|
|
||||||
$this->includeVendors = $enabled;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function areVendorsIncluded()
|
|
||||||
{
|
|
||||||
return $this->includeVendors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setIncludeFiles($enabled = true)
|
|
||||||
{
|
|
||||||
$this->includeFiles = $enabled;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function areFilesIncluded()
|
|
||||||
{
|
|
||||||
return $this->includeFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setToolbarFile($file)
|
|
||||||
{
|
|
||||||
$this->toolbarFile = $file;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getToolbarFile()
|
|
||||||
{
|
|
||||||
return $this->toolbarFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setToolbarClass($className)
|
|
||||||
{
|
|
||||||
$this->toolbarClass = $className;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getToolbarClass()
|
|
||||||
{
|
|
||||||
return $this->toolbarClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setToolbarVariableName($name)
|
|
||||||
{
|
|
||||||
$this->toolbarVariableName = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getToolbarVariableName()
|
|
||||||
{
|
|
||||||
return $this->toolbarVariableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderIncludes()
|
|
||||||
{
|
|
||||||
$cssFiles = array();
|
|
||||||
$jsFiles = array();
|
|
||||||
|
|
||||||
if ($this->includeVendors) {
|
|
||||||
$cssFiles = array_merge($cssFiles, $this->cssVendors);
|
|
||||||
$jsFiles = array_merge($jsFiles, $this->jsVendors);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->includeFiles) {
|
|
||||||
$cssFiles = array_merge($cssFiles, $this->cssFiles);
|
|
||||||
$jsFiles = array_merge($jsFiles, $this->jsFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
$jsFiles[] = $this->toolbarFile;
|
|
||||||
|
|
||||||
$html = '';
|
|
||||||
foreach ($cssFiles as $file) {
|
|
||||||
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n",
|
|
||||||
$this->makeUrlRelativeTo($file, $this->baseUrl));
|
|
||||||
}
|
|
||||||
foreach ($jsFiles as $file) {
|
|
||||||
$html .= sprintf('<script type"text/javascript" src="%s"></script>' . "\n",
|
|
||||||
$this->makeUrlRelativeTo($file, $this->baseUrl));
|
|
||||||
}
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderToolbar()
|
|
||||||
{
|
|
||||||
return sprintf('<script type="text/javascript">var %s = new %s(%s);</script>' . "\n",
|
|
||||||
$this->toolbarVariableName, $this->toolbarClass, json_encode($this->debugBar->getData()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderAjaxToolbar()
|
|
||||||
{
|
|
||||||
return sprintf('<script type="text/javascript">%s.addDataStack(%s);</script>' . "\n",
|
|
||||||
$this->toolbarVariableName, json_encode($this->debugBar->getData()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderAll()
|
|
||||||
{
|
|
||||||
return $this->renderIncludes() . $this->renderToolbar();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function makeUrlRelativeTo($url, $root)
|
|
||||||
{
|
|
||||||
if (substr($url, 0, 1) === '/' || preg_match('/^[a-z]+:\/\//', $url)) {
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
return rtrim($root, '/') . "/$url";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the DebugBar package.
|
||||||
|
*
|
||||||
|
* (c) 2013 Maxime Bouroumeau-Fuseau
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace DebugBar;
|
namespace DebugBar;
|
||||||
|
|
||||||
use DebugBar\DataCollector\PhpInfoCollector;
|
use DebugBar\DataCollector\PhpInfoCollector;
|
||||||
use DebugBar\DataCollector\MessagesCollector;
|
use DebugBar\DataCollector\MessagesCollector;
|
||||||
use DebugBar\DataCollector\TimeCollector;
|
use DebugBar\DataCollector\TimeDataCollector;
|
||||||
use DebugBar\DataCollector\RequestDataCollector;
|
use DebugBar\DataCollector\RequestDataCollector;
|
||||||
use DebugBar\DataCollector\MemoryCollector;
|
use DebugBar\DataCollector\MemoryCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug bar subclass which adds all included collectors
|
||||||
|
*/
|
||||||
class StandardDebugBar extends DebugBar
|
class StandardDebugBar extends DebugBar
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->addCollector(new PhpInfoCollector());
|
$this->addCollector(new PhpInfoCollector());
|
||||||
$this->addCollector(new MessagesCollector());
|
$this->addCollector(new MessagesCollector());
|
||||||
$this->addCollector(new TimeCollector());
|
|
||||||
$this->addCollector(new RequestDataCollector());
|
$this->addCollector(new RequestDataCollector());
|
||||||
|
$this->addCollector(new TimeDataCollector());
|
||||||
$this->addCollector(new MemoryCollector());
|
$this->addCollector(new MemoryCollector());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
tests/DebugBar/Tests/DebugBarTestCase.php
Normal file
8
tests/DebugBar/Tests/DebugBarTestCase.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DebugBar\Tests;
|
||||||
|
|
||||||
|
abstract class DebugBarTestCase extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
338
web/debugbar.css
338
web/debugbar.css
@ -1,27 +1,27 @@
|
|||||||
.phpdebugbar {
|
.phpdebugbar {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
font-family: arial;
|
font-family: arial;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-header {
|
.phpdebugbar-header {
|
||||||
background: #efefef url(php-icon.png) no-repeat 5px 4px;
|
background: #efefef url(php-icon.png) no-repeat 5px 4px;
|
||||||
padding-left: 29px;
|
padding-left: 29px;
|
||||||
min-height: 26px;
|
min-height: 26px;
|
||||||
}
|
}
|
||||||
.phpdebugbar-header:before, .phpdebugbar-header:after {
|
.phpdebugbar-header:before, .phpdebugbar-header:after {
|
||||||
display: table;
|
display: table;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
content: "";
|
content: "";
|
||||||
}
|
}
|
||||||
.phpdebugbar-header:after {
|
.phpdebugbar-header:after {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
@ -29,79 +29,70 @@
|
|||||||
.phpdebugbar-tab,
|
.phpdebugbar-tab,
|
||||||
.phpdebugbar-indicator,
|
.phpdebugbar-indicator,
|
||||||
.phpdebugbar-close-btn {
|
.phpdebugbar-close-btn {
|
||||||
float: left;
|
float: left;
|
||||||
padding: 5px 8px;
|
padding: 5px 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #555;
|
color: #555;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.phpdebugbar-indicator,
|
.phpdebugbar-indicator,
|
||||||
.phpdebugbar-close-btn {
|
.phpdebugbar-close-btn {
|
||||||
float: right;
|
float: right;
|
||||||
border-right: 1px solid #ddd;
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phpdebugbar-tab.active {
|
.phpdebugbar-tab.active {
|
||||||
background: #ccc;
|
background: #ccc;
|
||||||
color: #444;
|
color: #444;
|
||||||
background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||||
background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||||
background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||||
background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||||
background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%);
|
||||||
|
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.41, rgb(173,173,173)), color-stop(0.71, rgb(209,209,209)));
|
||||||
background-image: -webkit-gradient(
|
|
||||||
linear,
|
|
||||||
left bottom,
|
|
||||||
left top,
|
|
||||||
color-stop(0.41, rgb(173,173,173)),
|
|
||||||
color-stop(0.71, rgb(209,209,209))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.phpdebugbar-close-btn {
|
.phpdebugbar-close-btn {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phpdebugbar-indicator {
|
.phpdebugbar-indicator {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.phpdebugbar-indicator .text {
|
.phpdebugbar-indicator .text {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
.phpdebugbar-indicator .tooltip {
|
.phpdebugbar-indicator .tooltip {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: -30px;
|
|
||||||
background: #efefef;
|
|
||||||
opacity: .7;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
color: #555;
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 2px 3px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phpdebugbar-indicator:hover .tooltip {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phpdebugbar-data-stacks {
|
|
||||||
float: right;
|
|
||||||
display: none;
|
display: none;
|
||||||
margin: 2px 0 0 7px;
|
position: absolute;
|
||||||
|
top: -30px;
|
||||||
|
background: #efefef;
|
||||||
|
opacity: .7;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
color: #555;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 3px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.phpdebugbar-indicator:hover .tooltip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phpdebugbar-datasets-switcher {
|
||||||
|
float: right;
|
||||||
|
display: none;
|
||||||
|
margin: 2px 0 0 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-body {
|
.phpdebugbar-body {
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
display: none;
|
display: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
}
|
}
|
||||||
|
.phpdebugbar-resize-handle {
|
||||||
.phpdebugbar-resize-handle {
|
|
||||||
display: none;
|
display: none;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -110,148 +101,151 @@
|
|||||||
cursor: move;
|
cursor: move;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -33px;
|
top: -33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-panel {
|
.phpdebugbar-panel {
|
||||||
display: none;
|
display: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.phpdebugbar-panel.active {
|
.phpdebugbar-panel.active {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-widgets-list {
|
.phpdebugbar-widgets-list {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-list .list-item {
|
.phpdebugbar-widgets-list .list-item {
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-list .list-item:hover {
|
.phpdebugbar-widgets-list .list-item:hover {
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-widgets-messages {
|
.phpdebugbar-widgets-messages {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-messages .list-item .value.warn:before {
|
.phpdebugbar-widgets-messages .list-item .value.warn:before {
|
||||||
font-family: FontAwesome;
|
font-family: FontAwesome;
|
||||||
content: "\f071";
|
content: "\f071";
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #ecb03d;
|
color: #ecb03d;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-messages .list-item .value.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-messages .list-item .value.error:before {
|
||||||
|
font-family: FontAwesome;
|
||||||
|
content: "\f057";
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-messages .list-item .backtrace,
|
||||||
|
.phpdebugbar-widgets-messages .list-item .label {
|
||||||
|
float: right;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
color: #888;
|
||||||
|
margin: 0 2px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-messages .toolbar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-messages .toolbar input {
|
||||||
|
border: 0;
|
||||||
|
margin-left: 7px;
|
||||||
|
width: 50%;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-messages .list-item .value.error {
|
.phpdebugbar-widgets-messages .toolbar input:focus {
|
||||||
color: red;
|
outline: none;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-messages .list-item .value.error:before {
|
.phpdebugbar-widgets-messages .toolbar .filter {
|
||||||
font-family: FontAwesome;
|
|
||||||
content: "\f057";
|
|
||||||
margin-right: 8px;
|
|
||||||
font-size: 11px;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-messages .list-item .backtrace,
|
|
||||||
.phpdebugbar-widgets-messages .list-item .label {
|
|
||||||
float: right;
|
float: right;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
color: #888;
|
background: #7cacd5;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #fff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-messages .toolbar {
|
.phpdebugbar-widgets-messages .toolbar .filter.disabled {
|
||||||
position: absolute;
|
background: #eee;
|
||||||
bottom: 0;
|
color: #888;
|
||||||
width: 100%;
|
}
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-messages .toolbar input {
|
|
||||||
border: 0;
|
|
||||||
margin-left: 7px;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-messages .toolbar input:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-messages .toolbar .filter {
|
|
||||||
float: right;
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 2px 4px;
|
|
||||||
background: #7cacd5;
|
|
||||||
margin: 0 2px;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-messages .toolbar .filter.disabled {
|
|
||||||
background: #eee;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-widgets-kvlist {
|
.phpdebugbar-widgets-kvlist {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-kvlist dt {
|
.phpdebugbar-widgets-kvlist dt {
|
||||||
float: left;
|
float: left;
|
||||||
width: 140px;
|
width: 140px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-kvlist dd {
|
.phpdebugbar-widgets-kvlist dd {
|
||||||
margin-left: 150px;
|
margin-left: 150px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-widgets-varlist {
|
.phpdebugbar-widgets-varlist {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------- */
|
/* -------------------------------------- */
|
||||||
|
|
||||||
.phpdebugbar-widgets-timeline {
|
.phpdebugbar-widgets-timeline {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-timeline li {
|
.phpdebugbar-widgets-timeline li {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-timeline li:hover {
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-timeline li .label {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: monospace;
|
||||||
|
color: #555;
|
||||||
|
top: 4px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
.phpdebugbar-widgets-timeline li .value {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
height: 10px;
|
||||||
|
background: #3db9ec;
|
||||||
|
top: 5px;
|
||||||
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
.phpdebugbar-widgets-timeline li .label {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: monospace;
|
|
||||||
color: #555;
|
|
||||||
top: 4px;
|
|
||||||
left: 5px;
|
|
||||||
}
|
|
||||||
.phpdebugbar-widgets-timeline li .value {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
height: 10px;
|
|
||||||
background: #3db9ec;
|
|
||||||
top: 5px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
461
web/debugbar.js
461
web/debugbar.js
@ -1,41 +1,176 @@
|
|||||||
if (typeof(PhpDebugBar) == 'undefined') {
|
if (typeof(PhpDebugBar) == 'undefined') {
|
||||||
|
// namespace
|
||||||
var PhpDebugBar = {};
|
var PhpDebugBar = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(localStorage) == 'undefined') {
|
if (typeof(localStorage) == 'undefined') {
|
||||||
|
// provide mock localStorage object for dumb browsers
|
||||||
var localStorage = {
|
var localStorage = {
|
||||||
setItem: function(key, value) {},
|
setItem: function(key, value) {},
|
||||||
getItem: function(key) { return null; }
|
getItem: function(key) { return null; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DebugBar
|
||||||
|
*
|
||||||
|
* Creates a bar that appends itself to the body of your page
|
||||||
|
* and sticks to the bottom.
|
||||||
|
*
|
||||||
|
* The bar can be customized by adding tabs and indicators.
|
||||||
|
* A data map is used to fill those controls with data provided
|
||||||
|
* from datasets.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
PhpDebugBar.DebugBar = (function($) {
|
PhpDebugBar.DebugBar = (function($) {
|
||||||
|
|
||||||
function getDictValue(dict, key, def) {
|
/**
|
||||||
|
* Returns the value from an object property.
|
||||||
|
* Using dots in the key, it is possible to retreive nested property values
|
||||||
|
*
|
||||||
|
* @param {Object} dict
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Object} default_value
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
function getDictValue(dict, key, default_value) {
|
||||||
var d = dict, parts = key.split('.');
|
var d = dict, parts = key.split('.');
|
||||||
for (var i = 0; i < parts.length; i++) {
|
for (var i = 0; i < parts.length; i++) {
|
||||||
if (!d[parts[i]]) {
|
if (!d[parts[i]]) {
|
||||||
return def;
|
return default_value;
|
||||||
}
|
}
|
||||||
d = d[parts[i]];
|
d = d[parts[i]];
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab
|
||||||
|
*
|
||||||
|
* A tab is composed of a tab label which is always visible and
|
||||||
|
* a tab panel which is visible only when the tab is active.
|
||||||
|
*
|
||||||
|
* The panel must contain a widget. A widget is an object which has
|
||||||
|
* an element property containing something appendable to a jQuery object.
|
||||||
|
*
|
||||||
|
* @this {Tab}
|
||||||
|
* @constructor
|
||||||
|
* @param {String} title
|
||||||
|
* @param {Object} widget
|
||||||
|
*/
|
||||||
|
var Tab = function(title, widget) {
|
||||||
|
this.tab = $('<a href="javascript:" class="phpdebugbar-tab" />').text(title);
|
||||||
|
this.panel = $('<div class="phpdebugbar-panel" />');
|
||||||
|
this.replaceWidget(widget);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title of the tab
|
||||||
|
*
|
||||||
|
* @this {Tab}
|
||||||
|
* @param {String} text
|
||||||
|
*/
|
||||||
|
Tab.prototype.setTitle = function(text) {
|
||||||
|
this.tab.text(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the widget inside the panel
|
||||||
|
*
|
||||||
|
* @this {Tab}
|
||||||
|
* @param {Object} new_widget
|
||||||
|
*/
|
||||||
|
Tab.prototype.replaceWidget = function(new_widget) {
|
||||||
|
this.panel.empty().append(new_widget.element);
|
||||||
|
this.widget = new_widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicator
|
||||||
|
*
|
||||||
|
* An indicator is a text and an icon to display single value information
|
||||||
|
* right inside the always visible part of the debug bar
|
||||||
|
*
|
||||||
|
* @this {Indicator}
|
||||||
|
* @constructor
|
||||||
|
* @param {String} icon
|
||||||
|
* @param {String} tooltip
|
||||||
|
* @param {String} position "right" or "left", default is "right"
|
||||||
|
*/
|
||||||
|
var Indicator = function(icon, tooltip, position) {
|
||||||
|
if (!position) {
|
||||||
|
position = 'right'
|
||||||
|
}
|
||||||
|
|
||||||
|
this.position = position;
|
||||||
|
this.element = $('<span class="phpdebugbar-indicator" />').css('float', position);
|
||||||
|
this.label = $('<span class="text" />').appendTo(this.element);
|
||||||
|
|
||||||
|
if (icon) {
|
||||||
|
$('<i class="icon-' + icon + '" />').insertBefore(this.label);
|
||||||
|
}
|
||||||
|
if (tooltip) {
|
||||||
|
this.element.append($('<span class="tooltip" />').text(tooltip));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text of the indicator
|
||||||
|
*
|
||||||
|
* @this {Indicator}
|
||||||
|
* @param {String} text
|
||||||
|
*/
|
||||||
|
Indicator.prototype.setText = function(text) {
|
||||||
|
this.element.find('.text').text(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tooltip of the indicator
|
||||||
|
*
|
||||||
|
* @this {Indicator}
|
||||||
|
* @param {String} text
|
||||||
|
*/
|
||||||
|
Indicator.prototype.setTooltip = function(text) {
|
||||||
|
this.element.find('.tooltip').text(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DebugBar
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
var DebugBar = function() {
|
var DebugBar = function() {
|
||||||
this.controls = {};
|
this.controls = {};
|
||||||
this.dataMap = {};
|
this.dataMap = {};
|
||||||
|
this.datasets = {};
|
||||||
this.initUI();
|
this.initUI();
|
||||||
this.init();
|
this.init();
|
||||||
this.restoreState();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialiazes the UI
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.initUI = function() {
|
DebugBar.prototype.initUI = function() {
|
||||||
|
var self = this;
|
||||||
this.element = $('<div class="phpdebugbar" />').appendTo('body');
|
this.element = $('<div class="phpdebugbar" />').appendTo('body');
|
||||||
this.header = $('<div class="phpdebugbar-header" />').appendTo(this.element);
|
this.header = $('<div class="phpdebugbar-header" />').appendTo(this.element);
|
||||||
this.body = $('<div class="phpdebugbar-body" />').appendTo(this.element);
|
this.body = $('<div class="phpdebugbar-body" />').appendTo(this.element);
|
||||||
this.resizeHandle = $('<div class="phpdebugbar-resize-handle" />').appendTo(this.body);
|
this.resizeHandle = $('<div class="phpdebugbar-resize-handle" />').appendTo(this.body);
|
||||||
|
this.firstPanelName = null;
|
||||||
|
this.activePanelName = null;
|
||||||
|
|
||||||
|
// allow resizing by dragging handle
|
||||||
this.body.drag('start', function(e, dd) {
|
this.body.drag('start', function(e, dd) {
|
||||||
dd.height = $(this).height();
|
dd.height = $(this).height();
|
||||||
}).drag(function(e, dd) {
|
}).drag(function(e, dd) {
|
||||||
@ -44,21 +179,35 @@ PhpDebugBar.DebugBar = (function($) {
|
|||||||
localStorage.setItem('phpdebugbar-height', h);
|
localStorage.setItem('phpdebugbar-height', h);
|
||||||
}, {handle: '.phpdebugbar-resize-handle'});
|
}, {handle: '.phpdebugbar-resize-handle'});
|
||||||
|
|
||||||
|
// close button
|
||||||
this.closeButton = $('<a class="phpdebugbar-close-btn" href="javascript:"><i class="icon-remove"></i></a>').appendTo(this.header);
|
this.closeButton = $('<a class="phpdebugbar-close-btn" href="javascript:"><i class="icon-remove"></i></a>').appendTo(this.header);
|
||||||
var self = this;
|
|
||||||
this.closeButton.click(function() {
|
this.closeButton.click(function() {
|
||||||
self.hidePanels();
|
self.hidePanels();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.stackSelectBox = $('<select class="phpdebugbar-data-stacks" />').appendTo(this.header);
|
// select box for data sets
|
||||||
this.stackSelectBox.change(function() {
|
this.datasetSelectBox = $('<select class="phpdebugbar-datasets-switcher" />').appendTo(this.header);
|
||||||
self.dataChangeHandler(self.stacks[this.value]);
|
this.datasetSelectBox.change(function() {
|
||||||
|
self.dataChangeHandler(self.datasets[this.value]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom initialiaze function for subsclasses
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.init = function() {};
|
DebugBar.prototype.init = function() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state of the DebugBar using localStorage
|
||||||
|
* This is not called by default in the constructor and
|
||||||
|
* needs to be called by subclasses in their init() method
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.restoreState = function() {
|
DebugBar.prototype.restoreState = function() {
|
||||||
|
// bar height
|
||||||
var height = localStorage.getItem('phpdebugbar-height');
|
var height = localStorage.getItem('phpdebugbar-height');
|
||||||
if (height) {
|
if (height) {
|
||||||
this.body.css('height', height);
|
this.body.css('height', height);
|
||||||
@ -66,86 +215,171 @@ PhpDebugBar.DebugBar = (function($) {
|
|||||||
localStorage.setItem('phpdebugbar-height', this.body.height());
|
localStorage.setItem('phpdebugbar-height', this.body.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bar visibility
|
||||||
var visible = localStorage.getItem('phpdebugbar-visible');
|
var visible = localStorage.getItem('phpdebugbar-visible');
|
||||||
if (visible && visible == '1') {
|
if (visible && visible == '1') {
|
||||||
this.showPanel(localStorage.getItem('phpdebugbar-panel'));
|
this.showPanel(localStorage.getItem('phpdebugbar-panel'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and adds a new tab
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name Internal name
|
||||||
|
* @param {Object} widget A widget object with an element property
|
||||||
|
* @param {String} title The text in the tab, if not specified, name will be used
|
||||||
|
* @return {Tab}
|
||||||
|
*/
|
||||||
DebugBar.prototype.createTab = function(name, widget, title) {
|
DebugBar.prototype.createTab = function(name, widget, title) {
|
||||||
|
var tab = new Tab(title || (name.replace(/[_\-]/g, ' ').charAt(0).toUpperCase() + name.slice(1)), widget);
|
||||||
|
return this.addTab(name, tab);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new tab
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name Internal name
|
||||||
|
* @param {Tab} tab Tab object
|
||||||
|
* @return {Tab}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.addTab = function(name, tab) {
|
||||||
if (this.isControl(name)) {
|
if (this.isControl(name)) {
|
||||||
throw new Exception(name + ' already exists');
|
throw new Exception(name + ' already exists');
|
||||||
}
|
}
|
||||||
|
|
||||||
var tab = $('<a href="javascript:" class="phpdebugbar-tab" />').text(title || (name.charAt(0).toUpperCase() + name.slice(1))),
|
var self = this;
|
||||||
panel = $('<div class="phpdebugbar-panel" data-id="' + name + '" />'),
|
tab.tab.appendTo(this.header).click(function() { self.showPanel(name); });
|
||||||
self = this;
|
tab.panel.appendTo(this.body);
|
||||||
|
|
||||||
tab.appendTo(this.header).click(function() { self.showPanel(name); });
|
this.controls[name] = tab;
|
||||||
panel.appendTo(this.body).append(widget.element);
|
if (this.firstPanelName == null) {
|
||||||
|
this.firstPanelName = name;
|
||||||
this.controls[name] = {type: "tab", tab: tab, panel: panel, widget: widget};
|
}
|
||||||
return widget;
|
return tab;
|
||||||
};
|
};
|
||||||
|
|
||||||
DebugBar.prototype.setTabTitle = function(name, title) {
|
/**
|
||||||
|
* Returns a Tab object
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Tab}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.getTab = function(name) {
|
||||||
if (this.isTab(name)) {
|
if (this.isTab(name)) {
|
||||||
this.controls[name].tab.text(title);
|
return this.controls[name];
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DebugBar.prototype.getTabWidget = function(name) {
|
|
||||||
if (this.isTab(name)) {
|
|
||||||
return this.controls[name].widget;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and adds an indicator
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name Internal name
|
||||||
|
* @param {String} icon
|
||||||
|
* @param {String} tooltip
|
||||||
|
* @param {String} position "right" or "left", default is "right"
|
||||||
|
* @return {Indicator}
|
||||||
|
*/
|
||||||
DebugBar.prototype.createIndicator = function(name, icon, tooltip, position) {
|
DebugBar.prototype.createIndicator = function(name, icon, tooltip, position) {
|
||||||
|
var indicator = new Indicator(icon, tooltip, position);
|
||||||
|
return this.addIndicator(name, indicator);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an indicator
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name Internal name
|
||||||
|
* @param {Indicator} indicator Indicator object
|
||||||
|
* @return {Indicator}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.addIndicator = function(name, indicator) {
|
||||||
if (this.isControl(name)) {
|
if (this.isControl(name)) {
|
||||||
throw new Exception(name + ' already exists');
|
throw new Exception(name + ' already exists');
|
||||||
}
|
}
|
||||||
if (!position) {
|
|
||||||
position = 'right'
|
|
||||||
}
|
|
||||||
|
|
||||||
var indicator = $('<span class="phpdebugbar-indicator" />').css('float', position),
|
if (indicator.position == 'right') {
|
||||||
text = $('<span class="text" />').appendTo(indicator);
|
indicator.element.appendTo(this.header);
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
$('<i class="icon-' + icon + '" />').insertBefore(text);
|
|
||||||
}
|
|
||||||
if (tooltip) {
|
|
||||||
indicator.append($('<span class="tooltip" />').text(tooltip));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position == 'right') {
|
|
||||||
indicator.appendTo(this.header);
|
|
||||||
} else {
|
} else {
|
||||||
indicator.insertBefore(this.header.children().first())
|
indicator.element.insertBefore(this.header.children().first())
|
||||||
}
|
}
|
||||||
|
|
||||||
this.controls[name] = {type: "indicator", indicator: indicator};
|
this.controls[name] = indicator;
|
||||||
return text;
|
return indicator;
|
||||||
};
|
};
|
||||||
|
|
||||||
DebugBar.prototype.setIndicatorText = function(name, text) {
|
/**
|
||||||
|
* Returns an Indicator object
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Indicator}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.getIndicator = function(name) {
|
||||||
if (this.isIndicator(name)) {
|
if (this.isIndicator(name)) {
|
||||||
this.controls[name].indicator.find('.text').text(text);
|
return this.controls[name];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a control
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @param {Object} control
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.addControl = function(name, control) {
|
||||||
|
if (control instanceof Tab) {
|
||||||
|
this.addTab(name, control);
|
||||||
|
} else if (control instanceof Indicator) {
|
||||||
|
this.addIndicator(name, control);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Unknown type of control");
|
||||||
|
}
|
||||||
|
return control;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there's a control under the specified name
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
DebugBar.prototype.isControl = function(name) {
|
DebugBar.prototype.isControl = function(name) {
|
||||||
return typeof(this.controls[name]) != 'undefined';
|
return typeof(this.controls[name]) != 'undefined';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a tab with the specified name exists
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
DebugBar.prototype.isTab = function(name) {
|
DebugBar.prototype.isTab = function(name) {
|
||||||
return typeof(this.controls[name]) != 'undefined' && this.controls[name].type === 'tab';
|
return this.isControl(name) && this.controls[name] instanceof Tab;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an indicator with the specified name exists
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
DebugBar.prototype.isIndicator = function(name) {
|
DebugBar.prototype.isIndicator = function(name) {
|
||||||
return this.isControl(name) && this.controls[name].type === 'indicator';
|
return this.isControl(name) && this.controls[name] instanceof Indicator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all tabs and indicators from the debug bar and hides it
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.reset = function() {
|
DebugBar.prototype.reset = function() {
|
||||||
this.hidePanels();
|
this.hidePanels();
|
||||||
this.body.find('.phpdebugbar-panel').remove();
|
this.body.find('.phpdebugbar-panel').remove();
|
||||||
@ -153,17 +387,22 @@ PhpDebugBar.DebugBar = (function($) {
|
|||||||
this.controls = {};
|
this.controls = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the debug bar and display a specified panel
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} name If not specified, display the first panel
|
||||||
|
*/
|
||||||
DebugBar.prototype.showPanel = function(name) {
|
DebugBar.prototype.showPanel = function(name) {
|
||||||
this.resizeHandle.show();
|
this.resizeHandle.show();
|
||||||
this.body.show();
|
this.body.show();
|
||||||
this.closeButton.show();
|
this.closeButton.show();
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
activePanel = this.body.find('.phpdebugbar-panel.active');
|
if (this.activePanelName) {
|
||||||
if (activePanel.length > 0) {
|
name = this.activePanelName;
|
||||||
name = activePanel.data('id');
|
|
||||||
} else {
|
} else {
|
||||||
name = this.body.find('.phpdebugbar-panel').first().data('id');
|
name = this.firstPanelName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,15 +412,26 @@ PhpDebugBar.DebugBar = (function($) {
|
|||||||
if (this.isTab(name)) {
|
if (this.isTab(name)) {
|
||||||
this.controls[name].tab.addClass('active');
|
this.controls[name].tab.addClass('active');
|
||||||
this.controls[name].panel.addClass('active').show();
|
this.controls[name].panel.addClass('active').show();
|
||||||
|
this.activePanelName = name;
|
||||||
}
|
}
|
||||||
localStorage.setItem('phpdebugbar-visible', '1');
|
localStorage.setItem('phpdebugbar-visible', '1');
|
||||||
localStorage.setItem('phpdebugbar-panel', name);
|
localStorage.setItem('phpdebugbar-panel', name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the first panel
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.showFirstPanel = function() {
|
DebugBar.prototype.showFirstPanel = function() {
|
||||||
this.showPanel(this.body.find('.phpdebugbar-panel').first().data('id'));
|
this.showPanel(this.firstPanelName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide panels and "close" the debug bar
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
*/
|
||||||
DebugBar.prototype.hidePanels = function() {
|
DebugBar.prototype.hidePanels = function() {
|
||||||
this.header.find('.phpdebugbar-tab.active').removeClass('active');
|
this.header.find('.phpdebugbar-tab.active').removeClass('active');
|
||||||
this.body.hide();
|
this.body.hide();
|
||||||
@ -190,40 +440,121 @@ PhpDebugBar.DebugBar = (function($) {
|
|||||||
localStorage.setItem('phpdebugbar-visible', '0');
|
localStorage.setItem('phpdebugbar-visible', '0');
|
||||||
};
|
};
|
||||||
|
|
||||||
DebugBar.prototype.setData = function(data) {
|
/**
|
||||||
this.stacks = {};
|
* Sets the data map used by dataChangeHandler to populate
|
||||||
this.addDataStack(data);
|
* indicators and widgets
|
||||||
|
*
|
||||||
|
* A data map is an object where properties are control names.
|
||||||
|
* The value of each property should be an array where the first
|
||||||
|
* item is the name of a property from the data object (nested properties
|
||||||
|
* can be specified) and the second item the default value.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* {"memory": ["memory.peak_usage_str", "0B"]}
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {Object} map
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.setDataMap = function(map) {
|
||||||
|
this.dataMap = map;
|
||||||
};
|
};
|
||||||
|
|
||||||
DebugBar.prototype.addDataStack = function(data, id) {
|
/**
|
||||||
id = id || ("Request #" + (Object.keys(this.stacks).length + 1));
|
* Same as setDataMap() but appends to the existing map
|
||||||
this.stacks[id] = data;
|
* rather than replacing it
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {Object} map
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.addDataMap = function(map) {
|
||||||
|
$.extend(this.dataMap, map);
|
||||||
|
};
|
||||||
|
|
||||||
this.stackSelectBox.append($('<option value="' + id + '">' + id + '</option>'));
|
/**
|
||||||
if (Object.keys(this.stacks).length > 1) {
|
* Resets datasets and add one set of data
|
||||||
this.stackSelectBox.show();
|
*
|
||||||
|
* For this method to be usefull, you need to specify
|
||||||
|
* a dataMap using setDataMap()
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {Object} data
|
||||||
|
* @return {String} Dataset's id
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.setData = function(data) {
|
||||||
|
this.datasets = {};
|
||||||
|
return this.addDataSet(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a dataset
|
||||||
|
*
|
||||||
|
* If more than one dataset are added, the dataset selector
|
||||||
|
* will be displayed.
|
||||||
|
*
|
||||||
|
* For this method to be usefull, you need to specify
|
||||||
|
* a dataMap using setDataMap()
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {String} id The name of this set, optional
|
||||||
|
* @return {String} Dataset's id
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.addDataSet = function(data, id) {
|
||||||
|
id = id || ("Request #" + (Object.keys(this.datasets).length + 1));
|
||||||
|
this.datasets[id] = data;
|
||||||
|
|
||||||
|
this.datasetSelectBox.append($('<option value="' + id + '">' + id + '</option>'));
|
||||||
|
if (Object.keys(this.datasets).length > 1) {
|
||||||
|
this.datasetSelectBox.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.switchDataStack(id);
|
this.showDataSet(id);
|
||||||
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
DebugBar.prototype.switchDataStack = function(id) {
|
/**
|
||||||
this.dataChangeHandler(this.stacks[id]);
|
* Returns the data from a dataset
|
||||||
this.stackSelectBox.val(id);
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} id
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.getDataSet = function(id) {
|
||||||
|
return this.datasets[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the currently displayed dataset
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {String} id
|
||||||
|
*/
|
||||||
|
DebugBar.prototype.showDataSet = function(id) {
|
||||||
|
this.dataChangeHandler(this.datasets[id]);
|
||||||
|
this.datasetSelectBox.val(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the current dataset is modified.
|
||||||
|
*
|
||||||
|
* @this {DebugBar}
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
DebugBar.prototype.dataChangeHandler = function(data) {
|
DebugBar.prototype.dataChangeHandler = function(data) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$.each(this.dataMap, function(key, def) {
|
$.each(this.dataMap, function(key, def) {
|
||||||
var d = getDictValue(data, def[0], def[1]);
|
var d = getDictValue(data, def[0], def[1]);
|
||||||
if (self.isIndicator(key)) {
|
if (self.isIndicator(key)) {
|
||||||
self.setIndicatorText(key, d);
|
self.getIndicator(key).setText(d);
|
||||||
} else {
|
} else {
|
||||||
self.getTabWidget(key).setData(d);
|
self.getTab(key).widget.setData(d);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DebugBar.Tab = Tab;
|
||||||
|
DebugBar.Indicator = Indicator;
|
||||||
|
|
||||||
return DebugBar;
|
return DebugBar;
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
|
|
||||||
var StandardPhpDebugBar = (function() {
|
|
||||||
|
|
||||||
var DebugBar = function(data) {
|
|
||||||
PhpDebugBar.DebugBar.apply(this);
|
|
||||||
this.setData(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
DebugBar.prototype = new PhpDebugBar.DebugBar();
|
|
||||||
|
|
||||||
DebugBar.prototype.init = function() {
|
|
||||||
this.createIndicator('memory', 'cogs', 'Memory Usage');
|
|
||||||
this.createIndicator('time', 'time', 'Request duration');
|
|
||||||
|
|
||||||
this.createTab('messages', new PhpDebugBar.Widgets.MessagesWidget());
|
|
||||||
this.createTab('request', new PhpDebugBar.Widgets.VariableListWidget());
|
|
||||||
this.createTab('timeline', new PhpDebugBar.Widgets.TimelineWidget());
|
|
||||||
|
|
||||||
this.dataMap = {
|
|
||||||
"memory": ["memory.peak_usage_str", "0B"],
|
|
||||||
"time": ["time.duration_str", "0ms"],
|
|
||||||
"messages": ["messages", []],
|
|
||||||
"request": ["request", {}],
|
|
||||||
"timeline": ["time", {}]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return DebugBar;
|
|
||||||
|
|
||||||
})();
|
|
266
web/widgets.js
266
web/widgets.js
@ -1,15 +1,35 @@
|
|||||||
if (typeof(PhpDebugBar) == 'undefined') {
|
if (typeof(PhpDebugBar) == 'undefined') {
|
||||||
|
// namespace
|
||||||
var PhpDebugBar = {};
|
var PhpDebugBar = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace
|
||||||
|
*/
|
||||||
PhpDebugBar.Widgets = (function($) {
|
PhpDebugBar.Widgets = (function($) {
|
||||||
|
|
||||||
var widgets = {};
|
var widgets = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces spaces with and line breaks with <br>
|
||||||
|
*
|
||||||
|
* @param {String} text
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
var htmlize = function(text) {
|
var htmlize = function(text) {
|
||||||
return text.replace(/\n/g, '<br>').replace(/\s/g, " ")
|
return text.replace(/\n/g, '<br>').replace(/\s/g, " ")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
widgets.htmlize = htmlize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of value, using JSON.stringify
|
||||||
|
* if it's an object.
|
||||||
|
*
|
||||||
|
* @param {Object} value
|
||||||
|
* @param {Boolean} prettify Uses htmlize() if true
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
var renderValue = function(value, prettify) {
|
var renderValue = function(value, prettify) {
|
||||||
if (typeof(value) !== 'string') {
|
if (typeof(value) !== 'string') {
|
||||||
if (prettify) {
|
if (prettify) {
|
||||||
@ -20,8 +40,21 @@ PhpDebugBar.Widgets = (function($) {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------
|
widgets.renderValue = renderValue;
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// Generic widgets
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays array element in a <ul> list
|
||||||
|
*
|
||||||
|
* @this {ListWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} data
|
||||||
|
* @param {Function} itemRenderer Optional
|
||||||
|
*/
|
||||||
var ListWidget = function(data, itemRenderer) {
|
var ListWidget = function(data, itemRenderer) {
|
||||||
this.element = $('<ul class="phpdebugbar-widgets-list" />');
|
this.element = $('<ul class="phpdebugbar-widgets-list" />');
|
||||||
if (itemRenderer) {
|
if (itemRenderer) {
|
||||||
@ -32,6 +65,12 @@ PhpDebugBar.Widgets = (function($) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data and updates the list
|
||||||
|
*
|
||||||
|
* @this {ListWidget}
|
||||||
|
* @param {Array} data
|
||||||
|
*/
|
||||||
ListWidget.prototype.setData = function(data) {
|
ListWidget.prototype.setData = function(data) {
|
||||||
this.element.empty();
|
this.element.empty();
|
||||||
for (var i = 0; i < data.length; i++) {
|
for (var i = 0; i < data.length; i++) {
|
||||||
@ -40,14 +79,154 @@ PhpDebugBar.Widgets = (function($) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the content of a <li> element
|
||||||
|
*
|
||||||
|
* @this {ListWidget}
|
||||||
|
* @param {jQuery} li The <li> element as a jQuery Object
|
||||||
|
* @param {Object} value An item from the data array
|
||||||
|
*/
|
||||||
ListWidget.prototype.itemRenderer = function(li, value) {
|
ListWidget.prototype.itemRenderer = function(li, value) {
|
||||||
li.html(renderValue(value));
|
li.html(renderValue(value));
|
||||||
};
|
};
|
||||||
|
|
||||||
widgets.ListWidget = ListWidget;
|
widgets.ListWidget = ListWidget;
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays object property/value paris in a <dl> list
|
||||||
|
*
|
||||||
|
* @this {KVListWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {Function} itemRenderer Optional
|
||||||
|
*/
|
||||||
|
var KVListWidget = function(data, itemRenderer) {
|
||||||
|
this.element = $('<dl class="phpdebugbar-widgets-kvlist" />');
|
||||||
|
if (itemRenderer) {
|
||||||
|
this.itemRenderer = itemRenderer;
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
this.setData(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data and updates the list
|
||||||
|
*
|
||||||
|
* @this {KVListWidget}
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
|
KVListWidget.prototype.setData = function(data) {
|
||||||
|
var self = this;
|
||||||
|
this.element.empty();
|
||||||
|
$.each(data, function(key, value) {
|
||||||
|
var dt = $('<dt class="key" />').appendTo(self.element);
|
||||||
|
var dd = $('<dd class="value" />').appendTo(self.element);
|
||||||
|
self.itemRenderer(dt, dd, key, value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the content of the <dt> and <dd> elements
|
||||||
|
*
|
||||||
|
* @this {KVListWidget}
|
||||||
|
* @param {jQuery} dt The <dt> element as a jQuery Object
|
||||||
|
* @param {jQuery} dd The <dd> element as a jQuery Object
|
||||||
|
* @param {String} key Property name
|
||||||
|
* @param {Object} value Property value
|
||||||
|
*/
|
||||||
|
KVListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||||
|
dt.text(key);
|
||||||
|
dd.html(htmlize(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
widgets.KVListWidget = KVListWidget;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension of KVListWidget where the data represents a list
|
||||||
|
* of variables
|
||||||
|
*
|
||||||
|
* @this {VariableListWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
|
var VariableListWidget = function(data) {
|
||||||
|
KVListWidget.apply(this, [data]);
|
||||||
|
this.element.addClass('phpdebugbar-widgets-varlist');
|
||||||
|
};
|
||||||
|
|
||||||
|
VariableListWidget.prototype = new KVListWidget();
|
||||||
|
VariableListWidget.constructor = VariableListWidget;
|
||||||
|
|
||||||
|
VariableListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
||||||
|
dt.text(key);
|
||||||
|
|
||||||
|
var v = value;
|
||||||
|
if (v.length > 100) {
|
||||||
|
v = v.substr(0, 100) + "...";
|
||||||
|
}
|
||||||
|
dd.text(v).click(function() {
|
||||||
|
if (dd.hasClass('pretty')) {
|
||||||
|
dd.text(v).removeClass('pretty');
|
||||||
|
} else {
|
||||||
|
dd.html(htmlize(value)).addClass('pretty');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
widgets.VariableListWidget = VariableListWidget;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iframe widget
|
||||||
|
*
|
||||||
|
* @this {IFrameWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {String} url
|
||||||
|
*/
|
||||||
|
var IFrameWidget = function(url) {
|
||||||
|
this.element = $('<iframe src="" class="phpdebugbar-widgets-iframe" seamless="seamless" border="0" width="100%" height="100%" />');
|
||||||
|
if (url) {
|
||||||
|
this.setData(url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the iframe url
|
||||||
|
*
|
||||||
|
* @this {IFrameWidget}
|
||||||
|
* @param {String} url
|
||||||
|
*/
|
||||||
|
IFrameWidget.prototype.setUrl = function(url) {
|
||||||
|
this.element.attr('src', url);
|
||||||
|
};
|
||||||
|
|
||||||
|
// for compatibility with data mapping
|
||||||
|
IFrameWidget.prototype.setData = function(url) {
|
||||||
|
this.setUrl(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
widgets.IFrameWidget = IFrameWidget;
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// Collector specific widgets
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for the MessagesCollector
|
||||||
|
*
|
||||||
|
* Uses ListWidget under the hood
|
||||||
|
*
|
||||||
|
* @this {MessagesWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {Array} data
|
||||||
|
*/
|
||||||
var MessagesWidget = function(data) {
|
var MessagesWidget = function(data) {
|
||||||
this.element = $('<div class="phpdebugbar-widgets-messages" />');
|
this.element = $('<div class="phpdebugbar-widgets-messages" />');
|
||||||
|
|
||||||
@ -142,80 +321,15 @@ PhpDebugBar.Widgets = (function($) {
|
|||||||
|
|
||||||
widgets.MessagesWidget = MessagesWidget;
|
widgets.MessagesWidget = MessagesWidget;
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
var KVListWidget = function(data, itemRenderer) {
|
|
||||||
this.element = $('<dl class="phpdebugbar-widgets-kvlist" />');
|
|
||||||
if (itemRenderer) {
|
|
||||||
this.itemRenderer = itemRenderer;
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
this.setData(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
KVListWidget.prototype.setData = function(data) {
|
|
||||||
var self = this;
|
|
||||||
this.element.empty();
|
|
||||||
$.each(data, function(key, value) {
|
|
||||||
var dt = $('<dt class="key" />').appendTo(self.element);
|
|
||||||
var dd = $('<dd class="value" />').appendTo(self.element);
|
|
||||||
self.itemRenderer(dt, dd, key, value);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
KVListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
|
||||||
dt.text(key);
|
|
||||||
dd.html(htmlize(value));
|
|
||||||
};
|
|
||||||
|
|
||||||
widgets.KVListWidget = KVListWidget;
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
|
|
||||||
var VariableListWidget = function(data) {
|
|
||||||
KVListWidget.apply(this, [data]);
|
|
||||||
this.element.addClass('phpdebugbar-widgets-varlist');
|
|
||||||
};
|
|
||||||
|
|
||||||
VariableListWidget.prototype = new KVListWidget();
|
|
||||||
VariableListWidget.constructor = VariableListWidget;
|
|
||||||
|
|
||||||
VariableListWidget.prototype.itemRenderer = function(dt, dd, key, value) {
|
|
||||||
dt.text(key);
|
|
||||||
|
|
||||||
var v = value;
|
|
||||||
if (v.length > 100) {
|
|
||||||
v = v.substr(0, 100) + "...";
|
|
||||||
}
|
|
||||||
dd.text(v).click(function() {
|
|
||||||
if (dd.hasClass('pretty')) {
|
|
||||||
dd.text(v).removeClass('pretty');
|
|
||||||
} else {
|
|
||||||
dd.html(htmlize(value)).addClass('pretty');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
widgets.VariableListWidget = VariableListWidget;
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
|
|
||||||
var IFrameWidget = function(url) {
|
|
||||||
this.element = $('<iframe src="" class="phpdebugbar-widgets-iframe" seamless="seamless" border="0" width="100%" height="100%" />');
|
|
||||||
if (url) {
|
|
||||||
this.setData(url);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IFrameWidget.prototype.setData = function(url) {
|
|
||||||
this.element.attr('src', url);
|
|
||||||
};
|
|
||||||
|
|
||||||
widgets.IFrameWidget = IFrameWidget;
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for the TimeDataCollector
|
||||||
|
*
|
||||||
|
* @this {TimelineWidget}
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} data
|
||||||
|
*/
|
||||||
var TimelineWidget = function(data) {
|
var TimelineWidget = function(data) {
|
||||||
this.element = $('<ul class="phpdebugbar-widgets-timeline" />');
|
this.element = $('<ul class="phpdebugbar-widgets-timeline" />');
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -240,7 +354,7 @@ PhpDebugBar.Widgets = (function($) {
|
|||||||
|
|
||||||
widgets.TimelineWidget = TimelineWidget;
|
widgets.TimelineWidget = TimelineWidget;
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
return widgets;
|
return widgets;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user