Laravel 5.6 updates
Travis config update Removed HHVM script as Laravel no longer support HHVM after releasing 5.3
This commit is contained in:
60
vendor/maximebf/debugbar/src/DebugBar/Bridge/Twig/TimeableTwigExtensionProfiler.php
vendored
Normal file
60
vendor/maximebf/debugbar/src/DebugBar/Bridge/Twig/TimeableTwigExtensionProfiler.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2017 Tim Riemenschneider
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\Bridge\Twig;
|
||||
|
||||
use DebugBar\DataCollector\TimeDataCollector;
|
||||
use Twig_Profiler_Profile;
|
||||
|
||||
/**
|
||||
* Class TimeableTwigExtensionProfiler
|
||||
*
|
||||
* Extends Twig_Extension_Profiler to add rendering times to the TimeDataCollector
|
||||
*
|
||||
* @package DebugBar\Bridge\Twig
|
||||
*/
|
||||
class TimeableTwigExtensionProfiler extends \Twig_Extension_Profiler
|
||||
{
|
||||
/**
|
||||
* @var \DebugBar\DataCollector\TimeDataCollector
|
||||
*/
|
||||
private $timeDataCollector;
|
||||
|
||||
/**
|
||||
* @param \DebugBar\DataCollector\TimeDataCollector $timeDataCollector
|
||||
*/
|
||||
public function setTimeDataCollector(TimeDataCollector $timeDataCollector)
|
||||
{
|
||||
$this->timeDataCollector = $timeDataCollector;
|
||||
}
|
||||
|
||||
public function __construct(\Twig_Profiler_Profile $profile, TimeDataCollector $timeDataCollector = null)
|
||||
{
|
||||
parent::__construct($profile);
|
||||
|
||||
$this->timeDataCollector = $timeDataCollector;
|
||||
}
|
||||
|
||||
public function enter(Twig_Profiler_Profile $profile)
|
||||
{
|
||||
if ($this->timeDataCollector && $profile->isTemplate()) {
|
||||
$this->timeDataCollector->startMeasure($profile->getName(), 'template ' . $profile->getName());
|
||||
}
|
||||
parent::enter($profile);
|
||||
}
|
||||
|
||||
public function leave(Twig_Profiler_Profile $profile)
|
||||
{
|
||||
parent::leave($profile);
|
||||
if ($this->timeDataCollector && $profile->isTemplate()) {
|
||||
$this->timeDataCollector->stopMeasure($profile->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ use Twig_TemplateInterface;
|
||||
/**
|
||||
* Wraps a Twig_Template to add profiling features
|
||||
*/
|
||||
class TraceableTwigTemplate implements Twig_TemplateInterface
|
||||
class TraceableTwigTemplate extends Twig_Template implements Twig_TemplateInterface
|
||||
{
|
||||
protected $template;
|
||||
|
||||
@@ -35,6 +35,11 @@ class TraceableTwigTemplate implements Twig_TemplateInterface
|
||||
return call_user_func_array(array($this->template, $name), $arguments);
|
||||
}
|
||||
|
||||
public function doDisplay(array $context, array $blocks = array())
|
||||
{
|
||||
return $this->template->doDisplay($context, $blocks);
|
||||
}
|
||||
|
||||
public function getTemplateName()
|
||||
{
|
||||
return $this->template->getTemplateName();
|
||||
|
||||
197
vendor/maximebf/debugbar/src/DebugBar/Bridge/TwigProfileCollector.php
vendored
Normal file
197
vendor/maximebf/debugbar/src/DebugBar/Bridge/TwigProfileCollector.php
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the DebugBar package.
|
||||
*
|
||||
* (c) 2017 Tim Riemenschneider
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DebugBar\Bridge;
|
||||
|
||||
use DebugBar\DataCollector\AssetProvider;
|
||||
use DebugBar\DataCollector\DataCollector;
|
||||
use DebugBar\DataCollector\Renderable;
|
||||
|
||||
/**
|
||||
* Collects data about rendered templates
|
||||
*
|
||||
* http://twig.sensiolabs.org/
|
||||
*
|
||||
* A Twig_Extension_Profiler should be added to your Twig_Environment
|
||||
* The root-Twig_Profiler_Profile-object should then be injected into this collector
|
||||
*
|
||||
* you can optionally provide the Twig_Environment or the Twig_Loader to also create
|
||||
* debug-links.
|
||||
*
|
||||
* @see \Twig_Extension_Profiler, \Twig_Profiler_Profile
|
||||
*
|
||||
* <code>
|
||||
* $env = new Twig_Environment($loader); // Or from a PSR11-container
|
||||
* $profile = new Twig_Profiler_Profile();
|
||||
* $env->addExtension(new Twig_Extension_Profile($profile));
|
||||
* $debugbar->addCollector(new TwigProfileCollector($profile, $env));
|
||||
* // or: $debugbar->addCollector(new TwigProfileCollector($profile, $loader));
|
||||
* </code>
|
||||
*/
|
||||
class TwigProfileCollector extends DataCollector implements Renderable, AssetProvider
|
||||
{
|
||||
/**
|
||||
* @var \Twig_Profiler_Profile
|
||||
*/
|
||||
private $profile;
|
||||
/**
|
||||
* @var \Twig_LoaderInterface
|
||||
*/
|
||||
private $loader;
|
||||
/** @var int */
|
||||
private $templateCount;
|
||||
/** @var int */
|
||||
private $blockCount;
|
||||
/** @var int */
|
||||
private $macroCount;
|
||||
/**
|
||||
* @var array[] {
|
||||
* @var string $name
|
||||
* @var int $render_time
|
||||
* @var string $render_time_str
|
||||
* @var string $memory_str
|
||||
* @var string $xdebug_link
|
||||
* }
|
||||
*/
|
||||
private $templates;
|
||||
|
||||
/**
|
||||
* TwigProfileCollector constructor.
|
||||
*
|
||||
* @param \Twig_Profiler_Profile $profile
|
||||
* @param \Twig_LoaderInterface|\Twig_Environment $loaderOrEnv
|
||||
*/
|
||||
public function __construct(\Twig_Profiler_Profile $profile, $loaderOrEnv = null)
|
||||
{
|
||||
$this->profile = $profile;
|
||||
if ($loaderOrEnv instanceof \Twig_Environment) {
|
||||
$loaderOrEnv = $loaderOrEnv->getLoader();
|
||||
}
|
||||
$this->loader = $loaderOrEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash where keys are control names and their values
|
||||
* an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
return array(
|
||||
'twig' => array(
|
||||
'icon' => 'leaf',
|
||||
'widget' => 'PhpDebugBar.Widgets.TemplatesWidget',
|
||||
'map' => 'twig',
|
||||
'default' => json_encode(array('templates' => array())),
|
||||
),
|
||||
'twig:badge' => array(
|
||||
'map' => 'twig.badge',
|
||||
'default' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAssets()
|
||||
{
|
||||
return array(
|
||||
'css' => 'widgets/templates/widget.css',
|
||||
'js' => 'widgets/templates/widget.js',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the DebugBar when data needs to be collected
|
||||
*
|
||||
* @return array Collected data
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$this->templateCount = $this->blockCount = $this->macroCount = 0;
|
||||
$this->templates = array();
|
||||
$this->computeData($this->profile);
|
||||
|
||||
return array(
|
||||
'nb_templates' => $this->templateCount,
|
||||
'nb_blocks' => $this->blockCount,
|
||||
'nb_macros' => $this->macroCount,
|
||||
'templates' => $this->templates,
|
||||
'accumulated_render_time' => $this->profile->getDuration(),
|
||||
'accumulated_render_time_str' => $this->getDataFormatter()->formatDuration($this->profile->getDuration()),
|
||||
'memory_usage_str' => $this->getDataFormatter()->formatBytes($this->profile->getMemoryUsage()),
|
||||
'callgraph' => $this->getHtmlCallGraph(),
|
||||
'badge' => implode(
|
||||
'/',
|
||||
array(
|
||||
$this->templateCount,
|
||||
$this->blockCount,
|
||||
$this->macroCount,
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique name of the collector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'twig';
|
||||
}
|
||||
|
||||
public function getHtmlCallGraph()
|
||||
{
|
||||
$dumper = new \Twig_Profiler_Dumper_Html();
|
||||
|
||||
return $dumper->dump($this->profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Xdebug Link to a file
|
||||
*
|
||||
* @return array {
|
||||
* @var string url
|
||||
* @var bool ajax
|
||||
* }
|
||||
*/
|
||||
public function getXdebugLink($template, $line = 1)
|
||||
{
|
||||
if (is_null($this->loader)) {
|
||||
return null;
|
||||
}
|
||||
$file = $this->loader->getSourceContext($template)->getPath();
|
||||
|
||||
return parent::getXdebugLink($file, $line);
|
||||
}
|
||||
|
||||
private function computeData(\Twig_Profiler_Profile $profile)
|
||||
{
|
||||
$this->templateCount += ($profile->isTemplate() ? 1 : 0);
|
||||
$this->blockCount += ($profile->isBlock() ? 1 : 0);
|
||||
$this->macroCount += ($profile->isMacro() ? 1 : 0);
|
||||
if ($profile->isTemplate()) {
|
||||
$this->templates[] = array(
|
||||
'name' => $profile->getName(),
|
||||
'render_time' => $profile->getDuration(),
|
||||
'render_time_str' => $this->getDataFormatter()->formatDuration($profile->getDuration()),
|
||||
'memory_str' => $this->getDataFormatter()->formatBytes($profile->getMemoryUsage()),
|
||||
'xdebug_link' => $this->getXdebugLink($profile->getTemplate()),
|
||||
);
|
||||
}
|
||||
foreach ($profile as $p) {
|
||||
$this->computeData($p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,21 @@ interface AssetProvider
|
||||
* - base_url
|
||||
* - css: an array of filenames
|
||||
* - js: an array of filenames
|
||||
* - inline_css: an array map of content ID to inline CSS content (not including <style> tag)
|
||||
* - inline_js: an array map of content ID to inline JS content (not including <script> tag)
|
||||
* - inline_head: an array map of content ID to arbitrary inline HTML content (typically
|
||||
* <style>/<script> tags); it must be embedded within the <head> element
|
||||
*
|
||||
* All keys are optional.
|
||||
*
|
||||
* Ideally, you should store static assets in filenames that are returned via the normal css/js
|
||||
* keys. However, the inline asset elements are useful when integrating with 3rd-party
|
||||
* libraries that require static assets that are only available in an inline format.
|
||||
*
|
||||
* The inline content arrays require special string array keys: the caller of this function
|
||||
* will use them to deduplicate content. This is particularly useful if multiple instances of
|
||||
* the same asset provider are used. Inline assets from all collectors are merged together into
|
||||
* the same array, so these content IDs effectively deduplicate the inline assets.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -13,12 +13,40 @@ namespace DebugBar\DataCollector;
|
||||
/**
|
||||
* Collects array data
|
||||
*/
|
||||
class ConfigCollector extends DataCollector implements Renderable
|
||||
class ConfigCollector extends DataCollector implements Renderable, AssetProvider
|
||||
{
|
||||
protected $name;
|
||||
|
||||
protected $data;
|
||||
|
||||
// The HTML var dumper requires debug bar users to support the new inline assets, which not all
|
||||
// may support yet - so return false by default for now.
|
||||
protected $useHtmlVarDumper = false;
|
||||
|
||||
/**
|
||||
* Sets a flag indicating whether the Symfony HtmlDumper will be used to dump variables for
|
||||
* rich variable rendering.
|
||||
*
|
||||
* @param bool $value
|
||||
* @return $this
|
||||
*/
|
||||
public function useHtmlVarDumper($value = true)
|
||||
{
|
||||
$this->useHtmlVarDumper = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the Symfony HtmlDumper will be used to dump variables for rich variable
|
||||
* rendering.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function isHtmlVarDumperUsed()
|
||||
{
|
||||
return $this->useHtmlVarDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $name
|
||||
@@ -46,7 +74,9 @@ class ConfigCollector extends DataCollector implements Renderable
|
||||
{
|
||||
$data = array();
|
||||
foreach ($this->data as $k => $v) {
|
||||
if (!is_string($v)) {
|
||||
if ($this->isHtmlVarDumperUsed()) {
|
||||
$v = $this->getVarDumper()->renderVar($v);
|
||||
} else if (!is_string($v)) {
|
||||
$v = $this->getDataFormatter()->formatVar($v);
|
||||
}
|
||||
$data[$k] = $v;
|
||||
@@ -62,16 +92,26 @@ class ConfigCollector extends DataCollector implements Renderable
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAssets() {
|
||||
return $this->isHtmlVarDumperUsed() ? $this->getVarDumper()->getAssets() : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
$name = $this->getName();
|
||||
$widget = $this->isHtmlVarDumperUsed()
|
||||
? "PhpDebugBar.Widgets.HtmlVariableListWidget"
|
||||
: "PhpDebugBar.Widgets.VariableListWidget";
|
||||
return array(
|
||||
"$name" => array(
|
||||
"icon" => "gear",
|
||||
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
|
||||
"widget" => $widget,
|
||||
"map" => "$name",
|
||||
"default" => "{}"
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace DebugBar\DataCollector;
|
||||
|
||||
use DebugBar\DataFormatter\DataFormatter;
|
||||
use DebugBar\DataFormatter\DataFormatterInterface;
|
||||
use DebugBar\DataFormatter\DebugBarVarDumper;
|
||||
|
||||
/**
|
||||
* Abstract class for data collectors
|
||||
@@ -19,8 +20,13 @@ use DebugBar\DataFormatter\DataFormatterInterface;
|
||||
abstract class DataCollector implements DataCollectorInterface
|
||||
{
|
||||
private static $defaultDataFormatter;
|
||||
private static $defaultVarDumper;
|
||||
|
||||
protected $dataFormater;
|
||||
protected $varDumper;
|
||||
protected $xdebugLinkTemplate = '';
|
||||
protected $xdebugShouldUseAjax = false;
|
||||
protected $xdebugReplacements = array();
|
||||
|
||||
/**
|
||||
* Sets the default data formater instance used by all collectors subclassing this class
|
||||
@@ -68,6 +74,78 @@ abstract class DataCollector implements DataCollectorInterface
|
||||
return $this->dataFormater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Xdebug Link to a file
|
||||
*
|
||||
* @param string $file
|
||||
* @param int $line
|
||||
*
|
||||
* @return array {
|
||||
* @var string $url
|
||||
* @var bool $ajax should be used to open the url instead of a normal links
|
||||
* }
|
||||
*/
|
||||
public function getXdebugLink($file, $line = 1)
|
||||
{
|
||||
if (count($this->xdebugReplacements)) {
|
||||
$file = strtr($file, $this->xdebugReplacements);
|
||||
}
|
||||
|
||||
$url = strtr($this->getXdebugLinkTemplate(), ['%f' => $file, '%l' => $line]);
|
||||
if ($url) {
|
||||
return ['url' => $url, 'ajax' => $this->getXdebugShouldUseAjax()];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default variable dumper used by all collectors subclassing this class
|
||||
*
|
||||
* @param DebugBarVarDumper $varDumper
|
||||
*/
|
||||
public static function setDefaultVarDumper(DebugBarVarDumper $varDumper)
|
||||
{
|
||||
self::$defaultVarDumper = $varDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default variable dumper
|
||||
*
|
||||
* @return DebugBarVarDumper
|
||||
*/
|
||||
public static function getDefaultVarDumper()
|
||||
{
|
||||
if (self::$defaultVarDumper === null) {
|
||||
self::$defaultVarDumper = new DebugBarVarDumper();
|
||||
}
|
||||
return self::$defaultVarDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable dumper instance used by this collector
|
||||
*
|
||||
* @param DebugBarVarDumper $varDumper
|
||||
* @return $this
|
||||
*/
|
||||
public function setVarDumper(DebugBarVarDumper $varDumper)
|
||||
{
|
||||
$this->varDumper = $varDumper;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable dumper instance used by this collector; note that collectors using this
|
||||
* instance need to be sure to return the static assets provided by the variable dumper.
|
||||
*
|
||||
* @return DebugBarVarDumper
|
||||
*/
|
||||
public function getVarDumper()
|
||||
{
|
||||
if ($this->varDumper === null) {
|
||||
$this->varDumper = self::getDefaultVarDumper();
|
||||
}
|
||||
return $this->varDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@@ -91,4 +169,66 @@ abstract class DataCollector implements DataCollectorInterface
|
||||
{
|
||||
return $this->getDataFormatter()->formatBytes($size, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getXdebugLinkTemplate()
|
||||
{
|
||||
if (empty($this->xdebugLinkTemplate) && !empty(ini_get('xdebug.file_link_format'))) {
|
||||
$this->xdebugLinkTemplate = ini_get('xdebug.file_link_format');
|
||||
}
|
||||
|
||||
return $this->xdebugLinkTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $xdebugLinkTemplate
|
||||
* @param bool $shouldUseAjax
|
||||
*/
|
||||
public function setXdebugLinkTemplate($xdebugLinkTemplate, $shouldUseAjax = false)
|
||||
{
|
||||
if ($xdebugLinkTemplate === 'idea') {
|
||||
$this->xdebugLinkTemplate = 'http://localhost:63342/api/file/?file=%f&line=%l';
|
||||
$this->xdebugShouldUseAjax = true;
|
||||
} else {
|
||||
$this->xdebugLinkTemplate = $xdebugLinkTemplate;
|
||||
$this->xdebugShouldUseAjax = $shouldUseAjax;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getXdebugShouldUseAjax()
|
||||
{
|
||||
return $this->xdebugShouldUseAjax;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an array of filename-replacements
|
||||
*
|
||||
* this is useful f.e. when using vagrant or remote servers,
|
||||
* where the path of the file is different between server and
|
||||
* development environment
|
||||
*
|
||||
* @return array key-value-pairs of replacements, key = path on server, value = replacement
|
||||
*/
|
||||
public function getXdebugReplacements()
|
||||
{
|
||||
return $this->xdebugReplacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $xdebugReplacements
|
||||
*/
|
||||
public function setXdebugReplacements($xdebugReplacements)
|
||||
{
|
||||
$this->xdebugReplacements = $xdebugReplacements;
|
||||
}
|
||||
|
||||
public function setXdebugReplacement($serverPath, $replacement)
|
||||
{
|
||||
$this->xdebugReplacements[$serverPath] = $replacement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,8 @@ class ExceptionsCollector extends DataCollector implements Renderable
|
||||
'code' => $e->getCode(),
|
||||
'file' => $filePath,
|
||||
'line' => $e->getLine(),
|
||||
'surrounding_lines' => $lines
|
||||
'surrounding_lines' => $lines,
|
||||
'xdebug_link' => $this->getXdebugLink($filePath, $e->getLine())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,32 @@ namespace DebugBar\DataCollector;
|
||||
*/
|
||||
class MemoryCollector extends DataCollector implements Renderable
|
||||
{
|
||||
protected $realUsage = false;
|
||||
|
||||
protected $peakUsage = 0;
|
||||
|
||||
/**
|
||||
* Returns whether total allocated memory page size is used instead of actual used memory size
|
||||
* by the application. See $real_usage parameter on memory_get_peak_usage for details.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getRealUsage()
|
||||
{
|
||||
return $this->realUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether total allocated memory page size is used instead of actual used memory size
|
||||
* by the application. See $real_usage parameter on memory_get_peak_usage for details.
|
||||
*
|
||||
* @param bool $realUsage
|
||||
*/
|
||||
public function setRealUsage($realUsage)
|
||||
{
|
||||
$this->realUsage = $realUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the peak memory usage
|
||||
*
|
||||
@@ -32,7 +56,7 @@ class MemoryCollector extends DataCollector implements Renderable
|
||||
*/
|
||||
public function updatePeakUsage()
|
||||
{
|
||||
$this->peakUsage = memory_get_peak_usage(true);
|
||||
$this->peakUsage = memory_get_peak_usage($this->realUsage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,11 +12,12 @@ namespace DebugBar\DataCollector;
|
||||
|
||||
use Psr\Log\AbstractLogger;
|
||||
use DebugBar\DataFormatter\DataFormatterInterface;
|
||||
use DebugBar\DataFormatter\DebugBarVarDumper;
|
||||
|
||||
/**
|
||||
* Provides a way to log messages
|
||||
*/
|
||||
class MessagesCollector extends AbstractLogger implements DataCollectorInterface, MessagesAggregateInterface, Renderable
|
||||
class MessagesCollector extends AbstractLogger implements DataCollectorInterface, MessagesAggregateInterface, Renderable, AssetProvider
|
||||
{
|
||||
protected $name;
|
||||
|
||||
@@ -26,6 +27,12 @@ class MessagesCollector extends AbstractLogger implements DataCollectorInterface
|
||||
|
||||
protected $dataFormater;
|
||||
|
||||
protected $varDumper;
|
||||
|
||||
// The HTML var dumper requires debug bar users to support the new inline assets, which not all
|
||||
// may support yet - so return false by default for now.
|
||||
protected $useHtmlVarDumper = false;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
@@ -57,6 +64,56 @@ class MessagesCollector extends AbstractLogger implements DataCollectorInterface
|
||||
return $this->dataFormater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable dumper instance used by this collector
|
||||
*
|
||||
* @param DebugBarVarDumper $varDumper
|
||||
* @return $this
|
||||
*/
|
||||
public function setVarDumper(DebugBarVarDumper $varDumper)
|
||||
{
|
||||
$this->varDumper = $varDumper;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable dumper instance used by this collector
|
||||
*
|
||||
* @return DebugBarVarDumper
|
||||
*/
|
||||
public function getVarDumper()
|
||||
{
|
||||
if ($this->varDumper === null) {
|
||||
$this->varDumper = DataCollector::getDefaultVarDumper();
|
||||
}
|
||||
return $this->varDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag indicating whether the Symfony HtmlDumper will be used to dump variables for
|
||||
* rich variable rendering. Be sure to set this flag before logging any messages for the
|
||||
* first time.
|
||||
*
|
||||
* @param bool $value
|
||||
* @return $this
|
||||
*/
|
||||
public function useHtmlVarDumper($value = true)
|
||||
{
|
||||
$this->useHtmlVarDumper = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the Symfony HtmlDumper will be used to dump variables for rich variable
|
||||
* rendering.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function isHtmlVarDumperUsed()
|
||||
{
|
||||
return $this->useHtmlVarDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message
|
||||
*
|
||||
@@ -67,12 +124,19 @@ class MessagesCollector extends AbstractLogger implements DataCollectorInterface
|
||||
*/
|
||||
public function addMessage($message, $label = 'info', $isString = true)
|
||||
{
|
||||
$messageText = $message;
|
||||
$messageHtml = null;
|
||||
if (!is_string($message)) {
|
||||
$message = $this->getDataFormatter()->formatVar($message);
|
||||
// Send both text and HTML representations; the text version is used for searches
|
||||
$messageText = $this->getDataFormatter()->formatVar($message);
|
||||
if ($this->isHtmlVarDumperUsed()) {
|
||||
$messageHtml = $this->getVarDumper()->renderVar($message);
|
||||
}
|
||||
$isString = false;
|
||||
}
|
||||
$this->messages[] = array(
|
||||
'message' => $message,
|
||||
'message' => $messageText,
|
||||
'message_html' => $messageHtml,
|
||||
'is_string' => $isString,
|
||||
'label' => $label,
|
||||
'time' => microtime(true)
|
||||
@@ -152,6 +216,13 @@ class MessagesCollector extends AbstractLogger implements DataCollectorInterface
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAssets() {
|
||||
return $this->isHtmlVarDumperUsed() ? $this->getVarDumper()->getAssets() : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ class TracedStatement
|
||||
public function start($startTime = null, $startMemory = null)
|
||||
{
|
||||
$this->startTime = $startTime ?: microtime(true);
|
||||
$this->startMemory = $startMemory ?: memory_get_usage(true);
|
||||
$this->startMemory = $startMemory ?: memory_get_usage(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +59,7 @@ class TracedStatement
|
||||
{
|
||||
$this->endTime = $endTime ?: microtime(true);
|
||||
$this->duration = $this->endTime - $this->startTime;
|
||||
$this->endMemory = $endMemory ?: memory_get_usage(true);
|
||||
$this->endMemory = $endMemory ?: memory_get_usage(false);
|
||||
$this->memoryDelta = $this->endMemory - $this->startMemory;
|
||||
$this->exception = $exception;
|
||||
$this->rowCount = $rowCount;
|
||||
@@ -110,7 +110,7 @@ class TracedStatement
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
$v = "$quoteLeft$v$quoteRight";
|
||||
if (!is_numeric($k)) {
|
||||
$sql = str_replace($k, $v, $sql);
|
||||
$sql = preg_replace("/{$k}\b/", $v, $sql, 1);
|
||||
} else {
|
||||
$p = strpos($sql, '?');
|
||||
$sql = substr($sql, 0, $p) . $v. substr($sql, $p + 1);
|
||||
|
||||
@@ -13,8 +13,16 @@ namespace DebugBar\DataCollector;
|
||||
/**
|
||||
* Collects info about PHP
|
||||
*/
|
||||
class PhpInfoCollector extends DataCollector
|
||||
class PhpInfoCollector extends DataCollector implements Renderable
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -27,10 +35,17 @@ class PhpInfoCollector extends DataCollector
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
public function getWidgets()
|
||||
{
|
||||
return 'php';
|
||||
return array(
|
||||
"php_version" => array(
|
||||
"icon" => "code",
|
||||
"tooltip" => "Version",
|
||||
"map" => "php.version",
|
||||
"default" => ""
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,36 @@ namespace DebugBar\DataCollector;
|
||||
/**
|
||||
* Collects info about the current request
|
||||
*/
|
||||
class RequestDataCollector extends DataCollector implements Renderable
|
||||
class RequestDataCollector extends DataCollector implements Renderable, AssetProvider
|
||||
{
|
||||
// The HTML var dumper requires debug bar users to support the new inline assets, which not all
|
||||
// may support yet - so return false by default for now.
|
||||
protected $useHtmlVarDumper = false;
|
||||
|
||||
/**
|
||||
* Sets a flag indicating whether the Symfony HtmlDumper will be used to dump variables for
|
||||
* rich variable rendering.
|
||||
*
|
||||
* @param bool $value
|
||||
* @return $this
|
||||
*/
|
||||
public function useHtmlVarDumper($value = true)
|
||||
{
|
||||
$this->useHtmlVarDumper = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the Symfony HtmlDumper will be used to dump variables for rich variable
|
||||
* rendering.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function isHtmlVarDumperUsed()
|
||||
{
|
||||
return $this->useHtmlVarDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -25,7 +53,12 @@ class RequestDataCollector extends DataCollector implements Renderable
|
||||
|
||||
foreach ($vars as $var) {
|
||||
if (isset($GLOBALS[$var])) {
|
||||
$data["$" . $var] = $this->getDataFormatter()->formatVar($GLOBALS[$var]);
|
||||
$key = "$" . $var;
|
||||
if ($this->isHtmlVarDumperUsed()) {
|
||||
$data[$key] = $this->getVarDumper()->renderVar($GLOBALS[$var]);
|
||||
} else {
|
||||
$data[$key] = $this->getDataFormatter()->formatVar($GLOBALS[$var]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,15 +73,25 @@ class RequestDataCollector extends DataCollector implements Renderable
|
||||
return 'request';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAssets() {
|
||||
return $this->isHtmlVarDumperUsed() ? $this->getVarDumper()->getAssets() : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
$widget = $this->isHtmlVarDumperUsed()
|
||||
? "PhpDebugBar.Widgets.HtmlVariableListWidget"
|
||||
: "PhpDebugBar.Widgets.VariableListWidget";
|
||||
return array(
|
||||
"request" => array(
|
||||
"icon" => "tags",
|
||||
"widget" => "PhpDebugBar.Widgets.VariableListWidget",
|
||||
"widget" => $widget,
|
||||
"map" => "request",
|
||||
"default" => "{}"
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ class TimeDataCollector extends DataCollector implements Renderable
|
||||
$requestStartTime = microtime(true);
|
||||
}
|
||||
}
|
||||
$this->requestStartTime = $requestStartTime;
|
||||
$this->requestStartTime = (float)$requestStartTime;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
315
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/DebugBarVarDumper.php
vendored
Normal file
315
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/DebugBarVarDumper.php
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
namespace DebugBar\DataFormatter;
|
||||
|
||||
use DebugBar\DataCollector\AssetProvider;
|
||||
use DebugBar\DataFormatter\VarDumper\DebugBarHtmlDumper;
|
||||
use DebugBar\DataFormatter\VarDumper\SeekingData;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
|
||||
/**
|
||||
* Clones and renders variables in HTML format using the Symfony VarDumper component.
|
||||
*
|
||||
* Cloning is decoupled from rendering, so that dumper users can have the fastest possible cloning
|
||||
* performance, while delaying rendering until it is actually needed.
|
||||
*/
|
||||
class DebugBarVarDumper implements AssetProvider
|
||||
{
|
||||
protected static $defaultClonerOptions = array();
|
||||
|
||||
protected static $defaultDumperOptions = array(
|
||||
'expanded_depth' => 0,
|
||||
'styles' => array(
|
||||
// NOTE: 'default' CSS is also specified in debugbar.css
|
||||
'default' => 'word-wrap: break-word; white-space: pre-wrap; word-break: normal',
|
||||
'num' => 'font-weight:bold; color:#1299DA',
|
||||
'const' => 'font-weight:bold',
|
||||
'str' => 'font-weight:bold; color:#3A9B26',
|
||||
'note' => 'color:#1299DA',
|
||||
'ref' => 'color:#7B7B7B',
|
||||
'public' => 'color:#000000',
|
||||
'protected' => 'color:#000000',
|
||||
'private' => 'color:#000000',
|
||||
'meta' => 'color:#B729D9',
|
||||
'key' => 'color:#3A9B26',
|
||||
'index' => 'color:#1299DA',
|
||||
'ellipsis' => 'color:#A0A000',
|
||||
),
|
||||
);
|
||||
|
||||
protected $clonerOptions;
|
||||
|
||||
protected $dumperOptions;
|
||||
|
||||
/** @var VarCloner */
|
||||
protected $cloner;
|
||||
|
||||
/** @var DebugBarHtmlDumper */
|
||||
protected $dumper;
|
||||
|
||||
/**
|
||||
* Gets the VarCloner instance with configuration options set.
|
||||
*
|
||||
* @return VarCloner
|
||||
*/
|
||||
protected function getCloner()
|
||||
{
|
||||
if (!$this->cloner) {
|
||||
$clonerOptions = $this->getClonerOptions();
|
||||
if (isset($clonerOptions['casters'])) {
|
||||
$this->cloner = new VarCloner($clonerOptions['casters']);
|
||||
} else {
|
||||
$this->cloner = new VarCloner();
|
||||
}
|
||||
if (isset($clonerOptions['additional_casters'])) {
|
||||
$this->cloner->addCasters($clonerOptions['additional_casters']);
|
||||
}
|
||||
if (isset($clonerOptions['max_items'])) {
|
||||
$this->cloner->setMaxItems($clonerOptions['max_items']);
|
||||
}
|
||||
if (isset($clonerOptions['max_string'])) {
|
||||
$this->cloner->setMaxString($clonerOptions['max_string']);
|
||||
}
|
||||
// setMinDepth was added to Symfony 3.4:
|
||||
if (isset($clonerOptions['min_depth']) && method_exists($this->cloner, 'setMinDepth')) {
|
||||
$this->cloner->setMinDepth($clonerOptions['min_depth']);
|
||||
}
|
||||
}
|
||||
return $this->cloner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DebugBarHtmlDumper instance with configuration options set.
|
||||
*
|
||||
* @return DebugBarHtmlDumper
|
||||
*/
|
||||
protected function getDumper()
|
||||
{
|
||||
if (!$this->dumper) {
|
||||
$this->dumper = new DebugBarHtmlDumper();
|
||||
$dumperOptions = $this->getDumperOptions();
|
||||
if (isset($dumperOptions['styles'])) {
|
||||
$this->dumper->setStyles($dumperOptions['styles']);
|
||||
}
|
||||
}
|
||||
return $this->dumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of non-default VarCloner configuration options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClonerOptions()
|
||||
{
|
||||
if ($this->clonerOptions === null) {
|
||||
$this->clonerOptions = self::$defaultClonerOptions;
|
||||
}
|
||||
return $this->clonerOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges an array of non-default VarCloner configuration options with the existing non-default
|
||||
* options.
|
||||
*
|
||||
* Configuration options are:
|
||||
* - casters: a map of VarDumper Caster objects to use instead of the default casters.
|
||||
* - additional_casters: a map of VarDumper Caster objects to use in addition to the default
|
||||
* casters.
|
||||
* - max_items: maximum number of items to clone beyond the minimum depth.
|
||||
* - max_string: maximum string size
|
||||
* - min_depth: minimum tree depth to clone before counting items against the max_items limit.
|
||||
* (Requires Symfony 3.4; ignored on older versions.)
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function mergeClonerOptions($options)
|
||||
{
|
||||
$this->clonerOptions = $options + $this->getClonerOptions();
|
||||
$this->cloner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the array of non-default VarCloner configuration options without retaining any of the
|
||||
* existing non-default options.
|
||||
*
|
||||
* Configuration options are:
|
||||
* - casters: a map of VarDumper Caster objects to use instead of the default casters.
|
||||
* - additional_casters: a map of VarDumper Caster objects to use in addition to the default
|
||||
* casters.
|
||||
* - max_items: maximum number of items to clone beyond the minimum depth.
|
||||
* - max_string: maximum string size
|
||||
* - min_depth: minimum tree depth to clone before counting items against the max_items limit.
|
||||
* (Requires Symfony 3.4; ignored on older versions.)
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function resetClonerOptions($options = null)
|
||||
{
|
||||
$this->clonerOptions = ($options ?: array()) + self::$defaultClonerOptions;
|
||||
$this->cloner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of non-default HtmlDumper configuration options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDumperOptions()
|
||||
{
|
||||
if ($this->dumperOptions === null) {
|
||||
$this->dumperOptions = self::$defaultDumperOptions;
|
||||
}
|
||||
return $this->dumperOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges an array of non-default HtmlDumper configuration options with the existing non-default
|
||||
* options.
|
||||
*
|
||||
* Configuration options are:
|
||||
* - styles: a map of CSS styles to include in the assets, as documented in
|
||||
* HtmlDumper::setStyles.
|
||||
* - expanded_depth: the tree depth to initially expand.
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
* - max_string: maximum string size.
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
* - file_link_format: link format for files; %f expanded to file and %l expanded to line
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function mergeDumperOptions($options)
|
||||
{
|
||||
$this->dumperOptions = $options + $this->getDumperOptions();
|
||||
$this->dumper = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the array of non-default HtmlDumper configuration options without retaining any of the
|
||||
* existing non-default options.
|
||||
*
|
||||
* Configuration options are:
|
||||
* - styles: a map of CSS styles to include in the assets, as documented in
|
||||
* HtmlDumper::setStyles.
|
||||
* - expanded_depth: the tree depth to initially expand.
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
* - max_string: maximum string size.
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
* - file_link_format: link format for files; %f expanded to file and %l expanded to line
|
||||
* (Requires Symfony 3.2; ignored on older versions.)
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function resetDumperOptions($options = null)
|
||||
{
|
||||
$this->dumperOptions = ($options ?: array()) + self::$defaultDumperOptions;
|
||||
$this->dumper = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the data from a variable and serializes it for later rendering.
|
||||
*
|
||||
* @param mixed $data The variable to capture.
|
||||
* @return string Serialized variable data.
|
||||
*/
|
||||
public function captureVar($data)
|
||||
{
|
||||
return serialize($this->getCloner()->cloneVar($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display options for the HTML dumper.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDisplayOptions()
|
||||
{
|
||||
$displayOptions = array();
|
||||
$dumperOptions = $this->getDumperOptions();
|
||||
// Only used by Symfony 3.2 and newer:
|
||||
if (isset($dumperOptions['expanded_depth'])) {
|
||||
$displayOptions['maxDepth'] = $dumperOptions['expanded_depth'];
|
||||
}
|
||||
// Only used by Symfony 3.2 and newer:
|
||||
if (isset($dumperOptions['max_string'])) {
|
||||
$displayOptions['maxStringLength'] = $dumperOptions['max_string'];
|
||||
}
|
||||
// Only used by Symfony 3.2 and newer:
|
||||
if (isset($dumperOptions['file_link_format'])) {
|
||||
$displayOptions['fileLinkFormat'] = $dumperOptions['file_link_format'];
|
||||
}
|
||||
return $displayOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders previously-captured data from captureVar to HTML and returns it as a string.
|
||||
*
|
||||
* @param string $capturedData Captured data from captureVar.
|
||||
* @param array $seekPath Pass an array of keys to traverse if you only want to render a subset
|
||||
* of the data.
|
||||
* @return string HTML rendering of the variable.
|
||||
*/
|
||||
public function renderCapturedVar($capturedData, $seekPath = array())
|
||||
{
|
||||
$data = unserialize($capturedData);
|
||||
// The seek method was added in Symfony 3.2; emulate the behavior via SeekingData for older
|
||||
// Symfony versions.
|
||||
if (!method_exists($data, 'seek')) {
|
||||
$data = new SeekingData($data->getRawData());
|
||||
}
|
||||
|
||||
foreach ($seekPath as $key) {
|
||||
$data = $data->seek($key);
|
||||
}
|
||||
|
||||
return $this->dump($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures and renders the data from a variable to HTML and returns it as a string.
|
||||
*
|
||||
* @param mixed $data The variable to capture and render.
|
||||
* @return string HTML rendering of the variable.
|
||||
*/
|
||||
public function renderVar($data)
|
||||
{
|
||||
return $this->dump($this->getCloner()->cloneVar($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns assets required for rendering variables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAssets() {
|
||||
$dumper = $this->getDumper();
|
||||
$dumper->setDumpHeader(null); // this will cause the default dump header to regenerate
|
||||
return array(
|
||||
'inline_head' => array(
|
||||
'html_var_dumper' => $dumper->getDumpHeaderByDebugBar(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to dump a Data object to HTML.
|
||||
*
|
||||
* @param Data $data
|
||||
* @return string
|
||||
*/
|
||||
protected function dump(Data $data)
|
||||
{
|
||||
$dumper = $this->getDumper();
|
||||
$output = fopen('php://memory', 'r+b');
|
||||
$dumper->setOutput($output);
|
||||
$dumper->setDumpHeader(''); // we don't actually want a dump header
|
||||
// NOTE: Symfony 3.2 added the third $extraDisplayOptions parameter. Older versions will
|
||||
// safely ignore it.
|
||||
$dumper->dump($data, null, $this->getDisplayOptions());
|
||||
$result = stream_get_contents($output, -1, 0);
|
||||
fclose($output);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
17
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/VarDumper/DebugBarHtmlDumper.php
vendored
Normal file
17
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/VarDumper/DebugBarHtmlDumper.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace DebugBar\DataFormatter\VarDumper;
|
||||
|
||||
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||
|
||||
/**
|
||||
* We have to extend the base HtmlDumper class in order to get access to the protected-only
|
||||
* getDumpHeader function.
|
||||
*/
|
||||
class DebugBarHtmlDumper extends HtmlDumper
|
||||
{
|
||||
public function getDumpHeaderByDebugBar() {
|
||||
// getDumpHeader is protected:
|
||||
return str_replace('pre.sf-dump', '.phpdebugbar pre.sf-dump', $this->getDumpHeader());
|
||||
}
|
||||
}
|
||||
103
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/VarDumper/SeekingData.php
vendored
Normal file
103
vendor/maximebf/debugbar/src/DebugBar/DataFormatter/VarDumper/SeekingData.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace DebugBar\DataFormatter\VarDumper;
|
||||
|
||||
use Symfony\Component\VarDumper\Cloner\Cursor;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
use Symfony\Component\VarDumper\Cloner\DumperInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\Stub;
|
||||
|
||||
/**
|
||||
* This class backports the seek() function from Symfony 3.2 to older versions - up to v2.6. The
|
||||
* class should not be used with newer Symfony versions that provide the seek function, as it relies
|
||||
* on a lot of undocumented functionality.
|
||||
*/
|
||||
class SeekingData extends Data
|
||||
{
|
||||
// Because the class copies/pastes the seek() implementation from Symfony 3.2, we reproduce its
|
||||
// copyright here; this class is subject to the following additional copyright:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Fabien Potencier
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
private $position = 0;
|
||||
private $key = 0;
|
||||
|
||||
/**
|
||||
* Seeks to a specific key in nested data structures.
|
||||
*
|
||||
* @param string|int $key The key to seek to
|
||||
*
|
||||
* @return self|null A clone of $this of null if the key is not set
|
||||
*/
|
||||
public function seek($key)
|
||||
{
|
||||
$thisData = $this->getRawData();
|
||||
$item = $thisData[$this->position][$this->key];
|
||||
|
||||
if (!$item instanceof Stub || !$item->position) {
|
||||
return;
|
||||
}
|
||||
$keys = array($key);
|
||||
|
||||
switch ($item->type) {
|
||||
case Stub::TYPE_OBJECT:
|
||||
$keys[] = "\0+\0".$key;
|
||||
$keys[] = "\0*\0".$key;
|
||||
$keys[] = "\0~\0".$key;
|
||||
$keys[] = "\0$item->class\0$key";
|
||||
case Stub::TYPE_ARRAY:
|
||||
case Stub::TYPE_RESOURCE:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$data = null;
|
||||
$children = $thisData[$item->position];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (isset($children[$key]) || array_key_exists($key, $children)) {
|
||||
$data = clone $this;
|
||||
$data->key = $key;
|
||||
$data->position = $item->position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dump(DumperInterface $dumper)
|
||||
{
|
||||
// Override the base class dump to use the position and key
|
||||
$refs = array(0);
|
||||
$class = new \ReflectionClass($this);
|
||||
$dumpItem = $class->getMethod('dumpItem');
|
||||
$dumpItem->setAccessible(true);
|
||||
$data = $this->getRawData();
|
||||
$args = array($dumper, new Cursor(), &$refs, $data[$this->position][$this->key]);
|
||||
$dumpItem->invokeArgs($this, $args);
|
||||
}
|
||||
}
|
||||
@@ -204,14 +204,33 @@ class DebugBar implements ArrayAccess
|
||||
*/
|
||||
public function collect()
|
||||
{
|
||||
$this->data = array(
|
||||
'__meta' => array(
|
||||
'id' => $this->getCurrentRequestId(),
|
||||
'datetime' => date('Y-m-d H:i:s'),
|
||||
'utime' => microtime(true),
|
||||
if (php_sapi_name() === 'cli') {
|
||||
$ip = gethostname();
|
||||
if ($ip) {
|
||||
$ip = gethostbyname($ip);
|
||||
} else {
|
||||
$ip = '127.0.0.1';
|
||||
}
|
||||
$request_variables = array(
|
||||
'method' => 'CLI',
|
||||
'uri' => isset($_SERVER['SCRIPT_FILENAME']) ? realpath($_SERVER['SCRIPT_FILENAME']) : null,
|
||||
'ip' => $ip
|
||||
);
|
||||
} else {
|
||||
$request_variables = array(
|
||||
'method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null,
|
||||
'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null,
|
||||
'ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null
|
||||
);
|
||||
}
|
||||
$this->data = array(
|
||||
'__meta' => array_merge(
|
||||
array(
|
||||
'id' => $this->getCurrentRequestId(),
|
||||
'datetime' => date('Y-m-d H:i:s'),
|
||||
'utime' => microtime(true)
|
||||
),
|
||||
$request_variables
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ class JavascriptRenderer
|
||||
|
||||
protected $ajaxHandlerBindToXHR = false;
|
||||
|
||||
protected $ajaxHandlerAutoShow = true;
|
||||
|
||||
protected $openHandlerClass = 'PhpDebugBar.OpenHandler';
|
||||
|
||||
protected $openHandlerUrl;
|
||||
@@ -117,6 +119,7 @@ class JavascriptRenderer
|
||||
* - ignore_collectors
|
||||
* - ajax_handler_classname
|
||||
* - ajax_handler_bind_to_jquery
|
||||
* - ajax_handler_auto_show
|
||||
* - open_handler_classname
|
||||
* - open_handler_url
|
||||
*
|
||||
@@ -169,6 +172,9 @@ class JavascriptRenderer
|
||||
if (array_key_exists('ajax_handler_bind_to_jquery', $options)) {
|
||||
$this->setBindAjaxHandlerToJquery($options['ajax_handler_bind_to_jquery']);
|
||||
}
|
||||
if (array_key_exists('ajax_handler_auto_show', $options)) {
|
||||
$this->setAjaxHandlerAutoShow($options['ajax_handler_auto_show']);
|
||||
}
|
||||
if (array_key_exists('open_handler_classname', $options)) {
|
||||
$this->setOpenHandlerClass($options['open_handler_classname']);
|
||||
}
|
||||
@@ -513,6 +519,28 @@ class JavascriptRenderer
|
||||
return $this->ajaxHandlerBindToXHR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether new ajax debug data will be immediately shown. Setting to false could be useful
|
||||
* if there are a lot of tracking events cluttering things.
|
||||
*
|
||||
* @param boolean $autoShow
|
||||
*/
|
||||
public function setAjaxHandlerAutoShow($autoShow = true)
|
||||
{
|
||||
$this->ajaxHandlerAutoShow = $autoShow;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the ajax handler will immediately show new ajax requests.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAjaxHandlerAutoShow()
|
||||
{
|
||||
return $this->ajaxHandlerAutoShow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class name of the js open handler
|
||||
*
|
||||
@@ -556,12 +584,13 @@ class JavascriptRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* Add assets to render in the head
|
||||
* Add assets stored in files to render in the head
|
||||
*
|
||||
* @param array $cssFiles An array of filenames
|
||||
* @param array $jsFiles An array of filenames
|
||||
* @param string $basePath Base path of those files
|
||||
* @param string $baseUrl Base url of those files
|
||||
* @return $this
|
||||
*/
|
||||
public function addAssets($cssFiles, $jsFiles, $basePath = null, $baseUrl = null)
|
||||
{
|
||||
@@ -574,10 +603,37 @@ class JavascriptRenderer
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add inline assets to render inline in the head. Ideally, you should store static assets in
|
||||
* files that you add with the addAssets function. However, adding inline assets is useful when
|
||||
* integrating with 3rd-party libraries that require static assets that are only available in an
|
||||
* inline format.
|
||||
*
|
||||
* The inline content arrays require special string array keys: they are used to deduplicate
|
||||
* content. This is particularly useful if multiple instances of the same asset end up being
|
||||
* added. Inline assets from all collectors are merged together into the same array, so these
|
||||
* content IDs effectively deduplicate the inline assets.
|
||||
*
|
||||
* @param array $inlineCss An array map of content ID to inline CSS content (not including <style> tag)
|
||||
* @param array $inlineJs An array map of content ID to inline JS content (not including <script> tag)
|
||||
* @param array $inlineHead An array map of content ID to arbitrary inline HTML content (typically
|
||||
* <style>/<script> tags); it must be embedded within the <head> element
|
||||
* @return $this
|
||||
*/
|
||||
public function addInlineAssets($inlineCss, $inlineJs, $inlineHead)
|
||||
{
|
||||
$this->additionalAssets[] = array(
|
||||
'inline_css' => (array) $inlineCss,
|
||||
'inline_js' => (array) $inlineJs,
|
||||
'inline_head' => (array) $inlineHead
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of asset files
|
||||
*
|
||||
* @param string $type Only return css or js files
|
||||
* @param string $type 'css', 'js', 'inline_css', 'inline_js', 'inline_head', or null for all
|
||||
* @param string $relativeTo The type of path to which filenames must be relative (path, url or null)
|
||||
* @return array
|
||||
*/
|
||||
@@ -585,6 +641,9 @@ class JavascriptRenderer
|
||||
{
|
||||
$cssFiles = $this->cssFiles;
|
||||
$jsFiles = $this->jsFiles;
|
||||
$inlineCss = array();
|
||||
$inlineJs = array();
|
||||
$inlineHead = array();
|
||||
|
||||
if ($this->includeVendors !== false) {
|
||||
if ($this->includeVendors === true || in_array('css', $this->includeVendors)) {
|
||||
@@ -615,11 +674,29 @@ class JavascriptRenderer
|
||||
$root = $this->getRelativeRoot($relativeTo,
|
||||
$this->makeUriRelativeTo($basePath, $this->basePath),
|
||||
$this->makeUriRelativeTo($baseUrl, $this->baseUrl));
|
||||
$cssFiles = array_merge($cssFiles, $this->makeUriRelativeTo((array) $assets['css'], $root));
|
||||
$jsFiles = array_merge($jsFiles, $this->makeUriRelativeTo((array) $assets['js'], $root));
|
||||
if (isset($assets['css'])) {
|
||||
$cssFiles = array_merge($cssFiles, $this->makeUriRelativeTo((array) $assets['css'], $root));
|
||||
}
|
||||
if (isset($assets['js'])) {
|
||||
$jsFiles = array_merge($jsFiles, $this->makeUriRelativeTo((array) $assets['js'], $root));
|
||||
}
|
||||
|
||||
if (isset($assets['inline_css'])) {
|
||||
$inlineCss = array_merge($inlineCss, (array) $assets['inline_css']);
|
||||
}
|
||||
if (isset($assets['inline_js'])) {
|
||||
$inlineJs = array_merge($inlineJs, (array) $assets['inline_js']);
|
||||
}
|
||||
if (isset($assets['inline_head'])) {
|
||||
$inlineHead = array_merge($inlineHead, (array) $assets['inline_head']);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->filterAssetArray(array($cssFiles, $jsFiles), $type);
|
||||
// Deduplicate files
|
||||
$cssFiles = array_unique($cssFiles);
|
||||
$jsFiles = array_unique($jsFiles);
|
||||
|
||||
return $this->filterAssetArray(array($cssFiles, $jsFiles, $inlineCss, $inlineJs, $inlineHead), $type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,53 +746,64 @@ class JavascriptRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a tuple of (css, js) assets according to $type
|
||||
* Filters a tuple of (css, js, inline_css, inline_js, inline_head) assets according to $type
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $type 'css', 'js' or null for both
|
||||
* @param string $type 'css', 'js', 'inline_css', 'inline_js', 'inline_head', or null for all
|
||||
* @return array
|
||||
*/
|
||||
protected function filterAssetArray($array, $type = null)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
if ($type === 'css') {
|
||||
return $array[0];
|
||||
}
|
||||
if ($type === 'js') {
|
||||
return $array[1];
|
||||
}
|
||||
return $array;
|
||||
$types = array('css', 'js', 'inline_css', 'inline_js', 'inline_head');
|
||||
$typeIndex = array_search(strtolower($type), $types);
|
||||
return $typeIndex !== false ? $array[$typeIndex] : $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tuple where the both items are Assetic AssetCollection,
|
||||
* the first one being css files and the second js files
|
||||
* Returns an array where all items are Assetic AssetCollection:
|
||||
* - The first one contains the CSS files
|
||||
* - The second one contains the JS files
|
||||
* - The third one contains arbitrary inline HTML (typically composed of <script>/<style>
|
||||
* elements); it must be embedded within the <head> element
|
||||
*
|
||||
* @param string $type Only return css or js collection
|
||||
* @return array or \Assetic\Asset\AssetCollection
|
||||
* @param string $type Optionally return only 'css', 'js', or 'inline_head' collection
|
||||
* @return array|\Assetic\Asset\AssetCollection
|
||||
*/
|
||||
public function getAsseticCollection($type = null)
|
||||
{
|
||||
list($cssFiles, $jsFiles) = $this->getAssets();
|
||||
return $this->filterAssetArray(array(
|
||||
$this->createAsseticCollection($cssFiles),
|
||||
$this->createAsseticCollection($jsFiles)
|
||||
), $type);
|
||||
$types = array('css', 'js', 'inline_head');
|
||||
$typeIndex = array_search(strtolower($type), $types);
|
||||
|
||||
list($cssFiles, $jsFiles, $inlineCss, $inlineJs, $inlineHead) = $this->getAssets();
|
||||
$collections = array(
|
||||
$this->createAsseticCollection($cssFiles, $inlineCss),
|
||||
$this->createAsseticCollection($jsFiles, $inlineJs),
|
||||
$this->createAsseticCollection(null, $inlineHead)
|
||||
);
|
||||
return $typeIndex !== false ? $collections[$typeIndex] : $collections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Assetic AssetCollection with the given files.
|
||||
* Create an Assetic AssetCollection with the given content.
|
||||
* Filenames will be converted to absolute path using
|
||||
* the base path.
|
||||
*
|
||||
* @param array $files
|
||||
* @param array|null $files Array of asset filenames.
|
||||
* @param array|null $content Array of inline asset content.
|
||||
* @return \Assetic\Asset\AssetCollection
|
||||
*/
|
||||
protected function createAsseticCollection($files)
|
||||
protected function createAsseticCollection($files = null, $content = null)
|
||||
{
|
||||
$assets = array();
|
||||
foreach ($files as $file) {
|
||||
$assets[] = new \Assetic\Asset\FileAsset($file);
|
||||
if ($files) {
|
||||
foreach ($files as $file) {
|
||||
$assets[] = new \Assetic\Asset\FileAsset($file);
|
||||
}
|
||||
}
|
||||
if ($content) {
|
||||
foreach ($content as $item) {
|
||||
$assets[] = new \Assetic\Asset\StringAsset($item);
|
||||
}
|
||||
}
|
||||
return new \Assetic\Asset\AssetCollection($assets);
|
||||
}
|
||||
@@ -727,7 +815,7 @@ class JavascriptRenderer
|
||||
*/
|
||||
public function dumpCssAssets($targetFilename = null)
|
||||
{
|
||||
$this->dumpAssets($this->getAssets('css'), $targetFilename);
|
||||
$this->dumpAssets($this->getAssets('css'), $this->getAssets('inline_css'), $targetFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -737,29 +825,48 @@ class JavascriptRenderer
|
||||
*/
|
||||
public function dumpJsAssets($targetFilename = null)
|
||||
{
|
||||
$this->dumpAssets($this->getAssets('js'), $targetFilename, $this->useRequireJs);
|
||||
$this->dumpAssets($this->getAssets('js'), $this->getAssets('inline_js'), $targetFilename, $this->useRequireJs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all inline HTML header assets to standard output or in a file (only returns assets not
|
||||
* already returned by dumpCssAssets or dumpJsAssets)
|
||||
*
|
||||
* @param string $targetFilename
|
||||
*/
|
||||
public function dumpHeadAssets($targetFilename = null)
|
||||
{
|
||||
$this->dumpAssets(null, $this->getAssets('inline_head'), $targetFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write assets to standard output or in a file
|
||||
*
|
||||
* @param array $files
|
||||
* @param array|null $files Filenames containing assets
|
||||
* @param array|null $content Inline content to dump
|
||||
* @param string $targetFilename
|
||||
* @param bool $useRequireJs
|
||||
*/
|
||||
protected function dumpAssets($files, $targetFilename = null, $useRequireJs = false)
|
||||
protected function dumpAssets($files = null, $content = null, $targetFilename = null, $useRequireJs = false)
|
||||
{
|
||||
$content = '';
|
||||
foreach ($files as $file) {
|
||||
$content .= file_get_contents($file) . "\n";
|
||||
$dumpedContent = '';
|
||||
if ($files) {
|
||||
foreach ($files as $file) {
|
||||
$dumpedContent .= file_get_contents($file) . "\n";
|
||||
}
|
||||
}
|
||||
if ($content) {
|
||||
foreach ($content as $item) {
|
||||
$dumpedContent .= $item . "\n";
|
||||
}
|
||||
}
|
||||
if ($useRequireJs) {
|
||||
$content = "define('debugbar', ['jquery'], function($){\r\n" . $content . "\r\n return PhpDebugBar; \r\n});";
|
||||
$dumpedContent = "define('debugbar', ['jquery'], function($){\r\n" . $dumpedContent . "\r\n return PhpDebugBar; \r\n});";
|
||||
}
|
||||
if ($targetFilename !== null) {
|
||||
file_put_contents($targetFilename, $content);
|
||||
file_put_contents($targetFilename, $dumpedContent);
|
||||
} else {
|
||||
echo $content;
|
||||
echo $dumpedContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,17 +879,29 @@ class JavascriptRenderer
|
||||
*/
|
||||
public function renderHead()
|
||||
{
|
||||
list($cssFiles, $jsFiles) = $this->getAssets(null, self::RELATIVE_URL);
|
||||
list($cssFiles, $jsFiles, $inlineCss, $inlineJs, $inlineHead) = $this->getAssets(null, self::RELATIVE_URL);
|
||||
$html = '';
|
||||
|
||||
foreach ($cssFiles as $file) {
|
||||
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n", $file);
|
||||
}
|
||||
|
||||
foreach ($inlineCss as $content) {
|
||||
$html .= sprintf('<style type="text/css">%s</style>' . "\n", $content);
|
||||
}
|
||||
|
||||
foreach ($jsFiles as $file) {
|
||||
$html .= sprintf('<script type="text/javascript" src="%s"></script>' . "\n", $file);
|
||||
}
|
||||
|
||||
foreach ($inlineJs as $content) {
|
||||
$html .= sprintf('<script type="text/javascript">%s</script>' . "\n", $content);
|
||||
}
|
||||
|
||||
foreach ($inlineHead as $content) {
|
||||
$html .= $content . "\n";
|
||||
}
|
||||
|
||||
if ($this->enableJqueryNoConflict && !$this->useRequireJs) {
|
||||
$html .= '<script type="text/javascript">jQuery.noConflict(true);</script>' . "\n";
|
||||
}
|
||||
@@ -897,7 +1016,12 @@ class JavascriptRenderer
|
||||
}
|
||||
|
||||
if ($this->ajaxHandlerClass) {
|
||||
$js .= sprintf("%s.ajaxHandler = new %s(%s);\n", $this->variableName, $this->ajaxHandlerClass, $this->variableName);
|
||||
$js .= sprintf("%s.ajaxHandler = new %s(%s, undefined, %s);\n",
|
||||
$this->variableName,
|
||||
$this->ajaxHandlerClass,
|
||||
$this->variableName,
|
||||
$this->ajaxHandlerAutoShow ? 'true' : 'false'
|
||||
);
|
||||
if ($this->ajaxHandlerBindToXHR) {
|
||||
$js .= sprintf("%s.ajaxHandler.bindToXHR();\n", $this->variableName);
|
||||
} elseif ($this->ajaxHandlerBindToJquery) {
|
||||
|
||||
@@ -11,15 +11,33 @@
|
||||
namespace DebugBar;
|
||||
|
||||
/**
|
||||
* Request id generator based on the $_SERVER array
|
||||
* Basic request ID generator
|
||||
*/
|
||||
class RequestIdGenerator implements RequestIdGeneratorInterface
|
||||
{
|
||||
protected $index = 0;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function generate()
|
||||
{
|
||||
return md5(serialize($_SERVER) . microtime());
|
||||
if (function_exists('random_bytes')) {
|
||||
// PHP 7 only
|
||||
return 'X' . bin2hex(random_bytes(16));
|
||||
} else if (function_exists('openssl_random_pseudo_bytes')) {
|
||||
// PHP >= 5.3.0, but OpenSSL may not always be available
|
||||
return 'X' . bin2hex(openssl_random_pseudo_bytes(16));
|
||||
} else {
|
||||
// Fall back to a rudimentary ID generator:
|
||||
// * $_SERVER array will make the ID unique to this request.
|
||||
// * spl_object_hash($this) will make the ID unique to this object instance.
|
||||
// (note that object hashes can be reused, but the other data here should prevent issues here).
|
||||
// * uniqid('', true) will use the current microtime(), plus additional random data.
|
||||
// * $this->index guarantees the uniqueness of IDs from the current object.
|
||||
$this->index++;
|
||||
$entropy = serialize($_SERVER) . uniqid('', true) . spl_object_hash($this) . $this->index;
|
||||
return 'X' . md5($entropy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ namespace DebugBar;
|
||||
interface RequestIdGeneratorInterface
|
||||
{
|
||||
/**
|
||||
* Generates a unique id for the current request
|
||||
* Generates a unique id for the current request. If called repeatedly, a new unique id must
|
||||
* always be returned on each call to generate() - even across different object instances.
|
||||
*
|
||||
* To avoid any potential confusion in ID --> value maps, the returned value must be
|
||||
* guaranteed to not be all-numeric.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@ div.phpdebugbar {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 0;
|
||||
font-family: arial, sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
background: #fff;
|
||||
z-index: 10000;
|
||||
font-size: 14px;
|
||||
@@ -64,15 +64,34 @@ div.phpdebugbar table {
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
div.phpdebugbar code, div.phpdebugbar pre {
|
||||
div.phpdebugbar input[type='text'], div.phpdebugbar input[type='password'] {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.phpdebugbar code, div.phpdebugbar pre, div.phpdebugbar samp {
|
||||
background: none;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 1em;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.phpdebugbar code, div.phpdebugbar pre {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
div.phpdebugbar pre.sf-dump {
|
||||
color: #a0a000;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
a.phpdebugbar-restore-btn {
|
||||
float: left;
|
||||
padding: 5px 8px;
|
||||
@@ -158,7 +177,7 @@ a.phpdebugbar-tab.phpdebugbar-active {
|
||||
margin-left: 5px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
padding: 0px 6px;
|
||||
padding: 0 6px;
|
||||
background: #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
@@ -170,6 +189,9 @@ a.phpdebugbar-tab.phpdebugbar-active {
|
||||
display: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
a.phpdebugbar-tab span.phpdebugbar-badge.phpdebugbar-visible {
|
||||
display: inline;
|
||||
}
|
||||
a.phpdebugbar-tab span.phpdebugbar-badge.phpdebugbar-important {
|
||||
background: #ed6868;
|
||||
color: white;
|
||||
@@ -181,7 +203,7 @@ a.phpdebugbar-close-btn, a.phpdebugbar-open-btn, a.phpdebugbar-restore-btn, a.ph
|
||||
}
|
||||
|
||||
a.phpdebugbar-minimize-btn , a.phpdebugbar-maximize-btn {
|
||||
padding-right: 0px !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
a.phpdebugbar-maximize-btn { display: none}
|
||||
|
||||
@@ -272,9 +272,9 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
this.bindAttr('badge', function(value) {
|
||||
if (value !== null) {
|
||||
this.$badge.text(value);
|
||||
this.$badge.show();
|
||||
this.$badge.addClass(csscls('visible'));
|
||||
} else {
|
||||
this.$badge.hide();
|
||||
this.$badge.removeClass(csscls('visible'));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -370,7 +370,15 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
return "#" + nb + suffix;
|
||||
}
|
||||
|
||||
var filename = data['__meta']['uri'].substr(data['__meta']['uri'].lastIndexOf('/') + 1);
|
||||
var uri = data['__meta']['uri'], filename;
|
||||
if (uri.length && uri.charAt(uri.length - 1) === '/') {
|
||||
// URI ends in a trailing /: get the portion before then to avoid returning an empty string
|
||||
filename = uri.substr(0, uri.length - 1); // strip trailing '/'
|
||||
filename = filename.substr(filename.lastIndexOf('/') + 1); // get last path segment
|
||||
filename += '/'; // add the trailing '/' back
|
||||
} else {
|
||||
filename = uri.substr(uri.lastIndexOf('/') + 1);
|
||||
}
|
||||
var label = "#" + nb + " " + filename + suffix + ' (' + data['__meta']['datetime'].split(' ')[1] + ')';
|
||||
return label;
|
||||
}
|
||||
@@ -895,9 +903,10 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
* @param {Object} data
|
||||
* @param {String} id The name of this set, optional
|
||||
* @param {String} suffix
|
||||
* @param {Bool} show Whether to show the new dataset, optional (default: true)
|
||||
* @return {String} Dataset's id
|
||||
*/
|
||||
addDataSet: function(data, id, suffix) {
|
||||
addDataSet: function(data, id, suffix, show) {
|
||||
var label = this.datesetTitleFormater.format(id, data, suffix);
|
||||
id = id || (getObjectSize(this.datasets) + 1);
|
||||
this.datasets[id] = data;
|
||||
@@ -907,7 +916,9 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
this.$datasets.show();
|
||||
}
|
||||
|
||||
this.showDataSet(id);
|
||||
if (typeof(show) == 'undefined' || show) {
|
||||
this.showDataSet(id);
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
@@ -915,14 +926,15 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
* Loads a dataset using the open handler
|
||||
*
|
||||
* @param {String} id
|
||||
* @param {Bool} show Whether to show the new dataset, optional (default: true)
|
||||
*/
|
||||
loadDataSet: function(id, suffix, callback) {
|
||||
loadDataSet: function(id, suffix, callback, show) {
|
||||
if (!this.openHandler) {
|
||||
throw new Error('loadDataSet() needs an open handler');
|
||||
}
|
||||
var self = this;
|
||||
this.openHandler.load(id, function(data) {
|
||||
self.addDataSet(data, id, suffix);
|
||||
self.addDataSet(data, id, suffix, show);
|
||||
callback && callback(data);
|
||||
});
|
||||
},
|
||||
@@ -1004,10 +1016,13 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
* AjaxHandler
|
||||
*
|
||||
* Extract data from headers of an XMLHttpRequest and adds a new dataset
|
||||
*
|
||||
* @param {Bool} autoShow Whether to immediately show new datasets, optional (default: true)
|
||||
*/
|
||||
var AjaxHandler = PhpDebugBar.AjaxHandler = function(debugbar, headerName) {
|
||||
var AjaxHandler = PhpDebugBar.AjaxHandler = function(debugbar, headerName, autoShow) {
|
||||
this.debugbar = debugbar;
|
||||
this.headerName = headerName || 'phpdebugbar';
|
||||
this.autoShow = typeof(autoShow) == 'undefined' ? true : autoShow;
|
||||
};
|
||||
|
||||
$.extend(AjaxHandler.prototype, {
|
||||
@@ -1039,7 +1054,7 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
loadFromId: function(xhr) {
|
||||
var id = this.extractIdFromHeaders(xhr);
|
||||
if (id && this.debugbar.openHandler) {
|
||||
this.debugbar.loadDataSet(id, "(ajax)");
|
||||
this.debugbar.loadDataSet(id, "(ajax)", undefined, this.autoShow);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1071,7 +1086,7 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
if (data.error) {
|
||||
throw new Error('Error loading debugbar data: ' + data.error);
|
||||
} else if(data.data) {
|
||||
this.debugbar.addDataSet(data.data, data.id, "(ajax)");
|
||||
this.debugbar.addDataSet(data.data, data.id, "(ajax)", this.autoShow);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@ div.phpdebugbar-openhandler {
|
||||
border: 2px solid #888;
|
||||
overflow: auto;
|
||||
z-index: 20001;
|
||||
font-family: arial;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 357 KiB After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,122 +4,122 @@ github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
div.phpdebugbar .hljs {
|
||||
display: block; padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8f8
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-template_comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-javadoc {
|
||||
div.phpdebugbar .hljs-comment,
|
||||
div.phpdebugbar .hljs-template_comment,
|
||||
div.phpdebugbar .diff .hljs-header,
|
||||
div.phpdebugbar .hljs-javadoc {
|
||||
color: #998;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.javascript .hljs-title,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
div.phpdebugbar .hljs-keyword,
|
||||
div.phpdebugbar .css .rule .hljs-keyword,
|
||||
div.phpdebugbar .hljs-winutils,
|
||||
div.phpdebugbar .javascript .hljs-title,
|
||||
div.phpdebugbar .nginx .hljs-title,
|
||||
div.phpdebugbar .hljs-subst,
|
||||
div.phpdebugbar .hljs-request,
|
||||
div.phpdebugbar .hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
div.phpdebugbar .hljs-number,
|
||||
div.phpdebugbar .hljs-hexcolor,
|
||||
div.phpdebugbar .ruby .hljs-constant {
|
||||
color: #099;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.tex .hljs-formula {
|
||||
div.phpdebugbar .hljs-string,
|
||||
div.phpdebugbar .hljs-tag .hljs-value,
|
||||
div.phpdebugbar .hljs-phpdoc,
|
||||
div.phpdebugbar .tex .hljs-formula {
|
||||
color: #d14
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.coffeescript .hljs-params,
|
||||
.scss .hljs-preprocessor {
|
||||
div.phpdebugbar .hljs-title,
|
||||
div.phpdebugbar .hljs-id,
|
||||
div.phpdebugbar .coffeescript .hljs-params,
|
||||
div.phpdebugbar .scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.javascript .hljs-title,
|
||||
.lisp .hljs-title,
|
||||
.clojure .hljs-title,
|
||||
.hljs-subst {
|
||||
div.phpdebugbar .javascript .hljs-title,
|
||||
div.phpdebugbar .lisp .hljs-title,
|
||||
div.phpdebugbar .clojure .hljs-title,
|
||||
div.phpdebugbar .hljs-subst {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.haskell .hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
div.phpdebugbar .hljs-class .hljs-title,
|
||||
div.phpdebugbar .haskell .hljs-type,
|
||||
div.phpdebugbar .vhdl .hljs-literal,
|
||||
div.phpdebugbar .tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rules .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
div.phpdebugbar .hljs-tag,
|
||||
div.phpdebugbar .hljs-tag .hljs-title,
|
||||
div.phpdebugbar .hljs-rules .hljs-property,
|
||||
div.phpdebugbar .django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body {
|
||||
div.phpdebugbar .hljs-attribute,
|
||||
div.phpdebugbar .hljs-variable,
|
||||
div.phpdebugbar .lisp .hljs-body {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
div.phpdebugbar .hljs-regexp {
|
||||
color: #009926
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
div.phpdebugbar .hljs-symbol,
|
||||
div.phpdebugbar .ruby .hljs-symbol .hljs-string,
|
||||
div.phpdebugbar .lisp .hljs-keyword,
|
||||
div.phpdebugbar .tex .hljs-special,
|
||||
div.phpdebugbar .hljs-prompt {
|
||||
color: #990073
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.lisp .hljs-title,
|
||||
.clojure .hljs-built_in {
|
||||
div.phpdebugbar .hljs-built_in,
|
||||
div.phpdebugbar .lisp .hljs-title,
|
||||
div.phpdebugbar .clojure .hljs-built_in {
|
||||
color: #0086b3
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
div.phpdebugbar .hljs-preprocessor,
|
||||
div.phpdebugbar .hljs-pragma,
|
||||
div.phpdebugbar .hljs-pi,
|
||||
div.phpdebugbar .hljs-doctype,
|
||||
div.phpdebugbar .hljs-shebang,
|
||||
div.phpdebugbar .hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
div.phpdebugbar .hljs-deletion {
|
||||
background: #fdd
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
div.phpdebugbar .hljs-addition {
|
||||
background: #dfd
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
div.phpdebugbar .diff .hljs-change {
|
||||
background: #0086b3
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
div.phpdebugbar .hljs-chunk {
|
||||
color: #aaa
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,8 +1,41 @@
|
||||
pre.phpdebugbar-widgets-code-block {
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
overflow: hidden;
|
||||
}
|
||||
pre.phpdebugbar-widgets-code-block code {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
pre.phpdebugbar-widgets-code-block code.phpdebugbar-widgets-numbered-code {
|
||||
padding: 5px;
|
||||
}
|
||||
pre.phpdebugbar-widgets-code-block code span.phpdebugbar-widgets-highlighted-line {
|
||||
background: #800000;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
min-width: 100%;
|
||||
}
|
||||
pre.phpdebugbar-widgets-code-block code span.phpdebugbar-widgets-highlighted-line span {
|
||||
background: none !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
pre.phpdebugbar-widgets-code-block ul {
|
||||
float: left;
|
||||
padding: 5px;
|
||||
background: #cacaca;
|
||||
border-right: 1px solid #aaa;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
ul.phpdebugbar-widgets-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
ul.phpdebugbar-widgets-list li.phpdebugbar-widgets-list-item {
|
||||
padding: 3px 6px;
|
||||
@@ -20,7 +53,7 @@ div.phpdebugbar-widgets-messages {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-list {
|
||||
div.phpdebugbar-widgets-messages ul.phpdebugbar-widgets-list {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-value.phpdebugbar-widgets-warning:before {
|
||||
@@ -40,6 +73,9 @@ div.phpdebugbar-widgets-messages {
|
||||
font-size: 11px;
|
||||
color: red;
|
||||
}
|
||||
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item pre.sf-dump {
|
||||
display: inline;
|
||||
}
|
||||
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-collector,
|
||||
div.phpdebugbar-widgets-messages li.phpdebugbar-widgets-list-item span.phpdebugbar-widgets-label {
|
||||
float: right;
|
||||
@@ -113,9 +149,13 @@ dl.phpdebugbar-widgets-kvlist {
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
dl.phpdebugbar-widgets-varlist {
|
||||
font-family: monospace;
|
||||
dl.phpdebugbar-widgets-varlist,
|
||||
dl.phpdebugbar-widgets-htmlvarlist {
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
dl.phpdebugbar-widgets-htmlvarlist dd {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
@@ -137,7 +177,7 @@ ul.phpdebugbar-widgets-timeline {
|
||||
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-collector {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
color: #555;
|
||||
top: 4px;
|
||||
left: 5px;
|
||||
@@ -151,7 +191,7 @@ ul.phpdebugbar-widgets-timeline {
|
||||
right: 5px;
|
||||
}
|
||||
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-value {
|
||||
display: block;
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
background: #3db9ec;
|
||||
@@ -164,7 +204,7 @@ ul.phpdebugbar-widgets-timeline {
|
||||
width: 70%;
|
||||
margin: 10px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
ul.phpdebugbar-widgets-timeline table.phpdebugbar-widgets-params td {
|
||||
@@ -205,5 +245,17 @@ div.phpdebugbar-widgets-exceptions li.phpdebugbar-widgets-list-item {
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
div.phpdebugbar-widgets-exceptions a.phpdebugbar-widgets-editor-link:before {
|
||||
font-family: PhpDebugbarFontAwesome;
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.phpdebugbar-widgets-exceptions a.phpdebugbar-widgets-editor-link:before {
|
||||
content: "\f08e";
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
*/
|
||||
PhpDebugBar.Widgets = {};
|
||||
|
||||
var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-');
|
||||
|
||||
/**
|
||||
* Replaces spaces with and line breaks with <br>
|
||||
*
|
||||
@@ -68,21 +70,54 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
*
|
||||
* @param {String} code
|
||||
* @param {String} lang
|
||||
* @param {Number} [firstLineNumber] If provided, shows line numbers beginning with the given value.
|
||||
* @param {Number} [highlightedLine] If provided, the given line number will be highlighted.
|
||||
* @return {String}
|
||||
*/
|
||||
var createCodeBlock = PhpDebugBar.Widgets.createCodeBlock = function(code, lang) {
|
||||
var pre = $('<pre />');
|
||||
$('<code />').text(code).appendTo(pre);
|
||||
var createCodeBlock = PhpDebugBar.Widgets.createCodeBlock = function(code, lang, firstLineNumber, highlightedLine) {
|
||||
var pre = $('<pre />').addClass(csscls('code-block'));
|
||||
// Add a newline to prevent <code> element from vertically collapsing too far if the last
|
||||
// code line was empty: that creates problems with the horizontal scrollbar being
|
||||
// incorrectly positioned - most noticeable when line numbers are shown.
|
||||
var codeElement = $('<code />').text(code + '\n').appendTo(pre);
|
||||
|
||||
// Add a span with a special class if we are supposed to highlight a line. highlight.js will
|
||||
// still correctly format code even with existing markup in it.
|
||||
if ($.isNumeric(highlightedLine)) {
|
||||
if ($.isNumeric(firstLineNumber)) {
|
||||
highlightedLine = highlightedLine - firstLineNumber + 1;
|
||||
}
|
||||
codeElement.html(function (index, html) {
|
||||
var currentLine = 1;
|
||||
return html.replace(/^.*$/gm, function(line) {
|
||||
if (currentLine++ == highlightedLine) {
|
||||
return '<span class="' + csscls('highlighted-line') + '">' + line + '</span>';
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Format the code
|
||||
if (lang) {
|
||||
pre.addClass("language-" + lang);
|
||||
}
|
||||
highlight(pre);
|
||||
|
||||
// Show line numbers in a list
|
||||
if ($.isNumeric(firstLineNumber)) {
|
||||
var lineCount = code.split('\n').length;
|
||||
var $lineNumbers = $('<ul />').prependTo(pre);
|
||||
pre.children().addClass(csscls('numbered-code'));
|
||||
for (var i = firstLineNumber; i < firstLineNumber + lineCount; i++) {
|
||||
$('<li />').text(i).appendTo($lineNumbers);
|
||||
}
|
||||
}
|
||||
|
||||
return pre;
|
||||
};
|
||||
|
||||
var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-widgets-');
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Generic widgets
|
||||
// ------------------------------------------------------------------
|
||||
@@ -214,7 +249,28 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* An extension of KVListWidget where the data represents a list
|
||||
* of variables whose contents are HTML; this is useful for showing
|
||||
* variable output from VarDumper's HtmlDumper.
|
||||
*
|
||||
* Options:
|
||||
* - data
|
||||
*/
|
||||
var HtmlVariableListWidget = PhpDebugBar.Widgets.HtmlVariableListWidget = KVListWidget.extend({
|
||||
|
||||
className: csscls('kvlist htmlvarlist'),
|
||||
|
||||
itemRenderer: function(dt, dd, key, value) {
|
||||
$('<span />').attr('title', key).text(key).appendTo(dt);
|
||||
dd.html(value);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Iframe widget
|
||||
*
|
||||
@@ -260,33 +316,37 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
var self = this;
|
||||
|
||||
this.$list = new ListWidget({ itemRenderer: function(li, value) {
|
||||
var m = value.message;
|
||||
if (m.length > 100) {
|
||||
m = m.substr(0, 100) + "...";
|
||||
}
|
||||
|
||||
var val = $('<span />').addClass(csscls('value')).text(m).appendTo(li);
|
||||
if (!value.is_string || value.message.length > 100) {
|
||||
var prettyVal = value.message;
|
||||
if (!value.is_string) {
|
||||
prettyVal = null;
|
||||
if (value.message_html) {
|
||||
var val = $('<span />').addClass(csscls('value')).html(value.message_html).appendTo(li);
|
||||
} else {
|
||||
var m = value.message;
|
||||
if (m.length > 100) {
|
||||
m = m.substr(0, 100) + "...";
|
||||
}
|
||||
li.css('cursor', 'pointer').click(function() {
|
||||
if (val.hasClass(csscls('pretty'))) {
|
||||
val.text(m).removeClass(csscls('pretty'));
|
||||
} else {
|
||||
prettyVal = prettyVal || createCodeBlock(value.message, 'php');
|
||||
val.addClass(csscls('pretty')).empty().append(prettyVal);
|
||||
|
||||
var val = $('<span />').addClass(csscls('value')).text(m).appendTo(li);
|
||||
if (!value.is_string || value.message.length > 100) {
|
||||
var prettyVal = value.message;
|
||||
if (!value.is_string) {
|
||||
prettyVal = null;
|
||||
}
|
||||
});
|
||||
li.css('cursor', 'pointer').click(function () {
|
||||
if (val.hasClass(csscls('pretty'))) {
|
||||
val.text(m).removeClass(csscls('pretty'));
|
||||
} else {
|
||||
prettyVal = prettyVal || createCodeBlock(value.message, 'php');
|
||||
val.addClass(csscls('pretty')).empty().append(prettyVal);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (value.collector) {
|
||||
$('<span />').addClass(csscls('collector')).text(value.collector).prependTo(li);
|
||||
}
|
||||
if (value.label) {
|
||||
val.addClass(csscls(value.label));
|
||||
$('<span />').addClass(csscls('label')).text(value.label).appendTo(li);
|
||||
}
|
||||
if (value.collector) {
|
||||
$('<span />').addClass(csscls('collector')).text(value.collector).appendTo(li);
|
||||
$('<span />').addClass(csscls('label')).text(value.label).prependTo(li);
|
||||
}
|
||||
}});
|
||||
|
||||
@@ -430,7 +490,17 @@ if (typeof(PhpDebugBar) == 'undefined') {
|
||||
this.$list = new ListWidget({ itemRenderer: function(li, e) {
|
||||
$('<span />').addClass(csscls('message')).text(e.message).appendTo(li);
|
||||
if (e.file) {
|
||||
$('<span />').addClass(csscls('filename')).text(e.file + "#" + e.line).appendTo(li);
|
||||
var header = $('<span />').addClass(csscls('filename')).text(e.file + "#" + e.line);
|
||||
if (e.xdebug_link) {
|
||||
if (e.xdebug_link.ajax) {
|
||||
$('<a title="' + e.xdebug_link.url + '"></a>').on('click', function () {
|
||||
$.ajax(e.xdebug_link.url);
|
||||
}).addClass(csscls('editor-link')).appendTo(header);
|
||||
} else {
|
||||
$('<a href="' + e.xdebug_link.url + '"></a>').addClass(csscls('editor-link')).appendTo(header);
|
||||
}
|
||||
}
|
||||
header.appendTo(li);
|
||||
}
|
||||
if (e.type) {
|
||||
$('<span />').addClass(csscls('type')).text(e.type).appendTo(li);
|
||||
|
||||
@@ -8,5 +8,5 @@ div.phpdebugbar-widgets-mails li.phpdebugbar-widgets-list-item pre.phpdebugbar-w
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
div.phpdebugbar-widgets-sqlqueries .phpdebugbar-widgets-status {
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
padding: 6px 6px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
@@ -15,6 +15,7 @@ div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-database,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-duration,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-memory,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-row-count,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-copy-clipboard,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-stmt-id {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
@@ -24,6 +25,7 @@ div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugb
|
||||
div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugbar-widgets-duration,
|
||||
div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugbar-widgets-memory,
|
||||
div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugbar-widgets-row-count,
|
||||
div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugbar-widgets-copy-clipboard,
|
||||
div.phpdebugbar-widgets-sqlqueries div.phpdebugbar-widgets-status span.phpdebugbar-widgets-stmt-id {
|
||||
color: #555;
|
||||
}
|
||||
@@ -31,6 +33,7 @@ div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-database:before,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-duration:before,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-memory:before,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-row-count:before,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-copy-clipboard:before,
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-stmt-id:before {
|
||||
font-family: PhpDebugbarFontAwesome;
|
||||
margin-right: 4px;
|
||||
@@ -51,12 +54,15 @@ div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-row-count:before {
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-stmt-id:before {
|
||||
content: "\f08d";
|
||||
}
|
||||
div.phpdebugbar-widgets-sqlqueries span.phpdebugbar-widgets-copy-clipboard:before {
|
||||
content: "\f0c5";
|
||||
}
|
||||
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params {
|
||||
display: none;
|
||||
width: 70%;
|
||||
margin: 10px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
div.phpdebugbar-widgets-sqlqueries table.phpdebugbar-widgets-params td {
|
||||
|
||||
@@ -24,7 +24,32 @@
|
||||
|
||||
this.set('exclude', excludedLabels);
|
||||
},
|
||||
|
||||
onCopyToClipboard: function (el) {
|
||||
var code = $(el).parent('li').find('code').get(0);
|
||||
var copy = function () {
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
alert('Query copied to the clipboard');
|
||||
} catch (err) {
|
||||
console.log('Oops, unable to copy');
|
||||
}
|
||||
};
|
||||
var select = function (node) {
|
||||
if (document.selection) {
|
||||
var range = document.body.createTextRange();
|
||||
range.moveToElementText(node);
|
||||
range.select();
|
||||
} else if (window.getSelection) {
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(node);
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
copy();
|
||||
window.getSelection().removeAllRanges();
|
||||
};
|
||||
select(code);
|
||||
},
|
||||
render: function() {
|
||||
this.$status = $('<div />').addClass(csscls('status')).appendTo(this.$el);
|
||||
|
||||
@@ -67,6 +92,14 @@
|
||||
li.addClass(csscls('error'));
|
||||
li.append($('<span />').addClass(csscls('error')).text("[" + stmt.error_code + "] " + stmt.error_message));
|
||||
}
|
||||
$('<span title="Copy to clipboard" />')
|
||||
.addClass(csscls('copy-clipboard'))
|
||||
.css('cursor', 'pointer')
|
||||
.on('click', function (event) {
|
||||
self.onCopyToClipboard(this);
|
||||
event.stopPropagation();
|
||||
})
|
||||
.appendTo(li);
|
||||
if (stmt.params && !$.isEmptyObject(stmt.params)) {
|
||||
var table = $('<table><tr><th colspan="2">Params</th></tr></table>').addClass(csscls('params')).appendTo(li);
|
||||
for (var key in stmt.params) {
|
||||
@@ -87,11 +120,15 @@
|
||||
this.$list.$el.appendTo(this.$el);
|
||||
|
||||
this.bindAttr('data', function(data) {
|
||||
// the PDO collector maybe is empty
|
||||
if (data.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
this.$list.set('data', data.statements);
|
||||
this.$status.empty();
|
||||
|
||||
// Search for duplicate statements.
|
||||
for (var sql = {}, unique = 0, i = 0; i < data.statements.length; i++) {
|
||||
for (var sql = {}, unique = 0, duplicate = 0, i = 0; i < data.statements.length; i++) {
|
||||
var stmt = data.statements[i].sql;
|
||||
if (data.statements[i].params && !$.isEmptyObject(data.statements[i].params)) {
|
||||
stmt += ' {' + $.param(data.statements[i].params, false) + '}';
|
||||
@@ -102,11 +139,13 @@
|
||||
// Add classes to all duplicate SQL statements.
|
||||
for (var stmt in sql) {
|
||||
if (sql[stmt].keys.length > 1) {
|
||||
unique++;
|
||||
duplicate += sql[stmt].keys.length;
|
||||
for (var i = 0; i < sql[stmt].keys.length; i++) {
|
||||
this.$list.$el.find('.' + csscls('list-item')).eq(sql[stmt].keys[i])
|
||||
.addClass(csscls('sql-duplicate')).addClass(csscls('sql-duplicate-'+unique));
|
||||
.addClass(csscls('sql-duplicate'));
|
||||
}
|
||||
} else {
|
||||
unique++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,8 +153,8 @@
|
||||
if (data.nb_failed_statements) {
|
||||
t.append(", " + data.nb_failed_statements + " of which failed");
|
||||
}
|
||||
if (unique) {
|
||||
t.append(", " + (data.nb_statements - unique) + " of which were duplicated");
|
||||
if (duplicate) {
|
||||
t.append(", " + duplicate + " of which were duplicates");
|
||||
t.append(", " + unique + " unique");
|
||||
}
|
||||
if (data.accumulated_duration_str) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
div.phpdebugbar-widgets-templates div.phpdebugbar-widgets-status {
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
padding: 6px 6px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
@@ -25,7 +25,9 @@ div.phpdebugbar-widgets-templates div.phpdebugbar-widgets-status span.phpdebugba
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-render-time:before,
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-memory:before,
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-param-count:before,
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-type:before {
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-type:before,
|
||||
div.phpdebugbar-widgets-templates a.phpdebugbar-widgets-editor-link:before
|
||||
{
|
||||
font-family: PhpDebugbarFontAwesome;
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
@@ -42,12 +44,16 @@ div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-param-count:before {
|
||||
div.phpdebugbar-widgets-templates span.phpdebugbar-widgets-type:before {
|
||||
content: "\f121";
|
||||
}
|
||||
div.phpdebugbar-widgets-templates a.phpdebugbar-widgets-editor-link:before {
|
||||
content: "\f08e";
|
||||
margin-left: 4px;
|
||||
}
|
||||
div.phpdebugbar-widgets-templates table.phpdebugbar-widgets-params {
|
||||
display: none;
|
||||
width: 70%;
|
||||
margin: 10px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: monospace;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
div.phpdebugbar-widgets-templates table.phpdebugbar-widgets-params td {
|
||||
|
||||
@@ -17,6 +17,16 @@
|
||||
|
||||
this.$list = new PhpDebugBar.Widgets.ListWidget({ itemRenderer: function(li, tpl) {
|
||||
$('<span />').addClass(csscls('name')).text(tpl.name).appendTo(li);
|
||||
|
||||
if (typeof tpl.xdebug_link !== 'undefined') {
|
||||
if (tpl.xdebug_link.ajax) {
|
||||
$('<a title="' + tpl.xdebug_link.url + '"></a>').on('click', function () {
|
||||
$.ajax(tpl.xdebug_link.url);
|
||||
}).addClass(csscls('editor-link')).appendTo(li);
|
||||
} else {
|
||||
$('<a href="' + tpl.xdebug_link.url + '"></a>').addClass(csscls('editor-link')).appendTo(li);
|
||||
}
|
||||
}
|
||||
if (tpl.render_time_str) {
|
||||
$('<span title="Render time" />').addClass(csscls('render-time')).text(tpl.render_time_str).appendTo(li);
|
||||
}
|
||||
@@ -47,13 +57,15 @@
|
||||
}
|
||||
}});
|
||||
this.$list.$el.appendTo(this.$el);
|
||||
this.$callgraph = $('<div />').addClass(csscls('callgraph')).appendTo(this.$el);
|
||||
|
||||
this.bindAttr('data', function(data) {
|
||||
this.$list.set('data', data.templates);
|
||||
this.$status.empty();
|
||||
this.$callgraph.empty();
|
||||
|
||||
var sentence = data.sentence || "templates were rendered";
|
||||
$('<span />').text(data.templates.length + " " + sentence).appendTo(this.$status);
|
||||
$('<span />').text(data.nb_templates + " " + sentence).appendTo(this.$status);
|
||||
|
||||
if (data.accumulated_render_time_str) {
|
||||
this.$status.append($('<span title="Accumulated render time" />').addClass(csscls('render-time')).text(data.accumulated_render_time_str));
|
||||
@@ -61,6 +73,15 @@
|
||||
if (data.memory_usage_str) {
|
||||
this.$status.append($('<span title="Memory usage" />').addClass(csscls('memory')).text(data.memory_usage_str));
|
||||
}
|
||||
if (data.nb_blocks > 0) {
|
||||
$('<div />').text(data.nb_blocks + " blocks were rendered").appendTo(this.$status);
|
||||
}
|
||||
if (data.nb_macros > 0) {
|
||||
$('<div />').text(data.nb_macros + " macros were rendered").appendTo(this.$status);
|
||||
}
|
||||
if (typeof data.callgraph !== 'undefined') {
|
||||
this.$callgraph.html(data.callgraph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace DebugBar\Storage;
|
||||
|
||||
use Memcached;
|
||||
use ReflectionMethod;
|
||||
|
||||
/**
|
||||
* Stores collected data into Memcache using the Memcached extension
|
||||
@@ -21,13 +22,20 @@ class MemcachedStorage implements StorageInterface
|
||||
|
||||
protected $keyNamespace;
|
||||
|
||||
protected $expiration;
|
||||
|
||||
protected $newGetMultiSignature;
|
||||
|
||||
/**
|
||||
* @param Memcached $memcached
|
||||
* @param string $keyNamespace Namespace for Memcached key names (to avoid conflict with other Memcached users).
|
||||
* @param int $expiration Expiration for Memcached entries (see Expiration Times in Memcached documentation).
|
||||
*/
|
||||
public function __construct(Memcached $memcached, $keyNamespace = 'phpdebugbar')
|
||||
public function __construct(Memcached $memcached, $keyNamespace = 'phpdebugbar', $expiration = 0)
|
||||
{
|
||||
$this->memcached = $memcached;
|
||||
$this->keyNamespace = $keyNamespace;
|
||||
$this->expiration = $expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +44,12 @@ class MemcachedStorage implements StorageInterface
|
||||
public function save($id, $data)
|
||||
{
|
||||
$key = $this->createKey($id);
|
||||
$this->memcached->set($key, $data);
|
||||
$this->memcached->set($key, $data, $this->expiration);
|
||||
if (!$this->memcached->append($this->keyNamespace, "|$key")) {
|
||||
$this->memcached->set($this->keyNamespace, $key);
|
||||
$this->memcached->set($this->keyNamespace, $key, $this->expiration);
|
||||
} else if ($this->expiration) {
|
||||
// append doesn't support updating expiration, so do it here:
|
||||
$this->memcached->touch($this->keyNamespace, $this->expiration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,15 +71,32 @@ class MemcachedStorage implements StorageInterface
|
||||
}
|
||||
|
||||
$results = array();
|
||||
foreach (explode('|', $keys) as $key) {
|
||||
if ($data = $this->memcached->get($key)) {
|
||||
$meta = $data['__meta'];
|
||||
if ($this->filter($meta, $filters)) {
|
||||
$results[] = $meta;
|
||||
$keys = array_reverse(explode('|', $keys)); // Reverse so newest comes first
|
||||
$keyPosition = 0; // Index in $keys to try to get next items from
|
||||
$remainingItems = $max + $offset; // Try to obtain this many remaining items
|
||||
// Loop until we've found $remainingItems matching items or no more items may exist.
|
||||
while ($remainingItems > 0 && $keyPosition < count($keys)) {
|
||||
// Consume some keys from $keys:
|
||||
$itemsToGet = array_slice($keys, $keyPosition, $remainingItems);
|
||||
$keyPosition += $remainingItems;
|
||||
// Try to get them, and filter them:
|
||||
$newItems = $this->memcachedGetMulti($itemsToGet, Memcached::GET_PRESERVE_ORDER);
|
||||
if ($newItems) {
|
||||
foreach ($newItems as $data) {
|
||||
$meta = $data['__meta'];
|
||||
if ($this->filter($meta, $filters)) {
|
||||
$remainingItems--;
|
||||
// Keep the result only if we've discarded $offset items first
|
||||
if ($offset <= 0) {
|
||||
$results[] = $meta;
|
||||
} else {
|
||||
$offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_slice($results, $offset, $max);
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,4 +136,23 @@ class MemcachedStorage implements StorageInterface
|
||||
{
|
||||
return md5("{$this->keyNamespace}.$id");
|
||||
}
|
||||
|
||||
/**
|
||||
* The memcached getMulti function changed in version 3.0.0 to only have two parameters.
|
||||
*
|
||||
* @param array $keys
|
||||
* @param int $flags
|
||||
*/
|
||||
protected function memcachedGetMulti($keys, $flags)
|
||||
{
|
||||
if ($this->newGetMultiSignature === null) {
|
||||
$this->newGetMultiSignature = (new ReflectionMethod('Memcached', 'getMulti'))->getNumberOfParameters() === 2;
|
||||
}
|
||||
if ($this->newGetMultiSignature) {
|
||||
return $this->memcached->getMulti($keys, $flags);
|
||||
} else {
|
||||
$null = null;
|
||||
return $this->memcached->getMulti($keys, $null, $flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
namespace DebugBar\Storage;
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
/**
|
||||
* Stores collected data into Redis
|
||||
*/
|
||||
@@ -25,7 +23,7 @@ class RedisStorage implements StorageInterface
|
||||
* @param \Predis\Client $redis Redis Client
|
||||
* @param string $hash
|
||||
*/
|
||||
public function __construct(Client $redis, $hash = 'phpdebugbar')
|
||||
public function __construct($redis, $hash = 'phpdebugbar')
|
||||
{
|
||||
$this->redis = $redis;
|
||||
$this->hash = $hash;
|
||||
@@ -36,7 +34,9 @@ class RedisStorage implements StorageInterface
|
||||
*/
|
||||
public function save($id, $data)
|
||||
{
|
||||
$this->redis->hset($this->hash, $id, serialize($data));
|
||||
$this->redis->hset("$this->hash:meta", $id, serialize($data['__meta']));
|
||||
unset($data['__meta']);
|
||||
$this->redis->hset("$this->hash:data", $id, serialize($data));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,8 @@ class RedisStorage implements StorageInterface
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
return unserialize($this->redis->hget($this->hash, $id));
|
||||
return array_merge(unserialize($this->redis->hget("$this->hash:data", $id)),
|
||||
array('__meta' => unserialize($this->redis->hget("$this->hash:meta", $id))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,14 +54,23 @@ class RedisStorage implements StorageInterface
|
||||
public function find(array $filters = array(), $max = 20, $offset = 0)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($this->redis->hgetall($this->hash) as $id => $data) {
|
||||
if ($data = unserialize($data)) {
|
||||
$meta = $data['__meta'];
|
||||
if ($this->filter($meta, $filters)) {
|
||||
$results[] = $meta;
|
||||
$cursor = "0";
|
||||
do {
|
||||
list($cursor, $data) = $this->redis->hscan("$this->hash:meta", $cursor);
|
||||
|
||||
foreach ($data as $meta) {
|
||||
if ($meta = unserialize($meta)) {
|
||||
if ($this->filter($meta, $filters)) {
|
||||
$results[] = $meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while($cursor);
|
||||
|
||||
usort($results, function ($a, $b) {
|
||||
return $a['utime'] < $b['utime'];
|
||||
});
|
||||
|
||||
return array_slice($results, $offset, $max);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user