From adfc6e95f83cf59029804e7f24d255f6c6b56c26 Mon Sep 17 00:00:00 2001 From: Mariusz Krzaczkowski Date: Thu, 22 Mar 2018 15:12:40 +0100 Subject: [PATCH] Added minor improvements --- composer.json | 80 +- src/DebugBar/Bridge/CacheCacheCollector.php | 79 +- src/DebugBar/Bridge/DoctrineCollector.php | 152 +- src/DebugBar/Bridge/MonologCollector.php | 163 +- src/DebugBar/Bridge/Propel2Collector.php | 539 ++-- src/DebugBar/Bridge/PropelCollector.php | 430 ++-- src/DebugBar/Bridge/SlimCollector.php | 75 +- .../Bridge/SwiftMailer/SwiftLogCollector.php | 34 +- .../Bridge/SwiftMailer/SwiftMailCollector.php | 120 +- .../Bridge/Twig/TraceableTwigEnvironment.php | 774 +++--- .../Bridge/Twig/TraceableTwigTemplate.php | 222 +- src/DebugBar/Bridge/Twig/TwigCollector.php | 100 +- .../DataCollector/AggregatedCollector.php | 326 +-- src/DebugBar/DataCollector/AssetProvider.php | 22 +- .../DataCollector/ConfigCollector.php | 115 +- src/DebugBar/DataCollector/DataCollector.php | 134 +- .../DataCollector/DataCollectorInterface.php | 26 +- .../DataCollector/ExceptionsCollector.php | 227 +- .../DataCollector/LocalizationCollector.php | 104 +- .../DataCollector/MemoryCollector.php | 100 +- .../MessagesAggregateInterface.php | 12 +- .../DataCollector/MessagesCollector.php | 308 ++- .../DataCollector/PDO/PDOCollector.php | 372 +-- .../DataCollector/PDO/TraceablePDO.php | 597 +++-- .../PDO/TraceablePDOStatement.php | 218 +- .../DataCollector/PDO/TracedStatement.php | 489 ++-- .../DataCollector/PhpInfoCollector.php | 36 +- src/DebugBar/DataCollector/Renderable.php | 16 +- .../DataCollector/RequestDataCollector.php | 72 +- .../DataCollector/TimeDataCollector.php | 435 ++-- src/DebugBar/DataFormatter/DataFormatter.php | 114 +- .../DataFormatter/DataFormatterInterface.php | 49 +- src/DebugBar/DebugBar.php | 895 +++---- src/DebugBar/DebugBarException.php | 1 - src/DebugBar/HttpDriverInterface.php | 85 +- src/DebugBar/JavascriptRenderer.php | 1927 +++++++------- src/DebugBar/OpenHandler.php | 186 +- src/DebugBar/PhpHttpDriver.php | 98 +- src/DebugBar/RequestIdGenerator.php | 16 +- src/DebugBar/RequestIdGeneratorInterface.php | 12 +- src/DebugBar/Resources/debugbar.css | 256 +- src/DebugBar/Resources/debugbar.js | 2289 +++++++++-------- src/DebugBar/Resources/debugbar.min.css | 1 + src/DebugBar/Resources/debugbar.min.js | 1 + src/DebugBar/Resources/debugbar.min.min.css | 1 + src/DebugBar/Resources/debugbar.min.min.js | 1 + src/DebugBar/Resources/openhandler.css | 82 +- src/DebugBar/Resources/openhandler.js | 396 +-- src/DebugBar/Resources/openhandler.min.css | 1 + src/DebugBar/Resources/openhandler.min.js | 1 + .../Resources/openhandler.min.min.css | 1 + src/DebugBar/Resources/openhandler.min.min.js | 1 + .../fonts/fontawesome-webfont.svg | 1305 +++++----- .../vendor/highlightjs/highlight.pack.js | 2 +- .../vendor/highlightjs/styles/github.css | 52 +- .../vendor/jquery/dist/jquery.min.js | 7 +- src/DebugBar/Resources/widgets.css | 226 +- src/DebugBar/Resources/widgets.js | 926 +++---- src/DebugBar/Resources/widgets.min.css | 1 + src/DebugBar/Resources/widgets.min.js | 1 + src/DebugBar/Resources/widgets.min.min.css | 0 src/DebugBar/Resources/widgets.min.min.js | 1 + .../Resources/widgets/mails/widget.css | 12 +- .../Resources/widgets/mails/widget.js | 64 +- .../Resources/widgets/mails/widget.min.css | 1 + .../Resources/widgets/mails/widget.min.js | 1 + .../widgets/mails/widget.min.min.css | 1 + .../Resources/widgets/mails/widget.min.min.js | 1 + .../Resources/widgets/sqlqueries/widget.css | 106 +- .../Resources/widgets/sqlqueries/widget.js | 260 +- .../widgets/sqlqueries/widget.min.css | 1 + .../widgets/sqlqueries/widget.min.js | 1 + .../widgets/sqlqueries/widget.min.min.css | 1 + .../widgets/sqlqueries/widget.min.min.js | 1 + .../Resources/widgets/templates/widget.css | 54 +- .../Resources/widgets/templates/widget.js | 116 +- .../widgets/templates/widget.min.css | 1 + .../Resources/widgets/templates/widget.min.js | 1 + .../widgets/templates/widget.min.min.css | 0 .../widgets/templates/widget.min.min.js | 1 + src/DebugBar/StandardDebugBar.php | 20 +- src/DebugBar/Storage/FileStorage.php | 204 +- src/DebugBar/Storage/MemcachedStorage.php | 169 +- src/DebugBar/Storage/PdoStorage.php | 215 +- src/DebugBar/Storage/RedisStorage.php | 123 +- src/DebugBar/Storage/StorageInterface.php | 56 +- 86 files changed, 8392 insertions(+), 8330 deletions(-) create mode 100644 src/DebugBar/Resources/debugbar.min.css create mode 100644 src/DebugBar/Resources/debugbar.min.js create mode 100644 src/DebugBar/Resources/debugbar.min.min.css create mode 100644 src/DebugBar/Resources/debugbar.min.min.js create mode 100644 src/DebugBar/Resources/openhandler.min.css create mode 100644 src/DebugBar/Resources/openhandler.min.js create mode 100644 src/DebugBar/Resources/openhandler.min.min.css create mode 100644 src/DebugBar/Resources/openhandler.min.min.js create mode 100644 src/DebugBar/Resources/widgets.min.css create mode 100644 src/DebugBar/Resources/widgets.min.js create mode 100644 src/DebugBar/Resources/widgets.min.min.css create mode 100644 src/DebugBar/Resources/widgets.min.min.js create mode 100644 src/DebugBar/Resources/widgets/mails/widget.min.css create mode 100644 src/DebugBar/Resources/widgets/mails/widget.min.js create mode 100644 src/DebugBar/Resources/widgets/mails/widget.min.min.css create mode 100644 src/DebugBar/Resources/widgets/mails/widget.min.min.js create mode 100644 src/DebugBar/Resources/widgets/sqlqueries/widget.min.css create mode 100644 src/DebugBar/Resources/widgets/sqlqueries/widget.min.js create mode 100644 src/DebugBar/Resources/widgets/sqlqueries/widget.min.min.css create mode 100644 src/DebugBar/Resources/widgets/sqlqueries/widget.min.min.js create mode 100644 src/DebugBar/Resources/widgets/templates/widget.min.css create mode 100644 src/DebugBar/Resources/widgets/templates/widget.min.js create mode 100644 src/DebugBar/Resources/widgets/templates/widget.min.min.css create mode 100644 src/DebugBar/Resources/widgets/templates/widget.min.min.js diff --git a/composer.json b/composer.json index c8d0c69d..1253e0fd 100644 --- a/composer.json +++ b/composer.json @@ -1,42 +1,42 @@ { - "name": "maximebf/debugbar", - "description": "Debug bar in the browser for php application", - "keywords": ["debug", "debugbar"], - "homepage": "https://github.com/maximebf/php-debugbar", - "type": "library", - "license": "MIT", - "authors": [ - { - "name": "Maxime Bouroumeau-Fuseau", - "email": "maxime.bouroumeau@gmail.com", - "homepage": "http://maximebf.com" - }, - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "require": { - "php": ">=5.3.0", - "psr/log": "^1.0", - "symfony/var-dumper": "^2.6|^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0|^5.0" - }, - "autoload": { - "psr-4": { - "DebugBar\\": "src/DebugBar/" - } - }, - "suggest": { - "kriswallsmith/assetic": "The best way to manage assets", - "monolog/monolog": "Log using Monolog", - "predis/predis": "Redis storage" - }, - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - } + "name": "yetiforce/debugbar", + "description": "Debug bar in the browser for php application", + "keywords": ["debug", "debugbar"], + "homepage": "https://github.com/maximebf/php-debugbar", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + } } diff --git a/src/DebugBar/Bridge/CacheCacheCollector.php b/src/DebugBar/Bridge/CacheCacheCollector.php index 7e7f46f9..34647975 100644 --- a/src/DebugBar/Bridge/CacheCacheCollector.php +++ b/src/DebugBar/Bridge/CacheCacheCollector.php @@ -15,7 +15,7 @@ use Monolog\Logger; /** - * Collects CacheCache operations + * Collects CacheCache operations. * * http://maximebf.github.io/CacheCache/ * @@ -29,47 +29,48 @@ */ class CacheCacheCollector extends MonologCollector { - protected $logger; + protected $logger; - /** - * CacheCacheCollector constructor. - * @param Cache|null $cache - * @param Logger|null $logger - * @param bool $level - * @param bool $bubble - */ - public function __construct(Cache $cache = null, Logger $logger = null, $level = Logger::DEBUG, $bubble = true) - { - parent::__construct(null, $level, $bubble); + /** + * CacheCacheCollector constructor. + * + * @param Cache|null $cache + * @param Logger|null $logger + * @param bool $level + * @param bool $bubble + */ + public function __construct(Cache $cache = null, Logger $logger = null, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct(null, $level, $bubble); - if ($logger === null) { - $logger = new Logger('Cache'); - } - $this->logger = $logger; + if ($logger === null) { + $logger = new Logger('Cache'); + } + $this->logger = $logger; - if ($cache !== null) { - $this->addCache($cache); - } - } + if ($cache !== null) { + $this->addCache($cache); + } + } - /** - * @param Cache $cache - */ - public function addCache(Cache $cache) - { - $backend = $cache->getBackend(); - if (!($backend instanceof LoggingBackend)) { - $backend = new LoggingBackend($backend, $this->logger); - } - $cache->setBackend($backend); - $this->addLogger($backend->getLogger()); - } + /** + * @param Cache $cache + */ + public function addCache(Cache $cache) + { + $backend = $cache->getBackend(); + if (!($backend instanceof LoggingBackend)) { + $backend = new LoggingBackend($backend, $this->logger); + } + $cache->setBackend($backend); + $this->addLogger($backend->getLogger()); + } - /** - * @return string - */ - public function getName() - { - return 'cache'; - } + /** + * @return string + */ + public function getName() + { + return 'cache'; + } } diff --git a/src/DebugBar/Bridge/DoctrineCollector.php b/src/DebugBar/Bridge/DoctrineCollector.php index 7c91da9b..a2f02b81 100644 --- a/src/DebugBar/Bridge/DoctrineCollector.php +++ b/src/DebugBar/Bridge/DoctrineCollector.php @@ -18,7 +18,7 @@ use Doctrine\ORM\EntityManager; /** - * Collects Doctrine queries + * Collects Doctrine queries. * * http://doctrine-project.org * @@ -32,84 +32,86 @@ */ class DoctrineCollector extends DataCollector implements Renderable, AssetProvider { - protected $debugStack; + protected $debugStack; - /** - * DoctrineCollector constructor. - * @param $debugStackOrEntityManager - * @throws DebugBarException - */ - public function __construct($debugStackOrEntityManager) - { - if ($debugStackOrEntityManager instanceof EntityManager) { - $debugStackOrEntityManager = $debugStackOrEntityManager->getConnection()->getConfiguration()->getSQLLogger(); - } - if (!($debugStackOrEntityManager instanceof DebugStack)) { - throw new DebugBarException("'DoctrineCollector' requires an 'EntityManager' or 'DebugStack' object"); - } - $this->debugStack = $debugStackOrEntityManager; - } + /** + * DoctrineCollector constructor. + * + * @param $debugStackOrEntityManager + * + * @throws DebugBarException + */ + public function __construct($debugStackOrEntityManager) + { + if ($debugStackOrEntityManager instanceof EntityManager) { + $debugStackOrEntityManager = $debugStackOrEntityManager->getConnection()->getConfiguration()->getSQLLogger(); + } + if (!($debugStackOrEntityManager instanceof DebugStack)) { + throw new DebugBarException("'DoctrineCollector' requires an 'EntityManager' or 'DebugStack' object"); + } + $this->debugStack = $debugStackOrEntityManager; + } - /** - * @return array - */ - public function collect() - { - $queries = array(); - $totalExecTime = 0; - foreach ($this->debugStack->queries as $q) { - $queries[] = array( - 'sql' => $q['sql'], - 'params' => (object) $q['params'], - 'duration' => $q['executionMS'], - 'duration_str' => $this->formatDuration($q['executionMS']) - ); - $totalExecTime += $q['executionMS']; - } + /** + * @return array + */ + public function collect() + { + $queries = []; + $totalExecTime = 0; + foreach ($this->debugStack->queries as $q) { + $queries[] = [ + 'sql' => $q['sql'], + 'params' => (object) $q['params'], + 'duration' => $q['executionMS'], + 'duration_str' => $this->formatDuration($q['executionMS']) + ]; + $totalExecTime += $q['executionMS']; + } - return array( - 'nb_statements' => count($queries), - 'accumulated_duration' => $totalExecTime, - 'accumulated_duration_str' => $this->formatDuration($totalExecTime), - 'statements' => $queries - ); - } + return [ + 'nb_statements' => count($queries), + 'accumulated_duration' => $totalExecTime, + 'accumulated_duration_str' => $this->formatDuration($totalExecTime), + 'statements' => $queries + ]; + } - /** - * @return string - */ - public function getName() - { - return 'doctrine'; - } + /** + * @return string + */ + public function getName() + { + return 'doctrine'; + } - /** - * @return array - */ - public function getWidgets() - { - return array( - "database" => array( - "icon" => "arrow-right", - "widget" => "PhpDebugBar.Widgets.SQLQueriesWidget", - "map" => "doctrine", - "default" => "[]" - ), - "database:badge" => array( - "map" => "doctrine.nb_statements", - "default" => 0 - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + return [ + 'database' => [ + 'icon' => 'arrow-right', + 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', + 'map' => 'doctrine', + 'default' => '[]' + ], + 'database:badge' => [ + 'map' => 'doctrine.nb_statements', + 'default' => 0 + ] + ]; + } - /** - * @return array - */ - public function getAssets() - { - return array( - 'css' => 'widgets/sqlqueries/widget.css', - 'js' => 'widgets/sqlqueries/widget.js' - ); - } + /** + * @return array + */ + public function getAssets() + { + return [ + 'css' => 'widgets/sqlqueries/widget.css', + 'js' => 'widgets/sqlqueries/widget.js' + ]; + } } diff --git a/src/DebugBar/Bridge/MonologCollector.php b/src/DebugBar/Bridge/MonologCollector.php index f24b296d..c7aed0d0 100644 --- a/src/DebugBar/Bridge/MonologCollector.php +++ b/src/DebugBar/Bridge/MonologCollector.php @@ -17,7 +17,7 @@ use Monolog\Logger; /** - * A monolog handler as well as a data collector + * A monolog handler as well as a data collector. * * https://github.com/Seldaek/monolog * @@ -27,92 +27,91 @@ */ class MonologCollector extends AbstractProcessingHandler implements DataCollectorInterface, Renderable, MessagesAggregateInterface { - protected $name; + protected $name; + protected $records = []; - protected $records = array(); + /** + * @param Logger $logger + * @param int $level + * @param bool $bubble + * @param string $name + */ + public function __construct(Logger $logger = null, $level = Logger::DEBUG, $bubble = true, $name = 'monolog') + { + parent::__construct($level, $bubble); + $this->name = $name; + if ($logger !== null) { + $this->addLogger($logger); + } + } - /** - * @param Logger $logger - * @param int $level - * @param boolean $bubble - * @param string $name - */ - public function __construct(Logger $logger = null, $level = Logger::DEBUG, $bubble = true, $name = 'monolog') - { - parent::__construct($level, $bubble); - $this->name = $name; - if ($logger !== null) { - $this->addLogger($logger); - } - } + /** + * Adds logger which messages you want to log. + * + * @param Logger $logger + */ + public function addLogger(Logger $logger) + { + $logger->pushHandler($this); + } - /** - * Adds logger which messages you want to log - * - * @param Logger $logger - */ - public function addLogger(Logger $logger) - { - $logger->pushHandler($this); - } + /** + * @param array $record + */ + protected function write(array $record) + { + $this->records[] = [ + 'message' => $record['formatted'], + 'is_string' => true, + 'label' => strtolower($record['level_name']), + 'time' => $record['datetime']->format('U') + ]; + } - /** - * @param array $record - */ - protected function write(array $record) - { - $this->records[] = array( - 'message' => $record['formatted'], - 'is_string' => true, - 'label' => strtolower($record['level_name']), - 'time' => $record['datetime']->format('U') - ); - } + /** + * @return array + */ + public function getMessages() + { + return $this->records; + } - /** - * @return array - */ - public function getMessages() - { - return $this->records; - } + /** + * @return array + */ + public function collect() + { + return [ + 'count' => count($this->records), + 'records' => $this->records + ]; + } - /** - * @return array - */ - public function collect() - { - return array( - 'count' => count($this->records), - 'records' => $this->records - ); - } + /** + * @return string + */ + public function getName() + { + return $this->name; + } - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return array - */ - public function getWidgets() - { - $name = $this->getName(); - return array( - $name => array( - "icon" => "suitcase", - "widget" => "PhpDebugBar.Widgets.MessagesWidget", - "map" => "$name.records", - "default" => "[]" - ), - "$name:badge" => array( - "map" => "$name.count", - "default" => "null" - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + $name = $this->getName(); + return [ + $name => [ + 'icon' => 'suitcase', + 'widget' => 'PhpDebugBar.Widgets.MessagesWidget', + 'map' => "$name.records", + 'default' => '[]' + ], + "$name:badge" => [ + 'map' => "$name.count", + 'default' => 'null' + ] + ]; + } } diff --git a/src/DebugBar/Bridge/Propel2Collector.php b/src/DebugBar/Bridge/Propel2Collector.php index 3df4dcc6..116d8867 100644 --- a/src/DebugBar/Bridge/Propel2Collector.php +++ b/src/DebugBar/Bridge/Propel2Collector.php @@ -18,11 +18,11 @@ use Propel\Runtime\Connection\ConnectionInterface; use Propel\Runtime\Connection\ProfilerConnectionWrapper; use Propel\Runtime\Propel; -use Psr\Log\LogLevel; use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; /** - * A Propel logger which acts as a data collector + * A Propel logger which acts as a data collector. * * http://propelorm.org/ * @@ -35,273 +35,270 @@ */ class Propel2Collector extends DataCollector implements Renderable, AssetProvider { - /** - * @var null|TestHandler - */ - protected $handler = null; - - /** - * @var null|Logger - */ - protected $logger = null; - - /** - * @var array - */ - protected $config = array(); - - /** - * @var array - */ - protected $errors = array(); - - /** - * @var int - */ - protected $queryCount = 0; - - /** - * @param ConnectionInterface $connection Propel connection - */ - public function __construct( - ConnectionInterface $connection, - array $logMethods = array( - 'beginTransaction', - 'commit', - 'rollBack', - 'forceRollBack', - 'exec', - 'query', - 'execute' - ) - ) { - if ($connection instanceof ProfilerConnectionWrapper) { - $connection->setLogMethods($logMethods); - - $this->config = $connection->getProfiler()->getConfiguration(); - - $this->handler = new TestHandler(); - - if ($connection->getLogger() instanceof Logger) { - $this->logger = $connection->getLogger(); - $this->logger->pushHandler($this->handler); - } else { - $this->errors[] = 'Supported only monolog logger'; - } - } else { - $this->errors[] = 'You need set ProfilerConnectionWrapper'; - } - } - - /** - * @return TestHandler|null - */ - public function getHandler() - { - return $this->handler; - } - - /** - * @return array - */ - public function getConfig() - { - return $this->config; - } - - /** - * @return Logger|null - */ - public function getLogger() - { - return $this->logger; - } - - /** - * @return LoggerInterface - */ - protected function getDefaultLogger() - { - return Propel::getServiceContainer()->getLogger(); - } - - /** - * @return int - */ - protected function getQueryCount() - { - return $this->queryCount; - } - - /** - * @param array $records - * @param array $config - * @return array - */ - protected function getStatements($records, $config) - { - $statements = array(); - foreach ($records as $record) { - $duration = null; - $memory = null; - - $isSuccess = ( LogLevel::INFO === strtolower($record['level_name']) ); - - $detailsCount = count($config['details']); - $parameters = explode($config['outerGlue'], $record['message'], $detailsCount + 1); - if (count($parameters) === ($detailsCount + 1)) { - $parameters = array_map('trim', $parameters); - $_details = array(); - foreach (array_splice($parameters, 0, $detailsCount) as $string) { - list($key, $value) = array_map('trim', explode($config['innerGlue'], $string, 2)); - $_details[$key] = $value; - } - - $details = array(); - foreach ($config['details'] as $key => $detail) { - if (isset($_details[$detail['name']])) { - $value = $_details[$detail['name']]; - if ('time' === $key) { - if (substr_count($value, 'ms')) { - $value = (float)$value / 1000; - } else { - $value = (float)$value; - } - } else { - $suffixes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); - $suffix = substr($value, -2); - $i = array_search($suffix, $suffixes, true); - $i = (false === $i) ? 0 : $i; - - $value = ((float)$value) * pow(1024, $i); - } - $details[$key] = $value; - } - } - - if (isset($details['time'])) { - $duration = $details['time']; - } - if (isset($details['memDelta'])) { - $memory = $details['memDelta']; - } - - $message = end($parameters); - - if ($isSuccess) { - $this->queryCount++; - } - - } else { - $message = $record['message']; - } - - $statement = array( - 'sql' => $message, - 'is_success' => $isSuccess, - 'duration' => $duration, - 'duration_str' => $this->getDataFormatter()->formatDuration($duration), - 'memory' => $memory, - 'memory_str' => $this->getDataFormatter()->formatBytes($memory), - ); - - if (false === $isSuccess) { - $statement['sql'] = ''; - $statement['error_code'] = $record['level']; - $statement['error_message'] = $message; - } - - $statements[] = $statement; - } - return $statements; - } - - /** - * @return array - */ - public function collect() - { - if (count($this->errors)) { - return array( - 'statements' => array_map(function ($message) { - return array('sql' => '', 'is_success' => false, 'error_code' => 500, 'error_message' => $message); - }, $this->errors), - 'nb_statements' => 0, - 'nb_failed_statements' => count($this->errors), - ); - } - - if ($this->getHandler() === null) { - return array(); - } - - $statements = $this->getStatements($this->getHandler()->getRecords(), $this->getConfig()); - - $failedStatement = count(array_filter($statements, function ($statement) { - return false === $statement['is_success']; - })); - $accumulatedDuration = array_reduce($statements, function ($accumulatedDuration, $statement) { - - $time = isset($statement['duration']) ? $statement['duration'] : 0; - return $accumulatedDuration += $time; - }); - $memoryUsage = array_reduce($statements, function ($memoryUsage, $statement) { - - $time = isset($statement['memory']) ? $statement['memory'] : 0; - return $memoryUsage += $time; - }); - - return array( - 'nb_statements' => $this->getQueryCount(), - 'nb_failed_statements' => $failedStatement, - 'accumulated_duration' => $accumulatedDuration, - 'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($accumulatedDuration), - 'memory_usage' => $memoryUsage, - 'memory_usage_str' => $this->getDataFormatter()->formatBytes($memoryUsage), - 'statements' => $statements - ); - } - - /** - * @return string - */ - public function getName() - { - $additionalName = ''; - if ($this->getLogger() !== $this->getDefaultLogger()) { - $additionalName = ' ('.$this->getLogger()->getName().')'; - } - - return 'propel2'.$additionalName; - } - - /** - * @return array - */ - public function getWidgets() - { - return array( - $this->getName() => array( - 'icon' => 'bolt', - 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', - 'map' => $this->getName(), - 'default' => '[]' - ), - $this->getName().':badge' => array( - 'map' => $this->getName().'.nb_statements', - 'default' => 0 - ), - ); - } - - /** - * @return array - */ - public function getAssets() - { - return array( - 'css' => 'widgets/sqlqueries/widget.css', - 'js' => 'widgets/sqlqueries/widget.js' - ); - } + /** + * @var null|TestHandler + */ + protected $handler; + + /** + * @var null|Logger + */ + protected $logger; + + /** + * @var array + */ + protected $config = []; + + /** + * @var array + */ + protected $errors = []; + + /** + * @var int + */ + protected $queryCount = 0; + + /** + * @param ConnectionInterface $connection Propel connection + */ + public function __construct( + ConnectionInterface $connection, array $logMethods = [ + 'beginTransaction', + 'commit', + 'rollBack', + 'forceRollBack', + 'exec', + 'query', + 'execute' + ] + ) { + if ($connection instanceof ProfilerConnectionWrapper) { + $connection->setLogMethods($logMethods); + + $this->config = $connection->getProfiler()->getConfiguration(); + + $this->handler = new TestHandler(); + + if ($connection->getLogger() instanceof Logger) { + $this->logger = $connection->getLogger(); + $this->logger->pushHandler($this->handler); + } else { + $this->errors[] = 'Supported only monolog logger'; + } + } else { + $this->errors[] = 'You need set ProfilerConnectionWrapper'; + } + } + + /** + * @return TestHandler|null + */ + public function getHandler() + { + return $this->handler; + } + + /** + * @return array + */ + public function getConfig() + { + return $this->config; + } + + /** + * @return Logger|null + */ + public function getLogger() + { + return $this->logger; + } + + /** + * @return LoggerInterface + */ + protected function getDefaultLogger() + { + return Propel::getServiceContainer()->getLogger(); + } + + /** + * @return int + */ + protected function getQueryCount() + { + return $this->queryCount; + } + + /** + * @param array $records + * @param array $config + * + * @return array + */ + protected function getStatements($records, $config) + { + $statements = []; + foreach ($records as $record) { + $duration = null; + $memory = null; + + $isSuccess = (LogLevel::INFO === strtolower($record['level_name'])); + + $detailsCount = count($config['details']); + $parameters = explode($config['outerGlue'], $record['message'], $detailsCount + 1); + if (count($parameters) === ($detailsCount + 1)) { + $parameters = array_map('trim', $parameters); + $_details = []; + foreach (array_splice($parameters, 0, $detailsCount) as $string) { + list($key, $value) = array_map('trim', explode($config['innerGlue'], $string, 2)); + $_details[$key] = $value; + } + + $details = []; + foreach ($config['details'] as $key => $detail) { + if (isset($_details[$detail['name']])) { + $value = $_details[$detail['name']]; + if ('time' === $key) { + if (substr_count($value, 'ms')) { + $value = (float) $value / 1000; + } else { + $value = (float) $value; + } + } else { + $suffixes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + $suffix = substr($value, -2); + $i = array_search($suffix, $suffixes, true); + $i = (false === $i) ? 0 : $i; + + $value = ((float) $value) * pow(1024, $i); + } + $details[$key] = $value; + } + } + + if (isset($details['time'])) { + $duration = $details['time']; + } + if (isset($details['memDelta'])) { + $memory = $details['memDelta']; + } + + $message = end($parameters); + + if ($isSuccess) { + $this->queryCount++; + } + } else { + $message = $record['message']; + } + + $statement = [ + 'sql' => $message, + 'is_success' => $isSuccess, + 'duration' => $duration, + 'duration_str' => $this->getDataFormatter()->formatDuration($duration), + 'memory' => $memory, + 'memory_str' => $this->getDataFormatter()->formatBytes($memory), + ]; + + if (false === $isSuccess) { + $statement['sql'] = ''; + $statement['error_code'] = $record['level']; + $statement['error_message'] = $message; + } + + $statements[] = $statement; + } + return $statements; + } + + /** + * @return array + */ + public function collect() + { + if (count($this->errors)) { + return [ + 'statements' => array_map(function ($message) { + return ['sql' => '', 'is_success' => false, 'error_code' => 500, 'error_message' => $message]; + }, $this->errors), + 'nb_statements' => 0, + 'nb_failed_statements' => count($this->errors), + ]; + } + + if ($this->getHandler() === null) { + return []; + } + + $statements = $this->getStatements($this->getHandler()->getRecords(), $this->getConfig()); + + $failedStatement = count(array_filter($statements, function ($statement) { + return false === $statement['is_success']; + })); + $accumulatedDuration = array_reduce($statements, function ($accumulatedDuration, $statement) { + $time = $statement['duration'] ?? 0; + return $accumulatedDuration += $time; + }); + $memoryUsage = array_reduce($statements, function ($memoryUsage, $statement) { + $time = $statement['memory'] ?? 0; + return $memoryUsage += $time; + }); + + return [ + 'nb_statements' => $this->getQueryCount(), + 'nb_failed_statements' => $failedStatement, + 'accumulated_duration' => $accumulatedDuration, + 'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($accumulatedDuration), + 'memory_usage' => $memoryUsage, + 'memory_usage_str' => $this->getDataFormatter()->formatBytes($memoryUsage), + 'statements' => $statements + ]; + } + + /** + * @return string + */ + public function getName() + { + $additionalName = ''; + if ($this->getLogger() !== $this->getDefaultLogger()) { + $additionalName = ' (' . $this->getLogger()->getName() . ')'; + } + + return 'propel2' . $additionalName; + } + + /** + * @return array + */ + public function getWidgets() + { + return [ + $this->getName() => [ + 'icon' => 'bolt', + 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', + 'map' => $this->getName(), + 'default' => '[]' + ], + $this->getName() . ':badge' => [ + 'map' => $this->getName() . '.nb_statements', + 'default' => 0 + ], + ]; + } + + /** + * @return array + */ + public function getAssets() + { + return [ + 'css' => 'widgets/sqlqueries/widget.css', + 'js' => 'widgets/sqlqueries/widget.js' + ]; + } } diff --git a/src/DebugBar/Bridge/PropelCollector.php b/src/DebugBar/Bridge/PropelCollector.php index 93ad4ff8..6390eaf0 100644 --- a/src/DebugBar/Bridge/PropelCollector.php +++ b/src/DebugBar/Bridge/PropelCollector.php @@ -17,11 +17,11 @@ use Propel; use PropelConfiguration; use PropelPDO; -use Psr\Log\LogLevel; use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; /** - * A Propel logger which acts as a data collector + * A Propel logger which acts as a data collector. * * http://propelorm.org/ * @@ -36,218 +36,216 @@ */ class PropelCollector extends DataCollector implements BasicLogger, Renderable, AssetProvider { - protected $logger; - - protected $statements = array(); - - protected $accumulatedTime = 0; - - protected $peakMemory = 0; - - /** - * Sets the needed configuration option in propel to enable query logging - * - * @param PropelConfiguration $config Apply profiling on a specific config - */ - public static function enablePropelProfiling(PropelConfiguration $config = null) - { - if ($config === null) { - $config = Propel::getConfiguration(PropelConfiguration::TYPE_OBJECT); - } - $config->setParameter('debugpdo.logging.details.method.enabled', true); - $config->setParameter('debugpdo.logging.details.time.enabled', true); - $config->setParameter('debugpdo.logging.details.mem.enabled', true); - $allMethods = array( - 'PropelPDO::__construct', // logs connection opening - 'PropelPDO::__destruct', // logs connection close - 'PropelPDO::exec', // logs a query - 'PropelPDO::query', // logs a query - 'PropelPDO::beginTransaction', // logs a transaction begin - 'PropelPDO::commit', // logs a transaction commit - 'PropelPDO::rollBack', // logs a transaction rollBack (watch out for the capital 'B') - 'DebugPDOStatement::execute', // logs a query from a prepared statement - ); - $config->setParameter('debugpdo.logging.methods', $allMethods, false); - } - - /** - * @param LoggerInterface $logger A logger to forward non-query log lines to - * @param PropelPDO $conn Bound this collector to a connection only - */ - public function __construct(LoggerInterface $logger = null, PropelPDO $conn = null) - { - if ($conn) { - $conn->setLogger($this); - } else { - Propel::setLogger($this); - } - $this->logger = $logger; - $this->logQueriesToLogger = false; - } - - public function setLogQueriesToLogger($enable = true) - { - $this->logQueriesToLogger = $enable; - return $this; - } - - public function isLogQueriesToLogger() - { - return $this->logQueriesToLogger; - } - - public function emergency($m) - { - $this->log($m, Propel::LOG_EMERG); - } - - public function alert($m) - { - $this->log($m, Propel::LOG_ALERT); - } - - public function crit($m) - { - $this->log($m, Propel::LOG_CRIT); - } - - public function err($m) - { - $this->log($m, Propel::LOG_ERR); - } - - public function warning($m) - { - $this->log($m, Propel::LOG_WARNING); - } - - public function notice($m) - { - $this->log($m, Propel::LOG_NOTICE); - } - - public function info($m) - { - $this->log($m, Propel::LOG_INFO); - } - - public function debug($m) - { - $this->log($m, Propel::LOG_DEBUG); - } - - public function log($message, $severity = null) - { - if (strpos($message, 'DebugPDOStatement::execute') !== false) { - list($sql, $duration_str) = $this->parseAndLogSqlQuery($message); - if (!$this->logQueriesToLogger) { - return; - } - $message = "$sql ($duration_str)"; - } - - if ($this->logger !== null) { - $this->logger->log($this->convertLogLevel($severity), $message); - } - } - - /** - * Converts Propel log levels to PSR log levels - * - * @param int $level - * @return string - */ - protected function convertLogLevel($level) - { - $map = array( - Propel::LOG_EMERG => LogLevel::EMERGENCY, - Propel::LOG_ALERT => LogLevel::ALERT, - Propel::LOG_CRIT => LogLevel::CRITICAL, - Propel::LOG_ERR => LogLevel::ERROR, - Propel::LOG_WARNING => LogLevel::WARNING, - Propel::LOG_NOTICE => LogLevel::NOTICE, - Propel::LOG_DEBUG => LogLevel::DEBUG - ); - return $map[$level]; - } - - /** - * Parse a log line to extract query information - * - * @param string $message - */ - protected function parseAndLogSqlQuery($message) - { - $parts = explode('|', $message, 4); - $sql = trim($parts[3]); - - $duration = 0; - if (preg_match('/([0-9]+\.[0-9]+)/', $parts[1], $matches)) { - $duration = (float) $matches[1]; - } - - $memory = 0; - if (preg_match('/([0-9]+\.[0-9]+) ([A-Z]{1,2})/', $parts[2], $matches)) { - $memory = (float) $matches[1]; - if ($matches[2] == 'KB') { - $memory *= 1024; - } elseif ($matches[2] == 'MB') { - $memory *= 1024 * 1024; - } - } - - $this->statements[] = array( - 'sql' => $sql, - 'is_success' => true, - 'duration' => $duration, - 'duration_str' => $this->formatDuration($duration), - 'memory' => $memory, - 'memory_str' => $this->formatBytes($memory) - ); - $this->accumulatedTime += $duration; - $this->peakMemory = max($this->peakMemory, $memory); - return array($sql, $this->formatDuration($duration)); - } - - public function collect() - { - return array( - 'nb_statements' => count($this->statements), - 'nb_failed_statements' => 0, - 'accumulated_duration' => $this->accumulatedTime, - 'accumulated_duration_str' => $this->formatDuration($this->accumulatedTime), - 'peak_memory_usage' => $this->peakMemory, - 'peak_memory_usage_str' => $this->formatBytes($this->peakMemory), - 'statements' => $this->statements - ); - } - - public function getName() - { - return 'propel'; - } - - public function getWidgets() - { - return array( - "propel" => array( - "icon" => "bolt", - "widget" => "PhpDebugBar.Widgets.SQLQueriesWidget", - "map" => "propel", - "default" => "[]" - ), - "propel:badge" => array( - "map" => "propel.nb_statements", - "default" => 0 - ) - ); - } - - public function getAssets() - { - return array( - 'css' => 'widgets/sqlqueries/widget.css', - 'js' => 'widgets/sqlqueries/widget.js' - ); - } + protected $logger; + protected $statements = []; + protected $accumulatedTime = 0; + protected $peakMemory = 0; + + /** + * Sets the needed configuration option in propel to enable query logging. + * + * @param PropelConfiguration $config Apply profiling on a specific config + */ + public static function enablePropelProfiling(PropelConfiguration $config = null) + { + if ($config === null) { + $config = Propel::getConfiguration(PropelConfiguration::TYPE_OBJECT); + } + $config->setParameter('debugpdo.logging.details.method.enabled', true); + $config->setParameter('debugpdo.logging.details.time.enabled', true); + $config->setParameter('debugpdo.logging.details.mem.enabled', true); + $allMethods = [ + 'PropelPDO::__construct', // logs connection opening + 'PropelPDO::__destruct', // logs connection close + 'PropelPDO::exec', // logs a query + 'PropelPDO::query', // logs a query + 'PropelPDO::beginTransaction', // logs a transaction begin + 'PropelPDO::commit', // logs a transaction commit + 'PropelPDO::rollBack', // logs a transaction rollBack (watch out for the capital 'B') + 'DebugPDOStatement::execute', // logs a query from a prepared statement + ]; + $config->setParameter('debugpdo.logging.methods', $allMethods, false); + } + + /** + * @param LoggerInterface $logger A logger to forward non-query log lines to + * @param PropelPDO $conn Bound this collector to a connection only + */ + public function __construct(LoggerInterface $logger = null, PropelPDO $conn = null) + { + if ($conn) { + $conn->setLogger($this); + } else { + Propel::setLogger($this); + } + $this->logger = $logger; + $this->logQueriesToLogger = false; + } + + public function setLogQueriesToLogger($enable = true) + { + $this->logQueriesToLogger = $enable; + return $this; + } + + public function isLogQueriesToLogger() + { + return $this->logQueriesToLogger; + } + + public function emergency($m) + { + $this->log($m, Propel::LOG_EMERG); + } + + public function alert($m) + { + $this->log($m, Propel::LOG_ALERT); + } + + public function crit($m) + { + $this->log($m, Propel::LOG_CRIT); + } + + public function err($m) + { + $this->log($m, Propel::LOG_ERR); + } + + public function warning($m) + { + $this->log($m, Propel::LOG_WARNING); + } + + public function notice($m) + { + $this->log($m, Propel::LOG_NOTICE); + } + + public function info($m) + { + $this->log($m, Propel::LOG_INFO); + } + + public function debug($m) + { + $this->log($m, Propel::LOG_DEBUG); + } + + public function log($message, $severity = null) + { + if (strpos($message, 'DebugPDOStatement::execute') !== false) { + list($sql, $duration_str) = $this->parseAndLogSqlQuery($message); + if (!$this->logQueriesToLogger) { + return; + } + $message = "$sql ($duration_str)"; + } + + if ($this->logger !== null) { + $this->logger->log($this->convertLogLevel($severity), $message); + } + } + + /** + * Converts Propel log levels to PSR log levels. + * + * @param int $level + * + * @return string + */ + protected function convertLogLevel($level) + { + $map = [ + Propel::LOG_EMERG => LogLevel::EMERGENCY, + Propel::LOG_ALERT => LogLevel::ALERT, + Propel::LOG_CRIT => LogLevel::CRITICAL, + Propel::LOG_ERR => LogLevel::ERROR, + Propel::LOG_WARNING => LogLevel::WARNING, + Propel::LOG_NOTICE => LogLevel::NOTICE, + Propel::LOG_DEBUG => LogLevel::DEBUG + ]; + return $map[$level]; + } + + /** + * Parse a log line to extract query information. + * + * @param string $message + */ + protected function parseAndLogSqlQuery($message) + { + $parts = explode('|', $message, 4); + $sql = trim($parts[3]); + + $duration = 0; + if (preg_match('/([0-9]+\.[0-9]+)/', $parts[1], $matches)) { + $duration = (float) $matches[1]; + } + + $memory = 0; + if (preg_match('/([0-9]+\.[0-9]+) ([A-Z]{1,2})/', $parts[2], $matches)) { + $memory = (float) $matches[1]; + if ($matches[2] == 'KB') { + $memory *= 1024; + } elseif ($matches[2] == 'MB') { + $memory *= 1024 * 1024; + } + } + + $this->statements[] = [ + 'sql' => $sql, + 'is_success' => true, + 'duration' => $duration, + 'duration_str' => $this->formatDuration($duration), + 'memory' => $memory, + 'memory_str' => $this->formatBytes($memory) + ]; + $this->accumulatedTime += $duration; + $this->peakMemory = max($this->peakMemory, $memory); + return [$sql, $this->formatDuration($duration)]; + } + + public function collect() + { + return [ + 'nb_statements' => count($this->statements), + 'nb_failed_statements' => 0, + 'accumulated_duration' => $this->accumulatedTime, + 'accumulated_duration_str' => $this->formatDuration($this->accumulatedTime), + 'peak_memory_usage' => $this->peakMemory, + 'peak_memory_usage_str' => $this->formatBytes($this->peakMemory), + 'statements' => $this->statements + ]; + } + + public function getName() + { + return 'propel'; + } + + public function getWidgets() + { + return [ + 'propel' => [ + 'icon' => 'bolt', + 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', + 'map' => 'propel', + 'default' => '[]' + ], + 'propel:badge' => [ + 'map' => 'propel.nb_statements', + 'default' => 0 + ] + ]; + } + + public function getAssets() + { + return [ + 'css' => 'widgets/sqlqueries/widget.css', + 'js' => 'widgets/sqlqueries/widget.js' + ]; + } } diff --git a/src/DebugBar/Bridge/SlimCollector.php b/src/DebugBar/Bridge/SlimCollector.php index 030a3baf..fa298364 100644 --- a/src/DebugBar/Bridge/SlimCollector.php +++ b/src/DebugBar/Bridge/SlimCollector.php @@ -16,51 +16,50 @@ use Slim\Slim; /** - * Collects messages from a Slim logger + * Collects messages from a Slim logger. * * http://slimframework.com */ class SlimCollector extends MessagesCollector { - protected $slim; + protected $slim; + protected $originalLogWriter; - protected $originalLogWriter; + public function __construct(Slim $slim) + { + $this->slim = $slim; + if ($log = $slim->getLog()) { + $this->originalLogWriter = $log->getWriter(); + $log->setWriter($this); + $log->setEnabled(true); + } + } - public function __construct(Slim $slim) - { - $this->slim = $slim; - if ($log = $slim->getLog()) { - $this->originalLogWriter = $log->getWriter(); - $log->setWriter($this); - $log->setEnabled(true); - } - } + public function write($message, $level) + { + if ($this->originalLogWriter) { + $this->originalLogWriter->write($message, $level); + } + $this->addMessage($message, $this->getLevelName($level)); + } - public function write($message, $level) - { - if ($this->originalLogWriter) { - $this->originalLogWriter->write($message, $level); - } - $this->addMessage($message, $this->getLevelName($level)); - } + protected function getLevelName($level) + { + $map = [ + Log::EMERGENCY => LogLevel::EMERGENCY, + Log::ALERT => LogLevel::ALERT, + Log::CRITICAL => LogLevel::CRITICAL, + Log::ERROR => LogLevel::ERROR, + Log::WARN => LogLevel::WARNING, + Log::NOTICE => LogLevel::NOTICE, + Log::INFO => LogLevel::INFO, + Log::DEBUG => LogLevel::DEBUG + ]; + return $map[$level]; + } - protected function getLevelName($level) - { - $map = array( - Log::EMERGENCY => LogLevel::EMERGENCY, - Log::ALERT => LogLevel::ALERT, - Log::CRITICAL => LogLevel::CRITICAL, - Log::ERROR => LogLevel::ERROR, - Log::WARN => LogLevel::WARNING, - Log::NOTICE => LogLevel::NOTICE, - Log::INFO => LogLevel::INFO, - Log::DEBUG => LogLevel::DEBUG - ); - return $map[$level]; - } - - public function getName() - { - return 'slim'; - } + public function getName() + { + return 'slim'; + } } diff --git a/src/DebugBar/Bridge/SwiftMailer/SwiftLogCollector.php b/src/DebugBar/Bridge/SwiftMailer/SwiftLogCollector.php index fdef79a0..42f95576 100644 --- a/src/DebugBar/Bridge/SwiftMailer/SwiftLogCollector.php +++ b/src/DebugBar/Bridge/SwiftMailer/SwiftLogCollector.php @@ -16,29 +16,29 @@ use Swift_Plugins_LoggerPlugin; /** - * Collects log messages + * Collects log messages. * * http://swiftmailer.org/ */ class SwiftLogCollector extends MessagesCollector implements Swift_Plugins_Logger { - public function __construct(Swift_Mailer $mailer) - { - $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($this)); - } + public function __construct(Swift_Mailer $mailer) + { + $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($this)); + } - public function add($entry) - { - $this->addMessage($entry); - } + public function add($entry) + { + $this->addMessage($entry); + } - public function dump() - { - return implode(PHP_EOL, $this->_log); - } + public function dump() + { + return implode(PHP_EOL, $this->_log); + } - public function getName() - { - return 'swiftmailer_logs'; - } + public function getName() + { + return 'swiftmailer_logs'; + } } diff --git a/src/DebugBar/Bridge/SwiftMailer/SwiftMailCollector.php b/src/DebugBar/Bridge/SwiftMailer/SwiftMailCollector.php index 01a5e906..c767f4f4 100644 --- a/src/DebugBar/Bridge/SwiftMailer/SwiftMailCollector.php +++ b/src/DebugBar/Bridge/SwiftMailer/SwiftMailCollector.php @@ -17,76 +17,76 @@ use Swift_Plugins_MessageLogger; /** - * Collects data about sent mails + * Collects data about sent mails. * * http://swiftmailer.org/ */ class SwiftMailCollector extends DataCollector implements Renderable, AssetProvider { - protected $messagesLogger; + protected $messagesLogger; - public function __construct(Swift_Mailer $mailer) - { - $this->messagesLogger = new Swift_Plugins_MessageLogger(); - $mailer->registerPlugin($this->messagesLogger); - } + public function __construct(Swift_Mailer $mailer) + { + $this->messagesLogger = new Swift_Plugins_MessageLogger(); + $mailer->registerPlugin($this->messagesLogger); + } - public function collect() - { - $mails = array(); - foreach ($this->messagesLogger->getMessages() as $msg) { - $mails[] = array( - 'to' => $this->formatTo($msg->getTo()), - 'subject' => $msg->getSubject(), - 'headers' => $msg->getHeaders()->toString() - ); - } - return array( - 'count' => count($mails), - 'mails' => $mails - ); - } + public function collect() + { + $mails = []; + foreach ($this->messagesLogger->getMessages() as $msg) { + $mails[] = [ + 'to' => $this->formatTo($msg->getTo()), + 'subject' => $msg->getSubject(), + 'headers' => $msg->getHeaders()->toString() + ]; + } + return [ + 'count' => count($mails), + 'mails' => $mails + ]; + } - protected function formatTo($to) - { - if (!$to) { - return ''; - } + protected function formatTo($to) + { + if (!$to) { + return ''; + } - $f = array(); - foreach ($to as $k => $v) { - $f[] = (empty($v) ? '' : "$v ") . "<$k>"; - } - return implode(', ', $f); - } + $f = []; + foreach ($to as $k => $v) { + $f[] = (empty($v) ? '' : "$v ") . "<$k>"; + } + return implode(', ', $f); + } - public function getName() - { - return 'swiftmailer_mails'; - } + public function getName() + { + return 'swiftmailer_mails'; + } - public function getWidgets() - { - return array( - 'emails' => array( - 'icon' => 'inbox', - 'widget' => 'PhpDebugBar.Widgets.MailsWidget', - 'map' => 'swiftmailer_mails.mails', - 'default' => '[]', - 'title' => 'Mails' - ), - 'emails:badge' => array( - 'map' => 'swiftmailer_mails.count', - 'default' => 'null' - ) - ); - } + public function getWidgets() + { + return [ + 'emails' => [ + 'icon' => 'inbox', + 'widget' => 'PhpDebugBar.Widgets.MailsWidget', + 'map' => 'swiftmailer_mails.mails', + 'default' => '[]', + 'title' => 'Mails' + ], + 'emails:badge' => [ + 'map' => 'swiftmailer_mails.count', + 'default' => 'null' + ] + ]; + } - public function getAssets() - { - return array( - 'css' => 'widgets/mails/widget.css', - 'js' => 'widgets/mails/widget.js' - ); - } + public function getAssets() + { + return [ + 'css' => 'widgets/mails/widget.css', + 'js' => 'widgets/mails/widget.js' + ]; + } } diff --git a/src/DebugBar/Bridge/Twig/TraceableTwigEnvironment.php b/src/DebugBar/Bridge/Twig/TraceableTwigEnvironment.php index cdaae7a4..f8fadc32 100644 --- a/src/DebugBar/Bridge/Twig/TraceableTwigEnvironment.php +++ b/src/DebugBar/Bridge/Twig/TraceableTwigEnvironment.php @@ -23,395 +23,393 @@ use Twig_TokenStream; /** - * Wrapped a Twig Environment to provide profiling features + * Wrapped a Twig Environment to provide profiling features. */ class TraceableTwigEnvironment extends Twig_Environment { - protected $twig; - - protected $renderedTemplates = array(); - - protected $timeDataCollector; - - /** - * @param Twig_Environment $twig - * @param TimeDataCollector $timeDataCollector - */ - public function __construct(Twig_Environment $twig, TimeDataCollector $timeDataCollector = null) - { - $this->twig = $twig; - $this->timeDataCollector = $timeDataCollector; - } - - public function __call($name, $arguments) - { - return call_user_func_array(array($this->twig, $name), $arguments); - } - - public function getRenderedTemplates() - { - return $this->renderedTemplates; - } - - public function addRenderedTemplate(array $info) - { - $this->renderedTemplates[] = $info; - } - - public function getTimeDataCollector() - { - return $this->timeDataCollector; - } - - public function getBaseTemplateClass() - { - return $this->twig->getBaseTemplateClass(); - } - - public function setBaseTemplateClass($class) - { - $this->twig->setBaseTemplateClass($class); - } - - public function enableDebug() - { - $this->twig->enableDebug(); - } - - public function disableDebug() - { - $this->twig->disableDebug(); - } - - public function isDebug() - { - return $this->twig->isDebug(); - } - - public function enableAutoReload() - { - $this->twig->enableAutoReload(); - } - - public function disableAutoReload() - { - $this->twig->disableAutoReload(); - } - - public function isAutoReload() - { - return $this->twig->isAutoReload(); - } - - public function enableStrictVariables() - { - $this->twig->enableStrictVariables(); - } - - public function disableStrictVariables() - { - $this->twig->disableStrictVariables(); - } - - public function isStrictVariables() - { - return $this->twig->isStrictVariables(); - } - - public function getCache($original = true) - { - return $this->twig->getCache($original); - } - - public function setCache($cache) - { - $this->twig->setCache($cache); - } - - public function getCacheFilename($name) - { - return $this->twig->getCacheFilename($name); - } - - public function getTemplateClass($name, $index = null) - { - return $this->twig->getTemplateClass($name, $index); - } - - public function getTemplateClassPrefix() - { - return $this->twig->getTemplateClassPrefix(); - } - - public function render($name, array $context = array()) - { - return $this->loadTemplate($name)->render($context); - } - - public function display($name, array $context = array()) - { - $this->loadTemplate($name)->display($context); - } - - public function loadTemplate($name, $index = null) - { - $cls = $this->twig->getTemplateClass($name, $index); - - if (isset($this->twig->loadedTemplates[$cls])) { - return $this->twig->loadedTemplates[$cls]; - } - - if (!class_exists($cls, false)) { - if (false === $cache = $this->getCacheFilename($name)) { - eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); - } else { - if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { - $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); - } - - require_once $cache; - } - } - - if (!$this->twig->runtimeInitialized) { - $this->initRuntime(); - } - - return $this->twig->loadedTemplates[$cls] = new TraceableTwigTemplate($this, new $cls($this)); - } - - public function isTemplateFresh($name, $time) - { - return $this->twig->isTemplateFresh($name, $time); - } - - public function resolveTemplate($names) - { - return $this->twig->resolveTemplate($names); - } - - public function clearTemplateCache() - { - $this->twig->clearTemplateCache(); - } - - public function clearCacheFiles() - { - $this->twig->clearCacheFiles(); - } - - public function getLexer() - { - return $this->twig->getLexer(); - } - - public function setLexer(Twig_LexerInterface $lexer) - { - $this->twig->setLexer($lexer); - } - - public function tokenize($source, $name = null) - { - return $this->twig->tokenize($source, $name); - } - - public function getParser() - { - return $this->twig->getParser(); - } - - public function setParser(Twig_ParserInterface $parser) - { - $this->twig->setParser($parser); - } - - public function parse(Twig_TokenStream $tokens) - { - return $this->twig->parse($tokens); - } - - public function getCompiler() - { - return $this->twig->getCompiler(); - } - - public function setCompiler(Twig_CompilerInterface $compiler) - { - $this->twig->setCompiler($compiler); - } - - public function compile(Twig_NodeInterface $node) - { - return $this->twig->compile($node); - } - - public function compileSource($source, $name = null) - { - return $this->twig->compileSource($source, $name); - } - - public function setLoader(Twig_LoaderInterface $loader) - { - $this->twig->setLoader($loader); - } - - public function getLoader() - { - return $this->twig->getLoader(); - } - - public function setCharset($charset) - { - $this->twig->setCharset($charset); - } - - public function getCharset() - { - return $this->twig->getCharset(); - } - - public function initRuntime() - { - $this->twig->initRuntime(); - } - - public function hasExtension($name) - { - return $this->twig->hasExtension($name); - } - - public function getExtension($name) - { - return $this->twig->getExtension($name); - } - - public function addExtension(Twig_ExtensionInterface $extension) - { - $this->twig->addExtension($extension); - } - - public function removeExtension($name) - { - $this->twig->removeExtension($name); - } - - public function setExtensions(array $extensions) - { - $this->twig->setExtensions($extensions); - } - - public function getExtensions() - { - return $this->twig->getExtensions(); - } - - public function addTokenParser(Twig_TokenParserInterface $parser) - { - $this->twig->addTokenParser($parser); - } - - public function getTokenParsers() - { - return $this->twig->getTokenParsers(); - } - - public function getTags() - { - return $this->twig->getTags(); - } - - public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) - { - $this->twig->addNodeVisitor($visitor); - } - - public function getNodeVisitors() - { - return $this->twig->getNodeVisitors(); - } - - public function addFilter($name, $filter = null) - { - $this->twig->addFilter($name, $filter); - } - - public function getFilter($name) - { - return $this->twig->getFilter($name); - } - - public function registerUndefinedFilterCallback($callable) - { - $this->twig->registerUndefinedFilterCallback($callable); - } - - public function getFilters() - { - return $this->twig->getFilters(); - } - - public function addTest($name, $test = null) - { - $this->twig->addTest($name, $test); - } - - public function getTests() - { - return $this->twig->getTests(); - } - - public function getTest($name) - { - return $this->twig->getTest($name); - } - - public function addFunction($name, $function = null) - { - $this->twig->addFunction($name, $function); - } - - public function getFunction($name) - { - return $this->twig->getFunction($name); - } - - public function registerUndefinedFunctionCallback($callable) - { - $this->twig->registerUndefinedFunctionCallback($callable); - } - - public function getFunctions() - { - return $this->twig->getFunctions(); - } - - public function addGlobal($name, $value) - { - $this->twig->addGlobal($name, $value); - } - - public function getGlobals() - { - return $this->twig->getGlobals(); - } - - public function mergeGlobals(array $context) - { - return $this->twig->mergeGlobals($context); - } - - public function getUnaryOperators() - { - return $this->twig->getUnaryOperators(); - } - - public function getBinaryOperators() - { - return $this->twig->getBinaryOperators(); - } - - public function computeAlternatives($name, $items) - { - return $this->twig->computeAlternatives($name, $items); - } + protected $twig; + protected $renderedTemplates = []; + protected $timeDataCollector; + + /** + * @param Twig_Environment $twig + * @param TimeDataCollector $timeDataCollector + */ + public function __construct(Twig_Environment $twig, TimeDataCollector $timeDataCollector = null) + { + $this->twig = $twig; + $this->timeDataCollector = $timeDataCollector; + } + + public function __call($name, $arguments) + { + return call_user_func_array([$this->twig, $name], $arguments); + } + + public function getRenderedTemplates() + { + return $this->renderedTemplates; + } + + public function addRenderedTemplate(array $info) + { + $this->renderedTemplates[] = $info; + } + + public function getTimeDataCollector() + { + return $this->timeDataCollector; + } + + public function getBaseTemplateClass() + { + return $this->twig->getBaseTemplateClass(); + } + + public function setBaseTemplateClass($class) + { + $this->twig->setBaseTemplateClass($class); + } + + public function enableDebug() + { + $this->twig->enableDebug(); + } + + public function disableDebug() + { + $this->twig->disableDebug(); + } + + public function isDebug() + { + return $this->twig->isDebug(); + } + + public function enableAutoReload() + { + $this->twig->enableAutoReload(); + } + + public function disableAutoReload() + { + $this->twig->disableAutoReload(); + } + + public function isAutoReload() + { + return $this->twig->isAutoReload(); + } + + public function enableStrictVariables() + { + $this->twig->enableStrictVariables(); + } + + public function disableStrictVariables() + { + $this->twig->disableStrictVariables(); + } + + public function isStrictVariables() + { + return $this->twig->isStrictVariables(); + } + + public function getCache($original = true) + { + return $this->twig->getCache($original); + } + + public function setCache($cache) + { + $this->twig->setCache($cache); + } + + public function getCacheFilename($name) + { + return $this->twig->getCacheFilename($name); + } + + public function getTemplateClass($name, $index = null) + { + return $this->twig->getTemplateClass($name, $index); + } + + public function getTemplateClassPrefix() + { + return $this->twig->getTemplateClassPrefix(); + } + + public function render($name, array $context = []) + { + return $this->loadTemplate($name)->render($context); + } + + public function display($name, array $context = []) + { + $this->loadTemplate($name)->display($context); + } + + public function loadTemplate($name, $index = null) + { + $cls = $this->twig->getTemplateClass($name, $index); + + if (isset($this->twig->loadedTemplates[$cls])) { + return $this->twig->loadedTemplates[$cls]; + } + + if (!class_exists($cls, false)) { + if (false === $cache = $this->getCacheFilename($name)) { + eval('?>' . $this->compileSource($this->getLoader()->getSource($name), $name)); + } else { + if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { + $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); + } + + require_once $cache; + } + } + + if (!$this->twig->runtimeInitialized) { + $this->initRuntime(); + } + + return $this->twig->loadedTemplates[$cls] = new TraceableTwigTemplate($this, new $cls($this)); + } + + public function isTemplateFresh($name, $time) + { + return $this->twig->isTemplateFresh($name, $time); + } + + public function resolveTemplate($names) + { + return $this->twig->resolveTemplate($names); + } + + public function clearTemplateCache() + { + $this->twig->clearTemplateCache(); + } + + public function clearCacheFiles() + { + $this->twig->clearCacheFiles(); + } + + public function getLexer() + { + return $this->twig->getLexer(); + } + + public function setLexer(Twig_LexerInterface $lexer) + { + $this->twig->setLexer($lexer); + } + + public function tokenize($source, $name = null) + { + return $this->twig->tokenize($source, $name); + } + + public function getParser() + { + return $this->twig->getParser(); + } + + public function setParser(Twig_ParserInterface $parser) + { + $this->twig->setParser($parser); + } + + public function parse(Twig_TokenStream $tokens) + { + return $this->twig->parse($tokens); + } + + public function getCompiler() + { + return $this->twig->getCompiler(); + } + + public function setCompiler(Twig_CompilerInterface $compiler) + { + $this->twig->setCompiler($compiler); + } + + public function compile(Twig_NodeInterface $node) + { + return $this->twig->compile($node); + } + + public function compileSource($source, $name = null) + { + return $this->twig->compileSource($source, $name); + } + + public function setLoader(Twig_LoaderInterface $loader) + { + $this->twig->setLoader($loader); + } + + public function getLoader() + { + return $this->twig->getLoader(); + } + + public function setCharset($charset) + { + $this->twig->setCharset($charset); + } + + public function getCharset() + { + return $this->twig->getCharset(); + } + + public function initRuntime() + { + $this->twig->initRuntime(); + } + + public function hasExtension($name) + { + return $this->twig->hasExtension($name); + } + + public function getExtension($name) + { + return $this->twig->getExtension($name); + } + + public function addExtension(Twig_ExtensionInterface $extension) + { + $this->twig->addExtension($extension); + } + + public function removeExtension($name) + { + $this->twig->removeExtension($name); + } + + public function setExtensions(array $extensions) + { + $this->twig->setExtensions($extensions); + } + + public function getExtensions() + { + return $this->twig->getExtensions(); + } + + public function addTokenParser(Twig_TokenParserInterface $parser) + { + $this->twig->addTokenParser($parser); + } + + public function getTokenParsers() + { + return $this->twig->getTokenParsers(); + } + + public function getTags() + { + return $this->twig->getTags(); + } + + public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) + { + $this->twig->addNodeVisitor($visitor); + } + + public function getNodeVisitors() + { + return $this->twig->getNodeVisitors(); + } + + public function addFilter($name, $filter = null) + { + $this->twig->addFilter($name, $filter); + } + + public function getFilter($name) + { + return $this->twig->getFilter($name); + } + + public function registerUndefinedFilterCallback($callable) + { + $this->twig->registerUndefinedFilterCallback($callable); + } + + public function getFilters() + { + return $this->twig->getFilters(); + } + + public function addTest($name, $test = null) + { + $this->twig->addTest($name, $test); + } + + public function getTests() + { + return $this->twig->getTests(); + } + + public function getTest($name) + { + return $this->twig->getTest($name); + } + + public function addFunction($name, $function = null) + { + $this->twig->addFunction($name, $function); + } + + public function getFunction($name) + { + return $this->twig->getFunction($name); + } + + public function registerUndefinedFunctionCallback($callable) + { + $this->twig->registerUndefinedFunctionCallback($callable); + } + + public function getFunctions() + { + return $this->twig->getFunctions(); + } + + public function addGlobal($name, $value) + { + $this->twig->addGlobal($name, $value); + } + + public function getGlobals() + { + return $this->twig->getGlobals(); + } + + public function mergeGlobals(array $context) + { + return $this->twig->mergeGlobals($context); + } + + public function getUnaryOperators() + { + return $this->twig->getUnaryOperators(); + } + + public function getBinaryOperators() + { + return $this->twig->getBinaryOperators(); + } + + public function computeAlternatives($name, $items) + { + return $this->twig->computeAlternatives($name, $items); + } } diff --git a/src/DebugBar/Bridge/Twig/TraceableTwigTemplate.php b/src/DebugBar/Bridge/Twig/TraceableTwigTemplate.php index dab53d15..0448d602 100644 --- a/src/DebugBar/Bridge/Twig/TraceableTwigTemplate.php +++ b/src/DebugBar/Bridge/Twig/TraceableTwigTemplate.php @@ -14,118 +14,118 @@ use Twig_TemplateInterface; /** - * Wraps a Twig_Template to add profiling features + * Wraps a Twig_Template to add profiling features. */ class TraceableTwigTemplate implements Twig_TemplateInterface { - protected $template; - - /** - * @param TraceableTwigEnvironment $env - * @param Twig_Template $template - */ - public function __construct(TraceableTwigEnvironment $env, Twig_Template $template) - { - $this->env = $env; - $this->template = $template; - } - - public function __call($name, $arguments) - { - return call_user_func_array(array($this->template, $name), $arguments); - } - - public function getTemplateName() - { - return $this->template->getTemplateName(); - } - - public function getEnvironment() - { - return $this->template->getEnvironment(); - } - - public function getParent(array $context) - { - return $this->template->getParent($context); - } - - public function isTraitable() - { - return $this->template->isTraitable(); - } - - public function displayParentBlock($name, array $context, array $blocks = array()) - { - $this->template->displayParentBlock($name, $context, $blocks); - } - - public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true) - { - $this->template->displayBlock($name, $context, $blocks, $useBlocks); - } - - public function renderParentBlock($name, array $context, array $blocks = array()) - { - return $this->template->renderParentBlock($name, $context, $blocks); - } - - public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true) - { - return $this->template->renderBlock($name, $context, $blocks, $useBlocks); - } - - public function hasBlock($name) - { - return $this->template->hasBlock($name); - } - - public function getBlockNames() - { - return $this->template->getBlockNames(); - } - - public function getBlocks() - { - return $this->template->getBlocks(); - } - - public function display(array $context, array $blocks = array()) - { - $start = microtime(true); - $this->template->display($context, $blocks); - $end = microtime(true); - - if ($timeDataCollector = $this->env->getTimeDataCollector()) { - $name = sprintf("twig.render(%s)", $this->template->getTemplateName()); - $timeDataCollector->addMeasure($name, $start, $end); - } - - $this->env->addRenderedTemplate(array( - 'name' => $this->template->getTemplateName(), - 'render_time' => $end - $start - )); - } - - public function render(array $context) - { - $level = ob_get_level(); - ob_start(); - try { - $this->display($context); - } catch (Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } - - return ob_get_clean(); - } - - public static function clearCache() - { - Twig_Template::clearCache(); - } + protected $template; + + /** + * @param TraceableTwigEnvironment $env + * @param Twig_Template $template + */ + public function __construct(TraceableTwigEnvironment $env, Twig_Template $template) + { + $this->env = $env; + $this->template = $template; + } + + public function __call($name, $arguments) + { + return call_user_func_array([$this->template, $name], $arguments); + } + + public function getTemplateName() + { + return $this->template->getTemplateName(); + } + + public function getEnvironment() + { + return $this->template->getEnvironment(); + } + + public function getParent(array $context) + { + return $this->template->getParent($context); + } + + public function isTraitable() + { + return $this->template->isTraitable(); + } + + public function displayParentBlock($name, array $context, array $blocks = []) + { + $this->template->displayParentBlock($name, $context, $blocks); + } + + public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true) + { + $this->template->displayBlock($name, $context, $blocks, $useBlocks); + } + + public function renderParentBlock($name, array $context, array $blocks = []) + { + return $this->template->renderParentBlock($name, $context, $blocks); + } + + public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true) + { + return $this->template->renderBlock($name, $context, $blocks, $useBlocks); + } + + public function hasBlock($name) + { + return $this->template->hasBlock($name); + } + + public function getBlockNames() + { + return $this->template->getBlockNames(); + } + + public function getBlocks() + { + return $this->template->getBlocks(); + } + + public function display(array $context, array $blocks = []) + { + $start = microtime(true); + $this->template->display($context, $blocks); + $end = microtime(true); + + if ($timeDataCollector = $this->env->getTimeDataCollector()) { + $name = sprintf('twig.render(%s)', $this->template->getTemplateName()); + $timeDataCollector->addMeasure($name, $start, $end); + } + + $this->env->addRenderedTemplate([ + 'name' => $this->template->getTemplateName(), + 'render_time' => $end - $start + ]); + } + + public function render(array $context) + { + $level = ob_get_level(); + ob_start(); + try { + $this->display($context); + } catch (Exception $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + + throw $e; + } + + return ob_get_clean(); + } + + public static function clearCache() + { + Twig_Template::clearCache(); + } } diff --git a/src/DebugBar/Bridge/Twig/TwigCollector.php b/src/DebugBar/Bridge/Twig/TwigCollector.php index fde5a3f8..25347bf9 100644 --- a/src/DebugBar/Bridge/Twig/TwigCollector.php +++ b/src/DebugBar/Bridge/Twig/TwigCollector.php @@ -15,7 +15,7 @@ use DebugBar\DataCollector\Renderable; /** - * Collects data about rendered templates + * Collects data about rendered templates. * * http://twig.sensiolabs.org/ * @@ -29,59 +29,59 @@ */ class TwigCollector extends DataCollector implements Renderable, AssetProvider { - public function __construct(TraceableTwigEnvironment $twig) - { - $this->twig = $twig; - } + public function __construct(TraceableTwigEnvironment $twig) + { + $this->twig = $twig; + } - public function collect() - { - $templates = array(); - $accuRenderTime = 0; + public function collect() + { + $templates = []; + $accuRenderTime = 0; - foreach ($this->twig->getRenderedTemplates() as $tpl) { - $accuRenderTime += $tpl['render_time']; - $templates[] = array( - 'name' => $tpl['name'], - 'render_time' => $tpl['render_time'], - 'render_time_str' => $this->formatDuration($tpl['render_time']) - ); - } + foreach ($this->twig->getRenderedTemplates() as $tpl) { + $accuRenderTime += $tpl['render_time']; + $templates[] = [ + 'name' => $tpl['name'], + 'render_time' => $tpl['render_time'], + 'render_time_str' => $this->formatDuration($tpl['render_time']) + ]; + } - return array( - 'nb_templates' => count($templates), - 'templates' => $templates, - 'accumulated_render_time' => $accuRenderTime, - 'accumulated_render_time_str' => $this->formatDuration($accuRenderTime) - ); - } + return [ + 'nb_templates' => count($templates), + 'templates' => $templates, + 'accumulated_render_time' => $accuRenderTime, + 'accumulated_render_time_str' => $this->formatDuration($accuRenderTime) + ]; + } - public function getName() - { - return 'twig'; - } + public function getName() + { + return 'twig'; + } - public function getWidgets() - { - return array( - 'twig' => array( - 'icon' => 'leaf', - 'widget' => 'PhpDebugBar.Widgets.TemplatesWidget', - 'map' => 'twig', - 'default' => '[]' - ), - 'twig:badge' => array( - 'map' => 'twig.nb_templates', - 'default' => 0 - ) - ); - } + public function getWidgets() + { + return [ + 'twig' => [ + 'icon' => 'leaf', + 'widget' => 'PhpDebugBar.Widgets.TemplatesWidget', + 'map' => 'twig', + 'default' => '[]' + ], + 'twig:badge' => [ + 'map' => 'twig.nb_templates', + 'default' => 0 + ] + ]; + } - public function getAssets() - { - return array( - 'css' => 'widgets/templates/widget.css', - 'js' => 'widgets/templates/widget.js' - ); - } + public function getAssets() + { + return [ + 'css' => 'widgets/templates/widget.css', + 'js' => 'widgets/templates/widget.js' + ]; + } } diff --git a/src/DebugBar/DataCollector/AggregatedCollector.php b/src/DebugBar/DataCollector/AggregatedCollector.php index c1fd96ae..bf70ac7f 100644 --- a/src/DebugBar/DataCollector/AggregatedCollector.php +++ b/src/DebugBar/DataCollector/AggregatedCollector.php @@ -14,7 +14,7 @@ use DebugBar\DebugBarException; /** - * Aggregates data from multiple collectors + * Aggregates data from multiple collectors. * * * $aggcollector = new AggregateCollector('foobar'); @@ -25,165 +25,167 @@ */ class AggregatedCollector implements DataCollectorInterface, ArrayAccess { - protected $name; - - protected $mergeProperty; - - protected $sort; - - protected $collectors = array(); - - /** - * @param string $name - * @param string $mergeProperty - * @param boolean $sort - */ - public function __construct($name, $mergeProperty = null, $sort = false) - { - $this->name = $name; - $this->mergeProperty = $mergeProperty; - $this->sort = $sort; - } - - /** - * @param DataCollectorInterface $collector - */ - public function addCollector(DataCollectorInterface $collector) - { - $this->collectors[$collector->getName()] = $collector; - } - - /** - * @return array - */ - public function getCollectors() - { - return $this->collectors; - } - - /** - * Merge data from one of the key/value pair of the collected data - * - * @param string $property - */ - public function setMergeProperty($property) - { - $this->mergeProperty = $property; - } - - /** - * @return string - */ - public function getMergeProperty() - { - return $this->mergeProperty; - } - - /** - * Sorts the collected data - * - * If true, sorts using sort() - * If it is a string, sorts the data using the value from a key/value pair of the array - * - * @param bool|string $sort - */ - public function setSort($sort) - { - $this->sort = $sort; - } - - /** - * @return bool|string - */ - public function getSort() - { - return $this->sort; - } - - /** - * @return array - */ - public function collect() - { - $aggregate = array(); - foreach ($this->collectors as $collector) { - $data = $collector->collect(); - if ($this->mergeProperty !== null) { - $data = $data[$this->mergeProperty]; - } - $aggregate = array_merge($aggregate, $data); - } - - return $this->sort($aggregate); - } - - /** - * Sorts the collected data - * - * @param array $data - * @return array - */ - protected function sort($data) - { - if (is_string($this->sort)) { - $p = $this->sort; - usort($data, function ($a, $b) use ($p) { - if ($a[$p] == $b[$p]) { - return 0; - } - return $a[$p] < $b[$p] ? -1 : 1; - }); - } elseif ($this->sort === true) { - sort($data); - } - return $data; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - // -------------------------------------------- - // ArrayAccess implementation - - /** - * @param mixed $key - * @param mixed $value - * @throws DebugBarException - */ - public function offsetSet($key, $value) - { - throw new DebugBarException("AggregatedCollector[] is read-only"); - } - - /** - * @param mixed $key - * @return mixed - */ - public function offsetGet($key) - { - return $this->collectors[$key]; - } - - /** - * @param mixed $key - * @return bool - */ - public function offsetExists($key) - { - return isset($this->collectors[$key]); - } - - /** - * @param mixed $key - * @throws DebugBarException - */ - public function offsetUnset($key) - { - throw new DebugBarException("AggregatedCollector[] is read-only"); - } + protected $name; + protected $mergeProperty; + protected $sort; + protected $collectors = []; + + /** + * @param string $name + * @param string $mergeProperty + * @param bool $sort + */ + public function __construct($name, $mergeProperty = null, $sort = false) + { + $this->name = $name; + $this->mergeProperty = $mergeProperty; + $this->sort = $sort; + } + + /** + * @param DataCollectorInterface $collector + */ + public function addCollector(DataCollectorInterface $collector) + { + $this->collectors[$collector->getName()] = $collector; + } + + /** + * @return array + */ + public function getCollectors() + { + return $this->collectors; + } + + /** + * Merge data from one of the key/value pair of the collected data. + * + * @param string $property + */ + public function setMergeProperty($property) + { + $this->mergeProperty = $property; + } + + /** + * @return string + */ + public function getMergeProperty() + { + return $this->mergeProperty; + } + + /** + * Sorts the collected data. + * + * If true, sorts using sort() + * If it is a string, sorts the data using the value from a key/value pair of the array + * + * @param bool|string $sort + */ + public function setSort($sort) + { + $this->sort = $sort; + } + + /** + * @return bool|string + */ + public function getSort() + { + return $this->sort; + } + + /** + * @return array + */ + public function collect() + { + $aggregate = []; + foreach ($this->collectors as $collector) { + $data = $collector->collect(); + if ($this->mergeProperty !== null) { + $data = $data[$this->mergeProperty]; + } + $aggregate = array_merge($aggregate, $data); + } + + return $this->sort($aggregate); + } + + /** + * Sorts the collected data. + * + * @param array $data + * + * @return array + */ + protected function sort($data) + { + if (is_string($this->sort)) { + $p = $this->sort; + usort($data, function ($a, $b) use ($p) { + if ($a[$p] == $b[$p]) { + return 0; + } + return $a[$p] < $b[$p] ? -1 : 1; + }); + } elseif ($this->sort === true) { + sort($data); + } + return $data; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + // -------------------------------------------- + // ArrayAccess implementation + + /** + * @param mixed $key + * @param mixed $value + * + * @throws DebugBarException + */ + public function offsetSet($key, $value) + { + throw new DebugBarException('AggregatedCollector[] is read-only'); + } + + /** + * @param mixed $key + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->collectors[$key]; + } + + /** + * @param mixed $key + * + * @return bool + */ + public function offsetExists($key) + { + return isset($this->collectors[$key]); + } + + /** + * @param mixed $key + * + * @throws DebugBarException + */ + public function offsetUnset($key) + { + throw new DebugBarException('AggregatedCollector[] is read-only'); + } } diff --git a/src/DebugBar/DataCollector/AssetProvider.php b/src/DebugBar/DataCollector/AssetProvider.php index 6910f737..cb90731b 100644 --- a/src/DebugBar/DataCollector/AssetProvider.php +++ b/src/DebugBar/DataCollector/AssetProvider.php @@ -11,18 +11,18 @@ namespace DebugBar\DataCollector; /** - * Indicates that a DataCollector provides some assets + * Indicates that a DataCollector provides some assets. */ interface AssetProvider { - /** - * Returns an array with the following keys: - * - base_path - * - base_url - * - css: an array of filenames - * - js: an array of filenames - * - * @return array - */ - function getAssets(); + /** + * Returns an array with the following keys: + * - base_path + * - base_url + * - css: an array of filenames + * - js: an array of filenames. + * + * @return array + */ + public function getAssets(); } diff --git a/src/DebugBar/DataCollector/ConfigCollector.php b/src/DebugBar/DataCollector/ConfigCollector.php index 692b5470..174cf7bd 100644 --- a/src/DebugBar/DataCollector/ConfigCollector.php +++ b/src/DebugBar/DataCollector/ConfigCollector.php @@ -11,70 +11,69 @@ namespace DebugBar\DataCollector; /** - * Collects array data + * Collects array data. */ class ConfigCollector extends DataCollector implements Renderable { - protected $name; + protected $name; + protected $data; - protected $data; + /** + * @param array $data + * @param string $name + */ + public function __construct(array $data = [], $name = 'config') + { + $this->name = $name; + $this->data = $data; + } - /** - * @param array $data - * @param string $name - */ - public function __construct(array $data = array(), $name = 'config') - { - $this->name = $name; - $this->data = $data; - } + /** + * Sets the data. + * + * @param array $data + */ + public function setData(array $data) + { + $this->data = $data; + } - /** - * Sets the data - * - * @param array $data - */ - public function setData(array $data) - { - $this->data = $data; - } + /** + * @return array + */ + public function collect() + { + $data = []; + foreach ($this->data as $k => $v) { + if (!is_string($v)) { + $v = $this->getDataFormatter()->formatVar($v); + } + $data[$k] = $v; + } + return $data; + } - /** - * @return array - */ - public function collect() - { - $data = array(); - foreach ($this->data as $k => $v) { - if (!is_string($v)) { - $v = $this->getDataFormatter()->formatVar($v); - } - $data[$k] = $v; - } - return $data; - } + /** + * @return string + */ + public function getName() + { + return $this->name; + } - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return array - */ - public function getWidgets() - { - $name = $this->getName(); - return array( - "$name" => array( - "icon" => "gear", - "widget" => "PhpDebugBar.Widgets.VariableListWidget", - "map" => "$name", - "default" => "{}" - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + $name = $this->getName(); + return [ + "$name" => [ + 'icon' => 'gear', + 'widget' => 'PhpDebugBar.Widgets.VariableListWidget', + 'map' => "$name", + 'default' => '{}' + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/DataCollector.php b/src/DebugBar/DataCollector/DataCollector.php index aae5cbad..0630eb97 100644 --- a/src/DebugBar/DataCollector/DataCollector.php +++ b/src/DebugBar/DataCollector/DataCollector.php @@ -14,81 +14,81 @@ use DebugBar\DataFormatter\DataFormatterInterface; /** - * Abstract class for data collectors + * Abstract class for data collectors. */ abstract class DataCollector implements DataCollectorInterface { - private static $defaultDataFormatter; + private static $defaultDataFormatter; + protected $dataFormater; - protected $dataFormater; + /** + * Sets the default data formater instance used by all collectors subclassing this class. + * + * @param DataFormatterInterface $formater + */ + public static function setDefaultDataFormatter(DataFormatterInterface $formater) + { + self::$defaultDataFormatter = $formater; + } - /** - * Sets the default data formater instance used by all collectors subclassing this class - * - * @param DataFormatterInterface $formater - */ - public static function setDefaultDataFormatter(DataFormatterInterface $formater) - { - self::$defaultDataFormatter = $formater; - } + /** + * Returns the default data formater. + * + * @return DataFormatterInterface + */ + public static function getDefaultDataFormatter() + { + if (self::$defaultDataFormatter === null) { + self::$defaultDataFormatter = new DataFormatter(); + } + return self::$defaultDataFormatter; + } - /** - * Returns the default data formater - * - * @return DataFormatterInterface - */ - public static function getDefaultDataFormatter() - { - if (self::$defaultDataFormatter === null) { - self::$defaultDataFormatter = new DataFormatter(); - } - return self::$defaultDataFormatter; - } + /** + * Sets the data formater instance used by this collector. + * + * @param DataFormatterInterface $formater + * + * @return $this + */ + public function setDataFormatter(DataFormatterInterface $formater) + { + $this->dataFormater = $formater; + return $this; + } - /** - * Sets the data formater instance used by this collector - * - * @param DataFormatterInterface $formater - * @return $this - */ - public function setDataFormatter(DataFormatterInterface $formater) - { - $this->dataFormater = $formater; - return $this; - } + /** + * @return DataFormatterInterface + */ + public function getDataFormatter() + { + if ($this->dataFormater === null) { + $this->dataFormater = self::getDefaultDataFormatter(); + } + return $this->dataFormater; + } - /** - * @return DataFormatterInterface - */ - public function getDataFormatter() - { - if ($this->dataFormater === null) { - $this->dataFormater = self::getDefaultDataFormatter(); - } - return $this->dataFormater; - } + /** + * @deprecated + */ + public function formatVar($var) + { + return $this->getDataFormatter()->formatVar($var); + } - /** - * @deprecated - */ - public function formatVar($var) - { - return $this->getDataFormatter()->formatVar($var); - } + /** + * @deprecated + */ + public function formatDuration($seconds) + { + return $this->getDataFormatter()->formatDuration($seconds); + } - /** - * @deprecated - */ - public function formatDuration($seconds) - { - return $this->getDataFormatter()->formatDuration($seconds); - } - - /** - * @deprecated - */ - public function formatBytes($size, $precision = 2) - { - return $this->getDataFormatter()->formatBytes($size, $precision); - } + /** + * @deprecated + */ + public function formatBytes($size, $precision = 2) + { + return $this->getDataFormatter()->formatBytes($size, $precision); + } } diff --git a/src/DebugBar/DataCollector/DataCollectorInterface.php b/src/DebugBar/DataCollector/DataCollectorInterface.php index b7f234cb..ad47e37f 100644 --- a/src/DebugBar/DataCollector/DataCollectorInterface.php +++ b/src/DebugBar/DataCollector/DataCollectorInterface.php @@ -11,21 +11,21 @@ namespace DebugBar\DataCollector; /** - * DataCollector Interface + * DataCollector Interface. */ interface DataCollectorInterface { - /** - * Called by the DebugBar when data needs to be collected - * - * @return array Collected data - */ - function collect(); + /** + * Called by the DebugBar when data needs to be collected. + * + * @return array Collected data + */ + public function collect(); - /** - * Returns the unique name of the collector - * - * @return string - */ - function getName(); + /** + * Returns the unique name of the collector. + * + * @return string + */ + public function getName(); } diff --git a/src/DebugBar/DataCollector/ExceptionsCollector.php b/src/DebugBar/DataCollector/ExceptionsCollector.php index 9fefd641..02a5837a 100644 --- a/src/DebugBar/DataCollector/ExceptionsCollector.php +++ b/src/DebugBar/DataCollector/ExceptionsCollector.php @@ -11,131 +11,134 @@ namespace DebugBar\DataCollector; use Exception; -use Symfony\Component\Debug\Exception\FatalThrowableError; /** - * Collects info about exceptions + * Collects info about exceptions. */ class ExceptionsCollector extends DataCollector implements Renderable { - protected $exceptions = array(); - protected $chainExceptions = false; + protected $exceptions = []; + protected $chainExceptions = false; - /** - * Adds an exception to be profiled in the debug bar - * - * @param Exception $e - * @deprecated in favor on addThrowable - */ - public function addException(Exception $e) - { - $this->addThrowable($e); - } + /** + * Adds an exception to be profiled in the debug bar. + * + * @param Exception $e + * + * @deprecated in favor on addThrowable + */ + public function addException(Exception $e) + { + $this->addThrowable($e); + } - /** - * Adds a Throwable to be profiled in the debug bar - * - * @param \Throwable $e - */ - public function addThrowable($e) - { - $this->exceptions[] = $e; - if ($this->chainExceptions && $previous = $e->getPrevious()) { - $this->addThrowable($previous); - } - } + /** + * Adds a Throwable to be profiled in the debug bar. + * + * @param \Throwable $e + */ + public function addThrowable($e) + { + $this->exceptions[] = $e; + if ($this->chainExceptions && $previous = $e->getPrevious()) { + $this->addThrowable($previous); + } + } - /** - * Configure whether or not all chained exceptions should be shown. - * - * @param bool $chainExceptions - */ - public function setChainExceptions($chainExceptions = true) - { - $this->chainExceptions = $chainExceptions; - } + /** + * Configure whether or not all chained exceptions should be shown. + * + * @param bool $chainExceptions + */ + public function setChainExceptions($chainExceptions = true) + { + $this->chainExceptions = $chainExceptions; + } - /** - * Returns the list of exceptions being profiled - * - * @return array[\Throwable] - */ - public function getExceptions() - { - return $this->exceptions; - } + /** + * Returns the list of exceptions being profiled. + * + * @return array[\Throwable] + */ + public function getExceptions() + { + return $this->exceptions; + } - public function collect() - { - return array( - 'count' => count($this->exceptions), - 'exceptions' => array_map(array($this, 'formatThrowableData'), $this->exceptions) - ); - } + public function collect() + { + return [ + 'count' => count($this->exceptions), + 'exceptions' => array_map([$this, 'formatThrowableData'], $this->exceptions) + ]; + } - /** - * Returns exception data as an array - * - * @param Exception $e - * @return array - * @deprecated in favor on formatThrowableData - */ - public function formatExceptionData(Exception $e) - { - return $this->formatThrowableData($e); - } + /** + * Returns exception data as an array. + * + * @param Exception $e + * + * @return array + * + * @deprecated in favor on formatThrowableData + */ + public function formatExceptionData(Exception $e) + { + return $this->formatThrowableData($e); + } - /** - * Returns Throwable data as an array - * - * @param \Throwable $e - * @return array - */ - public function formatThrowableData($e) - { - $filePath = $e->getFile(); - if ($filePath && file_exists($filePath)) { - $lines = file($filePath); - $start = $e->getLine() - 4; - $lines = array_slice($lines, $start < 0 ? 0 : $start, 7); - } else { - $lines = array("Cannot open the file ($filePath) in which the exception occurred "); - } + /** + * Returns Throwable data as an array. + * + * @param \Throwable $e + * + * @return array + */ + public function formatThrowableData($e) + { + $filePath = $e->getFile(); + if ($filePath && file_exists($filePath)) { + $lines = file($filePath); + $start = $e->getLine() - 4; + $lines = array_slice($lines, $start < 0 ? 0 : $start, 7); + } else { + $lines = ["Cannot open the file ($filePath) in which the exception occurred "]; + } - return array( - 'type' => get_class($e), - 'message' => $e->getMessage(), - 'code' => $e->getCode(), - 'file' => $filePath, - 'line' => $e->getLine(), - 'surrounding_lines' => $lines - ); - } + return [ + 'type' => get_class($e), + 'message' => $e->getMessage(), + 'code' => $e->getCode(), + 'file' => $filePath, + 'line' => $e->getLine(), + 'surrounding_lines' => $lines + ]; + } - /** - * @return string - */ - public function getName() - { - return 'exceptions'; - } + /** + * @return string + */ + public function getName() + { + return 'exceptions'; + } - /** - * @return array - */ - public function getWidgets() - { - return array( - 'exceptions' => array( - 'icon' => 'bug', - 'widget' => 'PhpDebugBar.Widgets.ExceptionsWidget', - 'map' => 'exceptions.exceptions', - 'default' => '[]' - ), - 'exceptions:badge' => array( - 'map' => 'exceptions.count', - 'default' => 'null' - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + return [ + 'exceptions' => [ + 'icon' => 'bug', + 'widget' => 'PhpDebugBar.Widgets.ExceptionsWidget', + 'map' => 'exceptions.exceptions', + 'default' => '[]' + ], + 'exceptions:badge' => [ + 'map' => 'exceptions.count', + 'default' => 'null' + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/LocalizationCollector.php b/src/DebugBar/DataCollector/LocalizationCollector.php index 276cd0e3..1061c045 100644 --- a/src/DebugBar/DataCollector/LocalizationCollector.php +++ b/src/DebugBar/DataCollector/LocalizationCollector.php @@ -11,63 +11,63 @@ namespace DebugBar\DataCollector; /** - * Collects info about the current localization state + * Collects info about the current localization state. */ class LocalizationCollector extends DataCollector implements Renderable { - /** - * Get the current locale - * - * @return string - */ - public function getLocale() - { - return setlocale(LC_ALL, 0); - } + /** + * Get the current locale. + * + * @return string + */ + public function getLocale() + { + return setlocale(LC_ALL, 0); + } - /** - * Get the current translations domain - * - * @return string - */ - public function getDomain() - { - return textdomain(); - } + /** + * Get the current translations domain. + * + * @return string + */ + public function getDomain() + { + return textdomain(); + } - /** - * @return array - */ - public function collect() - { - return array( - 'locale' => $this->getLocale(), - 'domain' => $this->getDomain(), - ); - } + /** + * @return array + */ + public function collect() + { + return [ + 'locale' => $this->getLocale(), + 'domain' => $this->getDomain(), + ]; + } - /** - * @return string - */ - public function getName() - { - return 'localization'; - } + /** + * @return string + */ + public function getName() + { + return 'localization'; + } - /** - * @return array - */ - public function getWidgets() - { - return array( - 'domain' => array( - 'icon' => 'bookmark', - 'map' => 'localization.domain', - ), - 'locale' => array( - 'icon' => 'flag', - 'map' => 'localization.locale', - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + return [ + 'domain' => [ + 'icon' => 'bookmark', + 'map' => 'localization.domain', + ], + 'locale' => [ + 'icon' => 'flag', + 'map' => 'localization.locale', + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/MemoryCollector.php b/src/DebugBar/DataCollector/MemoryCollector.php index 462c616f..9a64b5c4 100644 --- a/src/DebugBar/DataCollector/MemoryCollector.php +++ b/src/DebugBar/DataCollector/MemoryCollector.php @@ -11,62 +11,62 @@ namespace DebugBar\DataCollector; /** - * Collects info about memory usage + * Collects info about memory usage. */ class MemoryCollector extends DataCollector implements Renderable { - protected $peakUsage = 0; + protected $peakUsage = 0; - /** - * Returns the peak memory usage - * - * @return integer - */ - public function getPeakUsage() - { - return $this->peakUsage; - } + /** + * Returns the peak memory usage. + * + * @return int + */ + public function getPeakUsage() + { + return $this->peakUsage; + } - /** - * Updates the peak memory usage value - */ - public function updatePeakUsage() - { - $this->peakUsage = memory_get_peak_usage(true); - } + /** + * Updates the peak memory usage value. + */ + public function updatePeakUsage() + { + $this->peakUsage = memory_get_peak_usage(true); + } - /** - * @return array - */ - public function collect() - { - $this->updatePeakUsage(); - return array( - 'peak_usage' => $this->peakUsage, - 'peak_usage_str' => $this->getDataFormatter()->formatBytes($this->peakUsage) - ); - } + /** + * @return array + */ + public function collect() + { + $this->updatePeakUsage(); + return [ + 'peak_usage' => $this->peakUsage, + 'peak_usage_str' => $this->getDataFormatter()->formatBytes($this->peakUsage) + ]; + } - /** - * @return string - */ - public function getName() - { - return 'memory'; - } + /** + * @return string + */ + public function getName() + { + return 'memory'; + } - /** - * @return array - */ - public function getWidgets() - { - return array( - "memory" => array( - "icon" => "cogs", - "tooltip" => "Memory Usage", - "map" => "memory.peak_usage_str", - "default" => "'0B'" - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + return [ + 'memory' => [ + 'icon' => 'cogs', + 'tooltip' => 'Memory Usage', + 'map' => 'memory.peak_usage_str', + 'default' => "'0B'" + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/MessagesAggregateInterface.php b/src/DebugBar/DataCollector/MessagesAggregateInterface.php index 1e2d4d2d..7f68d749 100644 --- a/src/DebugBar/DataCollector/MessagesAggregateInterface.php +++ b/src/DebugBar/DataCollector/MessagesAggregateInterface.php @@ -12,10 +12,10 @@ interface MessagesAggregateInterface { - /** - * Returns collected messages - * - * @return array - */ - public function getMessages(); + /** + * Returns collected messages. + * + * @return array + */ + public function getMessages(); } diff --git a/src/DebugBar/DataCollector/MessagesCollector.php b/src/DebugBar/DataCollector/MessagesCollector.php index b9806295..ae000c62 100644 --- a/src/DebugBar/DataCollector/MessagesCollector.php +++ b/src/DebugBar/DataCollector/MessagesCollector.php @@ -10,165 +10,163 @@ namespace DebugBar\DataCollector; -use Psr\Log\AbstractLogger; use DebugBar\DataFormatter\DataFormatterInterface; +use Psr\Log\AbstractLogger; /** - * Provides a way to log messages + * Provides a way to log messages. */ class MessagesCollector extends AbstractLogger implements DataCollectorInterface, MessagesAggregateInterface, Renderable { - protected $name; - - protected $messages = array(); - - protected $aggregates = array(); - - protected $dataFormater; - - /** - * @param string $name - */ - public function __construct($name = 'messages') - { - $this->name = $name; - } - - /** - * Sets the data formater instance used by this collector - * - * @param DataFormatterInterface $formater - * @return $this - */ - public function setDataFormatter(DataFormatterInterface $formater) - { - $this->dataFormater = $formater; - return $this; - } - - /** - * @return DataFormatterInterface - */ - public function getDataFormatter() - { - if ($this->dataFormater === null) { - $this->dataFormater = DataCollector::getDefaultDataFormatter(); - } - return $this->dataFormater; - } - - /** - * Adds a message - * - * A message can be anything from an object to a string - * - * @param mixed $message - * @param string $label - */ - public function addMessage($message, $label = 'info', $isString = true) - { - if (!is_string($message)) { - $message = $this->getDataFormatter()->formatVar($message); - $isString = false; - } - $this->messages[] = array( - 'message' => $message, - 'is_string' => $isString, - 'label' => $label, - 'time' => microtime(true) - ); - } - - /** - * Aggregates messages from other collectors - * - * @param MessagesAggregateInterface $messages - */ - public function aggregate(MessagesAggregateInterface $messages) - { - $this->aggregates[] = $messages; - } - - /** - * @return array - */ - public function getMessages() - { - $messages = $this->messages; - foreach ($this->aggregates as $collector) { - $msgs = array_map(function ($m) use ($collector) { - $m['collector'] = $collector->getName(); - return $m; - }, $collector->getMessages()); - $messages = array_merge($messages, $msgs); - } - - // sort messages by their timestamp - usort($messages, function ($a, $b) { - if ($a['time'] === $b['time']) { - return 0; - } - return $a['time'] < $b['time'] ? -1 : 1; - }); - - return $messages; - } - - /** - * @param $level - * @param $message - * @param array $context - */ - public function log($level, $message, array $context = array()) - { - $this->addMessage($message, $level); - } - - /** - * Deletes all messages - */ - public function clear() - { - $this->messages = array(); - } - - /** - * @return array - */ - public function collect() - { - $messages = $this->getMessages(); - return array( - 'count' => count($messages), - 'messages' => $messages - ); - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return array - */ - public function getWidgets() - { - $name = $this->getName(); - return array( - "$name" => array( - 'icon' => 'list-alt', - "widget" => "PhpDebugBar.Widgets.MessagesWidget", - "map" => "$name.messages", - "default" => "[]" - ), - "$name:badge" => array( - "map" => "$name.count", - "default" => "null" - ) - ); - } + protected $name; + protected $messages = []; + protected $aggregates = []; + protected $dataFormater; + + /** + * @param string $name + */ + public function __construct($name = 'messages') + { + $this->name = $name; + } + + /** + * Sets the data formater instance used by this collector. + * + * @param DataFormatterInterface $formater + * + * @return $this + */ + public function setDataFormatter(DataFormatterInterface $formater) + { + $this->dataFormater = $formater; + return $this; + } + + /** + * @return DataFormatterInterface + */ + public function getDataFormatter() + { + if ($this->dataFormater === null) { + $this->dataFormater = DataCollector::getDefaultDataFormatter(); + } + return $this->dataFormater; + } + + /** + * Adds a message. + * + * A message can be anything from an object to a string + * + * @param mixed $message + * @param string $label + */ + public function addMessage($message, $label = 'info', $isString = true) + { + if (!is_string($message)) { + $message = $this->getDataFormatter()->formatVar($message); + $isString = false; + } + $this->messages[] = [ + 'message' => $message, + 'is_string' => $isString, + 'label' => $label, + 'time' => microtime(true) + ]; + } + + /** + * Aggregates messages from other collectors. + * + * @param MessagesAggregateInterface $messages + */ + public function aggregate(MessagesAggregateInterface $messages) + { + $this->aggregates[] = $messages; + } + + /** + * @return array + */ + public function getMessages() + { + $messages = $this->messages; + foreach ($this->aggregates as $collector) { + $msgs = array_map(function ($m) use ($collector) { + $m['collector'] = $collector->getName(); + return $m; + }, $collector->getMessages()); + $messages = array_merge($messages, $msgs); + } + + // sort messages by their timestamp + usort($messages, function ($a, $b) { + if ($a['time'] === $b['time']) { + return 0; + } + return $a['time'] < $b['time'] ? -1 : 1; + }); + + return $messages; + } + + /** + * @param $level + * @param $message + * @param array $context + */ + public function log($level, $message, array $context = []) + { + $this->addMessage($message, $level); + } + + /** + * Deletes all messages. + */ + public function clear() + { + $this->messages = []; + } + + /** + * @return array + */ + public function collect() + { + $messages = $this->getMessages(); + return [ + 'count' => count($messages), + 'messages' => $messages + ]; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return array + */ + public function getWidgets() + { + $name = $this->getName(); + return [ + "$name" => [ + 'icon' => 'list-alt', + 'widget' => 'PhpDebugBar.Widgets.MessagesWidget', + 'map' => "$name.messages", + 'default' => '[]' + ], + "$name:badge" => [ + 'map' => "$name.count", + 'default' => 'null' + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/PDO/PDOCollector.php b/src/DebugBar/DataCollector/PDO/PDOCollector.php index e9952ed4..12b8c320 100644 --- a/src/DebugBar/DataCollector/PDO/PDOCollector.php +++ b/src/DebugBar/DataCollector/PDO/PDOCollector.php @@ -8,193 +8,193 @@ use DebugBar\DataCollector\TimeDataCollector; /** - * Collects data about SQL statements executed with PDO + * Collects data about SQL statements executed with PDO. */ class PDOCollector extends DataCollector implements Renderable, AssetProvider { - protected $connections = array(); - - protected $timeCollector; - - protected $renderSqlWithParams = false; - - protected $sqlQuotationChar = '<>'; - - /** - * @param TraceablePDO $pdo - * @param TimeDataCollector $timeCollector - */ - public function __construct(TraceablePDO $pdo = null, TimeDataCollector $timeCollector = null) - { - $this->timeCollector = $timeCollector; - if ($pdo !== null) { - $this->addConnection($pdo, 'default'); - } - } - - /** - * Renders the SQL of traced statements with params embeded - * - * @param boolean $enabled - */ - public function setRenderSqlWithParams($enabled = true, $quotationChar = '<>') - { - $this->renderSqlWithParams = $enabled; - $this->sqlQuotationChar = $quotationChar; - } - - /** - * @return bool - */ - public function isSqlRenderedWithParams() - { - return $this->renderSqlWithParams; - } - - /** - * @return string - */ - public function getSqlQuotationChar() - { - return $this->sqlQuotationChar; - } - - /** - * Adds a new PDO instance to be collector - * - * @param TraceablePDO $pdo - * @param string $name Optional connection name - */ - public function addConnection(TraceablePDO $pdo, $name = null) - { - if ($name === null) { - $name = spl_object_hash($pdo); - } - $this->connections[$name] = $pdo; - } - - /** - * Returns PDO instances to be collected - * - * @return array - */ - public function getConnections() - { - return $this->connections; - } - - /** - * @return array - */ - public function collect() - { - $data = array( - 'nb_statements' => 0, - 'nb_failed_statements' => 0, - 'accumulated_duration' => 0, - 'memory_usage' => 0, - 'peak_memory_usage' => 0, - 'statements' => array() - ); - - foreach ($this->connections as $name => $pdo) { - $pdodata = $this->collectPDO($pdo, $this->timeCollector); - $data['nb_statements'] += $pdodata['nb_statements']; - $data['nb_failed_statements'] += $pdodata['nb_failed_statements']; - $data['accumulated_duration'] += $pdodata['accumulated_duration']; - $data['memory_usage'] += $pdodata['memory_usage']; - $data['peak_memory_usage'] = max($data['peak_memory_usage'], $pdodata['peak_memory_usage']); - $data['statements'] = array_merge($data['statements'], - array_map(function ($s) use ($name) { $s['connection'] = $name; return $s; }, $pdodata['statements'])); - } - - $data['accumulated_duration_str'] = $this->getDataFormatter()->formatDuration($data['accumulated_duration']); - $data['memory_usage_str'] = $this->getDataFormatter()->formatBytes($data['memory_usage']); - $data['peak_memory_usage_str'] = $this->getDataFormatter()->formatBytes($data['peak_memory_usage']); - - return $data; - } - - /** - * Collects data from a single TraceablePDO instance - * - * @param TraceablePDO $pdo - * @param TimeDataCollector $timeCollector - * @return array - */ - protected function collectPDO(TraceablePDO $pdo, TimeDataCollector $timeCollector = null) - { - $stmts = array(); - foreach ($pdo->getExecutedStatements() as $stmt) { - $stmts[] = array( - 'sql' => $this->renderSqlWithParams ? $stmt->getSqlWithParams($this->sqlQuotationChar) : $stmt->getSql(), - 'row_count' => $stmt->getRowCount(), - 'stmt_id' => $stmt->getPreparedId(), - 'prepared_stmt' => $stmt->getSql(), - 'params' => (object) $stmt->getParameters(), - 'duration' => $stmt->getDuration(), - 'duration_str' => $this->getDataFormatter()->formatDuration($stmt->getDuration()), - 'memory' => $stmt->getMemoryUsage(), - 'memory_str' => $this->getDataFormatter()->formatBytes($stmt->getMemoryUsage()), - 'end_memory' => $stmt->getEndMemory(), - 'end_memory_str' => $this->getDataFormatter()->formatBytes($stmt->getEndMemory()), - 'is_success' => $stmt->isSuccess(), - 'error_code' => $stmt->getErrorCode(), - 'error_message' => $stmt->getErrorMessage() - ); - if ($timeCollector !== null) { - $timeCollector->addMeasure($stmt->getSql(), $stmt->getStartTime(), $stmt->getEndTime()); - } - } - - return array( - 'nb_statements' => count($stmts), - 'nb_failed_statements' => count($pdo->getFailedExecutedStatements()), - 'accumulated_duration' => $pdo->getAccumulatedStatementsDuration(), - 'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($pdo->getAccumulatedStatementsDuration()), - 'memory_usage' => $pdo->getMemoryUsage(), - 'memory_usage_str' => $this->getDataFormatter()->formatBytes($pdo->getPeakMemoryUsage()), - 'peak_memory_usage' => $pdo->getPeakMemoryUsage(), - 'peak_memory_usage_str' => $this->getDataFormatter()->formatBytes($pdo->getPeakMemoryUsage()), - 'statements' => $stmts - ); - } - - /** - * @return string - */ - public function getName() - { - return 'pdo'; - } - - /** - * @return array - */ - public function getWidgets() - { - return array( - "database" => array( - "icon" => "inbox", - "widget" => "PhpDebugBar.Widgets.SQLQueriesWidget", - "map" => "pdo", - "default" => "[]" - ), - "database:badge" => array( - "map" => "pdo.nb_statements", - "default" => 0 - ) - ); - } - - /** - * @return array - */ - public function getAssets() - { - return array( - 'css' => 'widgets/sqlqueries/widget.css', - 'js' => 'widgets/sqlqueries/widget.js' - ); - } + protected $connections = []; + protected $timeCollector; + protected $renderSqlWithParams = false; + protected $sqlQuotationChar = '<>'; + + /** + * @param TraceablePDO $pdo + * @param TimeDataCollector $timeCollector + */ + public function __construct(TraceablePDO $pdo = null, TimeDataCollector $timeCollector = null) + { + $this->timeCollector = $timeCollector; + if ($pdo !== null) { + $this->addConnection($pdo, 'default'); + } + } + + /** + * Renders the SQL of traced statements with params embeded. + * + * @param bool $enabled + */ + public function setRenderSqlWithParams($enabled = true, $quotationChar = '<>') + { + $this->renderSqlWithParams = $enabled; + $this->sqlQuotationChar = $quotationChar; + } + + /** + * @return bool + */ + public function isSqlRenderedWithParams() + { + return $this->renderSqlWithParams; + } + + /** + * @return string + */ + public function getSqlQuotationChar() + { + return $this->sqlQuotationChar; + } + + /** + * Adds a new PDO instance to be collector. + * + * @param TraceablePDO $pdo + * @param string $name Optional connection name + */ + public function addConnection(TraceablePDO $pdo, $name = null) + { + if ($name === null) { + $name = spl_object_hash($pdo); + } + $this->connections[$name] = $pdo; + } + + /** + * Returns PDO instances to be collected. + * + * @return array + */ + public function getConnections() + { + return $this->connections; + } + + /** + * @return array + */ + public function collect() + { + $data = [ + 'nb_statements' => 0, + 'nb_failed_statements' => 0, + 'accumulated_duration' => 0, + 'memory_usage' => 0, + 'peak_memory_usage' => 0, + 'statements' => [] + ]; + + foreach ($this->connections as $name => $pdo) { + $pdodata = $this->collectPDO($pdo, $this->timeCollector); + $data['nb_statements'] += $pdodata['nb_statements']; + $data['nb_failed_statements'] += $pdodata['nb_failed_statements']; + $data['accumulated_duration'] += $pdodata['accumulated_duration']; + $data['memory_usage'] += $pdodata['memory_usage']; + $data['peak_memory_usage'] = max($data['peak_memory_usage'], $pdodata['peak_memory_usage']); + $data['statements'] = array_merge($data['statements'], array_map(function ($s) use ($name) { + $s['connection'] = $name; + return $s; + }, $pdodata['statements'])); + } + + $data['accumulated_duration_str'] = $this->getDataFormatter()->formatDuration($data['accumulated_duration']); + $data['memory_usage_str'] = $this->getDataFormatter()->formatBytes($data['memory_usage']); + $data['peak_memory_usage_str'] = $this->getDataFormatter()->formatBytes($data['peak_memory_usage']); + + return $data; + } + + /** + * Collects data from a single TraceablePDO instance. + * + * @param TraceablePDO $pdo + * @param TimeDataCollector $timeCollector + * + * @return array + */ + protected function collectPDO(TraceablePDO $pdo, TimeDataCollector $timeCollector = null) + { + $stmts = []; + foreach ($pdo->getExecutedStatements() as $stmt) { + $stmts[] = [ + 'sql' => $this->renderSqlWithParams ? $stmt->getSqlWithParams($this->sqlQuotationChar) : $stmt->getSql(), + 'row_count' => $stmt->getRowCount(), + 'stmt_id' => $stmt->getPreparedId(), + 'prepared_stmt' => $stmt->getSql(), + 'params' => (object) $stmt->getParameters(), + 'duration' => $stmt->getDuration(), + 'duration_str' => $this->getDataFormatter()->formatDuration($stmt->getDuration()), + 'memory' => $stmt->getMemoryUsage(), + 'memory_str' => $this->getDataFormatter()->formatBytes($stmt->getMemoryUsage()), + 'end_memory' => $stmt->getEndMemory(), + 'end_memory_str' => $this->getDataFormatter()->formatBytes($stmt->getEndMemory()), + 'is_success' => $stmt->isSuccess(), + 'error_code' => $stmt->getErrorCode(), + 'error_message' => $stmt->getErrorMessage() + ]; + if ($timeCollector !== null) { + $timeCollector->addMeasure($stmt->getSql(), $stmt->getStartTime(), $stmt->getEndTime()); + } + } + + return [ + 'nb_statements' => count($stmts), + 'nb_failed_statements' => count($pdo->getFailedExecutedStatements()), + 'accumulated_duration' => $pdo->getAccumulatedStatementsDuration(), + 'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($pdo->getAccumulatedStatementsDuration()), + 'memory_usage' => $pdo->getMemoryUsage(), + 'memory_usage_str' => $this->getDataFormatter()->formatBytes($pdo->getPeakMemoryUsage()), + 'peak_memory_usage' => $pdo->getPeakMemoryUsage(), + 'peak_memory_usage_str' => $this->getDataFormatter()->formatBytes($pdo->getPeakMemoryUsage()), + 'statements' => $stmts + ]; + } + + /** + * @return string + */ + public function getName() + { + return 'pdo'; + } + + /** + * @return array + */ + public function getWidgets() + { + return [ + 'database' => [ + 'icon' => 'inbox', + 'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget', + 'map' => 'pdo', + 'default' => '[]' + ], + 'database:badge' => [ + 'map' => 'pdo.nb_statements', + 'default' => 0 + ] + ]; + } + + /** + * @return array + */ + public function getAssets() + { + return [ + 'css' => 'widgets/sqlqueries/widget.css', + 'js' => 'widgets/sqlqueries/widget.js' + ]; + } } diff --git a/src/DebugBar/DataCollector/PDO/TraceablePDO.php b/src/DebugBar/DataCollector/PDO/TraceablePDO.php index 8d1e2aa1..d5b4ced5 100644 --- a/src/DebugBar/DataCollector/PDO/TraceablePDO.php +++ b/src/DebugBar/DataCollector/PDO/TraceablePDO.php @@ -4,308 +4,339 @@ use PDO; use PDOException; -use DebugBar\DataCollector\PDO\TraceablePDOStatement; /** - * A PDO proxy which traces statements + * A PDO proxy which traces statements. */ class TraceablePDO extends PDO { - /** @var PDO */ - protected $pdo; + /** @var PDO */ + protected $pdo; - /** @var array */ - protected $executedStatements = array(); + /** @var array */ + protected $executedStatements = []; - public function __construct(PDO $pdo) - { - $this->pdo = $pdo; - $this->pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DebugBar\DataCollector\PDO\TraceablePDOStatement', array($this))); - } + public function __construct(PDO $pdo) + { + $this->pdo = $pdo; + $this->pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['DebugBar\DataCollector\PDO\TraceablePDOStatement', [$this]]); + } /** - * Initiates a transaction - * + * Initiates a transaction. + * * @link http://php.net/manual/en/pdo.begintransaction.php + * * @return bool TRUE on success or FALSE on failure. */ - public function beginTransaction() - { - return $this->pdo->beginTransaction(); - } - - /** - * Commits a transaction - * - * @link http://php.net/manual/en/pdo.commit.php - * @return bool TRUE on success or FALSE on failure. - */ - public function commit() - { - return $this->pdo->commit(); - } - - /** - * Fetch extended error information associated with the last operation on the database handle - * - * @link http://php.net/manual/en/pdo.errorinfo.php - * @return array PDO::errorInfo returns an array of error information - */ - public function errorCode() - { - return $this->pdo->errorCode(); - } - - /** - * Fetch extended error information associated with the last operation on the database handle - * - * @link http://php.net/manual/en/pdo.errorinfo.php - * @return array PDO::errorInfo returns an array of error information - */ - public function errorInfo() - { - return $this->pdo->errorInfo(); - } - - /** - * Execute an SQL statement and return the number of affected rows - * - * @link http://php.net/manual/en/pdo.exec.php - * @param string $statement - * @return int|bool PDO::exec returns the number of rows that were modified or deleted by the - * SQL statement you issued. If no rows were affected, PDO::exec returns 0. This function may - * return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. - * Please read the section on Booleans for more information - */ - public function exec($statement) - { - return $this->profileCall('exec', $statement, func_get_args()); - } - - /** - * Retrieve a database connection attribute - * - * @link http://php.net/manual/en/pdo.getattribute.php - * @param int $attribute One of the PDO::ATTR_* constants - * @return mixed A successful call returns the value of the requested PDO attribute. - * An unsuccessful call returns null. - */ - public function getAttribute($attribute) - { - return $this->pdo->getAttribute($attribute); - } - - /** - * Checks if inside a transaction - * - * @link http://php.net/manual/en/pdo.intransaction.php - * @return bool TRUE if a transaction is currently active, and FALSE if not. - */ - public function inTransaction() - { - return $this->pdo->inTransaction(); - } - - /** - * Returns the ID of the last inserted row or sequence value - * - * @link http://php.net/manual/en/pdo.lastinsertid.php - * @param string $name [optional] - * @return string If a sequence name was not specified for the name parameter, PDO::lastInsertId - * returns a string representing the row ID of the last row that was inserted into the database. - */ - public function lastInsertId($name = null) - { - return $this->pdo->lastInsertId($name); - } + public function beginTransaction() + { + return $this->pdo->beginTransaction(); + } /** - * Prepares a statement for execution and returns a statement object - * + * Commits a transaction. + * + * @link http://php.net/manual/en/pdo.commit.php + * + * @return bool TRUE on success or FALSE on failure. + */ + public function commit() + { + return $this->pdo->commit(); + } + + /** + * Fetch extended error information associated with the last operation on the database handle. + * + * @link http://php.net/manual/en/pdo.errorinfo.php + * + * @return array PDO::errorInfo returns an array of error information + */ + public function errorCode() + { + return $this->pdo->errorCode(); + } + + /** + * Fetch extended error information associated with the last operation on the database handle. + * + * @link http://php.net/manual/en/pdo.errorinfo.php + * + * @return array PDO::errorInfo returns an array of error information + */ + public function errorInfo() + { + return $this->pdo->errorInfo(); + } + + /** + * Execute an SQL statement and return the number of affected rows. + * + * @link http://php.net/manual/en/pdo.exec.php + * + * @param string $statement + * + * @return int|bool PDO::exec returns the number of rows that were modified or deleted by the + * SQL statement you issued. If no rows were affected, PDO::exec returns 0. This function may + * return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. + * Please read the section on Booleans for more information + */ + public function exec($statement) + { + return $this->profileCall('exec', $statement, func_get_args()); + } + + /** + * Retrieve a database connection attribute. + * + * @link http://php.net/manual/en/pdo.getattribute.php + * + * @param int $attribute One of the PDO::ATTR_* constants + * + * @return mixed A successful call returns the value of the requested PDO attribute. + * An unsuccessful call returns null. + */ + public function getAttribute($attribute) + { + return $this->pdo->getAttribute($attribute); + } + + /** + * Checks if inside a transaction. + * + * @link http://php.net/manual/en/pdo.intransaction.php + * + * @return bool TRUE if a transaction is currently active, and FALSE if not. + */ + public function inTransaction() + { + return $this->pdo->inTransaction(); + } + + /** + * Returns the ID of the last inserted row or sequence value. + * + * @link http://php.net/manual/en/pdo.lastinsertid.php + * + * @param string $name [optional] + * + * @return string If a sequence name was not specified for the name parameter, PDO::lastInsertId + * returns a string representing the row ID of the last row that was inserted into the database. + */ + public function lastInsertId($name = null) + { + return $this->pdo->lastInsertId($name); + } + + /** + * Prepares a statement for execution and returns a statement object. + * * @link http://php.net/manual/en/pdo.prepare.php - * @param string $statement This must be a valid SQL statement template for the target DB server. - * @param array $driver_options [optional] This array holds one or more key=>value pairs to - * set attribute values for the PDOStatement object that this method returns. + * + * @param string $statement This must be a valid SQL statement template for the target DB server. + * @param array $driver_options [optional] This array holds one or more key=>value pairs to + * set attribute values for the PDOStatement object that this method returns. + * * @return TraceablePDOStatement|bool If the database server successfully prepares the statement, - * PDO::prepare returns a PDOStatement object. If the database server cannot successfully prepare - * the statement, PDO::prepare returns FALSE or emits PDOException (depending on error handling). + * PDO::prepare returns a PDOStatement object. If the database server cannot successfully prepare + * the statement, PDO::prepare returns FALSE or emits PDOException (depending on error handling). */ - public function prepare($statement, $driver_options = array()) - { - return $this->pdo->prepare($statement, $driver_options); - } + public function prepare($statement, $driver_options = []) + { + return $this->pdo->prepare($statement, $driver_options); + } /** - * Executes an SQL statement, returning a result set as a PDOStatement object - * + * Executes an SQL statement, returning a result set as a PDOStatement object. + * * @link http://php.net/manual/en/pdo.query.php - * @param string $statement + * + * @param string $statement + * * @return TraceablePDOStatement|bool PDO::query returns a PDOStatement object, or FALSE on - * failure. - */ - public function query($statement) - { - return $this->profileCall('query', $statement, func_get_args()); - } - - /** - * Quotes a string for use in a query. - * - * @link http://php.net/manual/en/pdo.quote.php - * @param string $string The string to be quoted. - * @param int $parameter_type [optional] Provides a data type hint for drivers that have - * alternate quoting styles. - * @return string|bool A quoted string that is theoretically safe to pass into an SQL statement. - * Returns FALSE if the driver does not support quoting in this way. - */ - public function quote($string, $parameter_type = PDO::PARAM_STR) - { - return $this->pdo->quote($string, $parameter_type); - } - - /** - * Rolls back a transaction - * - * @link http://php.net/manual/en/pdo.rollback.php - * @return bool TRUE on success or FALSE on failure. - */ - public function rollBack() - { - return $this->pdo->rollBack(); - } - - /** - * Set an attribute - * - * @link http://php.net/manual/en/pdo.setattribute.php - * @param int $attribute - * @param mixed $value - * @return bool TRUE on success or FALSE on failure. - */ - public function setAttribute($attribute, $value) - { - return $this->pdo->setAttribute($attribute, $value); - } - - /** - * Profiles a call to a PDO method - * - * @param string $method - * @param string $sql - * @param array $args - * @return mixed The result of the call - */ - protected function profileCall($method, $sql, array $args) - { - $trace = new TracedStatement($sql); - $trace->start(); - - $ex = null; - try { - $result = call_user_func_array(array($this->pdo, $method), $args); - } catch (PDOException $e) { - $ex = $e; - } - - if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION && $result === false) { - $error = $this->pdo->errorInfo(); - $ex = new PDOException($error[2], $error[0]); - } - - $trace->end($ex); - $this->addExecutedStatement($trace); - - if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION && $ex !== null) { - throw $ex; - } - return $result; - } - - /** - * Adds an executed TracedStatement - * - * @param TracedStatement $stmt - */ - public function addExecutedStatement(TracedStatement $stmt) - { - $this->executedStatements[] = $stmt; - } - - /** - * Returns the accumulated execution time of statements - * - * @return int - */ - public function getAccumulatedStatementsDuration() - { - return array_reduce($this->executedStatements, function ($v, $s) { return $v + $s->getDuration(); }); - } - - /** - * Returns the peak memory usage while performing statements - * - * @return int - */ - public function getMemoryUsage() - { - return array_reduce($this->executedStatements, function ($v, $s) { return $v + $s->getMemoryUsage(); }); - } - - /** - * Returns the peak memory usage while performing statements - * - * @return int - */ - public function getPeakMemoryUsage() - { - return array_reduce($this->executedStatements, function ($v, $s) { $m = $s->getEndMemory(); return $m > $v ? $m : $v; }); - } - - /** - * Returns the list of executed statements as TracedStatement objects - * - * @return array - */ - public function getExecutedStatements() - { - return $this->executedStatements; - } - - /** - * Returns the list of failed statements - * - * @return array - */ - public function getFailedExecutedStatements() - { - return array_filter($this->executedStatements, function ($s) { return !$s->isSuccess(); }); - } - - /** - * @param $name - * @return mixed - */ - public function __get($name) - { - return $this->pdo->$name; - } - - /** - * @param $name - * @param $value - */ - public function __set($name, $value) - { - $this->pdo->$name = $value; - } - - /** - * @param $name - * @param $args - * @return mixed - */ - public function __call($name, $args) - { - return call_user_func_array(array($this->pdo, $name), $args); - } + * failure. + */ + public function query($statement) + { + return $this->profileCall('query', $statement, func_get_args()); + } + + /** + * Quotes a string for use in a query. + * + * @link http://php.net/manual/en/pdo.quote.php + * + * @param string $string The string to be quoted. + * @param int $parameter_type [optional] Provides a data type hint for drivers that have + * alternate quoting styles. + * + * @return string|bool A quoted string that is theoretically safe to pass into an SQL statement. + * Returns FALSE if the driver does not support quoting in this way. + */ + public function quote($string, $parameter_type = PDO::PARAM_STR) + { + return $this->pdo->quote($string, $parameter_type); + } + + /** + * Rolls back a transaction. + * + * @link http://php.net/manual/en/pdo.rollback.php + * + * @return bool TRUE on success or FALSE on failure. + */ + public function rollBack() + { + return $this->pdo->rollBack(); + } + + /** + * Set an attribute. + * + * @link http://php.net/manual/en/pdo.setattribute.php + * + * @param int $attribute + * @param mixed $value + * + * @return bool TRUE on success or FALSE on failure. + */ + public function setAttribute($attribute, $value) + { + return $this->pdo->setAttribute($attribute, $value); + } + + /** + * Profiles a call to a PDO method. + * + * @param string $method + * @param string $sql + * @param array $args + * + * @return mixed The result of the call + */ + protected function profileCall($method, $sql, array $args) + { + $trace = new TracedStatement($sql); + $trace->start(); + + $ex = null; + try { + $result = call_user_func_array([$this->pdo, $method], $args); + } catch (PDOException $e) { + $ex = $e; + } + + if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION && $result === false) { + $error = $this->pdo->errorInfo(); + $ex = new PDOException($error[2], $error[0]); + } + + $trace->end($ex); + $this->addExecutedStatement($trace); + + if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION && $ex !== null) { + throw $ex; + } + return $result; + } + + /** + * Adds an executed TracedStatement. + * + * @param TracedStatement $stmt + */ + public function addExecutedStatement(TracedStatement $stmt) + { + $this->executedStatements[] = $stmt; + } + + /** + * Returns the accumulated execution time of statements. + * + * @return int + */ + public function getAccumulatedStatementsDuration() + { + return array_reduce($this->executedStatements, function ($v, $s) { + return $v + $s->getDuration(); + }); + } + + /** + * Returns the peak memory usage while performing statements. + * + * @return int + */ + public function getMemoryUsage() + { + return array_reduce($this->executedStatements, function ($v, $s) { + return $v + $s->getMemoryUsage(); + }); + } + + /** + * Returns the peak memory usage while performing statements. + * + * @return int + */ + public function getPeakMemoryUsage() + { + return array_reduce($this->executedStatements, function ($v, $s) { + $m = $s->getEndMemory(); + return $m > $v ? $m : $v; + }); + } + + /** + * Returns the list of executed statements as TracedStatement objects. + * + * @return array + */ + public function getExecutedStatements() + { + return $this->executedStatements; + } + + /** + * Returns the list of failed statements. + * + * @return array + */ + public function getFailedExecutedStatements() + { + return array_filter($this->executedStatements, function ($s) { + return !$s->isSuccess(); + }); + } + + /** + * @param $name + * + * @return mixed + */ + public function __get($name) + { + return $this->pdo->$name; + } + + /** + * @param $name + * @param $value + */ + public function __set($name, $value) + { + $this->pdo->$name = $value; + } + + /** + * @param $name + * @param $args + * + * @return mixed + */ + public function __call($name, $args) + { + return call_user_func_array([$this->pdo, $name], $args); + } } diff --git a/src/DebugBar/DataCollector/PDO/TraceablePDOStatement.php b/src/DebugBar/DataCollector/PDO/TraceablePDOStatement.php index 58a83d89..affdcf1f 100644 --- a/src/DebugBar/DataCollector/PDO/TraceablePDOStatement.php +++ b/src/DebugBar/DataCollector/PDO/TraceablePDOStatement.php @@ -7,123 +7,131 @@ use PDOStatement; /** - * A traceable PDO statement to use with Traceablepdo + * A traceable PDO statement to use with Traceablepdo. */ class TraceablePDOStatement extends PDOStatement { - /** @var PDO */ - protected $pdo; + /** @var PDO */ + protected $pdo; - /** @var array */ - protected $boundParameters = array(); + /** @var array */ + protected $boundParameters = []; - /** - * TraceablePDOStatement constructor. - * - * @param TraceablePDO $pdo - */ - protected function __construct(TraceablePDO $pdo) - { - $this->pdo = $pdo; - } + /** + * TraceablePDOStatement constructor. + * + * @param TraceablePDO $pdo + */ + protected function __construct(TraceablePDO $pdo) + { + $this->pdo = $pdo; + } - /** - * Bind a column to a PHP variable - * - * @link http://php.net/manual/en/pdostatement.bindcolumn.php - * @param mixed $column Number of the column (1-indexed) or name of the column in the result set - * @param mixed $param Name of the PHP variable to which the column will be bound. - * @param int $type [optional] Data type of the parameter, specified by the PDO::PARAM_* - * constants. - * @param int $maxlen [optional] A hint for pre-allocation. - * @param mixed $driverdata [optional] Optional parameter(s) for the driver. - * @return bool TRUE on success or FALSE on failure. - */ - public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) - { - $this->boundParameters[$column] = $param; - $args = array_merge(array($column, &$param), array_slice(func_get_args(), 2)); - return call_user_func_array(array("parent", 'bindColumn'), $args); - } + /** + * Bind a column to a PHP variable. + * + * @link http://php.net/manual/en/pdostatement.bindcolumn.php + * + * @param mixed $column Number of the column (1-indexed) or name of the column in the result set + * @param mixed $param Name of the PHP variable to which the column will be bound. + * @param int $type [optional] Data type of the parameter, specified by the PDO::PARAM_* + * constants. + * @param int $maxlen [optional] A hint for pre-allocation. + * @param mixed $driverdata [optional] Optional parameter(s) for the driver. + * + * @return bool TRUE on success or FALSE on failure. + */ + public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) + { + $this->boundParameters[$column] = $param; + $args = array_merge([$column, &$param], array_slice(func_get_args(), 2)); + return call_user_func_array(['parent', 'bindColumn'], $args); + } - /** - * Binds a parameter to the specified variable name - * - * @link http://php.net/manual/en/pdostatement.bindparam.php - * @param mixed $parameter Parameter identifier. For a prepared statement using named - * placeholders, this will be a parameter name of the form :name. For a prepared statement using - * question mark placeholders, this will be the 1-indexed position of the parameter. - * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. - * @param int $data_type [optional] Explicit data type for the parameter using the PDO::PARAM_* - * constants. - * @param int $length [optional] Length of the data type. To indicate that a parameter is an OUT - * parameter from a stored procedure, you must explicitly set the length. - * @param mixed $driver_options [optional] - * @return bool TRUE on success or FALSE on failure. - */ - public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null) - { - $this->boundParameters[$parameter] = $variable; - $args = array_merge(array($parameter, &$variable), array_slice(func_get_args(), 2)); - return call_user_func_array(array("parent", 'bindParam'), $args); - } + /** + * Binds a parameter to the specified variable name. + * + * @link http://php.net/manual/en/pdostatement.bindparam.php + * + * @param mixed $parameter Parameter identifier. For a prepared statement using named + * placeholders, this will be a parameter name of the form :name. For a prepared statement using + * question mark placeholders, this will be the 1-indexed position of the parameter. + * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. + * @param int $data_type [optional] Explicit data type for the parameter using the PDO::PARAM_* + * constants. + * @param int $length [optional] Length of the data type. To indicate that a parameter is an OUT + * parameter from a stored procedure, you must explicitly set the length. + * @param mixed $driver_options [optional] + * + * @return bool TRUE on success or FALSE on failure. + */ + public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null) + { + $this->boundParameters[$parameter] = $variable; + $args = array_merge([$parameter, &$variable], array_slice(func_get_args(), 2)); + return call_user_func_array(['parent', 'bindParam'], $args); + } - /** - * Binds a value to a parameter - * - * @link http://php.net/manual/en/pdostatement.bindvalue.php - * @param mixed $parameter Parameter identifier. For a prepared statement using named - * placeholders, this will be a parameter name of the form :name. For a prepared statement using - * question mark placeholders, this will be the 1-indexed position of the parameter. - * @param mixed $value The value to bind to the parameter. - * @param int $data_type [optional] Explicit data type for the parameter using the PDO::PARAM_* - * constants. - * @return bool TRUE on success or FALSE on failure. - */ - public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR) - { - $this->boundParameters[$parameter] = $value; - return call_user_func_array(array("parent", 'bindValue'), func_get_args()); - } + /** + * Binds a value to a parameter. + * + * @link http://php.net/manual/en/pdostatement.bindvalue.php + * + * @param mixed $parameter Parameter identifier. For a prepared statement using named + * placeholders, this will be a parameter name of the form :name. For a prepared statement using + * question mark placeholders, this will be the 1-indexed position of the parameter. + * @param mixed $value The value to bind to the parameter. + * @param int $data_type [optional] Explicit data type for the parameter using the PDO::PARAM_* + * constants. + * + * @return bool TRUE on success or FALSE on failure. + */ + public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR) + { + $this->boundParameters[$parameter] = $value; + return call_user_func_array(['parent', 'bindValue'], func_get_args()); + } - /** - * Executes a prepared statement - * - * @link http://php.net/manual/en/pdostatement.execute.php - * @param array $input_parameters [optional] An array of values with as many elements as there - * are bound parameters in the SQL statement being executed. All values are treated as - * PDO::PARAM_STR. - * @return bool TRUE on success or FALSE on failure. - */ - public function execute($input_parameters = null) - { - $preparedId = spl_object_hash($this); - $boundParameters = $this->boundParameters; - if (is_array($input_parameters)) { - $boundParameters = array_merge($boundParameters, $input_parameters); - } + /** + * Executes a prepared statement. + * + * @link http://php.net/manual/en/pdostatement.execute.php + * + * @param array $input_parameters [optional] An array of values with as many elements as there + * are bound parameters in the SQL statement being executed. All values are treated as + * PDO::PARAM_STR. + * + * @return bool TRUE on success or FALSE on failure. + */ + public function execute($input_parameters = null) + { + $preparedId = spl_object_hash($this); + $boundParameters = $this->boundParameters; + if (is_array($input_parameters)) { + $boundParameters = array_merge($boundParameters, $input_parameters); + } - $trace = new TracedStatement($this->queryString, $boundParameters, $preparedId); - $trace->start(); + $trace = new TracedStatement($this->queryString, $boundParameters, $preparedId); + $trace->start(); - $ex = null; - try { - $result = parent::execute($input_parameters); - } catch (PDOException $e) { - $ex = $e; - } + $ex = null; + try { + $result = parent::execute($input_parameters); + } catch (PDOException $e) { + $ex = $e; + } - if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION && $result === false) { - $error = $this->errorInfo(); - $ex = new PDOException($error[2], (int) $error[0]); - } + if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) !== PDO::ERRMODE_EXCEPTION && $result === false) { + $error = $this->errorInfo(); + $ex = new PDOException($error[2], (int) $error[0]); + } - $trace->end($ex, $this->rowCount()); - $this->pdo->addExecutedStatement($trace); + $trace->end($ex, $this->rowCount()); + $this->pdo->addExecutedStatement($trace); - if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION && $ex !== null) { - throw $ex; - } - return $result; - } + if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION && $ex !== null) { + throw $ex; + } + return $result; + } } diff --git a/src/DebugBar/DataCollector/PDO/TracedStatement.php b/src/DebugBar/DataCollector/PDO/TracedStatement.php index 1ccc583f..bad48d58 100644 --- a/src/DebugBar/DataCollector/PDO/TracedStatement.php +++ b/src/DebugBar/DataCollector/PDO/TracedStatement.php @@ -3,255 +3,248 @@ namespace DebugBar\DataCollector\PDO; /** - * Holds information about a statement + * Holds information about a statement. */ class TracedStatement { - protected $sql; - - protected $rowCount; - - protected $parameters; - - protected $startTime; - - protected $endTime; - - protected $duration; - - protected $startMemory; - - protected $endMemory; - - protected $memoryDelta; - - protected $exception; - - /** - * @param string $sql - * @param array $params - * @param string $preparedId - */ - public function __construct($sql, array $params = array(), $preparedId = null) - { - $this->sql = $sql; - $this->parameters = $this->checkParameters($params); - $this->preparedId = $preparedId; - } - - /** - * @param null $startTime - * @param null $startMemory - */ - public function start($startTime = null, $startMemory = null) - { - $this->startTime = $startTime ?: microtime(true); - $this->startMemory = $startMemory ?: memory_get_usage(true); - } - - /** - * @param \Exception|null $exception - * @param int $rowCount - * @param null $endTime - * @param null $endMemory - */ - public function end(\Exception $exception = null, $rowCount = 0, $endTime = null, $endMemory = null) - { - $this->endTime = $endTime ?: microtime(true); - $this->duration = $this->endTime - $this->startTime; - $this->endMemory = $endMemory ?: memory_get_usage(true); - $this->memoryDelta = $this->endMemory - $this->startMemory; - $this->exception = $exception; - $this->rowCount = $rowCount; - } - - /** - * Check parameters for illegal (non UTF-8) strings, like Binary data. - * - * @param $params - * @return mixed - */ - public function checkParameters($params) - { - foreach ($params as &$param) { - if (!mb_check_encoding($param, 'UTF-8')) { - $param = '[BINARY DATA]'; - } - } - return $params; - } - - /** - * Returns the SQL string used for the query - * - * @return string - */ - public function getSql() - { - return $this->sql; - } - - /** - * Returns the SQL string with any parameters used embedded - * - * @param string $quotationChar - * @return string - */ - public function getSqlWithParams($quotationChar = '<>') - { - if (($l = strlen($quotationChar)) > 1) { - $quoteLeft = substr($quotationChar, 0, $l / 2); - $quoteRight = substr($quotationChar, $l / 2); - } else { - $quoteLeft = $quoteRight = $quotationChar; - } - - $sql = $this->sql; - foreach ($this->parameters as $k => $v) { - $v = "$quoteLeft$v$quoteRight"; - if (!is_numeric($k)) { - $sql = str_replace($k, $v, $sql); - } else { - $p = strpos($sql, '?'); - $sql = substr($sql, 0, $p) . $v. substr($sql, $p + 1); - } - } - return $sql; - } - - /** - * Returns the number of rows affected/returned - * - * @return int - */ - public function getRowCount() - { - return $this->rowCount; - } - - /** - * Returns an array of parameters used with the query - * - * @return array - */ - public function getParameters() - { - $params = array(); - foreach ($this->parameters as $name => $param) { - $params[$name] = htmlentities($param, ENT_QUOTES, 'UTF-8', false); - } - return $params; - } - - /** - * Returns the prepared statement id - * - * @return string - */ - public function getPreparedId() - { - return $this->preparedId; - } - - /** - * Checks if this is a prepared statement - * - * @return boolean - */ - public function isPrepared() - { - return $this->preparedId !== null; - } - - /** - * @return mixed - */ - public function getStartTime() - { - return $this->startTime; - } - - /** - * @return mixed - */ - public function getEndTime() - { - return $this->endTime; - } - - /** - * Returns the duration in seconds of the execution - * - * @return int - */ - public function getDuration() - { - return $this->duration; - } - - /** - * @return mixed - */ - public function getStartMemory() - { - return $this->startMemory; - } - - /** - * @return mixed - */ - public function getEndMemory() - { - return $this->endMemory; - } - - /** - * Returns the memory usage during the execution - * - * @return int - */ - public function getMemoryUsage() - { - return $this->memoryDelta; - } - - /** - * Checks if the statement was successful - * - * @return boolean - */ - public function isSuccess() - { - return $this->exception === null; - } - - /** - * Returns the exception triggered - * - * @return \Exception - */ - public function getException() - { - return $this->exception; - } - - /** - * Returns the exception's code - * - * @return string - */ - public function getErrorCode() - { - return $this->exception !== null ? $this->exception->getCode() : 0; - } - - /** - * Returns the exception's message - * - * @return string - */ - public function getErrorMessage() - { - return $this->exception !== null ? $this->exception->getMessage() : ''; - } + protected $sql; + protected $rowCount; + protected $parameters; + protected $startTime; + protected $endTime; + protected $duration; + protected $startMemory; + protected $endMemory; + protected $memoryDelta; + protected $exception; + + /** + * @param string $sql + * @param array $params + * @param string $preparedId + */ + public function __construct($sql, array $params = [], $preparedId = null) + { + $this->sql = $sql; + $this->parameters = $this->checkParameters($params); + $this->preparedId = $preparedId; + } + + /** + * @param null $startTime + * @param null $startMemory + */ + public function start($startTime = null, $startMemory = null) + { + $this->startTime = $startTime ?: microtime(true); + $this->startMemory = $startMemory ?: memory_get_usage(true); + } + + /** + * @param \Exception|null $exception + * @param int $rowCount + * @param null $endTime + * @param null $endMemory + */ + public function end(\Exception $exception = null, $rowCount = 0, $endTime = null, $endMemory = null) + { + $this->endTime = $endTime ?: microtime(true); + $this->duration = $this->endTime - $this->startTime; + $this->endMemory = $endMemory ?: memory_get_usage(true); + $this->memoryDelta = $this->endMemory - $this->startMemory; + $this->exception = $exception; + $this->rowCount = $rowCount; + } + + /** + * Check parameters for illegal (non UTF-8) strings, like Binary data. + * + * @param $params + * + * @return mixed + */ + public function checkParameters($params) + { + foreach ($params as &$param) { + if (!mb_check_encoding($param, 'UTF-8')) { + $param = '[BINARY DATA]'; + } + } + return $params; + } + + /** + * Returns the SQL string used for the query. + * + * @return string + */ + public function getSql() + { + return $this->sql; + } + + /** + * Returns the SQL string with any parameters used embedded. + * + * @param string $quotationChar + * + * @return string + */ + public function getSqlWithParams($quotationChar = '<>') + { + if (($l = strlen($quotationChar)) > 1) { + $quoteLeft = substr($quotationChar, 0, $l / 2); + $quoteRight = substr($quotationChar, $l / 2); + } else { + $quoteLeft = $quoteRight = $quotationChar; + } + + $sql = $this->sql; + foreach ($this->parameters as $k => $v) { + $v = "$quoteLeft$v$quoteRight"; + if (!is_numeric($k)) { + $sql = str_replace($k, $v, $sql); + } else { + $p = strpos($sql, '?'); + $sql = substr($sql, 0, $p) . $v . substr($sql, $p + 1); + } + } + return $sql; + } + + /** + * Returns the number of rows affected/returned. + * + * @return int + */ + public function getRowCount() + { + return $this->rowCount; + } + + /** + * Returns an array of parameters used with the query. + * + * @return array + */ + public function getParameters() + { + $params = []; + foreach ($this->parameters as $name => $param) { + $params[$name] = htmlentities($param, ENT_QUOTES, 'UTF-8', false); + } + return $params; + } + + /** + * Returns the prepared statement id. + * + * @return string + */ + public function getPreparedId() + { + return $this->preparedId; + } + + /** + * Checks if this is a prepared statement. + * + * @return bool + */ + public function isPrepared() + { + return $this->preparedId !== null; + } + + /** + * @return mixed + */ + public function getStartTime() + { + return $this->startTime; + } + + /** + * @return mixed + */ + public function getEndTime() + { + return $this->endTime; + } + + /** + * Returns the duration in seconds of the execution. + * + * @return int + */ + public function getDuration() + { + return $this->duration; + } + + /** + * @return mixed + */ + public function getStartMemory() + { + return $this->startMemory; + } + + /** + * @return mixed + */ + public function getEndMemory() + { + return $this->endMemory; + } + + /** + * Returns the memory usage during the execution. + * + * @return int + */ + public function getMemoryUsage() + { + return $this->memoryDelta; + } + + /** + * Checks if the statement was successful. + * + * @return bool + */ + public function isSuccess() + { + return $this->exception === null; + } + + /** + * Returns the exception triggered. + * + * @return \Exception + */ + public function getException() + { + return $this->exception; + } + + /** + * Returns the exception's code. + * + * @return string + */ + public function getErrorCode() + { + return $this->exception !== null ? $this->exception->getCode() : 0; + } + + /** + * Returns the exception's message. + * + * @return string + */ + public function getErrorMessage() + { + return $this->exception !== null ? $this->exception->getMessage() : ''; + } } diff --git a/src/DebugBar/DataCollector/PhpInfoCollector.php b/src/DebugBar/DataCollector/PhpInfoCollector.php index 89019479..d486e9b6 100644 --- a/src/DebugBar/DataCollector/PhpInfoCollector.php +++ b/src/DebugBar/DataCollector/PhpInfoCollector.php @@ -11,26 +11,26 @@ namespace DebugBar\DataCollector; /** - * Collects info about PHP + * Collects info about PHP. */ class PhpInfoCollector extends DataCollector { - /** - * @return array - */ - public function collect() - { - return array( - 'version' => PHP_VERSION, - 'interface' => PHP_SAPI - ); - } + /** + * @return array + */ + public function collect() + { + return [ + 'version' => PHP_VERSION, + 'interface' => PHP_SAPI + ]; + } - /** - * @return string - */ - public function getName() - { - return 'php'; - } + /** + * @return string + */ + public function getName() + { + return 'php'; + } } diff --git a/src/DebugBar/DataCollector/Renderable.php b/src/DebugBar/DataCollector/Renderable.php index 1a6a833f..4379b712 100644 --- a/src/DebugBar/DataCollector/Renderable.php +++ b/src/DebugBar/DataCollector/Renderable.php @@ -11,15 +11,15 @@ namespace DebugBar\DataCollector; /** - * Indicates that a DataCollector is renderable using JavascriptRenderer + * Indicates that a DataCollector is renderable using JavascriptRenderer. */ interface Renderable { - /** - * Returns a hash where keys are control names and their values - * an array of options as defined in {@see DebugBar\JavascriptRenderer::addControl()} - * - * @return array - */ - function getWidgets(); + /** + * 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(); } diff --git a/src/DebugBar/DataCollector/RequestDataCollector.php b/src/DebugBar/DataCollector/RequestDataCollector.php index 6306e488..37da039a 100644 --- a/src/DebugBar/DataCollector/RequestDataCollector.php +++ b/src/DebugBar/DataCollector/RequestDataCollector.php @@ -11,47 +11,47 @@ namespace DebugBar\DataCollector; /** - * Collects info about the current request + * Collects info about the current request. */ class RequestDataCollector extends DataCollector implements Renderable { - /** - * @return array - */ - public function collect() - { - $vars = array('_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER'); - $data = array(); + /** + * @return array + */ + public function collect() + { + $vars = ['_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER']; + $data = []; - foreach ($vars as $var) { - if (isset($GLOBALS[$var])) { - $data["$" . $var] = $this->getDataFormatter()->formatVar($GLOBALS[$var]); - } - } + foreach ($vars as $var) { + if (isset($GLOBALS[$var])) { + $data['$' . $var] = $this->getDataFormatter()->formatVar($GLOBALS[$var]); + } + } - return $data; - } + return $data; + } - /** - * @return string - */ - public function getName() - { - return 'request'; - } + /** + * @return string + */ + public function getName() + { + return 'request'; + } - /** - * @return array - */ - public function getWidgets() - { - return array( - "request" => array( - "icon" => "tags", - "widget" => "PhpDebugBar.Widgets.VariableListWidget", - "map" => "request", - "default" => "{}" - ) - ); - } + /** + * @return array + */ + public function getWidgets() + { + return [ + 'request' => [ + 'icon' => 'tags', + 'widget' => 'PhpDebugBar.Widgets.VariableListWidget', + 'map' => 'request', + 'default' => '{}' + ] + ]; + } } diff --git a/src/DebugBar/DataCollector/TimeDataCollector.php b/src/DebugBar/DataCollector/TimeDataCollector.php index 5bbed41a..9ef744bb 100644 --- a/src/DebugBar/DataCollector/TimeDataCollector.php +++ b/src/DebugBar/DataCollector/TimeDataCollector.php @@ -14,225 +14,224 @@ /** * Collects info about the request duration as well as providing - * a way to log duration of any operations + * a way to log duration of any operations. */ class TimeDataCollector extends DataCollector implements Renderable { - /** - * @var float - */ - protected $requestStartTime; - - /** - * @var float - */ - protected $requestEndTime; - - /** - * @var array - */ - protected $startedMeasures = array(); - - /** - * @var array - */ - protected $measures = array(); - - /** - * @param float $requestStartTime - */ - public function __construct($requestStartTime = null) - { - if ($requestStartTime === null) { - if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { - $requestStartTime = $_SERVER['REQUEST_TIME_FLOAT']; - } else { - $requestStartTime = microtime(true); - } - } - $this->requestStartTime = $requestStartTime; - } - - /** - * Starts a measure - * - * @param string $name Internal name, used to stop the measure - * @param string|null $label Public name - * @param string|null $collector The source of the collector - */ - public function startMeasure($name, $label = null, $collector = null) - { - $start = microtime(true); - $this->startedMeasures[$name] = array( - 'label' => $label ?: $name, - 'start' => $start, - 'collector' => $collector - ); - } - - /** - * Check a measure exists - * - * @param string $name - * @return bool - */ - public function hasStartedMeasure($name) - { - return isset($this->startedMeasures[$name]); - } - - /** - * Stops a measure - * - * @param string $name - * @param array $params - * @throws DebugBarException - */ - public function stopMeasure($name, $params = array()) - { - $end = microtime(true); - if (!$this->hasStartedMeasure($name)) { - throw new DebugBarException("Failed stopping measure '$name' because it hasn't been started"); - } - $this->addMeasure( - $this->startedMeasures[$name]['label'], - $this->startedMeasures[$name]['start'], - $end, - $params, - $this->startedMeasures[$name]['collector'] - ); - unset($this->startedMeasures[$name]); - } - - /** - * Adds a measure - * - * @param string $label - * @param float $start - * @param float $end - * @param array $params - * @param string|null $collector - */ - public function addMeasure($label, $start, $end, $params = array(), $collector = null) - { - $this->measures[] = array( - 'label' => $label, - 'start' => $start, - 'relative_start' => $start - $this->requestStartTime, - 'end' => $end, - 'relative_end' => $end - $this->requestEndTime, - 'duration' => $end - $start, - 'duration_str' => $this->getDataFormatter()->formatDuration($end - $start), - 'params' => $params, - 'collector' => $collector - ); - } - - /** - * Utility function to measure the execution of a Closure - * - * @param string $label - * @param \Closure $closure - * @param string|null $collector - */ - public function measure($label, \Closure $closure, $collector = null) - { - $name = spl_object_hash($closure); - $this->startMeasure($name, $label, $collector); - $result = $closure(); - $params = is_array($result) ? $result : array(); - $this->stopMeasure($name, $params); - } - - /** - * Returns an array of all measures - * - * @return array - */ - public function getMeasures() - { - return $this->measures; - } - - /** - * Returns the request start time - * - * @return float - */ - public function getRequestStartTime() - { - return $this->requestStartTime; - } - - /** - * Returns the request end time - * - * @return float - */ - public function getRequestEndTime() - { - return $this->requestEndTime; - } - - /** - * Returns the duration of a request - * - * @return float - */ - public function getRequestDuration() - { - if ($this->requestEndTime !== null) { - return $this->requestEndTime - $this->requestStartTime; - } - return microtime(true) - $this->requestStartTime; - } - - /** - * @return array - * @throws DebugBarException - */ - public function collect() - { - $this->requestEndTime = microtime(true); - foreach (array_keys($this->startedMeasures) as $name) { - $this->stopMeasure($name); - } - - return array( - 'start' => $this->requestStartTime, - 'end' => $this->requestEndTime, - 'duration' => $this->getRequestDuration(), - 'duration_str' => $this->getDataFormatter()->formatDuration($this->getRequestDuration()), - 'measures' => array_values($this->measures) - ); - } - - /** - * @return string - */ - public function getName() - { - return 'time'; - } - - /** - * @return array - */ - public function getWidgets() - { - return array( - "time" => array( - "icon" => "clock-o", - "tooltip" => "Request Duration", - "map" => "time.duration_str", - "default" => "'0ms'" - ), - "timeline" => array( - "icon" => "tasks", - "widget" => "PhpDebugBar.Widgets.TimelineWidget", - "map" => "time", - "default" => "{}" - ) - ); - } + /** + * @var float + */ + protected $requestStartTime; + + /** + * @var float + */ + protected $requestEndTime; + + /** + * @var array + */ + protected $startedMeasures = []; + + /** + * @var array + */ + protected $measures = []; + + /** + * @param float $requestStartTime + */ + public function __construct($requestStartTime = null) + { + if ($requestStartTime === null) { + if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { + $requestStartTime = $_SERVER['REQUEST_TIME_FLOAT']; + } else { + $requestStartTime = microtime(true); + } + } + $this->requestStartTime = $requestStartTime; + } + + /** + * Starts a measure. + * + * @param string $name Internal name, used to stop the measure + * @param string|null $label Public name + * @param string|null $collector The source of the collector + */ + public function startMeasure($name, $label = null, $collector = null) + { + $start = microtime(true); + $this->startedMeasures[$name] = [ + 'label' => $label ?: $name, + 'start' => $start, + 'collector' => $collector + ]; + } + + /** + * Check a measure exists. + * + * @param string $name + * + * @return bool + */ + public function hasStartedMeasure($name) + { + return isset($this->startedMeasures[$name]); + } + + /** + * Stops a measure. + * + * @param string $name + * @param array $params + * + * @throws DebugBarException + */ + public function stopMeasure($name, $params = []) + { + $end = microtime(true); + if (!$this->hasStartedMeasure($name)) { + throw new DebugBarException("Failed stopping measure '$name' because it hasn't been started"); + } + $this->addMeasure( + $this->startedMeasures[$name]['label'], $this->startedMeasures[$name]['start'], $end, $params, $this->startedMeasures[$name]['collector'] + ); + unset($this->startedMeasures[$name]); + } + + /** + * Adds a measure. + * + * @param string $label + * @param float $start + * @param float $end + * @param array $params + * @param string|null $collector + */ + public function addMeasure($label, $start, $end, $params = [], $collector = null) + { + $this->measures[] = [ + 'label' => $label, + 'start' => $start, + 'relative_start' => $start - $this->requestStartTime, + 'end' => $end, + 'relative_end' => $end - $this->requestEndTime, + 'duration' => $end - $start, + 'duration_str' => $this->getDataFormatter()->formatDuration($end - $start), + 'params' => $params, + 'collector' => $collector + ]; + } + + /** + * Utility function to measure the execution of a Closure. + * + * @param string $label + * @param \Closure $closure + * @param string|null $collector + */ + public function measure($label, \Closure $closure, $collector = null) + { + $name = spl_object_hash($closure); + $this->startMeasure($name, $label, $collector); + $result = $closure(); + $params = is_array($result) ? $result : []; + $this->stopMeasure($name, $params); + } + + /** + * Returns an array of all measures. + * + * @return array + */ + public function getMeasures() + { + return $this->measures; + } + + /** + * Returns the request start time. + * + * @return float + */ + public function getRequestStartTime() + { + return $this->requestStartTime; + } + + /** + * Returns the request end time. + * + * @return float + */ + public function getRequestEndTime() + { + return $this->requestEndTime; + } + + /** + * Returns the duration of a request. + * + * @return float + */ + public function getRequestDuration() + { + if ($this->requestEndTime !== null) { + return $this->requestEndTime - $this->requestStartTime; + } + return microtime(true) - $this->requestStartTime; + } + + /** + * @throws DebugBarException + * + * @return array + */ + public function collect() + { + $this->requestEndTime = microtime(true); + foreach (array_keys($this->startedMeasures) as $name) { + $this->stopMeasure($name); + } + + return [ + 'start' => $this->requestStartTime, + 'end' => $this->requestEndTime, + 'duration' => $this->getRequestDuration(), + 'duration_str' => $this->getDataFormatter()->formatDuration($this->getRequestDuration()), + 'measures' => array_values($this->measures) + ]; + } + + /** + * @return string + */ + public function getName() + { + return 'time'; + } + + /** + * @return array + */ + public function getWidgets() + { + return [ + 'time' => [ + 'icon' => 'clock-o', + 'tooltip' => 'Request Duration', + 'map' => 'time.duration_str', + 'default' => "'0ms'" + ], + 'timeline' => [ + 'icon' => 'tasks', + 'widget' => 'PhpDebugBar.Widgets.TimelineWidget', + 'map' => 'time', + 'default' => '{}' + ] + ]; + } } diff --git a/src/DebugBar/DataFormatter/DataFormatter.php b/src/DebugBar/DataFormatter/DataFormatter.php index 7ffb1989..14614682 100644 --- a/src/DebugBar/DataFormatter/DataFormatter.php +++ b/src/DebugBar/DataFormatter/DataFormatter.php @@ -15,67 +15,69 @@ class DataFormatter implements DataFormatterInterface { - /** - * DataFormatter constructor. - */ - public function __construct() - { - $this->cloner = new VarCloner(); - $this->dumper = new CliDumper(); - } + /** + * DataFormatter constructor. + */ + public function __construct() + { + $this->cloner = new VarCloner(); + $this->dumper = new CliDumper(); + } - /** - * @param $data - * @return string - */ - public function formatVar($data) - { - $output = ''; + /** + * @param $data + * + * @return string + */ + public function formatVar($data) + { + $output = ''; - $this->dumper->dump( - $this->cloner->cloneVar($data), - function ($line, $depth) use (&$output) { - // A negative depth means "end of dump" - if ($depth >= 0) { - // Adds a two spaces indentation to the line - $output .= str_repeat(' ', $depth).$line."\n"; - } - } - ); + $this->dumper->dump( + $this->cloner->cloneVar($data), function ($line, $depth) use (&$output) { + // A negative depth means "end of dump" + if ($depth >= 0) { + // Adds a two spaces indentation to the line + $output .= str_repeat(' ', $depth) . $line . "\n"; + } + } + ); - return trim($output); - } + return trim($output); + } - /** - * @param float $seconds - * @return string - */ - public function formatDuration($seconds) - { - if ($seconds < 0.001) { - return round($seconds * 1000000) . 'μs'; - } elseif ($seconds < 1) { - return round($seconds * 1000, 2) . 'ms'; - } - return round($seconds, 2) . 's'; - } + /** + * @param float $seconds + * + * @return string + */ + public function formatDuration($seconds) + { + if ($seconds < 0.001) { + return round($seconds * 1000000) . 'μs'; + } elseif ($seconds < 1) { + return round($seconds * 1000, 2) . 'ms'; + } + return round($seconds, 2) . 's'; + } - /** - * @param string $size - * @param int $precision - * @return string - */ - public function formatBytes($size, $precision = 2) - { - if ($size === 0 || $size === null) { - return "0B"; - } + /** + * @param string $size + * @param int $precision + * + * @return string + */ + public function formatBytes($size, $precision = 2) + { + if ($size === 0 || $size === null) { + return '0B'; + } - $sign = $size < 0 ? '-' : ''; - $size = abs($size); + $sign = $size < 0 ? '-' : ''; + $size = abs($size); - $base = log($size) / log(1024); - $suffixes = array('B', 'KB', 'MB', 'GB', 'TB'); - return $sign . round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; - } + $base = log($size) / log(1024); + $suffixes = ['B', 'KB', 'MB', 'GB', 'TB']; + return $sign . round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; + } } diff --git a/src/DebugBar/DataFormatter/DataFormatterInterface.php b/src/DebugBar/DataFormatter/DataFormatterInterface.php index cb7b426e..b2d26ae5 100644 --- a/src/DebugBar/DataFormatter/DataFormatterInterface.php +++ b/src/DebugBar/DataFormatter/DataFormatterInterface.php @@ -11,32 +11,35 @@ namespace DebugBar\DataFormatter; /** - * Formats data to be outputed as string + * Formats data to be outputed as string. */ interface DataFormatterInterface { - /** - * Transforms a PHP variable to a string representation - * - * @param mixed $var - * @return string - */ - function formatVar($data); + /** + * Transforms a PHP variable to a string representation. + * + * @param mixed $var + * + * @return string + */ + public function formatVar($data); - /** - * Transforms a duration in seconds in a readable string - * - * @param float $seconds - * @return string - */ - function formatDuration($seconds); + /** + * Transforms a duration in seconds in a readable string. + * + * @param float $seconds + * + * @return string + */ + public function formatDuration($seconds); - /** - * Transforms a size in bytes to a human readable string - * - * @param string $size - * @param integer $precision - * @return string - */ - function formatBytes($size, $precision = 2); + /** + * Transforms a size in bytes to a human readable string. + * + * @param string $size + * @param int $precision + * + * @return string + */ + public function formatBytes($size, $precision = 2); } diff --git a/src/DebugBar/DebugBar.php b/src/DebugBar/DebugBar.php index d771d2a7..c76c812b 100644 --- a/src/DebugBar/DebugBar.php +++ b/src/DebugBar/DebugBar.php @@ -15,7 +15,7 @@ use DebugBar\Storage\StorageInterface; /** - * Main DebugBar object + * Main DebugBar object. * * Manages data collectors. DebugBar provides an array-like access * to collectors by name. @@ -28,447 +28,454 @@ */ class DebugBar implements ArrayAccess { - public static $useOpenHandlerWhenSendingDataHeaders = false; - - protected $collectors = array(); - - protected $data; - - protected $jsRenderer; - - protected $requestIdGenerator; - - protected $requestId; - - protected $storage; - - protected $httpDriver; - - protected $stackSessionNamespace = 'PHPDEBUGBAR_STACK_DATA'; - - protected $stackAlwaysUseSessionStorage = false; - - /** - * Adds a data collector - * - * @param DataCollectorInterface $collector - * - * @throws DebugBarException - * @return $this - */ - public function addCollector(DataCollectorInterface $collector) - { - if ($collector->getName() === '__meta') { - throw new DebugBarException("'__meta' is a reserved name and cannot be used as a collector name"); - } - if (isset($this->collectors[$collector->getName()])) { - throw new DebugBarException("'{$collector->getName()}' is already a registered collector"); - } - $this->collectors[$collector->getName()] = $collector; - return $this; - } - - /** - * Checks if a data collector has been added - * - * @param string $name - * @return boolean - */ - public function hasCollector($name) - { - return isset($this->collectors[$name]); - } - - /** - * Returns a data collector - * - * @param string $name - * @return DataCollectorInterface - * @throws DebugBarException - */ - public function getCollector($name) - { - if (!isset($this->collectors[$name])) { - throw new DebugBarException("'$name' is not a registered collector"); - } - return $this->collectors[$name]; - } - - /** - * Returns an array of all data collectors - * - * @return array[DataCollectorInterface] - */ - public function getCollectors() - { - return $this->collectors; - } - - /** - * Sets the request id generator - * - * @param RequestIdGeneratorInterface $generator - * @return $this - */ - public function setRequestIdGenerator(RequestIdGeneratorInterface $generator) - { - $this->requestIdGenerator = $generator; - return $this; - } - - /** - * @return RequestIdGeneratorInterface - */ - public function getRequestIdGenerator() - { - if ($this->requestIdGenerator === null) { - $this->requestIdGenerator = new RequestIdGenerator(); - } - return $this->requestIdGenerator; - } - - /** - * Returns the id of the current request - * - * @return string - */ - public function getCurrentRequestId() - { - if ($this->requestId === null) { - $this->requestId = $this->getRequestIdGenerator()->generate(); - } - return $this->requestId; - } - - /** - * Sets the storage backend to use to store the collected data - * - * @param StorageInterface $storage - * @return $this - */ - public function setStorage(StorageInterface $storage = null) - { - $this->storage = $storage; - return $this; - } - - /** - * @return StorageInterface - */ - public function getStorage() - { - return $this->storage; - } - - /** - * Checks if the data will be persisted - * - * @return boolean - */ - public function isDataPersisted() - { - return $this->storage !== null; - } - - /** - * Sets the HTTP driver - * - * @param HttpDriverInterface $driver - * @return $this - */ - public function setHttpDriver(HttpDriverInterface $driver) - { - $this->httpDriver = $driver; - return $this; - } - - /** - * Returns the HTTP driver - * - * If no http driver where defined, a PhpHttpDriver is automatically created - * - * @return HttpDriverInterface - */ - public function getHttpDriver() - { - if ($this->httpDriver === null) { - $this->httpDriver = new PhpHttpDriver(); - } - return $this->httpDriver; - } - - /** - * Collects the data from the collectors - * - * @return array - */ - public function collect() - { - $this->data = array( - '__meta' => array( - 'id' => $this->getCurrentRequestId(), - 'datetime' => date('Y-m-d H:i:s'), - 'utime' => microtime(true), - '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 - ) - ); - - foreach ($this->collectors as $name => $collector) { - $this->data[$name] = $collector->collect(); - } - - // Remove all invalid (non UTF-8) characters - array_walk_recursive($this->data, function (&$item) { - if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) { - $item = mb_convert_encoding($item, 'UTF-8', 'UTF-8'); - } - }); - - if ($this->storage !== null) { - $this->storage->save($this->getCurrentRequestId(), $this->data); - } - - return $this->data; - } - - /** - * Returns collected data - * - * Will collect the data if none have been collected yet - * - * @return array - */ - public function getData() - { - if ($this->data === null) { - $this->collect(); - } - return $this->data; - } - - /** - * Returns an array of HTTP headers containing the data - * - * @param string $headerName - * @param integer $maxHeaderLength - * @return array - */ - public function getDataAsHeaders($headerName = 'phpdebugbar', $maxHeaderLength = 4096, $maxTotalHeaderLength = 250000) - { - $data = rawurlencode(json_encode(array( - 'id' => $this->getCurrentRequestId(), - 'data' => $this->getData() - ))); - - if (strlen($data) > $maxTotalHeaderLength) { - $data = rawurlencode(json_encode(array( - 'error' => 'Maximum header size exceeded' - ))); - } - - $chunks = array(); - - while (strlen($data) > $maxHeaderLength) { - $chunks[] = substr($data, 0, $maxHeaderLength); - $data = substr($data, $maxHeaderLength); - } - $chunks[] = $data; - - $headers = array(); - for ($i = 0, $c = count($chunks); $i < $c; $i++) { - $name = $headerName . ($i > 0 ? "-$i" : ''); - $headers[$name] = $chunks[$i]; - } - - return $headers; - } - - /** - * Sends the data through the HTTP headers - * - * @param bool $useOpenHandler - * @param string $headerName - * @param integer $maxHeaderLength - * @return $this - */ - public function sendDataInHeaders($useOpenHandler = null, $headerName = 'phpdebugbar', $maxHeaderLength = 4096) - { - if ($useOpenHandler === null) { - $useOpenHandler = self::$useOpenHandlerWhenSendingDataHeaders; - } - if ($useOpenHandler && $this->storage !== null) { - $this->getData(); - $headerName .= '-id'; - $headers = array($headerName => $this->getCurrentRequestId()); - } else { - $headers = $this->getDataAsHeaders($headerName, $maxHeaderLength); - } - $this->getHttpDriver()->setHeaders($headers); - return $this; - } - - /** - * Stacks the data in the session for later rendering - */ - public function stackData() - { - $http = $this->initStackSession(); - - $data = null; - if (!$this->isDataPersisted() || $this->stackAlwaysUseSessionStorage) { - $data = $this->getData(); - } elseif ($this->data === null) { - $this->collect(); - } - - $stack = $http->getSessionValue($this->stackSessionNamespace); - $stack[$this->getCurrentRequestId()] = $data; - $http->setSessionValue($this->stackSessionNamespace, $stack); - return $this; - } - - /** - * Checks if there is stacked data in the session - * - * @return boolean - */ - public function hasStackedData() - { - try { - $http = $this->initStackSession(); - } catch (DebugBarException $e) { - return false; - } - return count($http->getSessionValue($this->stackSessionNamespace)) > 0; - } - - /** - * Returns the data stacked in the session - * - * @param boolean $delete Whether to delete the data in the session - * @return array - */ - public function getStackedData($delete = true) - { - $http = $this->initStackSession(); - $stackedData = $http->getSessionValue($this->stackSessionNamespace); - if ($delete) { - $http->deleteSessionValue($this->stackSessionNamespace); - } - - $datasets = array(); - if ($this->isDataPersisted() && !$this->stackAlwaysUseSessionStorage) { - foreach ($stackedData as $id => $data) { - $datasets[$id] = $this->getStorage()->get($id); - } - } else { - $datasets = $stackedData; - } - - return $datasets; - } - - /** - * Sets the key to use in the $_SESSION array - * - * @param string $ns - * @return $this - */ - public function setStackDataSessionNamespace($ns) - { - $this->stackSessionNamespace = $ns; - return $this; - } - - /** - * Returns the key used in the $_SESSION array - * - * @return string - */ - public function getStackDataSessionNamespace() - { - return $this->stackSessionNamespace; - } - - /** - * Sets whether to only use the session to store stacked data even - * if a storage is enabled - * - * @param boolean $enabled - * @return $this - */ - public function setStackAlwaysUseSessionStorage($enabled = true) - { - $this->stackAlwaysUseSessionStorage = $enabled; - return $this; - } - - /** - * Checks if the session is always used to store stacked data - * even if a storage is enabled - * - * @return boolean - */ - public function isStackAlwaysUseSessionStorage() - { - return $this->stackAlwaysUseSessionStorage; - } - - /** - * Initializes the session for stacked data - * @return HttpDriverInterface - * @throws DebugBarException - */ - protected function initStackSession() - { - $http = $this->getHttpDriver(); - if (!$http->isSessionStarted()) { - throw new DebugBarException("Session must be started before using stack data in the debug bar"); - } - - if (!$http->hasSessionValue($this->stackSessionNamespace)) { - $http->setSessionValue($this->stackSessionNamespace, array()); - } - - return $http; - } - - /** - * Returns a JavascriptRenderer for this instance - * @param string $baseUrl - * @param string $basePath - * @return JavascriptRenderer - */ - public function getJavascriptRenderer($baseUrl = null, $basePath = null) - { - if ($this->jsRenderer === null) { - $this->jsRenderer = new JavascriptRenderer($this, $baseUrl, $basePath); - } - return $this->jsRenderer; - } - - // -------------------------------------------- - // ArrayAccess implementation - - public function offsetSet($key, $value) - { - throw new DebugBarException("DebugBar[] is read-only"); - } - - public function offsetGet($key) - { - return $this->getCollector($key); - } - - public function offsetExists($key) - { - return $this->hasCollector($key); - } - - public function offsetUnset($key) - { - throw new DebugBarException("DebugBar[] is read-only"); - } + public static $useOpenHandlerWhenSendingDataHeaders = false; + protected $collectors = []; + protected $data; + protected $jsRenderer; + protected $requestIdGenerator; + protected $requestId; + protected $storage; + protected $httpDriver; + protected $stackSessionNamespace = 'PHPDEBUGBAR_STACK_DATA'; + protected $stackAlwaysUseSessionStorage = false; + + /** + * Adds a data collector. + * + * @param DataCollectorInterface $collector + * + * @throws DebugBarException + * + * @return $this + */ + public function addCollector(DataCollectorInterface $collector) + { + if ($collector->getName() === '__meta') { + throw new DebugBarException("'__meta' is a reserved name and cannot be used as a collector name"); + } + if (isset($this->collectors[$collector->getName()])) { + throw new DebugBarException("'{$collector->getName()}' is already a registered collector"); + } + $this->collectors[$collector->getName()] = $collector; + return $this; + } + + /** + * Checks if a data collector has been added. + * + * @param string $name + * + * @return bool + */ + public function hasCollector($name) + { + return isset($this->collectors[$name]); + } + + /** + * Returns a data collector. + * + * @param string $name + * + * @throws DebugBarException + * + * @return DataCollectorInterface + */ + public function getCollector($name) + { + if (!isset($this->collectors[$name])) { + throw new DebugBarException("'$name' is not a registered collector"); + } + return $this->collectors[$name]; + } + + /** + * Returns an array of all data collectors. + * + * @return array[DataCollectorInterface] + */ + public function getCollectors() + { + return $this->collectors; + } + + /** + * Sets the request id generator. + * + * @param RequestIdGeneratorInterface $generator + * + * @return $this + */ + public function setRequestIdGenerator(RequestIdGeneratorInterface $generator) + { + $this->requestIdGenerator = $generator; + return $this; + } + + /** + * @return RequestIdGeneratorInterface + */ + public function getRequestIdGenerator() + { + if ($this->requestIdGenerator === null) { + $this->requestIdGenerator = new RequestIdGenerator(); + } + return $this->requestIdGenerator; + } + + /** + * Returns the id of the current request. + * + * @return string + */ + public function getCurrentRequestId() + { + if ($this->requestId === null) { + $this->requestId = $this->getRequestIdGenerator()->generate(); + } + return $this->requestId; + } + + /** + * Sets the storage backend to use to store the collected data. + * + * @param StorageInterface $storage + * + * @return $this + */ + public function setStorage(StorageInterface $storage = null) + { + $this->storage = $storage; + return $this; + } + + /** + * @return StorageInterface + */ + public function getStorage() + { + return $this->storage; + } + + /** + * Checks if the data will be persisted. + * + * @return bool + */ + public function isDataPersisted() + { + return $this->storage !== null; + } + + /** + * Sets the HTTP driver. + * + * @param HttpDriverInterface $driver + * + * @return $this + */ + public function setHttpDriver(HttpDriverInterface $driver) + { + $this->httpDriver = $driver; + return $this; + } + + /** + * Returns the HTTP driver. + * + * If no http driver where defined, a PhpHttpDriver is automatically created + * + * @return HttpDriverInterface + */ + public function getHttpDriver() + { + if ($this->httpDriver === null) { + $this->httpDriver = new PhpHttpDriver(); + } + return $this->httpDriver; + } + + /** + * Collects the data from the collectors. + * + * @return array + */ + public function collect() + { + $this->data = [ + '__meta' => [ + 'id' => $this->getCurrentRequestId(), + 'datetime' => date('Y-m-d H:i:s'), + 'utime' => microtime(true), + 'method' => $_SERVER['REQUEST_METHOD'] ?? null, + 'uri' => $_SERVER['REQUEST_URI'] ?? null, + 'ip' => $_SERVER['REMOTE_ADDR'] ?? null + ] + ]; + + foreach ($this->collectors as $name => $collector) { + $this->data[$name] = $collector->collect(); + } + + // Remove all invalid (non UTF-8) characters + array_walk_recursive($this->data, function (&$item) { + if (is_string($item) && !mb_check_encoding($item, 'UTF-8')) { + $item = mb_convert_encoding($item, 'UTF-8', 'UTF-8'); + } + }); + + if ($this->storage !== null) { + $this->storage->save($this->getCurrentRequestId(), $this->data); + } + + return $this->data; + } + + /** + * Returns collected data. + * + * Will collect the data if none have been collected yet + * + * @return array + */ + public function getData() + { + if ($this->data === null) { + $this->collect(); + } + return $this->data; + } + + /** + * Returns an array of HTTP headers containing the data. + * + * @param string $headerName + * @param int $maxHeaderLength + * + * @return array + */ + public function getDataAsHeaders($headerName = 'phpdebugbar', $maxHeaderLength = 4096, $maxTotalHeaderLength = 250000) + { + $data = rawurlencode(json_encode([ + 'id' => $this->getCurrentRequestId(), + 'data' => $this->getData() + ])); + + if (strlen($data) > $maxTotalHeaderLength) { + $data = rawurlencode(json_encode([ + 'error' => 'Maximum header size exceeded' + ])); + } + + $chunks = []; + + while (strlen($data) > $maxHeaderLength) { + $chunks[] = substr($data, 0, $maxHeaderLength); + $data = substr($data, $maxHeaderLength); + } + $chunks[] = $data; + + $headers = []; + for ($i = 0, $c = count($chunks); $i < $c; $i++) { + $name = $headerName . ($i > 0 ? "-$i" : ''); + $headers[$name] = $chunks[$i]; + } + + return $headers; + } + + /** + * Sends the data through the HTTP headers. + * + * @param bool $useOpenHandler + * @param string $headerName + * @param int $maxHeaderLength + * + * @return $this + */ + public function sendDataInHeaders($useOpenHandler = null, $headerName = 'phpdebugbar', $maxHeaderLength = 4096) + { + if ($useOpenHandler === null) { + $useOpenHandler = self::$useOpenHandlerWhenSendingDataHeaders; + } + if ($useOpenHandler && $this->storage !== null) { + $this->getData(); + $headerName .= '-id'; + $headers = [$headerName => $this->getCurrentRequestId()]; + } else { + $headers = $this->getDataAsHeaders($headerName, $maxHeaderLength); + } + $this->getHttpDriver()->setHeaders($headers); + return $this; + } + + /** + * Stacks the data in the session for later rendering. + */ + public function stackData() + { + $http = $this->initStackSession(); + + $data = null; + if (!$this->isDataPersisted() || $this->stackAlwaysUseSessionStorage) { + $data = $this->getData(); + } elseif ($this->data === null) { + $this->collect(); + } + + $stack = $http->getSessionValue($this->stackSessionNamespace); + $stack[$this->getCurrentRequestId()] = $data; + $http->setSessionValue($this->stackSessionNamespace, $stack); + return $this; + } + + /** + * Checks if there is stacked data in the session. + * + * @return bool + */ + public function hasStackedData() + { + try { + $http = $this->initStackSession(); + } catch (DebugBarException $e) { + return false; + } + return count($http->getSessionValue($this->stackSessionNamespace)) > 0; + } + + /** + * Returns the data stacked in the session. + * + * @param bool $delete Whether to delete the data in the session + * + * @return array + */ + public function getStackedData($delete = true) + { + $http = $this->initStackSession(); + $stackedData = $http->getSessionValue($this->stackSessionNamespace); + if ($delete) { + $http->deleteSessionValue($this->stackSessionNamespace); + } + + $datasets = []; + if ($this->isDataPersisted() && !$this->stackAlwaysUseSessionStorage) { + foreach ($stackedData as $id => $data) { + $datasets[$id] = $this->getStorage()->get($id); + } + } else { + $datasets = $stackedData; + } + + return $datasets; + } + + /** + * Sets the key to use in the $_SESSION array. + * + * @param string $ns + * + * @return $this + */ + public function setStackDataSessionNamespace($ns) + { + $this->stackSessionNamespace = $ns; + return $this; + } + + /** + * Returns the key used in the $_SESSION array. + * + * @return string + */ + public function getStackDataSessionNamespace() + { + return $this->stackSessionNamespace; + } + + /** + * Sets whether to only use the session to store stacked data even + * if a storage is enabled. + * + * @param bool $enabled + * + * @return $this + */ + public function setStackAlwaysUseSessionStorage($enabled = true) + { + $this->stackAlwaysUseSessionStorage = $enabled; + return $this; + } + + /** + * Checks if the session is always used to store stacked data + * even if a storage is enabled. + * + * @return bool + */ + public function isStackAlwaysUseSessionStorage() + { + return $this->stackAlwaysUseSessionStorage; + } + + /** + * Initializes the session for stacked data. + * + * @throws DebugBarException + * + * @return HttpDriverInterface + */ + protected function initStackSession() + { + $http = $this->getHttpDriver(); + if (!$http->isSessionStarted()) { + throw new DebugBarException('Session must be started before using stack data in the debug bar'); + } + + if (!$http->hasSessionValue($this->stackSessionNamespace)) { + $http->setSessionValue($this->stackSessionNamespace, []); + } + + return $http; + } + + /** + * Returns a JavascriptRenderer for this instance. + * + * @param string $baseUrl + * @param string $basePath + * + * @return JavascriptRenderer + */ + public function getJavascriptRenderer($baseUrl = null, $basePath = null) + { + if ($this->jsRenderer === null) { + $this->jsRenderer = new JavascriptRenderer($this, $baseUrl, $basePath); + } + return $this->jsRenderer; + } + + // -------------------------------------------- + // ArrayAccess implementation + + public function offsetSet($key, $value) + { + throw new DebugBarException('DebugBar[] is read-only'); + } + + public function offsetGet($key) + { + return $this->getCollector($key); + } + + public function offsetExists($key) + { + return $this->hasCollector($key); + } + + public function offsetUnset($key) + { + throw new DebugBarException('DebugBar[] is read-only'); + } } diff --git a/src/DebugBar/DebugBarException.php b/src/DebugBar/DebugBarException.php index 32ffe255..892694cd 100644 --- a/src/DebugBar/DebugBarException.php +++ b/src/DebugBar/DebugBarException.php @@ -12,5 +12,4 @@ class DebugBarException extends \Exception { - // } diff --git a/src/DebugBar/HttpDriverInterface.php b/src/DebugBar/HttpDriverInterface.php index 1a7a3cf4..5c99d1fe 100644 --- a/src/DebugBar/HttpDriverInterface.php +++ b/src/DebugBar/HttpDriverInterface.php @@ -12,53 +12,56 @@ /** * Provides an abstraction of PHP native features for easier integration - * in third party frameworks + * in third party frameworks. */ interface HttpDriverInterface { - /** - * Sets HTTP headers - * - * @param array $headers - * @return - */ - function setHeaders(array $headers); + /** + * Sets HTTP headers. + * + * @param array $headers + * + * @return + */ + public function setHeaders(array $headers); - /** - * Checks if the session is started - * - * @return boolean - */ - function isSessionStarted(); + /** + * Checks if the session is started. + * + * @return bool + */ + public function isSessionStarted(); - /** - * Sets a value in the session - * - * @param string $name - * @param string $value - */ - function setSessionValue($name, $value); + /** + * Sets a value in the session. + * + * @param string $name + * @param string $value + */ + public function setSessionValue($name, $value); - /** - * Checks if a value is in the session - * - * @param string $name - * @return boolean - */ - function hasSessionValue($name); + /** + * Checks if a value is in the session. + * + * @param string $name + * + * @return bool + */ + public function hasSessionValue($name); - /** - * Returns a value from the session - * - * @param string $name - * @return mixed - */ - function getSessionValue($name); + /** + * Returns a value from the session. + * + * @param string $name + * + * @return mixed + */ + public function getSessionValue($name); - /** - * Deletes a value from the session - * - * @param string $name - */ - function deleteSessionValue($name); + /** + * Deletes a value from the session. + * + * @param string $name + */ + public function deleteSessionValue($name); } diff --git a/src/DebugBar/JavascriptRenderer.php b/src/DebugBar/JavascriptRenderer.php index 73d8404b..3424bcb0 100644 --- a/src/DebugBar/JavascriptRenderer.php +++ b/src/DebugBar/JavascriptRenderer.php @@ -14,989 +14,956 @@ use DebugBar\DataCollector\Renderable; /** - * Renders the debug bar using the client side javascript implementation + * Renders the debug bar using the client side javascript implementation. * * Generates all the needed initialization code of controls */ class JavascriptRenderer { - const INITIALIZE_CONSTRUCTOR = 2; - - const INITIALIZE_CONTROLS = 4; - - const REPLACEABLE_TAG = "{--DEBUGBAR_OB_START_REPLACE_ME--}"; - - const RELATIVE_PATH = 'path'; - - const RELATIVE_URL = 'url'; - - protected $debugBar; - - protected $baseUrl; - - protected $basePath; - - protected $cssVendors = array( - 'fontawesome' => 'vendor/font-awesome/css/font-awesome.min.css', - 'highlightjs' => 'vendor/highlightjs/styles/github.css' - ); - - protected $jsVendors = array( - 'jquery' => 'vendor/jquery/dist/jquery.min.js', - 'highlightjs' => 'vendor/highlightjs/highlight.pack.js' - ); - - protected $includeVendors = true; - - protected $cssFiles = array('debugbar.css', 'widgets.css', 'openhandler.css'); - - protected $jsFiles = array('debugbar.js', 'widgets.js', 'openhandler.js'); - - protected $additionalAssets = array(); - - protected $javascriptClass = 'PhpDebugBar.DebugBar'; - - protected $variableName = 'phpdebugbar'; - - protected $enableJqueryNoConflict = true; - - protected $useRequireJs = false; - - protected $initialization; - - protected $controls = array(); - - protected $ignoredCollectors = array(); - - protected $ajaxHandlerClass = 'PhpDebugBar.AjaxHandler'; - - protected $ajaxHandlerBindToJquery = true; - - protected $ajaxHandlerBindToXHR = false; - - protected $openHandlerClass = 'PhpDebugBar.OpenHandler'; - - protected $openHandlerUrl; - - /** - * @param \DebugBar\DebugBar $debugBar - * @param string $baseUrl - * @param string $basePath - */ - public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null) - { - $this->debugBar = $debugBar; - - if ($baseUrl === null) { - $baseUrl = '/vendor/maximebf/debugbar/src/DebugBar/Resources'; - } - $this->baseUrl = $baseUrl; - - if ($basePath === null) { - $basePath = __DIR__ . DIRECTORY_SEPARATOR . 'Resources'; - } - $this->basePath = $basePath; - - // bitwise operations cannot be done in class definition :( - $this->initialization = self::INITIALIZE_CONSTRUCTOR | self::INITIALIZE_CONTROLS; - } - - /** - * Sets options from an array - * - * Options: - * - base_path - * - base_url - * - include_vendors - * - javascript_class - * - variable_name - * - initialization - * - enable_jquery_noconflict - * - controls - * - disable_controls - * - ignore_collectors - * - ajax_handler_classname - * - ajax_handler_bind_to_jquery - * - open_handler_classname - * - open_handler_url - * - * @param array $options [description] - */ - public function setOptions(array $options) - { - if (array_key_exists('base_path', $options)) { - $this->setBasePath($options['base_path']); - } - if (array_key_exists('base_url', $options)) { - $this->setBaseUrl($options['base_url']); - } - if (array_key_exists('include_vendors', $options)) { - $this->setIncludeVendors($options['include_vendors']); - } - if (array_key_exists('javascript_class', $options)) { - $this->setJavascriptClass($options['javascript_class']); - } - if (array_key_exists('variable_name', $options)) { - $this->setVariableName($options['variable_name']); - } - if (array_key_exists('initialization', $options)) { - $this->setInitialization($options['initialization']); - } - if (array_key_exists('enable_jquery_noconflict', $options)) { - $this->setEnableJqueryNoConflict($options['enable_jquery_noconflict']); - } - if (array_key_exists('use_requirejs', $options)) { - $this->setUseRequireJs($options['use_requirejs']); - } - if (array_key_exists('controls', $options)) { - foreach ($options['controls'] as $name => $control) { - $this->addControl($name, $control); - } - } - if (array_key_exists('disable_controls', $options)) { - foreach ((array) $options['disable_controls'] as $name) { - $this->disableControl($name); - } - } - if (array_key_exists('ignore_collectors', $options)) { - foreach ((array) $options['ignore_collectors'] as $name) { - $this->ignoreCollector($name); - } - } - if (array_key_exists('ajax_handler_classname', $options)) { - $this->setAjaxHandlerClass($options['ajax_handler_classname']); - } - if (array_key_exists('ajax_handler_bind_to_jquery', $options)) { - $this->setBindAjaxHandlerToJquery($options['ajax_handler_bind_to_jquery']); - } - if (array_key_exists('open_handler_classname', $options)) { - $this->setOpenHandlerClass($options['open_handler_classname']); - } - if (array_key_exists('open_handler_url', $options)) { - $this->setOpenHandlerUrl($options['open_handler_url']); - } - } - - /** - * Sets the path which assets are relative to - * - * @param string $path - */ - public function setBasePath($path) - { - $this->basePath = $path; - return $this; - } - - /** - * Returns the path which assets are relative to - * - * @return string - */ - public function getBasePath() - { - return $this->basePath; - } - - /** - * Sets the base URL from which assets will be served - * - * @param string $url - */ - public function setBaseUrl($url) - { - $this->baseUrl = $url; - return $this; - } - - /** - * Returns the base URL from which assets will be served - * - * @return string - */ - public function getBaseUrl() - { - return $this->baseUrl; - } - - /** - * Whether to include vendor assets - * - * You can only include js or css vendors using - * setIncludeVendors('css') or setIncludeVendors('js') - * - * @param boolean $enabled - */ - public function setIncludeVendors($enabled = true) - { - if (is_string($enabled)) { - $enabled = array($enabled); - } - $this->includeVendors = $enabled; - - if (!$enabled || (is_array($enabled) && !in_array('js', $enabled))) { - // no need to call jQuery.noConflict() if we do not include our own version - $this->enableJqueryNoConflict = false; - } - - return $this; - } - - /** - * Checks if vendors assets are included - * - * @return boolean - */ - public function areVendorsIncluded() - { - return $this->includeVendors !== false; - } - - /** - * Disable a specific vendor's assets. - * - * @param string $name "jquery", "fontawesome", "highlightjs" - * - * @return void - */ - public function disableVendor($name) - { - if (array_key_exists($name, $this->cssVendors)) { - unset($this->cssVendors[$name]); - } - if (array_key_exists($name, $this->jsVendors)) { - unset($this->jsVendors[$name]); - } - } - - /** - * Sets the javascript class name - * - * @param string $className - */ - public function setJavascriptClass($className) - { - $this->javascriptClass = $className; - return $this; - } - - /** - * Returns the javascript class name - * - * @return string - */ - public function getJavascriptClass() - { - return $this->javascriptClass; - } - - /** - * Sets the variable name of the class instance - * - * @param string $name - */ - public function setVariableName($name) - { - $this->variableName = $name; - return $this; - } - - /** - * Returns the variable name of the class instance - * - * @return string - */ - public function getVariableName() - { - return $this->variableName; - } - - /** - * Sets what should be initialized - * - * - INITIALIZE_CONSTRUCTOR: only initializes the instance - * - INITIALIZE_CONTROLS: initializes the controls and data mapping - * - INITIALIZE_CONSTRUCTOR | INITIALIZE_CONTROLS: initialize everything (default) - * - * @param integer $init - */ - public function setInitialization($init) - { - $this->initialization = $init; - return $this; - } - - /** - * Returns what should be initialized - * - * @return integer - */ - public function getInitialization() - { - return $this->initialization; - } - - /** - * Sets whether to call jQuery.noConflict() - * - * @param boolean $enabled - */ - public function setEnableJqueryNoConflict($enabled = true) - { - $this->enableJqueryNoConflict = $enabled; - return $this; - } - - /** - * Checks if jQuery.noConflict() will be called - * - * @return boolean - */ - public function isJqueryNoConflictEnabled() - { - return $this->enableJqueryNoConflict; - } - - /** - * Sets whether to use RequireJS or not - * - * @param boolean $enabled - * @return $this - */ - public function setUseRequireJs($enabled = true) - { - $this->useRequireJs = $enabled; - return $this; - } - - /** - * Checks if RequireJS is used - * - * @return boolean - */ - public function isRequireJsUsed() - { - return $this->useRequireJs; - } - - /** - * Adds a control to initialize - * - * Possible options: - * - icon: icon name - * - tooltip: string - * - widget: widget class name - * - title: tab title - * - map: a property name from the data to map the control to - * - default: a js string, default value of the data map - * - * "icon" or "widget" are at least needed - * - * @param string $name - * @param array $options - */ - public function addControl($name, array $options) - { - if (count(array_intersect(array_keys($options), array('icon', 'widget', 'tab', 'indicator'))) === 0) { - throw new DebugBarException("Not enough options for control '$name'"); - } - $this->controls[$name] = $options; - return $this; - } - - /** - * Disables a control - * - * @param string $name - */ - public function disableControl($name) - { - $this->controls[$name] = null; - return $this; - } - - /** - * Returns the list of controls - * - * This does not include controls provided by collectors - * - * @return array - */ - public function getControls() - { - return $this->controls; - } - - /** - * Ignores widgets provided by a collector - * - * @param string $name - */ - public function ignoreCollector($name) - { - $this->ignoredCollectors[] = $name; - return $this; - } - - /** - * Returns the list of ignored collectors - * - * @return array - */ - public function getIgnoredCollectors() - { - return $this->ignoredCollectors; - } - - /** - * Sets the class name of the ajax handler - * - * Set to false to disable - * - * @param string $className - */ - public function setAjaxHandlerClass($className) - { - $this->ajaxHandlerClass = $className; - return $this; - } - - /** - * Returns the class name of the ajax handler - * - * @return string - */ - public function getAjaxHandlerClass() - { - return $this->ajaxHandlerClass; - } - - /** - * Sets whether to call bindToJquery() on the ajax handler - * - * @param boolean $bind - */ - public function setBindAjaxHandlerToJquery($bind = true) - { - $this->ajaxHandlerBindToJquery = $bind; - return $this; - } - - /** - * Checks whether bindToJquery() will be called on the ajax handler - * - * @return boolean - */ - public function isAjaxHandlerBoundToJquery() - { - return $this->ajaxHandlerBindToJquery; - } - - /** - * Sets whether to call bindToXHR() on the ajax handler - * - * @param boolean $bind - */ - public function setBindAjaxHandlerToXHR($bind = true) - { - $this->ajaxHandlerBindToXHR = $bind; - return $this; - } - - /** - * Checks whether bindToXHR() will be called on the ajax handler - * - * @return boolean - */ - public function isAjaxHandlerBoundToXHR() - { - return $this->ajaxHandlerBindToXHR; - } - - /** - * Sets the class name of the js open handler - * - * @param string $className - */ - public function setOpenHandlerClass($className) - { - $this->openHandlerClass = $className; - return $this; - } - - /** - * Returns the class name of the js open handler - * - * @return string - */ - public function getOpenHandlerClass() - { - return $this->openHandlerClass; - } - - /** - * Sets the url of the open handler - * - * @param string $url - */ - public function setOpenHandlerUrl($url) - { - $this->openHandlerUrl = $url; - return $this; - } - - /** - * Returns the url for the open handler - * - * @return string - */ - public function getOpenHandlerUrl() - { - return $this->openHandlerUrl; - } - - /** - * Add assets 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 - */ - public function addAssets($cssFiles, $jsFiles, $basePath = null, $baseUrl = null) - { - $this->additionalAssets[] = array( - 'base_path' => $basePath, - 'base_url' => $baseUrl, - 'css' => (array) $cssFiles, - 'js' => (array) $jsFiles - ); - return $this; - } - - /** - * Returns the list of asset files - * - * @param string $type Only return css or js files - * @param string $relativeTo The type of path to which filenames must be relative (path, url or null) - * @return array - */ - public function getAssets($type = null, $relativeTo = self::RELATIVE_PATH) - { - $cssFiles = $this->cssFiles; - $jsFiles = $this->jsFiles; - - if ($this->includeVendors !== false) { - if ($this->includeVendors === true || in_array('css', $this->includeVendors)) { - $cssFiles = array_merge($this->cssVendors, $cssFiles); - } - if ($this->includeVendors === true || in_array('js', $this->includeVendors)) { - $jsFiles = array_merge($this->jsVendors, $jsFiles); - } - } - - if ($relativeTo) { - $root = $this->getRelativeRoot($relativeTo, $this->basePath, $this->baseUrl); - $cssFiles = $this->makeUriRelativeTo($cssFiles, $root); - $jsFiles = $this->makeUriRelativeTo($jsFiles, $root); - } - - $additionalAssets = $this->additionalAssets; - // finds assets provided by collectors - foreach ($this->debugBar->getCollectors() as $collector) { - if (($collector instanceof AssetProvider) && !in_array($collector->getName(), $this->ignoredCollectors)) { - $additionalAssets[] = $collector->getAssets(); - } - } - - foreach ($additionalAssets as $assets) { - $basePath = isset($assets['base_path']) ? $assets['base_path'] : null; - $baseUrl = isset($assets['base_url']) ? $assets['base_url'] : null; - $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)); - } - - return $this->filterAssetArray(array($cssFiles, $jsFiles), $type); - } - - /** - * Returns the correct base according to the type - * - * @param string $relativeTo - * @param string $basePath - * @param string $baseUrl - * @return string - */ - protected function getRelativeRoot($relativeTo, $basePath, $baseUrl) - { - if ($relativeTo === self::RELATIVE_PATH) { - return $basePath; - } - if ($relativeTo === self::RELATIVE_URL) { - return $baseUrl; - } - return null; - } - - /** - * Makes a URI relative to another - * - * @param string|array $uri - * @param string $root - * @return string - */ - protected function makeUriRelativeTo($uri, $root) - { - if (!$root) { - return $uri; - } - - if (is_array($uri)) { - $uris = array(); - foreach ($uri as $u) { - $uris[] = $this->makeUriRelativeTo($u, $root); - } - return $uris; - } - - if (substr($uri, 0, 1) === '/' || preg_match('/^([a-zA-Z]+:\/\/|[a-zA-Z]:\/|[a-zA-Z]:\\\)/', $uri)) { - return $uri; - } - return rtrim($root, '/') . "/$uri"; - } - - /** - * Filters a tuple of (css, js) assets according to $type - * - * @param array $array - * @param string $type 'css', 'js' or null for both - * @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; - } - - /** - * Returns a tuple where the both items are Assetic AssetCollection, - * the first one being css files and the second js files - * - * @param string $type Only return css or js collection - * @return array or \Assetic\Asset\AssetCollection - */ - public function getAsseticCollection($type = null) - { - list($cssFiles, $jsFiles) = $this->getAssets(); - return $this->filterAssetArray(array( - $this->createAsseticCollection($cssFiles), - $this->createAsseticCollection($jsFiles) - ), $type); - } - - /** - * Create an Assetic AssetCollection with the given files. - * Filenames will be converted to absolute path using - * the base path. - * - * @param array $files - * @return \Assetic\Asset\AssetCollection - */ - protected function createAsseticCollection($files) - { - $assets = array(); - foreach ($files as $file) { - $assets[] = new \Assetic\Asset\FileAsset($file); - } - return new \Assetic\Asset\AssetCollection($assets); - } - - /** - * Write all CSS assets to standard output or in a file - * - * @param string $targetFilename - */ - public function dumpCssAssets($targetFilename = null) - { - $this->dumpAssets($this->getAssets('css'), $targetFilename); - } - - /** - * Write all JS assets to standard output or in a file - * - * @param string $targetFilename - */ - public function dumpJsAssets($targetFilename = null) - { - $this->dumpAssets($this->getAssets('js'), $targetFilename, $this->useRequireJs); - } - - /** - * Write assets to standard output or in a file - * - * @param array $files - * @param string $targetFilename - * @param bool $useRequireJs - */ - protected function dumpAssets($files, $targetFilename = null, $useRequireJs = false) - { - $content = ''; - foreach ($files as $file) { - $content .= file_get_contents($file) . "\n"; - } - if ($useRequireJs) { - $content = "define('debugbar', ['jquery'], function($){\r\n" . $content . "\r\n return PhpDebugBar; \r\n});"; - } - if ($targetFilename !== null) { - file_put_contents($targetFilename, $content); - } else { - echo $content; - } - } - - /** - * Renders the html to include needed assets - * - * Only useful if Assetic is not used - * - * @return string - */ - public function renderHead() - { - list($cssFiles, $jsFiles) = $this->getAssets(null, self::RELATIVE_URL); - $html = ''; - - foreach ($cssFiles as $file) { - $html .= sprintf('' . "\n", $file); - } - - foreach ($jsFiles as $file) { - $html .= sprintf('' . "\n", $file); - } - - if ($this->enableJqueryNoConflict && !$this->useRequireJs) { - $html .= '' . "\n"; - } - - return $html; - } - - /** - * Register shutdown to display the debug bar - * - * @param boolean $here Set position of HTML. True if is to current position or false for end file - * @param boolean $initialize Whether to render the de bug bar initialization code - * @param bool $renderStackedData - * @param bool $head - * @return string Return "{--DEBUGBAR_OB_START_REPLACE_ME--}" or return an empty string if $here == false - */ - public function renderOnShutdown($here = true, $initialize = true, $renderStackedData = true, $head = false) - { - register_shutdown_function(array($this, "replaceTagInBuffer"), $here, $initialize, $renderStackedData, $head); - - if (ob_get_level() === 0) { - ob_start(); - } - - return ($here) ? self::REPLACEABLE_TAG : ""; - } - - /** - * Same as renderOnShutdown() with $head = true - * - * @param boolean $here - * @param boolean $initialize - * @param boolean $renderStackedData - * @return string - */ - public function renderOnShutdownWithHead($here = true, $initialize = true, $renderStackedData = true) - { - return $this->renderOnShutdown($here, $initialize, $renderStackedData, true); - } - - /** - * Is callback function for register_shutdown_function(...) - * - * @param boolean $here Set position of HTML. True if is to current position or false for end file - * @param boolean $initialize Whether to render the de bug bar initialization code - * @param bool $renderStackedData - * @param bool $head - */ - public function replaceTagInBuffer($here = true, $initialize = true, $renderStackedData = true, $head = false) - { - $render = ($head ? $this->renderHead() : "") - . $this->render($initialize, $renderStackedData); - - $current = ($here && ob_get_level() > 0) ? ob_get_clean() : self::REPLACEABLE_TAG; - - echo str_replace(self::REPLACEABLE_TAG, $render, $current, $count); - - if ($count === 0) { - echo $render; - } - } - - /** - * Returns the code needed to display the debug bar - * - * AJAX request should not render the initialization code. - * - * @param boolean $initialize Whether or not to render the debug bar initialization code - * @param boolean $renderStackedData Whether or not to render the stacked data - * @return string - */ - public function render($initialize = true, $renderStackedData = true) - { - $js = ''; - - if ($initialize) { - $js = $this->getJsInitializationCode(); - } - - if ($renderStackedData && $this->debugBar->hasStackedData()) { - foreach ($this->debugBar->getStackedData() as $id => $data) { - $js .= $this->getAddDatasetCode($id, $data, '(stacked)'); - } - } - - $suffix = !$initialize ? '(ajax)' : null; - $js .= $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix); - - if ($this->useRequireJs){ - return "\n"; - } else { - return "\n"; - } - - } - - /** - * Returns the js code needed to initialize the debug bar - * - * @return string - */ - protected function getJsInitializationCode() - { - $js = ''; - - if (($this->initialization & self::INITIALIZE_CONSTRUCTOR) === self::INITIALIZE_CONSTRUCTOR) { - $js .= sprintf("var %s = new %s();\n", $this->variableName, $this->javascriptClass); - } - - if (($this->initialization & self::INITIALIZE_CONTROLS) === self::INITIALIZE_CONTROLS) { - $js .= $this->getJsControlsDefinitionCode($this->variableName); - } - - if ($this->ajaxHandlerClass) { - $js .= sprintf("%s.ajaxHandler = new %s(%s);\n", $this->variableName, $this->ajaxHandlerClass, $this->variableName); - if ($this->ajaxHandlerBindToXHR) { - $js .= sprintf("%s.ajaxHandler.bindToXHR();\n", $this->variableName); - } elseif ($this->ajaxHandlerBindToJquery) { - $js .= sprintf("if (jQuery) %s.ajaxHandler.bindToJquery(jQuery);\n", $this->variableName); - } - } - - if ($this->openHandlerUrl !== null) { - $js .= sprintf("%s.setOpenHandler(new %s(%s));\n", $this->variableName, - $this->openHandlerClass, - json_encode(array("url" => $this->openHandlerUrl))); - } - - return $js; - } - - /** - * Returns the js code needed to initialized the controls and data mapping of the debug bar - * - * Controls can be defined by collectors themselves or using {@see addControl()} - * - * @param string $varname Debug bar's variable name - * @return string - */ - protected function getJsControlsDefinitionCode($varname) - { - $js = ''; - $dataMap = array(); - $excludedOptions = array('indicator', 'tab', 'map', 'default', 'widget', 'position'); - - // finds controls provided by collectors - $widgets = array(); - foreach ($this->debugBar->getCollectors() as $collector) { - if (($collector instanceof Renderable) && !in_array($collector->getName(), $this->ignoredCollectors)) { - if ($w = $collector->getWidgets()) { - $widgets = array_merge($widgets, $w); - } - } - } - $controls = array_merge($widgets, $this->controls); - - foreach (array_filter($controls) as $name => $options) { - $opts = array_diff_key($options, array_flip($excludedOptions)); - - if (isset($options['tab']) || isset($options['widget'])) { - if (!isset($opts['title'])) { - $opts['title'] = ucfirst(str_replace('_', ' ', $name)); - } - $js .= sprintf("%s.addTab(\"%s\", new %s({%s%s}));\n", - $varname, - $name, - isset($options['tab']) ? $options['tab'] : 'PhpDebugBar.DebugBar.Tab', - substr(json_encode($opts, JSON_FORCE_OBJECT), 1, -1), - isset($options['widget']) ? sprintf('%s"widget": new %s()', count($opts) ? ', ' : '', $options['widget']) : '' - ); - } elseif (isset($options['indicator']) || isset($options['icon'])) { - $js .= sprintf("%s.addIndicator(\"%s\", new %s(%s), \"%s\");\n", - $varname, - $name, - isset($options['indicator']) ? $options['indicator'] : 'PhpDebugBar.DebugBar.Indicator', - json_encode($opts, JSON_FORCE_OBJECT), - isset($options['position']) ? $options['position'] : 'right' - ); - } - - if (isset($options['map']) && isset($options['default'])) { - $dataMap[$name] = array($options['map'], $options['default']); - } - } - - // creates the data mapping object - $mapJson = array(); - foreach ($dataMap as $name => $values) { - $mapJson[] = sprintf('"%s": ["%s", %s]', $name, $values[0], $values[1]); - } - $js .= sprintf("%s.setDataMap({\n%s\n});\n", $varname, implode(",\n", $mapJson)); - - // activate state restoration - $js .= sprintf("%s.restoreState();\n", $varname); - - return $js; - } - - /** - * Returns the js code needed to add a dataset - * - * @param string $requestId - * @param array $data - * @param mixed $suffix - * @return string - */ - protected function getAddDatasetCode($requestId, $data, $suffix = null) - { - $js = sprintf("%s.addDataSet(%s, \"%s\"%s);\n", - $this->variableName, - json_encode($data), - $requestId, - $suffix ? ", " . json_encode($suffix) : '' - ); - return $js; - } + const INITIALIZE_CONSTRUCTOR = 2; + const INITIALIZE_CONTROLS = 4; + const REPLACEABLE_TAG = '{--DEBUGBAR_OB_START_REPLACE_ME--}'; + const RELATIVE_PATH = 'path'; + const RELATIVE_URL = 'url'; + + protected $debugBar; + protected $baseUrl; + protected $basePath; + protected $cssVendors = [ + 'fontawesome' => 'vendor/font-awesome/css/font-awesome.min.css', + 'highlightjs' => 'vendor/highlightjs/styles/github.css' + ]; + protected $jsVendors = [ + 'jquery' => 'vendor/jquery/dist/jquery.min.js', + 'highlightjs' => 'vendor/highlightjs/highlight.pack.js' + ]; + protected $includeVendors = true; + protected $cssFiles = ['debugbar.css', 'widgets.css', 'openhandler.css']; + protected $jsFiles = ['debugbar.js', 'widgets.js', 'openhandler.js']; + protected $additionalAssets = []; + protected $javascriptClass = 'PhpDebugBar.DebugBar'; + protected $variableName = 'phpdebugbar'; + protected $enableJqueryNoConflict = true; + protected $useRequireJs = false; + protected $initialization; + protected $controls = []; + protected $ignoredCollectors = []; + protected $ajaxHandlerClass = 'PhpDebugBar.AjaxHandler'; + protected $ajaxHandlerBindToJquery = true; + protected $ajaxHandlerBindToXHR = false; + protected $openHandlerClass = 'PhpDebugBar.OpenHandler'; + protected $openHandlerUrl; + + /** + * @param \DebugBar\DebugBar $debugBar + * @param string $baseUrl + * @param string $basePath + */ + public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null) + { + $this->debugBar = $debugBar; + + if ($baseUrl === null) { + $baseUrl = '/vendor/maximebf/debugbar/src/DebugBar/Resources'; + } + $this->baseUrl = $baseUrl; + + if ($basePath === null) { + $basePath = __DIR__ . DIRECTORY_SEPARATOR . 'Resources'; + } + $this->basePath = $basePath; + + // bitwise operations cannot be done in class definition :( + $this->initialization = self::INITIALIZE_CONSTRUCTOR | self::INITIALIZE_CONTROLS; + } + + /** + * Sets options from an array. + * + * Options: + * - base_path + * - base_url + * - include_vendors + * - javascript_class + * - variable_name + * - initialization + * - enable_jquery_noconflict + * - controls + * - disable_controls + * - ignore_collectors + * - ajax_handler_classname + * - ajax_handler_bind_to_jquery + * - open_handler_classname + * - open_handler_url + * + * @param array $options [description] + */ + public function setOptions(array $options) + { + if (array_key_exists('base_path', $options)) { + $this->setBasePath($options['base_path']); + } + if (array_key_exists('base_url', $options)) { + $this->setBaseUrl($options['base_url']); + } + if (array_key_exists('include_vendors', $options)) { + $this->setIncludeVendors($options['include_vendors']); + } + if (array_key_exists('javascript_class', $options)) { + $this->setJavascriptClass($options['javascript_class']); + } + if (array_key_exists('variable_name', $options)) { + $this->setVariableName($options['variable_name']); + } + if (array_key_exists('initialization', $options)) { + $this->setInitialization($options['initialization']); + } + if (array_key_exists('enable_jquery_noconflict', $options)) { + $this->setEnableJqueryNoConflict($options['enable_jquery_noconflict']); + } + if (array_key_exists('use_requirejs', $options)) { + $this->setUseRequireJs($options['use_requirejs']); + } + if (array_key_exists('controls', $options)) { + foreach ($options['controls'] as $name => $control) { + $this->addControl($name, $control); + } + } + if (array_key_exists('disable_controls', $options)) { + foreach ((array) $options['disable_controls'] as $name) { + $this->disableControl($name); + } + } + if (array_key_exists('ignore_collectors', $options)) { + foreach ((array) $options['ignore_collectors'] as $name) { + $this->ignoreCollector($name); + } + } + if (array_key_exists('ajax_handler_classname', $options)) { + $this->setAjaxHandlerClass($options['ajax_handler_classname']); + } + if (array_key_exists('ajax_handler_bind_to_jquery', $options)) { + $this->setBindAjaxHandlerToJquery($options['ajax_handler_bind_to_jquery']); + } + if (array_key_exists('open_handler_classname', $options)) { + $this->setOpenHandlerClass($options['open_handler_classname']); + } + if (array_key_exists('open_handler_url', $options)) { + $this->setOpenHandlerUrl($options['open_handler_url']); + } + } + + /** + * Sets the path which assets are relative to. + * + * @param string $path + */ + public function setBasePath($path) + { + $this->basePath = $path; + return $this; + } + + /** + * Returns the path which assets are relative to. + * + * @return string + */ + public function getBasePath() + { + return $this->basePath; + } + + /** + * Sets the base URL from which assets will be served. + * + * @param string $url + */ + public function setBaseUrl($url) + { + $this->baseUrl = $url; + return $this; + } + + /** + * Returns the base URL from which assets will be served. + * + * @return string + */ + public function getBaseUrl() + { + return $this->baseUrl; + } + + /** + * Whether to include vendor assets. + * + * You can only include js or css vendors using + * setIncludeVendors('css') or setIncludeVendors('js') + * + * @param bool $enabled + */ + public function setIncludeVendors($enabled = true) + { + if (is_string($enabled)) { + $enabled = [$enabled]; + } + $this->includeVendors = $enabled; + + if (!$enabled || (is_array($enabled) && !in_array('js', $enabled))) { + // no need to call jQuery.noConflict() if we do not include our own version + $this->enableJqueryNoConflict = false; + } + + return $this; + } + + /** + * Checks if vendors assets are included. + * + * @return bool + */ + public function areVendorsIncluded() + { + return $this->includeVendors !== false; + } + + /** + * Disable a specific vendor's assets. + * + * @param string $name "jquery", "fontawesome", "highlightjs" + */ + public function disableVendor($name) + { + if (array_key_exists($name, $this->cssVendors)) { + unset($this->cssVendors[$name]); + } + if (array_key_exists($name, $this->jsVendors)) { + unset($this->jsVendors[$name]); + } + } + + /** + * Sets the javascript class name. + * + * @param string $className + */ + public function setJavascriptClass($className) + { + $this->javascriptClass = $className; + return $this; + } + + /** + * Returns the javascript class name. + * + * @return string + */ + public function getJavascriptClass() + { + return $this->javascriptClass; + } + + /** + * Sets the variable name of the class instance. + * + * @param string $name + */ + public function setVariableName($name) + { + $this->variableName = $name; + return $this; + } + + /** + * Returns the variable name of the class instance. + * + * @return string + */ + public function getVariableName() + { + return $this->variableName; + } + + /** + * Sets what should be initialized. + * + * - INITIALIZE_CONSTRUCTOR: only initializes the instance + * - INITIALIZE_CONTROLS: initializes the controls and data mapping + * - INITIALIZE_CONSTRUCTOR | INITIALIZE_CONTROLS: initialize everything (default) + * + * @param int $init + */ + public function setInitialization($init) + { + $this->initialization = $init; + return $this; + } + + /** + * Returns what should be initialized. + * + * @return int + */ + public function getInitialization() + { + return $this->initialization; + } + + /** + * Sets whether to call jQuery.noConflict(). + * + * @param bool $enabled + */ + public function setEnableJqueryNoConflict($enabled = true) + { + $this->enableJqueryNoConflict = $enabled; + return $this; + } + + /** + * Checks if jQuery.noConflict() will be called. + * + * @return bool + */ + public function isJqueryNoConflictEnabled() + { + return $this->enableJqueryNoConflict; + } + + /** + * Sets whether to use RequireJS or not. + * + * @param bool $enabled + * + * @return $this + */ + public function setUseRequireJs($enabled = true) + { + $this->useRequireJs = $enabled; + return $this; + } + + /** + * Checks if RequireJS is used. + * + * @return bool + */ + public function isRequireJsUsed() + { + return $this->useRequireJs; + } + + /** + * Adds a control to initialize. + * + * Possible options: + * - icon: icon name + * - tooltip: string + * - widget: widget class name + * - title: tab title + * - map: a property name from the data to map the control to + * - default: a js string, default value of the data map + * + * "icon" or "widget" are at least needed + * + * @param string $name + * @param array $options + */ + public function addControl($name, array $options) + { + if (count(array_intersect(array_keys($options), ['icon', 'widget', 'tab', 'indicator'])) === 0) { + throw new DebugBarException("Not enough options for control '$name'"); + } + $this->controls[$name] = $options; + return $this; + } + + /** + * Disables a control. + * + * @param string $name + */ + public function disableControl($name) + { + $this->controls[$name] = null; + return $this; + } + + /** + * Returns the list of controls. + * + * This does not include controls provided by collectors + * + * @return array + */ + public function getControls() + { + return $this->controls; + } + + /** + * Ignores widgets provided by a collector. + * + * @param string $name + */ + public function ignoreCollector($name) + { + $this->ignoredCollectors[] = $name; + return $this; + } + + /** + * Returns the list of ignored collectors. + * + * @return array + */ + public function getIgnoredCollectors() + { + return $this->ignoredCollectors; + } + + /** + * Sets the class name of the ajax handler. + * + * Set to false to disable + * + * @param string $className + */ + public function setAjaxHandlerClass($className) + { + $this->ajaxHandlerClass = $className; + return $this; + } + + /** + * Returns the class name of the ajax handler. + * + * @return string + */ + public function getAjaxHandlerClass() + { + return $this->ajaxHandlerClass; + } + + /** + * Sets whether to call bindToJquery() on the ajax handler. + * + * @param bool $bind + */ + public function setBindAjaxHandlerToJquery($bind = true) + { + $this->ajaxHandlerBindToJquery = $bind; + return $this; + } + + /** + * Checks whether bindToJquery() will be called on the ajax handler. + * + * @return bool + */ + public function isAjaxHandlerBoundToJquery() + { + return $this->ajaxHandlerBindToJquery; + } + + /** + * Sets whether to call bindToXHR() on the ajax handler. + * + * @param bool $bind + */ + public function setBindAjaxHandlerToXHR($bind = true) + { + $this->ajaxHandlerBindToXHR = $bind; + return $this; + } + + /** + * Checks whether bindToXHR() will be called on the ajax handler. + * + * @return bool + */ + public function isAjaxHandlerBoundToXHR() + { + return $this->ajaxHandlerBindToXHR; + } + + /** + * Sets the class name of the js open handler. + * + * @param string $className + */ + public function setOpenHandlerClass($className) + { + $this->openHandlerClass = $className; + return $this; + } + + /** + * Returns the class name of the js open handler. + * + * @return string + */ + public function getOpenHandlerClass() + { + return $this->openHandlerClass; + } + + /** + * Sets the url of the open handler. + * + * @param string $url + */ + public function setOpenHandlerUrl($url) + { + $this->openHandlerUrl = $url; + return $this; + } + + /** + * Returns the url for the open handler. + * + * @return string + */ + public function getOpenHandlerUrl() + { + return $this->openHandlerUrl; + } + + /** + * Add assets 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 + */ + public function addAssets($cssFiles, $jsFiles, $basePath = null, $baseUrl = null) + { + $this->additionalAssets[] = [ + 'base_path' => $basePath, + 'base_url' => $baseUrl, + 'css' => (array) $cssFiles, + 'js' => (array) $jsFiles + ]; + return $this; + } + + /** + * Returns the list of asset files. + * + * @param string $type Only return css or js files + * @param string $relativeTo The type of path to which filenames must be relative (path, url or null) + * + * @return array + */ + public function getAssets($type = null, $relativeTo = self::RELATIVE_PATH) + { + $cssFiles = $this->cssFiles; + $jsFiles = $this->jsFiles; + + if ($this->includeVendors !== false) { + if ($this->includeVendors === true || in_array('css', $this->includeVendors)) { + $cssFiles = array_merge($this->cssVendors, $cssFiles); + } + if ($this->includeVendors === true || in_array('js', $this->includeVendors)) { + $jsFiles = array_merge($this->jsVendors, $jsFiles); + } + } + + if ($relativeTo) { + $root = $this->getRelativeRoot($relativeTo, $this->basePath, $this->baseUrl); + $cssFiles = $this->makeUriRelativeTo($cssFiles, $root); + $jsFiles = $this->makeUriRelativeTo($jsFiles, $root); + } + + $additionalAssets = $this->additionalAssets; + // finds assets provided by collectors + foreach ($this->debugBar->getCollectors() as $collector) { + if (($collector instanceof AssetProvider) && !in_array($collector->getName(), $this->ignoredCollectors)) { + $additionalAssets[] = $collector->getAssets(); + } + } + + foreach ($additionalAssets as $assets) { + $basePath = $assets['base_path'] ?? null; + $baseUrl = $assets['base_url'] ?? null; + $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)); + } + + return $this->filterAssetArray([$cssFiles, $jsFiles], $type); + } + + /** + * Returns the correct base according to the type. + * + * @param string $relativeTo + * @param string $basePath + * @param string $baseUrl + * + * @return string + */ + protected function getRelativeRoot($relativeTo, $basePath, $baseUrl) + { + if ($relativeTo === self::RELATIVE_PATH) { + return $basePath; + } + if ($relativeTo === self::RELATIVE_URL) { + return $baseUrl; + } + return null; + } + + /** + * Makes a URI relative to another. + * + * @param string|array $uri + * @param string $root + * + * @return string + */ + protected function makeUriRelativeTo($uri, $root) + { + if (!$root) { + return $uri; + } + + if (is_array($uri)) { + $uris = []; + foreach ($uri as $u) { + $uris[] = $this->makeUriRelativeTo($u, $root); + } + return $uris; + } + + if (substr($uri, 0, 1) === '/' || preg_match('/^([a-zA-Z]+:\/\/|[a-zA-Z]:\/|[a-zA-Z]:\\\)/', $uri)) { + return $uri; + } + return rtrim($root, '/') . "/$uri"; + } + + /** + * Filters a tuple of (css, js) assets according to $type. + * + * @param array $array + * @param string $type 'css', 'js' or null for both + * + * @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; + } + + /** + * Returns a tuple where the both items are Assetic AssetCollection, + * the first one being css files and the second js files. + * + * @param string $type Only return css or js collection + * + * @return array or \Assetic\Asset\AssetCollection + */ + public function getAsseticCollection($type = null) + { + list($cssFiles, $jsFiles) = $this->getAssets(); + return $this->filterAssetArray([ + $this->createAsseticCollection($cssFiles), + $this->createAsseticCollection($jsFiles) + ], $type); + } + + /** + * Create an Assetic AssetCollection with the given files. + * Filenames will be converted to absolute path using + * the base path. + * + * @param array $files + * + * @return \Assetic\Asset\AssetCollection + */ + protected function createAsseticCollection($files) + { + $assets = []; + foreach ($files as $file) { + $assets[] = new \Assetic\Asset\FileAsset($file); + } + return new \Assetic\Asset\AssetCollection($assets); + } + + /** + * Write all CSS assets to standard output or in a file. + * + * @param string $targetFilename + */ + public function dumpCssAssets($targetFilename = null) + { + $this->dumpAssets($this->getAssets('css'), $targetFilename); + } + + /** + * Write all JS assets to standard output or in a file. + * + * @param string $targetFilename + */ + public function dumpJsAssets($targetFilename = null) + { + $this->dumpAssets($this->getAssets('js'), $targetFilename, $this->useRequireJs); + } + + /** + * Write assets to standard output or in a file. + * + * @param array $files + * @param string $targetFilename + * @param bool $useRequireJs + */ + protected function dumpAssets($files, $targetFilename = null, $useRequireJs = false) + { + $content = ''; + foreach ($files as $file) { + $content .= file_get_contents($file) . "\n"; + } + if ($useRequireJs) { + $content = "define('debugbar', ['jquery'], function($){\r\n" . $content . "\r\n return PhpDebugBar; \r\n});"; + } + if ($targetFilename !== null) { + file_put_contents($targetFilename, $content); + } else { + echo $content; + } + } + + /** + * Renders the html to include needed assets. + * + * Only useful if Assetic is not used + * + * @return string + */ + public function renderHead() + { + list($cssFiles, $jsFiles) = $this->getAssets(null, self::RELATIVE_URL); + $html = ''; + + foreach ($cssFiles as $file) { + $html .= sprintf('' . "\n", $file); + } + + foreach ($jsFiles as $file) { + $html .= sprintf('' . "\n", $file); + } + + if ($this->enableJqueryNoConflict && !$this->useRequireJs) { + $html .= '' . "\n"; + } + + return $html; + } + + /** + * Register shutdown to display the debug bar. + * + * @param bool $here Set position of HTML. True if is to current position or false for end file + * @param bool $initialize Whether to render the de bug bar initialization code + * @param bool $renderStackedData + * @param bool $head + * + * @return string Return "{--DEBUGBAR_OB_START_REPLACE_ME--}" or return an empty string if $here == false + */ + public function renderOnShutdown($here = true, $initialize = true, $renderStackedData = true, $head = false) + { + register_shutdown_function([$this, 'replaceTagInBuffer'], $here, $initialize, $renderStackedData, $head); + + if (ob_get_level() === 0) { + ob_start(); + } + + return ($here) ? self::REPLACEABLE_TAG : ''; + } + + /** + * Same as renderOnShutdown() with $head = true. + * + * @param bool $here + * @param bool $initialize + * @param bool $renderStackedData + * + * @return string + */ + public function renderOnShutdownWithHead($here = true, $initialize = true, $renderStackedData = true) + { + return $this->renderOnShutdown($here, $initialize, $renderStackedData, true); + } + + /** + * Is callback function for register_shutdown_function(...). + * + * @param bool $here Set position of HTML. True if is to current position or false for end file + * @param bool $initialize Whether to render the de bug bar initialization code + * @param bool $renderStackedData + * @param bool $head + */ + public function replaceTagInBuffer($here = true, $initialize = true, $renderStackedData = true, $head = false) + { + $render = ($head ? $this->renderHead() : '') + . $this->render($initialize, $renderStackedData); + + $current = ($here && ob_get_level() > 0) ? ob_get_clean() : self::REPLACEABLE_TAG; + + echo str_replace(self::REPLACEABLE_TAG, $render, $current, $count); + + if ($count === 0) { + echo $render; + } + } + + /** + * Returns the code needed to display the debug bar. + * + * AJAX request should not render the initialization code. + * + * @param bool $initialize Whether or not to render the debug bar initialization code + * @param bool $renderStackedData Whether or not to render the stacked data + * + * @return string + */ + public function render($initialize = true, $renderStackedData = true) + { + $js = ''; + + if ($initialize) { + $js = $this->getJsInitializationCode(); + } + + if ($renderStackedData && $this->debugBar->hasStackedData()) { + foreach ($this->debugBar->getStackedData() as $id => $data) { + $js .= $this->getAddDatasetCode($id, $data, '(stacked)'); + } + } + + $suffix = !$initialize ? '(ajax)' : null; + $js .= $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix); + + if ($this->useRequireJs) { + return "\n"; + } else { + return "\n"; + } + } + + /** + * Returns the js code needed to initialize the debug bar. + * + * @return string + */ + protected function getJsInitializationCode() + { + $js = ''; + + if (($this->initialization & self::INITIALIZE_CONSTRUCTOR) === self::INITIALIZE_CONSTRUCTOR) { + $js .= sprintf("var %s = new %s();\n", $this->variableName, $this->javascriptClass); + } + + if (($this->initialization & self::INITIALIZE_CONTROLS) === self::INITIALIZE_CONTROLS) { + $js .= $this->getJsControlsDefinitionCode($this->variableName); + } + + if ($this->ajaxHandlerClass) { + $js .= sprintf("%s.ajaxHandler = new %s(%s);\n", $this->variableName, $this->ajaxHandlerClass, $this->variableName); + if ($this->ajaxHandlerBindToXHR) { + $js .= sprintf("%s.ajaxHandler.bindToXHR();\n", $this->variableName); + } elseif ($this->ajaxHandlerBindToJquery) { + $js .= sprintf("if (jQuery) %s.ajaxHandler.bindToJquery(jQuery);\n", $this->variableName); + } + } + + if ($this->openHandlerUrl !== null) { + $js .= sprintf("%s.setOpenHandler(new %s(%s));\n", $this->variableName, $this->openHandlerClass, json_encode(['url' => $this->openHandlerUrl])); + } + + return $js; + } + + /** + * Returns the js code needed to initialized the controls and data mapping of the debug bar. + * + * Controls can be defined by collectors themselves or using {@see addControl()} + * + * @param string $varname Debug bar's variable name + * + * @return string + */ + protected function getJsControlsDefinitionCode($varname) + { + $js = ''; + $dataMap = []; + $excludedOptions = ['indicator', 'tab', 'map', 'default', 'widget', 'position']; + + // finds controls provided by collectors + $widgets = []; + foreach ($this->debugBar->getCollectors() as $collector) { + if (($collector instanceof Renderable) && !in_array($collector->getName(), $this->ignoredCollectors)) { + if ($w = $collector->getWidgets()) { + $widgets = array_merge($widgets, $w); + } + } + } + $controls = array_merge($widgets, $this->controls); + + foreach (array_filter($controls) as $name => $options) { + $opts = array_diff_key($options, array_flip($excludedOptions)); + + if (isset($options['tab']) || isset($options['widget'])) { + if (!isset($opts['title'])) { + $opts['title'] = ucfirst(str_replace('_', ' ', $name)); + } + $js .= sprintf("%s.addTab(\"%s\", new %s({%s%s}));\n", $varname, $name, $options['tab'] ?? 'PhpDebugBar.DebugBar.Tab', substr(json_encode($opts, JSON_FORCE_OBJECT), 1, -1), isset($options['widget']) ? sprintf('%s"widget": new %s()', count($opts) ? ', ' : '', $options['widget']) : '' + ); + } elseif (isset($options['indicator']) || isset($options['icon'])) { + $js .= sprintf("%s.addIndicator(\"%s\", new %s(%s), \"%s\");\n", $varname, $name, $options['indicator'] ?? 'PhpDebugBar.DebugBar.Indicator', json_encode($opts, JSON_FORCE_OBJECT), $options['position'] ?? 'right' + ); + } + + if (isset($options['map'], $options['default'])) { + $dataMap[$name] = [$options['map'], $options['default']]; + } + } + + // creates the data mapping object + $mapJson = []; + foreach ($dataMap as $name => $values) { + $mapJson[] = sprintf('"%s": ["%s", %s]', $name, $values[0], $values[1]); + } + $js .= sprintf("%s.setDataMap({\n%s\n});\n", $varname, implode(",\n", $mapJson)); + + // activate state restoration + $js .= sprintf("%s.restoreState();\n", $varname); + + return $js; + } + + /** + * Returns the js code needed to add a dataset. + * + * @param string $requestId + * @param array $data + * @param mixed $suffix + * + * @return string + */ + protected function getAddDatasetCode($requestId, $data, $suffix = null) + { + $js = sprintf("%s.addDataSet(%s, \"%s\"%s);\n", $this->variableName, json_encode($data), $requestId, $suffix ? ', ' . json_encode($suffix) : '' + ); + return $js; + } } diff --git a/src/DebugBar/OpenHandler.php b/src/DebugBar/OpenHandler.php index ee4df413..1b32911a 100644 --- a/src/DebugBar/OpenHandler.php +++ b/src/DebugBar/OpenHandler.php @@ -11,107 +11,115 @@ namespace DebugBar; /** - * Handler to list and open saved dataset + * Handler to list and open saved dataset. */ class OpenHandler { - protected $debugBar; + protected $debugBar; - /** - * @param DebugBar $debugBar - * @throws DebugBarException - */ - public function __construct(DebugBar $debugBar) - { - if (!$debugBar->isDataPersisted()) { - throw new DebugBarException("DebugBar must have a storage backend to use OpenHandler"); - } - $this->debugBar = $debugBar; - } + /** + * @param DebugBar $debugBar + * + * @throws DebugBarException + */ + public function __construct(DebugBar $debugBar) + { + if (!$debugBar->isDataPersisted()) { + throw new DebugBarException('DebugBar must have a storage backend to use OpenHandler'); + } + $this->debugBar = $debugBar; + } - /** - * Handles the current request - * - * @param array $request Request data - * @param bool $echo - * @param bool $sendHeader - * @return string - * @throws DebugBarException - */ - public function handle($request = null, $echo = true, $sendHeader = true) - { - if ($request === null) { - $request = $_REQUEST; - } + /** + * Handles the current request. + * + * @param array $request Request data + * @param bool $echo + * @param bool $sendHeader + * + * @throws DebugBarException + * + * @return string + */ + public function handle($request = null, $echo = true, $sendHeader = true) + { + if ($request === null) { + $request = $_REQUEST; + } - $op = 'find'; - if (isset($request['op'])) { - $op = $request['op']; - if (!in_array($op, array('find', 'get', 'clear'))) { - throw new DebugBarException("Invalid operation '{$request['op']}'"); - } - } + $op = 'find'; + if (isset($request['op'])) { + $op = $request['op']; + if (!in_array($op, ['find', 'get', 'clear'])) { + throw new DebugBarException("Invalid operation '{$request['op']}'"); + } + } - if ($sendHeader) { - $this->debugBar->getHttpDriver()->setHeaders(array( - 'Content-Type' => 'application/json' - )); - } + if ($sendHeader) { + $this->debugBar->getHttpDriver()->setHeaders([ + 'Content-Type' => 'application/json' + ]); + } - $response = json_encode(call_user_func(array($this, $op), $request)); - if ($echo) { - echo $response; - } - return $response; - } + $response = json_encode(call_user_func([$this, $op], $request)); + if ($echo) { + echo $response; + } + return $response; + } - /** - * Find operation - * @param $request - * @return array - */ - protected function find($request) - { - $max = 20; - if (isset($request['max'])) { - $max = $request['max']; - } + /** + * Find operation. + * + * @param $request + * + * @return array + */ + protected function find($request) + { + $max = 20; + if (isset($request['max'])) { + $max = $request['max']; + } - $offset = 0; - if (isset($request['offset'])) { - $offset = $request['offset']; - } + $offset = 0; + if (isset($request['offset'])) { + $offset = $request['offset']; + } - $filters = array(); - foreach (array('utime', 'datetime', 'ip', 'uri', 'method') as $key) { - if (isset($request[$key])) { - $filters[$key] = $request[$key]; - } - } + $filters = []; + foreach (['utime', 'datetime', 'ip', 'uri', 'method'] as $key) { + if (isset($request[$key])) { + $filters[$key] = $request[$key]; + } + } - return $this->debugBar->getStorage()->find($filters, $max, $offset); - } + return $this->debugBar->getStorage()->find($filters, $max, $offset); + } - /** - * Get operation - * @param $request - * @return array - * @throws DebugBarException - */ - protected function get($request) - { - if (!isset($request['id'])) { - throw new DebugBarException("Missing 'id' parameter in 'get' operation"); - } - return $this->debugBar->getStorage()->get($request['id']); - } + /** + * Get operation. + * + * @param $request + * + * @throws DebugBarException + * + * @return array + */ + protected function get($request) + { + if (!isset($request['id'])) { + throw new DebugBarException("Missing 'id' parameter in 'get' operation"); + } + return $this->debugBar->getStorage()->get($request['id']); + } - /** - * Clear operation - */ - protected function clear($request) - { - $this->debugBar->getStorage()->clear(); - return array('success' => true); - } + /** + * Clear operation. + */ + protected function clear($request) + { + $this->debugBar->getStorage()->clear(); + return ['success' => true]; + } } diff --git a/src/DebugBar/PhpHttpDriver.php b/src/DebugBar/PhpHttpDriver.php index 36e56f80..bbd5c42c 100644 --- a/src/DebugBar/PhpHttpDriver.php +++ b/src/DebugBar/PhpHttpDriver.php @@ -11,60 +11,62 @@ namespace DebugBar; /** - * HTTP driver for native php + * HTTP driver for native php. */ class PhpHttpDriver implements HttpDriverInterface { - /** - * @param array $headers - */ - function setHeaders(array $headers) - { - foreach ($headers as $name => $value) { - header("$name: $value"); - } - } + /** + * @param array $headers + */ + public function setHeaders(array $headers) + { + foreach ($headers as $name => $value) { + header("$name: $value"); + } + } - /** - * @return bool - */ - function isSessionStarted() - { - return isset($_SESSION); - } + /** + * @return bool + */ + public function isSessionStarted() + { + return isset($_SESSION); + } - /** - * @param string $name - * @param string $value - */ - function setSessionValue($name, $value) - { - $_SESSION[$name] = $value; - } + /** + * @param string $name + * @param string $value + */ + public function setSessionValue($name, $value) + { + $_SESSION[$name] = $value; + } - /** - * @param string $name - * @return bool - */ - function hasSessionValue($name) - { - return array_key_exists($name, $_SESSION); - } + /** + * @param string $name + * + * @return bool + */ + public function hasSessionValue($name) + { + return array_key_exists($name, $_SESSION); + } - /** - * @param string $name - * @return mixed - */ - function getSessionValue($name) - { - return $_SESSION[$name]; - } + /** + * @param string $name + * + * @return mixed + */ + public function getSessionValue($name) + { + return $_SESSION[$name]; + } - /** - * @param string $name - */ - function deleteSessionValue($name) - { - unset($_SESSION[$name]); - } + /** + * @param string $name + */ + public function deleteSessionValue($name) + { + unset($_SESSION[$name]); + } } diff --git a/src/DebugBar/RequestIdGenerator.php b/src/DebugBar/RequestIdGenerator.php index 21b3c0cc..5ecb5f41 100644 --- a/src/DebugBar/RequestIdGenerator.php +++ b/src/DebugBar/RequestIdGenerator.php @@ -11,15 +11,15 @@ namespace DebugBar; /** - * Request id generator based on the $_SERVER array + * Request id generator based on the $_SERVER array. */ class RequestIdGenerator implements RequestIdGeneratorInterface { - /** - * @return string - */ - public function generate() - { - return md5(serialize($_SERVER) . microtime()); - } + /** + * @return string + */ + public function generate() + { + return md5(serialize($_SERVER) . microtime()); + } } diff --git a/src/DebugBar/RequestIdGeneratorInterface.php b/src/DebugBar/RequestIdGeneratorInterface.php index c7276248..e125dec0 100644 --- a/src/DebugBar/RequestIdGeneratorInterface.php +++ b/src/DebugBar/RequestIdGeneratorInterface.php @@ -12,10 +12,10 @@ interface RequestIdGeneratorInterface { - /** - * Generates a unique id for the current request - * - * @return string - */ - function generate(); + /** + * Generates a unique id for the current request. + * + * @return string + */ + public function generate(); } diff --git a/src/DebugBar/Resources/debugbar.css b/src/DebugBar/Resources/debugbar.css index f8e4dc90..ff706610 100644 --- a/src/DebugBar/Resources/debugbar.css +++ b/src/DebugBar/Resources/debugbar.css @@ -1,41 +1,41 @@ /* Hide debugbar when printing a page */ @media print { - div.phpdebugbar { - display: none; - } + div.phpdebugbar { + display: none; + } } div.phpdebugbar { - position: fixed; - bottom: 0; - left: 0; - width: 100%; - border-top: 0; - font-family: arial, sans-serif; - background: #fff; - z-index: 10000; - font-size: 14px; - color: #000; - text-align: left; - line-height: 1; - letter-spacing: normal; + position: fixed; + bottom: 0; + left: 0; + width: 100%; + border-top: 0; + font-family: arial, sans-serif; + background: #fff; + z-index: 10000; + font-size: 14px; + color: #000; + text-align: left; + line-height: 1; + letter-spacing: normal; } div.phpdebugbar a, div.phpdebugbar-openhandler { - cursor: pointer; + cursor: pointer; } div.phpdebugbar-drag-capture { - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 10001; - background: none; - display: none; - cursor: n-resize; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 10001; + background: none; + display: none; + cursor: n-resize; } div.phpdebugbar-closed { @@ -43,56 +43,56 @@ div.phpdebugbar-closed { } div.phpdebugbar * { - margin: 0; - padding: 0; - border: 0; - font-weight: normal; - text-decoration: none; - clear: initial; - width: auto; - -moz-box-sizing: content-box; - box-sizing: content-box; + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + text-decoration: none; + clear: initial; + width: auto; + -moz-box-sizing: content-box; + box-sizing: content-box; } div.phpdebugbar ol, div.phpdebugbar ul { - list-style: none; + list-style: none; } div.phpdebugbar table { - border-collapse: collapse; - border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; } div.phpdebugbar code, div.phpdebugbar pre { - background: none; - font-family: monospace; - font-size: 1em; - border: 0; - padding: 0; - margin: 0; + background: none; + font-family: monospace; + font-size: 1em; + border: 0; + padding: 0; + margin: 0; } a.phpdebugbar-restore-btn { - float: left; - padding: 5px 8px; - font-size: 14px; - color: #555; - text-decoration: none; - border-right: 1px solid #ddd; + float: left; + padding: 5px 8px; + font-size: 14px; + color: #555; + text-decoration: none; + border-right: 1px solid #ddd; } div.phpdebugbar-resize-handle { - display: none; - height: 4px; - margin-top: -4px; - width: 100%; - background: none; - border-bottom: 1px solid #ccc; - cursor: n-resize; + display: none; + height: 4px; + margin-top: -4px; + width: 100%; + background: none; + border-bottom: 1px solid #ccc; + cursor: n-resize; } div.phpdebugbar-closed, div.phpdebugbar-minimized{ - border-top: 1px solid #ccc; + border-top: 1px solid #ccc; } /* -------------------------------------- */ @@ -100,38 +100,38 @@ div.phpdebugbar-header, a.phpdebugbar-restore-btn { background: #efefef url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ccircle%20fill%3D%22%23000%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%229%22%2F%3E%3Cpath%20d%3D%22M6.039%208.342c.463%200%20.772.084.927.251.154.168.191.455.11.862-.084.424-.247.727-.487.908-.241.182-.608.272-1.1.272h-.743l.456-2.293h.837zm-2.975%204.615h1.22l.29-1.457H5.62c.461%200%20.84-.047%201.139-.142.298-.095.569-.254.812-.477.205-.184.37-.387.497-.608.127-.222.217-.466.27-.734.13-.65.032-1.155-.292-1.518-.324-.362-.84-.543-1.545-.543H4.153l-1.089%205.479zM9.235%206.02h1.21l-.289%201.458h1.079c.679%200%201.147.115%201.405.347.258.231.335.607.232%201.125l-.507%202.55h-1.23l.481-2.424c.055-.276.035-.464-.06-.565-.095-.1-.298-.15-.608-.15H9.98L9.356%2011.5h-1.21l1.089-5.48M15.566%208.342c.464%200%20.773.084.928.251.154.168.19.455.11.862-.084.424-.247.727-.488.908-.24.182-.607.272-1.1.272h-.742l.456-2.293h.836zm-2.974%204.615h1.22l.29-1.457h1.046c.461%200%20.84-.047%201.139-.142.298-.095.569-.254.812-.477.205-.184.37-.387.497-.608.127-.222.217-.466.27-.734.129-.65.032-1.155-.292-1.518-.324-.362-.84-.543-1.545-.543H13.68l-1.089%205.479z%22%20fill%3D%22%23FFF%22%2F%3E%3C%2Fsvg%3E) no-repeat 5px 4px / 20px 20px; } div.phpdebugbar-header { - padding-left: 29px; - min-height: 26px; - line-height: 16px; + padding-left: 29px; + min-height: 26px; + line-height: 16px; } div.phpdebugbar-header:before, div.phpdebugbar-header:after { - display: table; - line-height: 0; - content: ""; + display: table; + line-height: 0; + content: ""; } div.phpdebugbar-header:after { - clear: both; + clear: both; } div.phpdebugbar-header-left { - float: left; + float: left; } div.phpdebugbar-header-right { - float: right; + float: right; } div.phpdebugbar-header > div > * { - padding: 5px 5px; - font-size: 14px; - color: #555; - text-decoration: none; + padding: 5px 5px; + font-size: 14px; + color: #555; + text-decoration: none; } div.phpdebugbar-header-left > * { - float: left; + float: left; } div.phpdebugbar-header-right > * { - float: right; + float: right; } div.phpdebugbar-header-right > select { - padding: 0; + padding: 0; } /* -------------------------------------- */ @@ -139,20 +139,20 @@ div.phpdebugbar-header-right > select { span.phpdebugbar-indicator, a.phpdebugbar-indicator, a.phpdebugbar-close-btn { - border-right: 1px solid #ddd; + border-right: 1px solid #ddd; } a.phpdebugbar-tab.phpdebugbar-active { - background: #ccc; - color: #444; - background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); - background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); - background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); - background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); - background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.41, rgb(173,173,173)), color-stop(0.71, rgb(209,209,209))); -} - a.phpdebugbar-tab span.phpdebugbar-badge { + background: #ccc; + color: #444; + background-image: linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); + background-image: -o-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); + background-image: -moz-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); + background-image: -webkit-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); + background-image: -ms-linear-gradient(bottom, rgb(173,173,173) 41%, rgb(209,209,209) 71%); + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.41, rgb(173,173,173)), color-stop(0.71, rgb(209,209,209))); +} +a.phpdebugbar-tab span.phpdebugbar-badge { display: none; margin-left: 5px; font-size: 11px; @@ -164,23 +164,23 @@ a.phpdebugbar-tab.phpdebugbar-active { font-weight: normal; text-shadow: none; vertical-align: middle; - } - a.phpdebugbar-tab i { +} +a.phpdebugbar-tab i { display: none; vertical-align: middle; - } - a.phpdebugbar-tab span.phpdebugbar-badge.phpdebugbar-important { +} +a.phpdebugbar-tab span.phpdebugbar-badge.phpdebugbar-important { background: #ed6868; color: white; - } +} a.phpdebugbar-close-btn, a.phpdebugbar-open-btn, a.phpdebugbar-restore-btn, a.phpdebugbar-minimize-btn , a.phpdebugbar-maximize-btn { - width: 16px; - height: 16px; + width: 16px; + height: 16px; } a.phpdebugbar-minimize-btn , a.phpdebugbar-maximize-btn { - padding-right: 0px !important; + padding-right: 0px !important; } a.phpdebugbar-maximize-btn { display: none} @@ -192,29 +192,29 @@ div.phpdebugbar-minimized a.phpdebugbar-maximize-btn { display: block} div.phpdebugbar-minimized a.phpdebugbar-minimize-btn { display: none} a.phpdebugbar-minimize-btn { - background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-down%22%3E%3Cpath%20d%3D%22M1683%20808l-742%20741q-19%2019-45%2019t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19%2045-19t45%2019l531%20531%20531-531q19-19%2045-19t45%2019l166%20165q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px; + background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-down%22%3E%3Cpath%20d%3D%22M1683%20808l-742%20741q-19%2019-45%2019t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19%2045-19t45%2019l531%20531%20531-531q19-19%2045-19t45%2019l166%20165q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px; } a.phpdebugbar-maximize-btn { - background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-up%22%3E%3Cpath%20d%3D%22M1683%201331l-166%20165q-19%2019-45%2019t-45-19l-531-531-531%20531q-19%2019-45%2019t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19%2045-19t45%2019l742%20741q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px; + background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-up%22%3E%3Cpath%20d%3D%22M1683%201331l-166%20165q-19%2019-45%2019t-45-19l-531-531-531%20531q-19%2019-45%2019t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19%2045-19t45%2019l742%20741q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px; } a.phpdebugbar-close-btn { - background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22close%22%3E%3Cpath%20d%3D%22M1490%201322q0%2040-28%2068l-136%20136q-28%2028-68%2028t-68-28l-294-294-294%20294q-28%2028-68%2028t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28%2068-28t68%2028l294%20294%20294-294q28-28%2068-28t68%2028l136%20136q28%2028%2028%2068t-28%2068l-294%20294%20294%20294q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) no-repeat 9px 6px / 14px 14px; + background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22close%22%3E%3Cpath%20d%3D%22M1490%201322q0%2040-28%2068l-136%20136q-28%2028-68%2028t-68-28l-294-294-294%20294q-28%2028-68%2028t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28%2068-28t68%2028l294%20294%20294-294q28-28%2068-28t68%2028l136%20136q28%2028%2028%2068t-28%2068l-294%20294%20294%20294q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) no-repeat 9px 6px / 14px 14px; } a.phpdebugbar-open-btn { - background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22folder-open%22%3E%3Cpath%20d%3D%22M1815%20952q0%2031-31%2066l-336%20396q-43%2051-120.5%2086.5t-143.5%2035.5h-1088q-34%200-60.5-13t-26.5-43q0-31%2031-66l336-396q43-51%20120.5-86.5t143.5-35.5h1088q34%200%2060.5%2013t26.5%2043zm-343-344v160h-832q-94%200-197%2047.5t-164%20119.5l-337%20396-5%206q0-4-.5-12.5t-.5-12.5v-960q0-92%2066-158t158-66h320q92%200%20158%2066t66%20158v32h544q92%200%20158%2066t66%20158z%22%2F%3E%3C%2Fsvg%3E) no-repeat 8px 6px / 14px 14px; + background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22folder-open%22%3E%3Cpath%20d%3D%22M1815%20952q0%2031-31%2066l-336%20396q-43%2051-120.5%2086.5t-143.5%2035.5h-1088q-34%200-60.5-13t-26.5-43q0-31%2031-66l336-396q43-51%20120.5-86.5t143.5-35.5h1088q34%200%2060.5%2013t26.5%2043zm-343-344v160h-832q-94%200-197%2047.5t-164%20119.5l-337%20396-5%206q0-4-.5-12.5t-.5-12.5v-960q0-92%2066-158t158-66h320q92%200%20158%2066t66%20158v32h544q92%200%20158%2066t66%20158z%22%2F%3E%3C%2Fsvg%3E) no-repeat 8px 6px / 14px 14px; } .phpdebugbar-indicator { - position: relative; - cursor: pointer; + position: relative; + cursor: pointer; } - .phpdebugbar-indicator span.phpdebugbar-text { +.phpdebugbar-indicator span.phpdebugbar-text { margin-left: 5px; - } - .phpdebugbar-indicator span.phpdebugbar-tooltip { +} +.phpdebugbar-indicator span.phpdebugbar-tooltip { display: none; position: absolute; top: -30px; @@ -228,51 +228,51 @@ a.phpdebugbar-open-btn { text-align: center; width: 200%; right: 0; - } - .phpdebugbar-indicator:hover span.phpdebugbar-tooltip:not(.phpdebugbar-disabled) { +} +.phpdebugbar-indicator:hover span.phpdebugbar-tooltip:not(.phpdebugbar-disabled) { display: block; - } +} select.phpdebugbar-datasets-switcher { - float: right; - display: none; - margin: 2px 0 0 7px; - max-width: 200px; - max-height: 23px; - padding: 0; + float: right; + display: none; + margin: 2px 0 0 7px; + max-width: 200px; + max-height: 23px; + padding: 0; } /* -------------------------------------- */ div.phpdebugbar-body { - border-top: 1px solid #ccc; - display: none; - position: relative; - height: 300px; + border-top: 1px solid #ccc; + display: none; + position: relative; + height: 300px; } /* -------------------------------------- */ div.phpdebugbar-panel { - display: none; - height: 100%; - overflow: auto; - width: 100%; + display: none; + height: 100%; + overflow: auto; + width: 100%; } div.phpdebugbar-panel.phpdebugbar-active { - display: block; + display: block; } /* -------------------------------------- */ div.phpdebugbar-mini-design a.phpdebugbar-tab { - position: relative; - border-right: 1px solid #ddd; + position: relative; + border-right: 1px solid #ddd; } - div.phpdebugbar-mini-design a.phpdebugbar-tab span.phpdebugbar-text { +div.phpdebugbar-mini-design a.phpdebugbar-tab span.phpdebugbar-text { display: none; - } - div.phpdebugbar-mini-design a.phpdebugbar-tab:hover span.phpdebugbar-text { +} +div.phpdebugbar-mini-design a.phpdebugbar-tab:hover span.phpdebugbar-text { display: block; position: absolute; top: -30px; @@ -285,7 +285,7 @@ div.phpdebugbar-mini-design a.phpdebugbar-tab { z-index: 1000; text-align: center; right: 0; - } - div.phpdebugbar-mini-design a.phpdebugbar-tab i { +} +div.phpdebugbar-mini-design a.phpdebugbar-tab i { display:inline-block; - } +} diff --git a/src/DebugBar/Resources/debugbar.js b/src/DebugBar/Resources/debugbar.js index e7f16f4a..ce8aa2ee 100644 --- a/src/DebugBar/Resources/debugbar.js +++ b/src/DebugBar/Resources/debugbar.js @@ -1,1144 +1,1153 @@ -if (typeof(PhpDebugBar) == 'undefined') { - // namespace - var PhpDebugBar = {}; - PhpDebugBar.$ = jQuery; +if (typeof (PhpDebugBar) == 'undefined') { + // namespace + var PhpDebugBar = {}; + PhpDebugBar.$ = jQuery; } -(function($) { - - if (typeof(localStorage) == 'undefined') { - // provide mock localStorage object for dumb browsers - localStorage = { - setItem: function(key, value) {}, - getItem: function(key) { return null; } - }; - } - - if (typeof(PhpDebugBar.utils) == 'undefined') { - PhpDebugBar.utils = {}; - } - - /** - * Returns the value from an object property. - * Using dots in the key, it is possible to retrieve nested property values - * - * @param {Object} dict - * @param {String} key - * @param {Object} default_value - * @return {Object} - */ - var getDictValue = PhpDebugBar.utils.getDictValue = function(dict, key, default_value) { - var d = dict, parts = key.split('.'); - for (var i = 0; i < parts.length; i++) { - if (!d[parts[i]]) { - return default_value; - } - d = d[parts[i]]; - } - return d; - } - - /** - * Counts the number of properties in an object - * - * @param {Object} obj - * @return {Integer} - */ - var getObjectSize = PhpDebugBar.utils.getObjectSize = function(obj) { - if (Object.keys) { - return Object.keys(obj).length; - } - var count = 0; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - count++; - } - } - return count; - } - - /** - * Returns a prefixed css class name - * - * @param {String} cls - * @return {String} - */ - PhpDebugBar.utils.csscls = function(cls, prefix) { - if (cls.indexOf(' ') > -1) { - var clss = cls.split(' '), out = []; - for (var i = 0, c = clss.length; i < c; i++) { - out.push(PhpDebugBar.utils.csscls(clss[i], prefix)); - } - return out.join(' '); - } - if (cls.indexOf('.') === 0) { - return '.' + prefix + cls.substr(1); - } - return prefix + cls; - }; - - /** - * Creates a partial function of csscls where the second - * argument is already defined - * - * @param {string} prefix - * @return {Function} - */ - PhpDebugBar.utils.makecsscls = function(prefix) { - var f = function(cls) { - return PhpDebugBar.utils.csscls(cls, prefix); - }; - return f; - } - - var csscls = PhpDebugBar.utils.makecsscls('phpdebugbar-'); - - - // ------------------------------------------------------------------ - - /** - * Base class for all elements with a visual component - * - * @param {Object} options - * @constructor - */ - var Widget = PhpDebugBar.Widget = function(options) { - this._attributes = $.extend({}, this.defaults); - this._boundAttributes = {}; - this.$el = $('<' + this.tagName + ' />'); - if (this.className) { - this.$el.addClass(this.className); - } - this.initialize.apply(this, [options || {}]); - this.render.apply(this); - }; - - $.extend(Widget.prototype, { - - tagName: 'div', - - className: null, - - defaults: {}, - - /** - * Called after the constructor - * - * @param {Object} options - */ - initialize: function(options) { - this.set(options); - }, - - /** - * Called after the constructor to render the element - */ - render: function() {}, - - /** - * Sets the value of an attribute - * - * @param {String} attr Can also be an object to set multiple attributes at once - * @param {Object} value - */ - set: function(attr, value) { - if (typeof(attr) != 'string') { - for (var k in attr) { - this.set(k, attr[k]); - } - return; - } - - this._attributes[attr] = value; - if (typeof(this._boundAttributes[attr]) !== 'undefined') { - for (var i = 0, c = this._boundAttributes[attr].length; i < c; i++) { - this._boundAttributes[attr][i].apply(this, [value]); - } - } - }, - - /** - * Checks if an attribute exists and is not null - * - * @param {String} attr - * @return {[type]} [description] - */ - has: function(attr) { - return typeof(this._attributes[attr]) !== 'undefined' && this._attributes[attr] !== null; - }, - - /** - * Returns the value of an attribute - * - * @param {String} attr - * @return {Object} - */ - get: function(attr) { - return this._attributes[attr]; - }, - - /** - * Registers a callback function that will be called whenever the value of the attribute changes - * - * If cb is a jQuery element, text() will be used to fill the element - * - * @param {String} attr - * @param {Function} cb - */ - bindAttr: function(attr, cb) { - if ($.isArray(attr)) { - for (var i = 0, c = attr.length; i < c; i++) { - this.bindAttr(attr[i], cb); - } - return; - } - - if (typeof(this._boundAttributes[attr]) == 'undefined') { - this._boundAttributes[attr] = []; - } - if (typeof(cb) == 'object') { - var el = cb; - cb = function(value) { el.text(value || ''); }; - } - this._boundAttributes[attr].push(cb); - if (this.has(attr)) { - cb.apply(this, [this._attributes[attr]]); - } - } - - }); - - - /** - * Creates a subclass - * - * Code from Backbone.js - * - * @param {Array} props Prototype properties - * @return {Function} - */ - Widget.extend = function(props) { - var parent = this; - - var child = function() { return parent.apply(this, arguments); }; - $.extend(child, parent); - - var Surrogate = function(){ this.constructor = child; }; - Surrogate.prototype = parent.prototype; - child.prototype = new Surrogate; - $.extend(child.prototype, props); - - child.__super__ = parent.prototype; - - return child; - }; - - // ------------------------------------------------------------------ - - /** - * Tab - * - * A tab is composed of a tab label which is always visible and - * a tab panel which is visible only when the tab is active. - * - * The panel must contain a widget. A widget is an object which has - * an element property containing something appendable to a jQuery object. - * - * Options: - * - title - * - badge - * - widget - * - data: forward data to widget data - */ - var Tab = Widget.extend({ - - className: csscls('panel'), - - render: function() { - this.$tab = $('').addClass(csscls('tab')); - - this.$icon = $('').appendTo(this.$tab); - this.bindAttr('icon', function(icon) { - if (icon) { - this.$icon.attr('class', 'phpdebugbar-fa phpdebugbar-fa-' + icon); - } else { - this.$icon.attr('class', ''); - } - }); - - this.bindAttr('title', $('').addClass(csscls('text')).appendTo(this.$tab)); - - this.$badge = $('').addClass(csscls('badge')).appendTo(this.$tab); - this.bindAttr('badge', function(value) { - if (value !== null) { - this.$badge.text(value); - this.$badge.show(); - } else { - this.$badge.hide(); - } - }); - - this.bindAttr('widget', function(widget) { - this.$el.empty().append(widget.$el); - }); - - this.bindAttr('data', function(data) { - if (this.has('widget')) { - this.get('widget').set('data', data); - } - }) - } - - }); - - // ------------------------------------------------------------------ - - /** - * Indicator - * - * An indicator is a text and an icon to display single value information - * right inside the always visible part of the debug bar - * - * Options: - * - icon - * - title - * - tooltip - * - data: alias of title - */ - var Indicator = Widget.extend({ - - tagName: 'span', - - className: csscls('indicator'), - - render: function() { - this.$icon = $('').appendTo(this.$el); - this.bindAttr('icon', function(icon) { - if (icon) { - this.$icon.attr('class', 'phpdebugbar-fa phpdebugbar-fa-' + icon); - } else { - this.$icon.attr('class', ''); - } - }); - - this.bindAttr(['title', 'data'], $('').addClass(csscls('text')).appendTo(this.$el)); - - this.$tooltip = $('').addClass(csscls('tooltip disabled')).appendTo(this.$el); - this.bindAttr('tooltip', function(tooltip) { - if (tooltip) { - this.$tooltip.text(tooltip).removeClass(csscls('disabled')); - } else { - this.$tooltip.addClass(csscls('disabled')); - } - }); - } - - }); - - // ------------------------------------------------------------------ - - /** - * Dataset title formater - * - * Formats the title of a dataset for the select box - */ - var DatasetTitleFormater = PhpDebugBar.DatasetTitleFormater = function(debugbar) { - this.debugbar = debugbar; - }; - - $.extend(DatasetTitleFormater.prototype, { - - /** - * Formats the title of a dataset - * - * @this {DatasetTitleFormater} - * @param {String} id - * @param {Object} data - * @param {String} suffix - * @return {String} - */ - format: function(id, data, suffix) { - if (suffix) { - suffix = ' ' + suffix; - } else { - suffix = ''; - } - - var nb = getObjectSize(this.debugbar.datasets) + 1; - - if (typeof(data['__meta']) === 'undefined') { - return "#" + nb + suffix; - } - - var filename = data['__meta']['uri'].substr(data['__meta']['uri'].lastIndexOf('/') + 1); - var label = "#" + nb + " " + filename + suffix + ' (' + data['__meta']['datetime'].split(' ')[1] + ')'; - return label; - } - - }); - - // ------------------------------------------------------------------ - - - /** - * DebugBar - * - * Creates a bar that appends itself to the body of your page - * and sticks to the bottom. - * - * The bar can be customized by adding tabs and indicators. - * A data map is used to fill those controls with data provided - * from datasets. - */ - var DebugBar = PhpDebugBar.DebugBar = Widget.extend({ - - className: "phpdebugbar " + csscls('minimized'), - - options: { - bodyMarginBottom: true, - bodyMarginBottomHeight: parseInt($('body').css('margin-bottom')) - }, - - initialize: function() { - this.controls = {}; - this.dataMap = {}; - this.datasets = {}; - this.firstTabName = null; - this.activePanelName = null; - this.datesetTitleFormater = new DatasetTitleFormater(this); - this.registerResizeHandler(); - }, - - /** - * Register resize event, for resize debugbar with reponsive css. - * - * @this {DebugBar} - */ - registerResizeHandler: function() { - if (typeof this.resize.bind == 'undefined') return; - - var f = this.resize.bind(this); - this.respCSSSize = 0; - $(window).resize(f); - setTimeout(f, 20); - }, - - /** - * Resizes the debugbar to fit the current browser window - */ - resize: function() { - var contentSize = this.respCSSSize; - if (this.respCSSSize == 0) { - this.$header.find("> div > *:visible").each(function () { - contentSize += $(this).outerWidth(); - }); - } - - var currentSize = this.$header.width(); - var cssClass = "phpdebugbar-mini-design"; - var bool = this.$header.hasClass(cssClass); - - if (currentSize <= contentSize && !bool) { - this.respCSSSize = contentSize; - this.$header.addClass(cssClass); - } else if (contentSize < currentSize && bool) { - this.respCSSSize = 0; - this.$header.removeClass(cssClass); - } - - // Reset height to ensure bar is still visible - this.setHeight(this.$body.height()); - }, - - /** - * Initialiazes the UI - * - * @this {DebugBar} - */ - render: function() { - var self = this; - this.$el.appendTo('body'); - this.$dragCapture = $('
').addClass(csscls('drag-capture')).appendTo(this.$el); - this.$resizehdle = $('
').addClass(csscls('resize-handle')).appendTo(this.$el); - this.$header = $('
').addClass(csscls('header')).appendTo(this.$el); - this.$headerLeft = $('
').addClass(csscls('header-left')).appendTo(this.$header); - this.$headerRight = $('
').addClass(csscls('header-right')).appendTo(this.$header); - var $body = this.$body = $('
').addClass(csscls('body')).appendTo(this.$el); - this.recomputeBottomOffset(); - - // dragging of resize handle - var pos_y, orig_h; - this.$resizehdle.on('mousedown', function(e) { - orig_h = $body.height(), pos_y = e.pageY; - $body.parents().on('mousemove', mousemove).on('mouseup', mouseup); - self.$dragCapture.show(); - e.preventDefault(); - }); - var mousemove = function(e) { - var h = orig_h + (pos_y - e.pageY); - self.setHeight(h); - }; - var mouseup = function() { - $body.parents().off('mousemove', mousemove).off('mouseup', mouseup); - self.$dragCapture.hide(); - }; - - // close button - this.$closebtn = $('').addClass(csscls('close-btn')).appendTo(this.$headerRight); - this.$closebtn.click(function() { - self.close(); - }); - - // minimize button - this.$minimizebtn = $('').addClass(csscls('minimize-btn') ).appendTo(this.$headerRight); - this.$minimizebtn.click(function() { - self.minimize(); - }); - - // maximize button - this.$maximizebtn = $('').addClass(csscls('maximize-btn') ).appendTo(this.$headerRight); - this.$maximizebtn.click(function() { - self.restore(); - }); - - // restore button - this.$restorebtn = $('').addClass(csscls('restore-btn')).hide().appendTo(this.$el); - this.$restorebtn.click(function() { - self.restore(); - }); - - // open button - this.$openbtn = $('').addClass(csscls('open-btn')).appendTo(this.$headerRight).hide(); - this.$openbtn.click(function() { - self.openHandler.show(function(id, dataset) { - self.addDataSet(dataset, id, "(opened)"); - self.showTab(); - }); - }); - - // select box for data sets - this.$datasets = $('').addClass(csscls('datasets-switcher')).appendTo(this.$headerRight); + this.$datasets.change(function () { + self.dataChangeHandler(self.datasets[this.value]); + self.showTab(); + }); + }, + + /** + * Sets the height of the debugbar body section + * Forces the height to lie within a reasonable range + * Stores the height in local storage so it can be restored + * Resets the document body bottom offset + * + * @this {DebugBar} + */ + setHeight: function (height) { + var min_h = 40; + var max_h = $(window).innerHeight() - this.$header.height() - 10; + height = Math.min(height, max_h); + height = Math.max(height, min_h); + this.$body.css('height', height); + localStorage.setItem('phpdebugbar-height', height); + this.recomputeBottomOffset(); + }, + + /** + * Restores the state of the DebugBar using localStorage + * This is not called by default in the constructor and + * needs to be called by subclasses in their init() method + * + * @this {DebugBar} + */ + restoreState: function () { + // bar height + var height = localStorage.getItem('phpdebugbar-height'); + this.setHeight(height || this.$body.height()); + + // bar visibility + var open = localStorage.getItem('phpdebugbar-open'); + if (open && open == '0') { + this.close(); + } else { + var visible = localStorage.getItem('phpdebugbar-visible'); + if (visible && visible == '1') { + var tab = localStorage.getItem('phpdebugbar-tab'); + if (this.isTab(tab)) { + this.showTab(tab); + } + } + } + }, + + /** + * Creates and adds a new tab + * + * @this {DebugBar} + * @param {String} name Internal name + * @param {Object} widget A widget object with an element property + * @param {String} title The text in the tab, if not specified, name will be used + * @return {Tab} + */ + createTab: function (name, widget, title) { + var tab = new Tab({ + title: title || (name.replace(/[_\-]/g, ' ').charAt(0).toUpperCase() + name.slice(1)), + widget: widget + }); + return this.addTab(name, tab); + }, + + /** + * Adds a new tab + * + * @this {DebugBar} + * @param {String} name Internal name + * @param {Tab} tab Tab object + * @return {Tab} + */ + addTab: function (name, tab) { + if (this.isControl(name)) { + throw new Error(name + ' already exists'); + } + + var self = this; + tab.$tab.appendTo(this.$headerLeft).click(function () { + if (!self.isMinimized() && self.activePanelName == name) { + self.minimize(); + } else { + self.showTab(name); + } + }); + tab.$el.appendTo(this.$body); + + this.controls[name] = tab; + if (this.firstTabName == null) { + this.firstTabName = name; + } + return tab; + }, + + /** + * Creates and adds an indicator + * + * @this {DebugBar} + * @param {String} name Internal name + * @param {String} icon + * @param {String} tooltip + * @param {String} position "right" or "left", default is "right" + * @return {Indicator} + */ + createIndicator: function (name, icon, tooltip, position) { + var indicator = new Indicator({ + icon: icon, + tooltip: tooltip + }); + return this.addIndicator(name, indicator, position); + }, + + /** + * Adds an indicator + * + * @this {DebugBar} + * @param {String} name Internal name + * @param {Indicator} indicator Indicator object + * @return {Indicator} + */ + addIndicator: function (name, indicator, position) { + if (this.isControl(name)) { + throw new Error(name + ' already exists'); + } + + if (position == 'left') { + indicator.$el.insertBefore(this.$headerLeft.children().first()); + } else { + indicator.$el.appendTo(this.$headerRight); + } + + this.controls[name] = indicator; + return indicator; + }, + + /** + * Returns a control + * + * @param {String} name + * @return {Object} + */ + getControl: function (name) { + if (this.isControl(name)) { + return this.controls[name]; + } + }, + + /** + * Checks if there's a control under the specified name + * + * @this {DebugBar} + * @param {String} name + * @return {Boolean} + */ + isControl: function (name) { + return typeof (this.controls[name]) != 'undefined'; + }, + + /** + * Checks if a tab with the specified name exists + * + * @this {DebugBar} + * @param {String} name + * @return {Boolean} + */ + isTab: function (name) { + return this.isControl(name) && this.controls[name] instanceof Tab; + }, + + /** + * Checks if an indicator with the specified name exists + * + * @this {DebugBar} + * @param {String} name + * @return {Boolean} + */ + isIndicator: function (name) { + return this.isControl(name) && this.controls[name] instanceof Indicator; + }, + + /** + * Removes all tabs and indicators from the debug bar and hides it + * + * @this {DebugBar} + */ + reset: function () { + this.minimize(); + var self = this; + $.each(this.controls, function (name, control) { + if (self.isTab(name)) { + control.$tab.remove(); + } + control.$el.remove(); + }); + this.controls = {}; + }, + + /** + * Open the debug bar and display the specified tab + * + * @this {DebugBar} + * @param {String} name If not specified, display the first tab + */ + showTab: function (name) { + if (!name) { + if (this.activePanelName) { + name = this.activePanelName; + } else { + name = this.firstTabName; + } + } + + if (!this.isTab(name)) { + throw new Error("Unknown tab '" + name + "'"); + } + + this.$resizehdle.show(); + this.$body.show(); + this.recomputeBottomOffset(); + + $(this.$header).find('> div > .' + csscls('active')).removeClass(csscls('active')); + $(this.$body).find('> .' + csscls('active')).removeClass(csscls('active')); + + this.controls[name].$tab.addClass(csscls('active')); + this.controls[name].$el.addClass(csscls('active')); + this.activePanelName = name; + + this.$el.removeClass(csscls('minimized')); + localStorage.setItem('phpdebugbar-visible', '1'); + localStorage.setItem('phpdebugbar-tab', name); + this.resize(); + }, + + /** + * Hide panels and minimize the debug bar + * + * @this {DebugBar} + */ + minimize: function () { + this.$header.find('> div > .' + csscls('active')).removeClass(csscls('active')); + this.$body.hide(); + this.$resizehdle.hide(); + this.recomputeBottomOffset(); + localStorage.setItem('phpdebugbar-visible', '0'); + this.$el.addClass(csscls('minimized')); + this.resize(); + }, + + /** + * Checks if the panel is minimized + * + * @return {Boolean} + */ + isMinimized: function () { + return this.$el.hasClass(csscls('minimized')); + }, + + /** + * Close the debug bar + * + * @this {DebugBar} + */ + close: function () { + this.$resizehdle.hide(); + this.$header.hide(); + this.$body.hide(); + this.$restorebtn.show(); + localStorage.setItem('phpdebugbar-open', '0'); + this.$el.addClass(csscls('closed')); + this.recomputeBottomOffset(); + }, + + /** + * Checks if the panel is closed + * + * @return {Boolean} + */ + isClosed: function () { + return this.$el.hasClass(csscls('closed')); + }, + + /** + * Restore the debug bar + * + * @this {DebugBar} + */ + restore: function () { + this.$resizehdle.show(); + this.$header.show(); + this.$restorebtn.hide(); + localStorage.setItem('phpdebugbar-open', '1'); + var tab = localStorage.getItem('phpdebugbar-tab'); + if (this.isTab(tab)) { + this.showTab(tab); + } + this.$el.removeClass(csscls('closed')); + this.resize(); + }, + + /** + * Recomputes the margin-bottom css property of the body so + * that the debug bar never hides any content + */ + recomputeBottomOffset: function () { + if (this.options.bodyMarginBottom) { + if (this.isClosed()) { + return $('body').css('margin-bottom', this.options.bodyMarginBottomHeight || ''); + } + + var offset = parseInt(this.$el.height()) + this.options.bodyMarginBottomHeight; + $('body').css('margin-bottom', offset); + } + }, + + /** + * Sets the data map used by dataChangeHandler to populate + * indicators and widgets + * + * A data map is an object where properties are control names. + * The value of each property should be an array where the first + * item is the name of a property from the data object (nested properties + * can be specified) and the second item the default value. + * + * Example: + * {"memory": ["memory.peak_usage_str", "0B"]} + * + * @this {DebugBar} + * @param {Object} map + */ + setDataMap: function (map) { + this.dataMap = map; + }, + + /** + * Same as setDataMap() but appends to the existing map + * rather than replacing it + * + * @this {DebugBar} + * @param {Object} map + */ + addDataMap: function (map) { + $.extend(this.dataMap, map); + }, + + /** + * Resets datasets and add one set of data + * + * For this method to be usefull, you need to specify + * a dataMap using setDataMap() + * + * @this {DebugBar} + * @param {Object} data + * @return {String} Dataset's id + */ + setData: function (data) { + this.datasets = {}; + return this.addDataSet(data); + }, + + /** + * Adds a dataset + * + * If more than one dataset are added, the dataset selector + * will be displayed. + * + * For this method to be usefull, you need to specify + * a dataMap using setDataMap() + * + * @this {DebugBar} + * @param {Object} data + * @param {String} id The name of this set, optional + * @param {String} suffix + * @return {String} Dataset's id + */ + addDataSet: function (data, id, suffix) { + var label = this.datesetTitleFormater.format(id, data, suffix); + id = id || (getObjectSize(this.datasets) + 1); + this.datasets[id] = data; + + this.$datasets.append($('')); + if (this.$datasets.children().length > 1) { + this.$datasets.show(); + } + + this.showDataSet(id); + return id; + }, + + /** + * Loads a dataset using the open handler + * + * @param {String} id + */ + loadDataSet: function (id, suffix, callback) { + 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); + callback && callback(data); + }); + }, + + /** + * Returns the data from a dataset + * + * @this {DebugBar} + * @param {String} id + * @return {Object} + */ + getDataSet: function (id) { + return this.datasets[id]; + }, + + /** + * Switch the currently displayed dataset + * + * @this {DebugBar} + * @param {String} id + */ + showDataSet: function (id) { + this.dataChangeHandler(this.datasets[id]); + this.$datasets.val(id); + }, + + /** + * Called when the current dataset is modified. + * + * @this {DebugBar} + * @param {Object} data + */ + dataChangeHandler: function (data) { + var self = this; + $.each(this.dataMap, function (key, def) { + var d = getDictValue(data, def[0], def[1]); + if (key.indexOf(':') != -1) { + key = key.split(':'); + self.getControl(key[0]).set(key[1], d); + } else { + self.getControl(key).set('data', d); + } + }); + }, + + /** + * Sets the handler to open past dataset + * + * @this {DebugBar} + * @param {object} handler + */ + setOpenHandler: function (handler) { + this.openHandler = handler; + if (handler !== null) { + this.$openbtn.show(); + } else { + this.$openbtn.hide(); + } + }, + + /** + * Returns the handler to open past dataset + * + * @this {DebugBar} + * @return {object} + */ + getOpenHandler: function () { + return this.openHandler; + } + + }); + + DebugBar.Tab = Tab; + DebugBar.Indicator = Indicator; + + // ------------------------------------------------------------------ + + /** + * AjaxHandler + * + * Extract data from headers of an XMLHttpRequest and adds a new dataset + */ + var AjaxHandler = PhpDebugBar.AjaxHandler = function (debugbar, headerName) { + this.debugbar = debugbar; + this.headerName = headerName || 'phpdebugbar'; + }; + + $.extend(AjaxHandler.prototype, { + + /** + * Handles an XMLHttpRequest + * + * @this {AjaxHandler} + * @param {XMLHttpRequest} xhr + * @return {Bool} + */ + handle: function (xhr) { + if (!this.loadFromId(xhr)) { + return this.loadFromData(xhr); + } + return true; + }, + + /** + * Checks if the HEADER-id exists and loads the dataset using the open handler + * + * @param {XMLHttpRequest} xhr + * @return {Bool} + */ + loadFromId: function (xhr) { + var id = this.extractIdFromHeaders(xhr); + if (id && this.debugbar.openHandler) { + this.debugbar.loadDataSet(id, "(ajax)"); + return true; + } + return false; + }, + + /** + * Extracts the id from the HEADER-id + * + * @param {XMLHttpRequest} xhr + * @return {String} + */ + extractIdFromHeaders: function (xhr) { + return xhr.getResponseHeader(this.headerName + '-id'); + }, + + /** + * Checks if the HEADER exists and loads the dataset + * + * @param {XMLHttpRequest} xhr + * @return {Bool} + */ + loadFromData: function (xhr) { + var raw = this.extractDataFromHeaders(xhr); + if (!raw) { + return false; + } + + var data = this.parseHeaders(raw); + if (data.error) { + throw new Error('Error loading debugbar data: ' + data.error); + } else if (data.data) { + this.debugbar.addDataSet(data.data, data.id, "(ajax)"); + } + return true; + }, + + /** + * Extract the data as a string from headers of an XMLHttpRequest + * + * @this {AjaxHandler} + * @param {XMLHttpRequest} xhr + * @return {string} + */ + extractDataFromHeaders: function (xhr) { + var data = xhr.getResponseHeader(this.headerName); + if (!data) { + return; + } + for (var i = 1; ; i++) { + var header = xhr.getResponseHeader(this.headerName + '-' + i); + if (!header) { + break; + } + data += header; + } + return decodeURIComponent(data); + }, + + /** + * Parses the string data into an object + * + * @this {AjaxHandler} + * @param {string} data + * @return {string} + */ + parseHeaders: function (data) { + return JSON.parse(data); + }, + + /** + * Attaches an event listener to jQuery.ajaxComplete() + * + * @this {AjaxHandler} + * @param {jQuery} jq Optional + */ + bindToJquery: function (jq) { + var self = this; + jq(document).ajaxComplete(function (e, xhr, settings) { + if (!settings.ignoreDebugBarAjaxHandler) { + self.handle(xhr); + } + }); + }, + + /** + * Attaches an event listener to XMLHttpRequest + * + * @this {AjaxHandler} + */ + bindToXHR: function () { + var self = this; + var proxied = XMLHttpRequest.prototype.open; + XMLHttpRequest.prototype.open = function (method, url, async, user, pass) { + var xhr = this; + this.addEventListener("readystatechange", function () { + var skipUrl = self.debugbar.openHandler ? self.debugbar.openHandler.get('url') : null; + if (xhr.readyState == 4 && url.indexOf(skipUrl) !== 0) { + self.handle(xhr); + } + }, false); + proxied.apply(this, Array.prototype.slice.call(arguments)); + }; + } + + }); })(PhpDebugBar.$); diff --git a/src/DebugBar/Resources/debugbar.min.css b/src/DebugBar/Resources/debugbar.min.css new file mode 100644 index 00000000..f7dfbe6e --- /dev/null +++ b/src/DebugBar/Resources/debugbar.min.css @@ -0,0 +1 @@ +@media print{div.phpdebugbar{display:none}}div.phpdebugbar{position:fixed;bottom:0;left:0;width:100%;border-top:0;font-family:arial,sans-serif;background:#fff;z-index:10000;font-size:14px;color:#000;text-align:left;line-height:1;letter-spacing:normal}div.phpdebugbar a,div.phpdebugbar-openhandler{cursor:pointer}div.phpdebugbar-drag-capture{position:fixed;top:0;bottom:0;left:0;right:0;z-index:10001;background:0;display:none;cursor:n-resize}div.phpdebugbar-closed{width:auto}div.phpdebugbar *{margin:0;padding:0;border:0;font-weight:normal;text-decoration:none;clear:initial;width:auto;-moz-box-sizing:content-box;box-sizing:content-box}div.phpdebugbar ol,div.phpdebugbar ul{list-style:none}div.phpdebugbar table{border-collapse:collapse;border-spacing:0}div.phpdebugbar code,div.phpdebugbar pre{background:0;font-family:monospace;font-size:1em;border:0;padding:0;margin:0}a.phpdebugbar-restore-btn{float:left;padding:5px 8px;font-size:14px;color:#555;text-decoration:none;border-right:1px solid #ddd}div.phpdebugbar-resize-handle{display:none;height:4px;margin-top:-4px;width:100%;background:0;border-bottom:1px solid #ccc;cursor:n-resize}div.phpdebugbar-closed,div.phpdebugbar-minimized{border-top:1px solid #ccc}div.phpdebugbar-header,a.phpdebugbar-restore-btn{background:#efefef url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ccircle%20fill%3D%22%23000%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%229%22%2F%3E%3Cpath%20d%3D%22M6.039%208.342c.463%200%20.772.084.927.251.154.168.191.455.11.862-.084.424-.247.727-.487.908-.241.182-.608.272-1.1.272h-.743l.456-2.293h.837zm-2.975%204.615h1.22l.29-1.457H5.62c.461%200%20.84-.047%201.139-.142.298-.095.569-.254.812-.477.205-.184.37-.387.497-.608.127-.222.217-.466.27-.734.13-.65.032-1.155-.292-1.518-.324-.362-.84-.543-1.545-.543H4.153l-1.089%205.479zM9.235%206.02h1.21l-.289%201.458h1.079c.679%200%201.147.115%201.405.347.258.231.335.607.232%201.125l-.507%202.55h-1.23l.481-2.424c.055-.276.035-.464-.06-.565-.095-.1-.298-.15-.608-.15H9.98L9.356%2011.5h-1.21l1.089-5.48M15.566%208.342c.464%200%20.773.084.928.251.154.168.19.455.11.862-.084.424-.247.727-.488.908-.24.182-.607.272-1.1.272h-.742l.456-2.293h.836zm-2.974%204.615h1.22l.29-1.457h1.046c.461%200%20.84-.047%201.139-.142.298-.095.569-.254.812-.477.205-.184.37-.387.497-.608.127-.222.217-.466.27-.734.129-.65.032-1.155-.292-1.518-.324-.362-.84-.543-1.545-.543H13.68l-1.089%205.479z%22%20fill%3D%22%23FFF%22%2F%3E%3C%2Fsvg%3E) no-repeat 5px 4px / 20px 20px}div.phpdebugbar-header{padding-left:29px;min-height:26px;line-height:16px}div.phpdebugbar-header:before,div.phpdebugbar-header:after{display:table;line-height:0;content:""}div.phpdebugbar-header:after{clear:both}div.phpdebugbar-header-left{float:left}div.phpdebugbar-header-right{float:right}div.phpdebugbar-header>div>*{padding:5px 5px;font-size:14px;color:#555;text-decoration:none}div.phpdebugbar-header-left>*{float:left}div.phpdebugbar-header-right>*{float:right}div.phpdebugbar-header-right>select{padding:0}span.phpdebugbar-indicator,a.phpdebugbar-indicator,a.phpdebugbar-close-btn{border-right:1px solid #ddd}a.phpdebugbar-tab.phpdebugbar-active{background:#ccc;color:#444;background-image:linear-gradient(bottom,#adadad 41%,#d1d1d1 71%);background-image:-o-linear-gradient(bottom,#adadad 41%,#d1d1d1 71%);background-image:-moz-linear-gradient(bottom,#adadad 41%,#d1d1d1 71%);background-image:-webkit-linear-gradient(bottom,#adadad 41%,#d1d1d1 71%);background-image:-ms-linear-gradient(bottom,#adadad 41%,#d1d1d1 71%);background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0.41,#adadad),color-stop(0.71,#d1d1d1))}a.phpdebugbar-tab span.phpdebugbar-badge{display:none;margin-left:5px;font-size:11px;line-height:14px;padding:0 6px;background:#ccc;border-radius:4px;color:#555;font-weight:normal;text-shadow:none;vertical-align:middle}a.phpdebugbar-tab i{display:none;vertical-align:middle}a.phpdebugbar-tab span.phpdebugbar-badge.phpdebugbar-important{background:#ed6868;color:white}a.phpdebugbar-close-btn,a.phpdebugbar-open-btn,a.phpdebugbar-restore-btn,a.phpdebugbar-minimize-btn,a.phpdebugbar-maximize-btn{width:16px;height:16px}a.phpdebugbar-minimize-btn,a.phpdebugbar-maximize-btn{padding-right:0 !important}a.phpdebugbar-maximize-btn{display:none}a.phpdebugbar-minimize-btn{display:block}div.phpdebugbar-minimized a.phpdebugbar-maximize-btn{display:block}div.phpdebugbar-minimized a.phpdebugbar-minimize-btn{display:none}a.phpdebugbar-minimize-btn{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-down%22%3E%3Cpath%20d%3D%22M1683%20808l-742%20741q-19%2019-45%2019t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19%2045-19t45%2019l531%20531%20531-531q19-19%2045-19t45%2019l166%20165q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px}a.phpdebugbar-maximize-btn{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22chevron-up%22%3E%3Cpath%20d%3D%22M1683%201331l-166%20165q-19%2019-45%2019t-45-19l-531-531-531%20531q-19%2019-45%2019t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19%2045-19t45%2019l742%20741q19%2019%2019%2045.5t-19%2045.5z%22%2F%3E%3C%2Fsvg%3E) no-repeat 6px 6px / 14px 14px}a.phpdebugbar-close-btn{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22close%22%3E%3Cpath%20d%3D%22M1490%201322q0%2040-28%2068l-136%20136q-28%2028-68%2028t-68-28l-294-294-294%20294q-28%2028-68%2028t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28%2068-28t68%2028l294%20294%20294-294q28-28%2068-28t68%2028l136%20136q28%2028%2028%2068t-28%2068l-294%20294%20294%20294q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) no-repeat 9px 6px / 14px 14px}a.phpdebugbar-open-btn{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%20id%3D%22folder-open%22%3E%3Cpath%20d%3D%22M1815%20952q0%2031-31%2066l-336%20396q-43%2051-120.5%2086.5t-143.5%2035.5h-1088q-34%200-60.5-13t-26.5-43q0-31%2031-66l336-396q43-51%20120.5-86.5t143.5-35.5h1088q34%200%2060.5%2013t26.5%2043zm-343-344v160h-832q-94%200-197%2047.5t-164%20119.5l-337%20396-5%206q0-4-.5-12.5t-.5-12.5v-960q0-92%2066-158t158-66h320q92%200%20158%2066t66%20158v32h544q92%200%20158%2066t66%20158z%22%2F%3E%3C%2Fsvg%3E) no-repeat 8px 6px / 14px 14px}.phpdebugbar-indicator{position:relative;cursor:pointer}.phpdebugbar-indicator span.phpdebugbar-text{margin-left:5px}.phpdebugbar-indicator span.phpdebugbar-tooltip{display:none;position:absolute;top:-30px;background:#efefef;opacity:.7;border:1px solid #ccc;color:#555;font-size:11px;padding:2px 3px;z-index:1000;text-align:center;width:200%;right:0}.phpdebugbar-indicator:hover span.phpdebugbar-tooltip:not(.phpdebugbar-disabled){display:block}select.phpdebugbar-datasets-switcher{float:right;display:none;margin:2px 0 0 7px;max-width:200px;max-height:23px;padding:0}div.phpdebugbar-body{border-top:1px solid #ccc;display:none;position:relative;height:300px}div.phpdebugbar-panel{display:none;height:100%;overflow:auto;width:100%}div.phpdebugbar-panel.phpdebugbar-active{display:block}div.phpdebugbar-mini-design a.phpdebugbar-tab{position:relative;border-right:1px solid #ddd}div.phpdebugbar-mini-design a.phpdebugbar-tab span.phpdebugbar-text{display:none}div.phpdebugbar-mini-design a.phpdebugbar-tab:hover span.phpdebugbar-text{display:block;position:absolute;top:-30px;background:#efefef;opacity:.7;border:1px solid #ccc;color:#555;font-size:11px;padding:2px 3px;z-index:1000;text-align:center;right:0}div.phpdebugbar-mini-design a.phpdebugbar-tab i{display:inline-block} \ No newline at end of file diff --git a/src/DebugBar/Resources/debugbar.min.js b/src/DebugBar/Resources/debugbar.min.js new file mode 100644 index 00000000..fb3bb73a --- /dev/null +++ b/src/DebugBar/Resources/debugbar.min.js @@ -0,0 +1 @@ +if(typeof(PhpDebugBar)=="undefined"){var PhpDebugBar={};PhpDebugBar.$=jQuery}(function(e){if(typeof(localStorage)=="undefined"){localStorage={setItem:function(k,l){},getItem:function(k){return null}}}if(typeof(PhpDebugBar.utils)=="undefined"){PhpDebugBar.utils={}}var h=PhpDebugBar.utils.getDictValue=function(p,m,k){var o=p,n=m.split(".");for(var l=0;l-1){var k=l.split(" "),m=[];for(var n=0,p=k.length;n");if(this.className){this.$el.addClass(this.className)}this.initialize.apply(this,[k||{}]);this.render.apply(this)};e.extend(f.prototype,{tagName:"div",className:null,defaults:{},initialize:function(k){this.set(k)},render:function(){},set:function(l,o){if(typeof(l)!="string"){for(var m in l){this.set(m,l[m])}return}this._attributes[l]=o;if(typeof(this._boundAttributes[l])!=="undefined"){for(var n=0,p=this._boundAttributes[l].length;n").addClass(c("tab"));this.$icon=e("").appendTo(this.$tab);this.bindAttr("icon",function(k){if(k){this.$icon.attr("class","phpdebugbar-fa phpdebugbar-fa-"+k)}else{this.$icon.attr("class","")}});this.bindAttr("title",e("").addClass(c("text")).appendTo(this.$tab));this.$badge=e("").addClass(c("badge")).appendTo(this.$tab);this.bindAttr("badge",function(k){if(k!==null){this.$badge.text(k);this.$badge.show()}else{this.$badge.hide()}});this.bindAttr("widget",function(k){this.$el.empty().append(k.$el)});this.bindAttr("data",function(k){if(this.has("widget")){this.get("widget").set("data",k)}})}});var j=f.extend({tagName:"span",className:c("indicator"),render:function(){this.$icon=e("").appendTo(this.$el);this.bindAttr("icon",function(k){if(k){this.$icon.attr("class","phpdebugbar-fa phpdebugbar-fa-"+k)}else{this.$icon.attr("class","")}});this.bindAttr(["title","data"],e("").addClass(c("text")).appendTo(this.$el));this.$tooltip=e("").addClass(c("tooltip disabled")).appendTo(this.$el);this.bindAttr("tooltip",function(k){if(k){this.$tooltip.text(k).removeClass(c("disabled"))}else{this.$tooltip.addClass(c("disabled"))}})}});var g=PhpDebugBar.DatasetTitleFormater=function(k){this.debugbar=k};e.extend(g.prototype,{format:function(p,n,o){if(o){o=" "+o}else{o=""}var k=i(this.debugbar.datasets)+1;if(typeof(n.__meta)==="undefined"){return"#"+k+o}var l=n.__meta["uri"].substr(n.__meta["uri"].lastIndexOf("/")+1);var m="#"+k+" "+l+o+" ("+n.__meta["datetime"].split(" ")[1]+")";return m}});var b=PhpDebugBar.DebugBar=f.extend({className:"phpdebugbar "+c("minimized"),options:{bodyMarginBottom:true,bodyMarginBottomHeight:parseInt(e("body").css("margin-bottom"))},initialize:function(){this.controls={};this.dataMap={};this.datasets={};this.firstTabName=null;this.activePanelName=null;this.datesetTitleFormater=new g(this);this.registerResizeHandler()},registerResizeHandler:function(){if(typeof this.resize.bind=="undefined"){return}var k=this.resize.bind(this);this.respCSSSize=0;e(window).resize(k);setTimeout(k,20)},resize:function(){var n=this.respCSSSize;if(this.respCSSSize==0){this.$header.find("> div > *:visible").each(function(){n+=e(this).outerWidth()})}var m=this.$header.width();var k="phpdebugbar-mini-design";var l=this.$header.hasClass(k);if(m<=n&&!l){this.respCSSSize=n;this.$header.addClass(k)}else{if(n").addClass(c("drag-capture")).appendTo(this.$el);this.$resizehdle=e("
").addClass(c("resize-handle")).appendTo(this.$el);this.$header=e("
").addClass(c("header")).appendTo(this.$el);this.$headerLeft=e("
").addClass(c("header-left")).appendTo(this.$header);this.$headerRight=e("
").addClass(c("header-right")).appendTo(this.$header);var n=this.$body=e("
").addClass(c("body")).appendTo(this.$el);this.recomputeBottomOffset();var k,p;this.$resizehdle.on("mousedown",function(q){p=n.height(),k=q.pageY;n.parents().on("mousemove",m).on("mouseup",o);l.$dragCapture.show();q.preventDefault()});var m=function(r){var q=p+(k-r.pageY);l.setHeight(q)};var o=function(){n.parents().off("mousemove",m).off("mouseup",o);l.$dragCapture.hide()};this.$closebtn=e("").addClass(c("close-btn")).appendTo(this.$headerRight);this.$closebtn.click(function(){l.close()});this.$minimizebtn=e("").addClass(c("minimize-btn")).appendTo(this.$headerRight);this.$minimizebtn.click(function(){l.minimize()});this.$maximizebtn=e("").addClass(c("maximize-btn")).appendTo(this.$headerRight);this.$maximizebtn.click(function(){l.restore()});this.$restorebtn=e("").addClass(c("restore-btn")).hide().appendTo(this.$el);this.$restorebtn.click(function(){l.restore()});this.$openbtn=e("").addClass(c("open-btn")).appendTo(this.$headerRight).hide();this.$openbtn.click(function(){l.openHandler.show(function(r,q){l.addDataSet(q,r,"(opened)");l.showTab()})});this.$datasets=e("").addClass(r("datasets-switcher")).appendTo(this.$headerRight);this.$datasets.change(function(){b.dataChangeHandler(b.datasets[this.value]);b.showTab()})},setHeight:function(c){var a=40;var b=p(window).innerHeight()-this.$header.height()-10;c=Math.min(c,b);c=Math.max(c,a);this.$body.css("height",c);localStorage.setItem("phpdebugbar-height",c);this.recomputeBottomOffset()},restoreState:function(){var c=localStorage.getItem("phpdebugbar-height");this.setHeight(c||this.$body.height());var b=localStorage.getItem("phpdebugbar-open");if(b&&b=="0"){this.close()}else{var d=localStorage.getItem("phpdebugbar-visible");if(d&&d=="1"){var a=localStorage.getItem("phpdebugbar-tab");if(this.isTab(a)){this.showTab(a)}}}},createTab:function(c,a,d){var b=new t({title:d||(c.replace(/[_\-]/g," ").charAt(0).toUpperCase()+c.slice(1)),widget:a});return this.addTab(c,b)},addTab:function(b,a){if(this.isControl(b)){throw new Error(b+" already exists")}var c=this;a.$tab.appendTo(this.$headerLeft).click(function(){if(!c.isMinimized()&&c.activePanelName==b){c.minimize()}else{c.showTab(b)}});a.$el.appendTo(this.$body);this.controls[b]=a;if(this.firstTabName==null){this.firstTabName=b}return a},createIndicator:function(a,e,d,c){var b=new k({icon:e,tooltip:d});return this.addIndicator(a,b,c)},addIndicator:function(a,b,c){if(this.isControl(a)){throw new Error(a+" already exists")}if(c=="left"){b.$el.insertBefore(this.$headerLeft.children().first())}else{b.$el.appendTo(this.$headerRight)}this.controls[a]=b;return b},getControl:function(a){if(this.isControl(a)){return this.controls[a]}},isControl:function(a){return typeof(this.controls[a])!="undefined"},isTab:function(a){return this.isControl(a)&&this.controls[a] instanceof t},isIndicator:function(a){return this.isControl(a)&&this.controls[a] instanceof k},reset:function(){this.minimize();var a=this;p.each(this.controls,function(c,b){if(a.isTab(c)){b.$tab.remove()}b.$el.remove()});this.controls={}},showTab:function(a){if(!a){if(this.activePanelName){a=this.activePanelName}else{a=this.firstTabName}}if(!this.isTab(a)){throw new Error("Unknown tab '"+a+"'")}this.$resizehdle.show();this.$body.show();this.recomputeBottomOffset();p(this.$header).find("> div > ."+r("active")).removeClass(r("active"));p(this.$body).find("> ."+r("active")).removeClass(r("active"));this.controls[a].$tab.addClass(r("active"));this.controls[a].$el.addClass(r("active"));this.activePanelName=a;this.$el.removeClass(r("minimized"));localStorage.setItem("phpdebugbar-visible","1");localStorage.setItem("phpdebugbar-tab",a);this.resize()},minimize:function(){this.$header.find("> div > ."+r("active")).removeClass(r("active"));this.$body.hide();this.$resizehdle.hide();this.recomputeBottomOffset();localStorage.setItem("phpdebugbar-visible","0");this.$el.addClass(r("minimized"));this.resize()},isMinimized:function(){return this.$el.hasClass(r("minimized"))},close:function(){this.$resizehdle.hide();this.$header.hide();this.$body.hide();this.$restorebtn.show();localStorage.setItem("phpdebugbar-open","0");this.$el.addClass(r("closed"));this.recomputeBottomOffset()},isClosed:function(){return this.$el.hasClass(r("closed"))},restore:function(){this.$resizehdle.show();this.$header.show();this.$restorebtn.hide();localStorage.setItem("phpdebugbar-open","1");var a=localStorage.getItem("phpdebugbar-tab");if(this.isTab(a)){this.showTab(a)}this.$el.removeClass(r("closed"));this.resize()},recomputeBottomOffset:function(){if(this.options.bodyMarginBottom){if(this.isClosed()){return p("body").css("margin-bottom",this.options.bodyMarginBottomHeight||"")}var a=parseInt(this.$el.height())+this.options.bodyMarginBottomHeight;p("body").css("margin-bottom",a)}},setDataMap:function(a){this.dataMap=a},addDataMap:function(a){p.extend(this.dataMap,a)},setData:function(a){this.datasets={};return this.addDataSet(a)},addDataSet:function(b,d,a){var c=this.datesetTitleFormater.format(d,b,a);d=d||(l(this.datasets)+1);this.datasets[d]=b;this.$datasets.append(p('"));if(this.$datasets.children().length>1){this.$datasets.show()}this.showDataSet(d);return d},loadDataSet:function(d,b,a){if(!this.openHandler){throw new Error("loadDataSet() needs an open handler")}var c=this;this.openHandler.load(d,function(e){c.addDataSet(e,d,b);a&&a(e)})},getDataSet:function(a){return this.datasets[a]},showDataSet:function(a){this.dataChangeHandler(this.datasets[a]);this.$datasets.val(a)},dataChangeHandler:function(a){var b=this;p.each(this.dataMap,function(c,e){var d=m(a,e[0],e[1]);if(c.indexOf(":")!=-1){c=c.split(":");b.getControl(c[0]).set(c[1],d)}else{b.getControl(c).set("data",d)}})},setOpenHandler:function(a){this.openHandler=a;if(a!==null){this.$openbtn.show()}else{this.$openbtn.hide()}},getOpenHandler:function(){return this.openHandler}});s.Tab=t;s.Indicator=k;var q=PhpDebugBar.AjaxHandler=function(b,a){this.debugbar=b;this.headerName=a||"phpdebugbar"};p.extend(q.prototype,{handle:function(a){if(!this.loadFromId(a)){return this.loadFromData(a)}return true},loadFromId:function(b){var a=this.extractIdFromHeaders(b);if(a&&this.debugbar.openHandler){this.debugbar.loadDataSet(a,"(ajax)");return true}return false},extractIdFromHeaders:function(a){return a.getResponseHeader(this.headerName+"-id")},loadFromData:function(a){var c=this.extractDataFromHeaders(a);if(!c){return false}var b=this.parseHeaders(c);if(b.error){throw new Error("Error loading debugbar data: "+b.error)}else{if(b.data){this.debugbar.addDataSet(b.data,b.id,"(ajax)")}}return true},extractDataFromHeaders:function(a){var b=a.getResponseHeader(this.headerName);if(!b){return}for(var c=1;;c++){var d=a.getResponseHeader(this.headerName+"-"+c);if(!d){break}b+=d}return decodeURIComponent(b)},parseHeaders:function(a){return JSON.parse(a)},bindToJquery:function(a){var b=this;a(document).ajaxComplete(function(e,d,c){if(!c.ignoreDebugBarAjaxHandler){b.handle(d)}})},bindToXHR:function(){var b=this;var a=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(d,h,g,c,f){var e=this;this.addEventListener("readystatechange",function(){var i=b.debugbar.openHandler?b.debugbar.openHandler.get("url"):null;if(e.readyState==4&&h.indexOf(i)!==0){b.handle(e)}},false);a.apply(this,Array.prototype.slice.call(arguments))}}})})(PhpDebugBar.$); \ No newline at end of file diff --git a/src/DebugBar/Resources/openhandler.css b/src/DebugBar/Resources/openhandler.css index d72aba5a..4bfa0011 100644 --- a/src/DebugBar/Resources/openhandler.css +++ b/src/DebugBar/Resources/openhandler.css @@ -26,44 +26,44 @@ div.phpdebugbar-openhandler { font-size: 14px; padding-bottom: 10px; } - div.phpdebugbar-openhandler a { - color: #555; - } - div.phpdebugbar-openhandler .phpdebugbar-openhandler-header { - background: #efefef url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAYAAABvVQZ0AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfdBgcKHQH1H7EUAAADV0lEQVQ4y7WUy28bVRSHvzvjJPbYY48dj80rTe28gCbCivPsAhBthJCoBIEQQGr/BMRjh1gA20plEYSQumFFQbBBEWVV0bLoQ1BC1YfcBDt1UicFZZzYje06M57LokVNaZJ2w7e7597zOzpX53fgfhSgzYzGDmk+7YQe0DMD/UNSD+gZzaedMKOxQ0DbnXf3IP5z1hLtyc8k8q1IuFX/N+i6LopyN7dYtNYR4ti1fO5doLqVmD+oBy90JLs6pJQ8CCEE2dxctnyz/AxQ2SwWjYRbzycTHbscx+Fh8Xg85OazC8VVKw2sqIDS3dlzJBo1X3Bdd8skKSVCiPvirusSChmhoB40rKJ1XFFVT/uGvXFwu+pBQ6erp5OdWq9v1A8KIdo9Ab9/MhJu9TUaDdbWVlEUFYlEureTP/n0IwpLNzh75gwetRlN06jdqoF7+5Mcx8br9fk0nzaJ1+s7nU4NysTupLRtW5ZKJVmpVOWpkz/LjkRCFgoFaduOrFarcnb2quzb0ytnZmZktVaT5fJNWSqV5P59+2RTU9Npxa/5e10p0XU/lmUxOryX7q5OIpEw4xPjxOMxnn/uWdqeaCNmxhgeHSSVSvHi2BidyS6OHv2S9z94D1e6exQzauqObZMeSGOtWNiOQ9iI4iIZGhplfb1CNpulNWyiqAr2xi0A5nN5QiEDze+n0QAkmic7/+diZ6K7bXLyTTxNKr19T/Hq+Css5Be4vpinWCwS8BsEQi3UajVMM45t24zsHaKv72leG59gcuINFKEsC6/X+13cfOT1S1cu8u03x8jl8ti2zfT0NCMjo9RqFS5fyhAMBejp6WZsbD9mLM6pk7+gqio/Hf+Ret1hLpv5Xhgh4+WwEZmey84ykO5HuuqWMwXgOA6ffzHF1NQR5jJ5FPWuxZaWCwcEEHzs0cfPeVtangwGjQdOfbVSpcXrRd0ktFZazVzLzw8rQHlpuXA4FAo/lIU0v3aPkBCCxesLh4Gyeic2c+Ov5d0xM57arsWtcF2XCxdnvpJSfgygbrr7wbJWioYRfqm5uXlH+6iqSr1eJ3P1yjuudD/cbp8BJIUQX/enBoYbjcaWQr//8ds5KeXbQG6n5biZXcABIDaYHkn+ev5sDvgbmAYW+L/5B5NrVZNHcIujAAAAAElFTkSuQmCC) no-repeat 5px 4px; - padding-left: 29px; - min-height: 26px; - line-height: 25px; - color: #555; - margin-bottom: 10px; - } - div.phpdebugbar-openhandler .phpdebugbar-openhandler-header a { - font-size: 14px; - color: #555; - text-decoration: none; - float: right; - padding: 5px 8px; - } - div.phpdebugbar-openhandler table { - width: 100%; - table-layout: fixed; - font-size: 14px; - } - div.phpdebugbar-openhandler table td { - padding: 6px 3px; - border-bottom: 1px solid #ddd; - } - div.phpdebugbar-openhandler table td a{ - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions { - text-align: center; - padding: 7px 0; - } - div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions a { - margin: 0 10px; - color: #555; - } +div.phpdebugbar-openhandler a { + color: #555; +} +div.phpdebugbar-openhandler .phpdebugbar-openhandler-header { + background: #efefef url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAYAAABvVQZ0AAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfdBgcKHQH1H7EUAAADV0lEQVQ4y7WUy28bVRSHvzvjJPbYY48dj80rTe28gCbCivPsAhBthJCoBIEQQGr/BMRjh1gA20plEYSQumFFQbBBEWVV0bLoQ1BC1YfcBDt1UicFZZzYje06M57LokVNaZJ2w7e7597zOzpX53fgfhSgzYzGDmk+7YQe0DMD/UNSD+gZzaedMKOxQ0DbnXf3IP5z1hLtyc8k8q1IuFX/N+i6LopyN7dYtNYR4ti1fO5doLqVmD+oBy90JLs6pJQ8CCEE2dxctnyz/AxQ2SwWjYRbzycTHbscx+Fh8Xg85OazC8VVKw2sqIDS3dlzJBo1X3Bdd8skKSVCiPvirusSChmhoB40rKJ1XFFVT/uGvXFwu+pBQ6erp5OdWq9v1A8KIdo9Ab9/MhJu9TUaDdbWVlEUFYlEureTP/n0IwpLNzh75gwetRlN06jdqoF7+5Mcx8br9fk0nzaJ1+s7nU4NysTupLRtW5ZKJVmpVOWpkz/LjkRCFgoFaduOrFarcnb2quzb0ytnZmZktVaT5fJNWSqV5P59+2RTU9Npxa/5e10p0XU/lmUxOryX7q5OIpEw4xPjxOMxnn/uWdqeaCNmxhgeHSSVSvHi2BidyS6OHv2S9z94D1e6exQzauqObZMeSGOtWNiOQ9iI4iIZGhplfb1CNpulNWyiqAr2xi0A5nN5QiEDze+n0QAkmic7/+diZ6K7bXLyTTxNKr19T/Hq+Css5Be4vpinWCwS8BsEQi3UajVMM45t24zsHaKv72leG59gcuINFKEsC6/X+13cfOT1S1cu8u03x8jl8ti2zfT0NCMjo9RqFS5fyhAMBejp6WZsbD9mLM6pk7+gqio/Hf+Ret1hLpv5Xhgh4+WwEZmey84ykO5HuuqWMwXgOA6ffzHF1NQR5jJ5FPWuxZaWCwcEEHzs0cfPeVtangwGjQdOfbVSpcXrRd0ktFZazVzLzw8rQHlpuXA4FAo/lIU0v3aPkBCCxesLh4Gyeic2c+Ov5d0xM57arsWtcF2XCxdnvpJSfgygbrr7wbJWioYRfqm5uXlH+6iqSr1eJ3P1yjuudD/cbp8BJIUQX/enBoYbjcaWQr//8ds5KeXbQG6n5biZXcABIDaYHkn+ev5sDvgbmAYW+L/5B5NrVZNHcIujAAAAAElFTkSuQmCC) no-repeat 5px 4px; + padding-left: 29px; + min-height: 26px; + line-height: 25px; + color: #555; + margin-bottom: 10px; +} +div.phpdebugbar-openhandler .phpdebugbar-openhandler-header a { + font-size: 14px; + color: #555; + text-decoration: none; + float: right; + padding: 5px 8px; +} +div.phpdebugbar-openhandler table { + width: 100%; + table-layout: fixed; + font-size: 14px; +} +div.phpdebugbar-openhandler table td { + padding: 6px 3px; + border-bottom: 1px solid #ddd; +} +div.phpdebugbar-openhandler table td a{ + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions { + text-align: center; + padding: 7px 0; +} +div.phpdebugbar-openhandler .phpdebugbar-openhandler-actions a { + margin: 0 10px; + color: #555; +} diff --git a/src/DebugBar/Resources/openhandler.js b/src/DebugBar/Resources/openhandler.js index 5633043f..0fe34483 100644 --- a/src/DebugBar/Resources/openhandler.js +++ b/src/DebugBar/Resources/openhandler.js @@ -1,202 +1,202 @@ -if (typeof(PhpDebugBar) == 'undefined') { - // namespace - var PhpDebugBar = {}; - PhpDebugBar.$ = jQuery; +if (typeof (PhpDebugBar) == 'undefined') { + // namespace + var PhpDebugBar = {}; + PhpDebugBar.$ = jQuery; } -(function($) { - - var csscls = function(cls) { - return PhpDebugBar.utils.csscls(cls, 'phpdebugbar-openhandler-'); - }; - - PhpDebugBar.OpenHandler = PhpDebugBar.Widget.extend({ - - className: 'phpdebugbar-openhandler', - - defaults: { - items_per_page: 20 - }, - - render: function() { - var self = this; - - this.$el.appendTo('body').hide(); - this.$closebtn = $(''); - this.$table = $(''); - $('
PHP DebugBar | Open
').addClass(csscls('header')).append(this.$closebtn).appendTo(this.$el); - $('
DateMethodURLIPFilter data
').append(this.$table).appendTo(this.$el); - this.$actions = $('
').addClass(csscls('actions')).appendTo(this.$el); - - this.$closebtn.on('click', function() { - self.hide(); - }); - - this.$loadmorebtn = $('Load more') - .appendTo(this.$actions) - .on('click', function() { - self.find(self.last_find_request, self.last_find_request.offset + self.get('items_per_page'), self.handleFind.bind(self)); - }); - - this.$showonlycurrentbtn = $('Show only current URL') - .appendTo(this.$actions) - .on('click', function() { - self.$table.empty(); - self.find({uri: window.location.pathname}, 0, self.handleFind.bind(self)); - }); - - this.$showallbtn = $('Show all') - .appendTo(this.$actions) - .on('click', function() { - self.refresh(); - }); - - this.$clearbtn = $('Delete all') - .appendTo(this.$actions) - .on('click', function() { - self.clear(function() { - self.hide(); - }); - }); - - this.addSearch(); - - this.$overlay = $('
').addClass(csscls('overlay')).hide().appendTo('body'); - this.$overlay.on('click', function() { - self.hide(); - }); - }, - - refresh: function() { - this.$table.empty(); - this.$loadmorebtn.show(); - this.find({}, 0, this.handleFind.bind(this)); - }, - - addSearch: function(){ - var self = this; - var searchBtn = $('