This commit is contained in:
Markus
2022-04-28 09:40:10 +02:00
commit 795794f992
9586 changed files with 1146991 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Debug\Exceptions;
/**
* Base Toolbar collector
*/
class BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = false;
/**
* Whether this collector needs to display
* a label or not.
*
* @var bool
*/
protected $hasLabel = false;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var bool
*/
protected $hasVarData = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = '';
/**
* Gets the Collector's title.
*/
public function getTitle(bool $safe = false): string
{
if ($safe) {
return str_replace(' ', '-', strtolower($this->title));
}
return $this->title;
}
/**
* Returns any information that should be shown next to the title.
*/
public function getTitleDetails(): string
{
return '';
}
/**
* Does this collector need it's own tab?
*/
public function hasTabContent(): bool
{
return (bool) $this->hasTabContent;
}
/**
* Does this collector have a label?
*/
public function hasLabel(): bool
{
return (bool) $this->hasLabel;
}
/**
* Does this collector have information for the timeline?
*/
public function hasTimelineData(): bool
{
return (bool) $this->hasTimeline;
}
/**
* Grabs the data for the timeline, properly formatted,
* or returns an empty array.
*/
public function timelineData(): array
{
if (! $this->hasTimeline) {
return [];
}
return $this->formatTimelineData();
}
/**
* Does this Collector have data that should be shown in the
* 'Vars' tab?
*/
public function hasVarData(): bool
{
return (bool) $this->hasVarData;
}
/**
* Gets a collection of data that should be shown in the 'Vars' tab.
* The format is an array of sections, each with their own array
* of key/value pairs:
*
* $data = [
* 'section 1' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* 'section 2' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* ];
*/
public function getVarData()
{
return null;
}
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*
* Timeline data should be formatted into arrays that look like:
*
* [
* 'name' => 'Database::Query',
* 'component' => 'Database',
* 'start' => 10 // milliseconds
* 'duration' => 15 // milliseconds
* ]
*/
protected function formatTimelineData(): array
{
return [];
}
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @return array|string
*/
public function display()
{
return [];
}
/**
* Clean Path
*
* This makes nicer looking paths for the error output.
*/
public function cleanPath(string $file): string
{
return Exceptions::cleanPath($file);
}
/**
* Gets the "badge" value for the button.
*/
public function getBadgeValue()
{
return null;
}
/**
* Does this collector have any data collected?
*
* If not, then the toolbar button won't get shown.
*/
public function isEmpty(): bool
{
return false;
}
/**
* Returns the HTML to display the icon. Should either
* be SVG, or a base-64 encoded.
*
* Recommended dimensions are 24px x 24px
*/
public function icon(): string
{
return '';
}
/**
* Return settings as an array.
*/
public function getAsArray(): array
{
return [
'title' => $this->getTitle(),
'titleSafe' => $this->getTitle(true),
'titleDetails' => $this->getTitleDetails(),
'display' => $this->display(),
'badgeValue' => $this->getBadgeValue(),
'isEmpty' => $this->isEmpty(),
'hasTabContent' => $this->hasTabContent(),
'hasLabel' => $this->hasLabel(),
'icon' => $this->icon(),
'hasTimelineData' => $this->hasTimelineData(),
'timelineData' => $this->timelineData(),
];
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\CodeIgniter;
use Config\App;
use Config\Services;
/**
* Debug toolbar configuration
*/
class Config
{
/**
* Return toolbar config values as an array.
*/
public static function display(): array
{
$config = config(App::class);
return [
'ciVersion' => CodeIgniter::CI_VERSION,
'phpVersion' => PHP_VERSION,
'phpSAPI' => PHP_SAPI,
'environment' => ENVIRONMENT,
'baseURL' => $config->baseURL,
'timezone' => app_timezone(),
'locale' => Services::request()->getLocale(),
'cspEnabled' => $config->CSPEnabled,
];
}
}

View File

@@ -0,0 +1,253 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Database\Query;
/**
* Collector for the Database tab of the Debug Toolbar.
*/
class Database extends BaseCollector
{
/**
* Whether this collector has timeline data.
*
* @var bool
*/
protected $hasTimeline = true;
/**
* Whether this collector should display its own tab.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* Whether this collector has data for the Vars tab.
*
* @var bool
*/
protected $hasVarData = false;
/**
* The name used to reference this collector in the toolbar.
*
* @var string
*/
protected $title = 'Database';
/**
* Array of database connections.
*
* @var array
*/
protected $connections;
/**
* The query instances that have been collected
* through the DBQuery Event.
*
* @var array
*/
protected static $queries = [];
/**
* Constructor
*/
public function __construct()
{
$this->getConnections();
}
/**
* The static method used during Events to collect
* data.
*
* @internal param $ array \CodeIgniter\Database\Query
*/
public static function collect(Query $query)
{
$config = config('Toolbar');
// Provide default in case it's not set
$max = $config->maxQueries ?: 100;
if (count(static::$queries) < $max) {
$queryString = $query->getQuery();
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
if (! is_cli()) {
// when called in the browser, the first two trace arrays
// are from the DB event trigger, which are unneeded
$backtrace = array_slice($backtrace, 2);
}
static::$queries[] = [
'query' => $query,
'string' => $queryString,
'duplicate' => in_array($queryString, array_column(static::$queries, 'string', null), true),
'trace' => $backtrace,
];
}
}
/**
* Returns timeline data formatted for the toolbar.
*
* @return array The formatted data or an empty array.
*/
protected function formatTimelineData(): array
{
$data = [];
foreach ($this->connections as $alias => $connection) {
// Connection Time
$data[] = [
'name' => 'Connecting to Database: "' . $alias . '"',
'component' => 'Database',
'start' => $connection->getConnectStart(),
'duration' => $connection->getConnectDuration(),
];
}
foreach (static::$queries as $query) {
$data[] = [
'name' => 'Query',
'component' => 'Database',
'start' => $query['query']->getStartTime(true),
'duration' => $query['query']->getDuration(),
'query' => $query['query']->debugToolbarDisplay(),
];
}
return $data;
}
/**
* Returns the data of this collector to be formatted in the toolbar
*/
public function display(): array
{
$data['queries'] = array_map(static function (array $query) {
$isDuplicate = $query['duplicate'] === true;
$firstNonSystemLine = '';
foreach ($query['trace'] as $index => &$line) {
// simplify file and line
if (isset($line['file'])) {
$line['file'] = clean_path($line['file']) . ':' . $line['line'];
unset($line['line']);
} else {
$line['file'] = '[internal function]';
}
// find the first trace line that does not originate from `system/`
if ($firstNonSystemLine === '' && strpos($line['file'], 'SYSTEMPATH') === false) {
$firstNonSystemLine = $line['file'];
}
// simplify function call
if (isset($line['class'])) {
$line['function'] = $line['class'] . $line['type'] . $line['function'];
unset($line['class'], $line['type']);
}
if (strrpos($line['function'], '{closure}') === false) {
$line['function'] .= '()';
}
$line['function'] = str_repeat(chr(0xC2) . chr(0xA0), 8) . $line['function'];
// add index numbering padded with nonbreaking space
$indexPadded = str_pad(sprintf('%d', $index + 1), 3, ' ', STR_PAD_LEFT);
$indexPadded = preg_replace('/\s/', chr(0xC2) . chr(0xA0), $indexPadded);
$line['index'] = $indexPadded . str_repeat(chr(0xC2) . chr(0xA0), 4);
}
return [
'hover' => $isDuplicate ? 'This query was called more than once.' : '',
'class' => $isDuplicate ? 'duplicate' : '',
'duration' => ((float) $query['query']->getDuration(5) * 1000) . ' ms',
'sql' => $query['query']->debugToolbarDisplay(),
'trace' => $query['trace'],
'trace-file' => $firstNonSystemLine,
'qid' => md5($query['query'] . microtime()),
];
}, static::$queries);
return $data;
}
/**
* Gets the "badge" value for the button.
*/
public function getBadgeValue(): int
{
return count(static::$queries);
}
/**
* Information to be displayed next to the title.
*
* @return string The number of queries (in parentheses) or an empty string.
*/
public function getTitleDetails(): string
{
$this->getConnections();
$queryCount = count(static::$queries);
$uniqueCount = count(array_filter(static::$queries, static function ($query) {
return $query['duplicate'] === false;
}));
$connectionCount = count($this->connections);
return sprintf(
'(%d total Quer%s, %d %s unique across %d Connection%s)',
$queryCount,
$queryCount > 1 ? 'ies' : 'y',
$uniqueCount,
$uniqueCount > 1 ? 'of them' : '',
$connectionCount,
$connectionCount > 1 ? 's' : ''
);
}
/**
* Does this collector have any data collected?
*/
public function isEmpty(): bool
{
return empty(static::$queries);
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADMSURBVEhLY6A3YExLSwsA4nIycQDIDIhRWEBqamo/UNF/SjDQjF6ocZgAKPkRiFeEhoYyQ4WIBiA9QAuWAPEHqBAmgLqgHcolGQD1V4DMgHIxwbCxYD+QBqcKINseKo6eWrBioPrtQBq/BcgY5ht0cUIYbBg2AJKkRxCNWkDQgtFUNJwtABr+F6igE8olGQD114HMgHIxAVDyAhA/AlpSA8RYUwoeXAPVex5qHCbIyMgwBCkAuQJIY00huDBUz/mUlBQDqHGjgBjAwAAACexpph6oHSQAAAAASUVORK5CYII=';
}
/**
* Gets the connections from the database config
*/
private function getConnections()
{
$this->connections = \Config\Database::getConnections();
}
}

View File

@@ -0,0 +1,141 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\View\RendererInterface;
use Config\Services;
/**
* Views collector
*/
class Events extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var bool
*/
protected $hasVarData = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Events';
/**
* Instance of the Renderer service
*
* @var RendererInterface
*/
protected $viewer;
/**
* Constructor.
*/
public function __construct()
{
$this->viewer = Services::renderer();
}
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*/
protected function formatTimelineData(): array
{
$data = [];
$rows = $this->viewer->getPerformanceData();
foreach ($rows as $info) {
$data[] = [
'name' => 'View: ' . $info['view'],
'component' => 'Views',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
/**
* Returns the data of this collector to be formatted in the toolbar
*/
public function display(): array
{
$data = [
'events' => [],
];
foreach (\CodeIgniter\Events\Events::getPerformanceLogs() as $row) {
$key = $row['event'];
if (! array_key_exists($key, $data['events'])) {
$data['events'][$key] = [
'event' => $key,
'duration' => ($row['end'] - $row['start']) * 1000,
'count' => 1,
];
continue;
}
$data['events'][$key]['duration'] += ($row['end'] - $row['start']) * 1000;
$data['events'][$key]['count']++;
}
foreach ($data['events'] as &$row) {
$row['duration'] = number_format($row['duration'], 2);
}
return $data;
}
/**
* Gets the "badge" value for the button.
*/
public function getBadgeValue(): int
{
return count(\CodeIgniter\Events\Events::getPerformanceLogs());
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEASURBVEhL7ZXNDcIwDIVTsRBH1uDQDdquUA6IM1xgCA6MwJUN2hk6AQzAz0vl0ETUxC5VT3zSU5w81/mRMGZysixbFEVR0jSKNt8geQU9aRpFmp/keX6AbjZ5oB74vsaN5lSzA4tLSjpBFxsjeSuRy4d2mDdQTWU7YLbXTNN05mKyovj5KL6B7q3hoy3KwdZxBlT+Ipz+jPHrBqOIynZgcZonoukb/0ckiTHqNvDXtXEAaygRbaB9FvUTjRUHsIYS0QaSp+Dw6wT4hiTmYHOcYZsdLQ2CbXa4ftuuYR4x9vYZgdb4vsFYUdmABMYeukK9/SUme3KMFQ77+Yfzh8eYF8+orDuDWU5LAAAAAElFTkSuQmCC';
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
/**
* Files collector
*/
class Files extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Files';
/**
* Returns any information that should be shown next to the title.
*/
public function getTitleDetails(): string
{
return '( ' . count(get_included_files()) . ' )';
}
/**
* Returns the data of this collector to be formatted in the toolbar
*/
public function display(): array
{
$rawFiles = get_included_files();
$coreFiles = [];
$userFiles = [];
foreach ($rawFiles as $file) {
$path = $this->cleanPath($file);
if (strpos($path, 'SYSTEMPATH') !== false) {
$coreFiles[] = [
'name' => basename($file),
'path' => $path,
];
} else {
$userFiles[] = [
'name' => basename($file),
'path' => $path,
];
}
}
sort($userFiles);
sort($coreFiles);
return [
'coreFiles' => $coreFiles,
'userFiles' => $userFiles,
];
}
/**
* Displays the number of included files as a badge in the tab button.
*/
public function getBadgeValue(): int
{
return count(get_included_files());
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGBSURBVEhL7ZQ9S8NQGIVTBQUncfMfCO4uLgoKbuKQOWg+OkXERRE1IAXrIHbVDrqIDuLiJgj+gro7S3dnpfq88b1FMTE3VZx64HBzzvvZWxKnj15QCcPwCD5HUfSWR+JtzgmtsUcQBEva5IIm9SwSu+95CAWbUuy67qBa32ByZEDpIaZYZSZMjjQuPcQUq8yEyYEb8FSerYeQVGbAFzJkX1PyQWLhgCz0BxTCekC1Wp0hsa6yokzhed4oje6Iz6rlJEkyIKfUEFtITVtQdAibn5rMyaYsMS+a5wTv8qeXMhcU16QZbKgl3hbs+L4/pnpdc87MElZgq10p5DxGdq8I7xrvUWUKvG3NbSK7ubngYzdJwSsF7TiOh9VOgfcEz1UayNe3JUPM1RWC5GXYgTfc75B4NBmXJnAtTfpABX0iPvEd9ezALwkplCFXcr9styiNOKc1RRZpaPM9tcqBwlWzGY1qPL9wjqRBgF5BH6j8HWh2S7MHlX8PrmbK+k/8PzjOOzx1D3i1pKTTAAAAAElFTkSuQmCC';
}
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
/**
* History collector
*/
class History extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* Whether this collector needs to display
* a label or not.
*
* @var bool
*/
protected $hasLabel = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'History';
/**
* @var array History files
*/
protected $files = [];
/**
* Specify time limit & file count for debug history.
*
* @param int $current Current history time
* @param int $limit Max history files
*/
public function setFiles(int $current, int $limit = 20)
{
$filenames = glob(WRITEPATH . 'debugbar/debugbar_*.json');
$files = [];
$counter = 0;
foreach (array_reverse($filenames) as $filename) {
$counter++;
// Oldest files will be deleted
if ($limit >= 0 && $counter > $limit) {
unlink($filename);
continue;
}
// Get the contents of this specific history request
$contents = file_get_contents($filename);
$contents = @json_decode($contents);
if (json_last_error() === JSON_ERROR_NONE) {
preg_match_all('/\d+/', $filename, $time);
$time = (int) end($time[0]);
// Debugbar files shown in History Collector
$files[] = [
'time' => $time,
'datetime' => date('Y-m-d H:i:s', $time),
'active' => $time === $current,
'status' => $contents->vars->response->statusCode,
'method' => $contents->method,
'url' => $contents->url,
'isAJAX' => $contents->isAJAX ? 'Yes' : 'No',
'contentType' => $contents->vars->response->contentType,
];
}
}
$this->files = $files;
}
/**
* Returns the data of this collector to be formatted in the toolbar
*/
public function display(): array
{
return ['files' => $this->files];
}
/**
* Displays the number of included files as a badge in the tab button.
*/
public function getBadgeValue(): int
{
return count($this->files);
}
/**
* Return true if there are no history files.
*/
public function isEmpty(): bool
{
return empty($this->files);
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJySURBVEhL3ZU7aJNhGIVTpV6i4qCIgkIHxcXLErS4FBwUFNwiCKGhuTYJGaIgnRoo4qRu6iCiiIuIXXTTIkIpuqoFwaGgonUQlC5KafU5ycmNP0lTdPLA4fu+8573/a4/f6hXpFKpwUwmc9fDfweKbk+n07fgEv33TLSbtt/hvwNFT1PsG/zdTE0Gp+GFfD6/2fbVIxqNrqPIRbjg4t/hY8aztcngfDabHXbKyiiXy2vcrcPH8oDCry2FKDrA+Ar6L01E/ypyXzXaARjDGGcoeNxSDZXE0dHRA5VRE5LJ5CFy5jzJuOX2wHRHRnjbklZ6isQ3tIctBaAd4vlK3jLtkOVWqABBXd47jGHLmjTmSScttQV5J+SjfcUweFQEbsjAas5aqoCLXutJl7vtQsAzpRowYqkBinyCC8Vicb2lOih8zoldd0F8RD7qTFiqAnGrAy8stUAvi/hbqDM+YzkAFrLPdR5ZqoLXsd+Bh5YCIH7JniVdquUWxOPxDfboHhrI5XJ7HHhiqQXox+APe/Qk64+gGYVCYZs8cMpSFQj9JOoFzVqqo7k4HIvFYpscCoAjOmLffUsNUGRaQUwDlmofUa34ecsdgXdcXo4wbakBgiUFafXJV8A4DJ/2UrxUKm3E95H8RbjLcgOJRGILhnmCP+FBy5XvwN2uIPcy1AJvWgqC4xm2aU4Xb3lF4I+Tpyf8hRe5w3J7YLymSeA8Z3nSclv4WLRyFdfOjzrUFX0klJUEtZtntCNc+F69cz/FiDzEPtjzmcUMOr83kDQEX6pAJxJfpL3OX22n01YN7SZCoQnaSdoZ+Jz+PZihH3wt/xlCoT9M6nEtmRSPCQAAAABJRU5ErkJggg==';
}
}

View File

@@ -0,0 +1,93 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\Services;
/**
* Loags collector
*/
class Logs extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Logs';
/**
* Our collected data.
*
* @var array
*/
protected $data;
/**
* Returns the data of this collector to be formatted in the toolbar
*/
public function display(): array
{
return [
'logs' => $this->collectLogs(),
];
}
/**
* Does this collector actually have any data to display?
*/
public function isEmpty(): bool
{
$this->collectLogs();
return empty($this->data);
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACYSURBVEhLYxgFJIHU1FSjtLS0i0D8AYj7gEKMEBkqAaAFF4D4ERCvAFrwH4gDoFIMKSkpFkB+OTEYqgUTACXfA/GqjIwMQyD9H2hRHlQKJFcBEiMGQ7VgAqCBvUgK32dmZspCpagGGNPT0/1BLqeF4bQHQJePpiIwhmrBBEADR1MRfgB0+WgqAmOoFkwANHA0FY0CUgEDAwCQ0PUpNB3kqwAAAABJRU5ErkJggg==';
}
/**
* Ensures the data has been collected.
*/
protected function collectLogs()
{
if (! empty($this->data)) {
return $this->data;
}
return $this->data = Services::logger(true)->logCache ?? [];
}
}

View File

@@ -0,0 +1,153 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\Services;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
/**
* Routes collector
*/
class Routes extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = false;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Routes';
/**
* Returns the data of this collector to be formatted in the toolbar
*
* @throws ReflectionException
*/
public function display(): array
{
$rawRoutes = Services::routes(true);
$router = Services::router(null, null, true);
// Matched Route
$route = $router->getMatchedRoute();
// Get our parameters
// Closure routes
if (is_callable($router->controllerName())) {
$method = new ReflectionFunction($router->controllerName());
} else {
try {
$method = new ReflectionMethod($router->controllerName(), $router->methodName());
} catch (ReflectionException $e) {
// If we're here, the method doesn't exist
// and is likely calculated in _remap.
$method = new ReflectionMethod($router->controllerName(), '_remap');
}
}
$rawParams = $method->getParameters();
$params = [];
foreach ($rawParams as $key => $param) {
$params[] = [
'name' => $param->getName(),
'value' => $router->params()[$key] ??
('&lt;empty&gt;&nbsp| default: ' . var_export($param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, true)),
];
}
$matchedRoute = [
[
'directory' => $router->directory(),
'controller' => $router->controllerName(),
'method' => $router->methodName(),
'paramCount' => count($router->params()),
'truePCount' => count($params),
'params' => $params,
],
];
// Defined Routes
$routes = [];
$methods = [
'get',
'head',
'post',
'patch',
'put',
'delete',
'options',
'trace',
'connect',
'cli',
];
foreach ($methods as $method) {
$raw = $rawRoutes->getRoutes($method);
foreach ($raw as $route => $handler) {
// filter for strings, as callbacks aren't displayable
if (is_string($handler)) {
$routes[] = [
'method' => strtoupper($method),
'route' => $route,
'handler' => $handler,
];
}
}
}
return [
'matchedRoute' => $matchedRoute,
'routes' => $routes,
];
}
/**
* Returns a count of all the routes in the system.
*/
public function getBadgeValue(): int
{
$rawRoutes = Services::routes(true);
return count($rawRoutes->getRoutes());
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFDSURBVEhL7ZRNSsNQFIUjVXSiOFEcuQIHDpzpxC0IGYeE/BEInbWlCHEDLsSiuANdhKDjgm6ggtSJ+l25ldrmmTwIgtgDh/t37r1J+16cX0dRFMtpmu5pWAkrvYjjOB7AETzStBFW+inxu3KUJMmhludQpoflS1zXban4LYqiO224h6VLTHr8Z+z8EpIHFF9gG78nDVmW7UgTHKjsCyY98QP+pcq+g8Ku2s8G8X3f3/I8b038WZTp+bO38zxfFd+I6YY6sNUvFlSDk9CRhiAI1jX1I9Cfw7GG1UB8LAuwbU0ZwQnbRDeEN5qqBxZMLtE1ti9LtbREnMIuOXnyIf5rGIb7Wq8HmlZgwYBH7ORTcKH5E4mpjeGt9fBZcHE2GCQ3Vt7oTNPNg+FXLHnSsHkw/FR+Gg2bB8Ptzrst/v6C/wrH+QB+duli6MYJdQAAAABJRU5ErkJggg==';
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\Services;
/**
* Timers collector
*/
class Timers extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = true;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = false;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Timers';
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*/
protected function formatTimelineData(): array
{
$data = [];
$benchmark = Services::timer(true);
$rows = $benchmark->getTimers(6);
foreach ($rows as $name => $info) {
if ($name === 'total_execution') {
continue;
}
$data[] = [
'name' => ucwords(str_replace('_', ' ', $name)),
'component' => 'Timer',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
}

View File

@@ -0,0 +1,147 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\View\RendererInterface;
use Config\Services;
/**
* Views collector
*/
class Views extends BaseCollector
{
/**
* Whether this collector has data that can
* be displayed in the Timeline.
*
* @var bool
*/
protected $hasTimeline = true;
/**
* Whether this collector needs to display
* content in a tab or not.
*
* @var bool
*/
protected $hasTabContent = false;
/**
* Whether this collector needs to display
* a label or not.
*
* @var bool
*/
protected $hasLabel = true;
/**
* Whether this collector has data that
* should be shown in the Vars tab.
*
* @var bool
*/
protected $hasVarData = true;
/**
* The 'title' of this Collector.
* Used to name things in the toolbar HTML.
*
* @var string
*/
protected $title = 'Views';
/**
* Instance of the Renderer service
*
* @var RendererInterface
*/
protected $viewer;
/**
* Views counter
*
* @var array
*/
protected $views = [];
/**
* Constructor.
*/
public function __construct()
{
$this->viewer = Services::renderer();
}
/**
* Child classes should implement this to return the timeline data
* formatted for correct usage.
*/
protected function formatTimelineData(): array
{
$data = [];
$rows = $this->viewer->getPerformanceData();
foreach ($rows as $info) {
$data[] = [
'name' => 'View: ' . $info['view'],
'component' => 'Views',
'start' => $info['start'],
'duration' => $info['end'] - $info['start'],
];
}
return $data;
}
/**
* Gets a collection of data that should be shown in the 'Vars' tab.
* The format is an array of sections, each with their own array
* of key/value pairs:
*
* $data = [
* 'section 1' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* 'section 2' => [
* 'foo' => 'bar,
* 'bar' => 'baz'
* ],
* ];
*/
public function getVarData(): array
{
return [
'View Data' => $this->viewer->getData(),
];
}
/**
* Returns a count of all views.
*/
public function getBadgeValue(): int
{
return count($this->viewer->getPerformanceData());
}
/**
* Display the icon.
*
* Icon from https://icons8.com - 1em package
*/
public function icon(): string
{
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADeSURBVEhL7ZSxDcIwEEWNYA0YgGmgyAaJLTcUaaBzQQEVjMEabBQxAdw53zTHiThEovGTfnE/9rsoRUxhKLOmaa6Uh7X2+UvguLCzVxN1XW9x4EYHzik033Hp3X0LO+DaQG8MDQcuq6qao4qkHuMgQggLvkPLjqh00ZgFDBacMJYFkuwFlH1mshdkZ5JPJERA9JpI6xNCBESvibQ+IURA9JpI6xNCBESvibQ+IURA9DTsuHTOrVFFxixgB/eUFlU8uKJ0eDBFOu/9EvoeKnlJS2/08Tc8NOwQ8sIfMeYFjqKDjdU2sp4AAAAASUVORK5CYII=';
}
}