├── registration.php
├── Controller
├── Assets
│ ├── Css.php
│ ├── Js.php
│ └── Base.php
└── OpenHandler
│ └── Handle.php
├── DataCollector
├── MessagesCollector.php
├── EventCollector.php
└── MagentoCollector.php
├── etc
├── frontend
│ ├── routes.xml
│ └── di.xml
├── module.xml
├── config.xml
├── di.xml
└── adminhtml
│ └── system.xml
├── Plugin
├── AddTimeDataCollectorPlugin.php
├── AddEventCollectorPlugin.php
├── AddMagentoCollectorPlugin.php
├── AddMessagesCollectorPlugin.php
├── ResponsePlugin.php
├── AbstractAddCollectorPlugin.php
└── EventManagerPlugin.php
├── API
└── ToolbarStateInterface.php
├── README.md
├── composer.json
├── helpers.php
├── JavascriptRenderer.php
├── Provider
└── StateProvider.php
├── DataFormatter
└── SimpleFormatter.php
├── view
└── base
│ └── web
│ ├── toolbar.css
│ └── font-awesome.css
├── Storage
└── FilesystemStorage.php
├── Toolbar.php
└── LICENSE.txt
/registration.php:
--------------------------------------------------------------------------------
1 | createResponse('text/css', function(){
10 | $this->toolbar->getJavascriptRenderer()->dumpCssAssets();
11 | });
12 | }
13 | }
--------------------------------------------------------------------------------
/Controller/Assets/Js.php:
--------------------------------------------------------------------------------
1 | createResponse('text/javascript', function(){
10 | $this->toolbar->getJavascriptRenderer()->dumpJsAssets();
11 | });
12 | }
13 | }
--------------------------------------------------------------------------------
/DataCollector/MessagesCollector.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Plugin/AddTimeDataCollectorPlugin.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 1
7 |
8 |
9 | 1
10 | 1
11 |
12 | 1
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/API/ToolbarStateInterface.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # magento2-toolbar
2 | Toolbar with developer and merchant functionality
3 |
4 | # Overview
5 | Goal is to create an extendible toolbar within Magento 2.
6 | The toolbar is displayed on both frontend and
7 | backend, and contains useful information for both developers and
8 | merchants.
9 |
10 | The toolbar is based on https://github.com/maximebf/php-debugbar
11 |
12 | Instead of extending from his extension, we have decided to create
13 | a new module, stripped down from all features: The empty toolbar (this module).
14 | Yet other modules can be created to add information to this toolbar.
15 |
16 | # Possible tabs
17 | - Observer and events
18 | - Plugin and interceptor (see [magento2-plugin-visualization](https://github.com/magento-hackathon/magento2-plugin-visualization))
19 | - Edit link (in backend) on various frontend pages
20 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "magento-hackathon/magento2-toolbar",
3 | "description": "Toolbar for Magento 2",
4 | "keywords": ["magento", "magento2", "toolbar", "debugbar", "profiler", "debug"],
5 | "type": "magento2-module",
6 | "authors": [
7 | {
8 | "name": "Barry vd. Heuvel"
9 | },
10 | {
11 | "name": "Elze Kool"
12 | }
13 | ],
14 | "license": [
15 | "OSL-3.0"
16 | ],
17 | "require": {
18 | "php": ">=7.0.0",
19 | "magento/framework": "~101.0",
20 | "maximebf/debugbar": "~1.15.0"
21 | },
22 | "autoload": {
23 | "psr-4": {
24 | "MagentoHackathon\\Toolbar\\": ""
25 | },
26 | "files": [
27 | "registration.php",
28 | "helpers.php"
29 | ]
30 | },
31 | "extra": {
32 | "branch-alias": {
33 | "dev-master": "0.1-dev"
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Plugin/ResponsePlugin.php:
--------------------------------------------------------------------------------
1 | toolbar = $toolbar;
22 | }
23 |
24 | /**
25 | * Add our toolbar to the response
26 | *
27 | * @param ResponseInterface $response
28 | */
29 | public function beforeSendResponse(ResponseInterface $response)
30 | {
31 | $this->toolbar->modifyResponse($response);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/helpers.php:
--------------------------------------------------------------------------------
1 | get(\MagentoHackathon\Toolbar\Toolbar::class);
13 |
14 | return $toolbar;
15 | }
16 | }
17 |
18 | if ( ! function_exists('debug')) {
19 |
20 | /**
21 | * @param mixed ...$args
22 | * @return void
23 | */
24 | function debug(...$args)
25 | {
26 | /** @var \MagentoHackathon\Toolbar\Toolbar $toolbar */
27 | $toolbar = \Magento\Framework\App\ObjectManager::getInstance()
28 | ->get(\MagentoHackathon\Toolbar\Toolbar::class);
29 |
30 | foreach ($args as $value) {
31 | $toolbar->addMessage($value);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Plugin/AbstractAddCollectorPlugin.php:
--------------------------------------------------------------------------------
1 |
14 | *
15 | *
16 | *
17 | */
18 | abstract class AbstractAddCollectorPlugin
19 | {
20 | /** @var Toolbar */
21 | protected $toolbar;
22 |
23 | /** @var DataCollectorInterface */
24 | protected $collector;
25 |
26 | /**
27 | * Constructor
28 | *
29 | * @param Toolbar $toolbar
30 | * @param DataCollectorInterface $collector
31 | */
32 | public function __construct(Toolbar $toolbar, DataCollectorInterface $collector)
33 | {
34 | $this->toolbar = $toolbar;
35 | $this->collector = $collector;
36 | }
37 |
38 | /**
39 | * Add the collector
40 | *
41 | */
42 | public function beforeLaunch()
43 | {
44 | $this->toolbar->addCollector($this->collector);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
10 |
13 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Controller/OpenHandler/Handle.php:
--------------------------------------------------------------------------------
1 | toolbar = $toolbar;
22 |
23 | parent::__construct($context);
24 | }
25 |
26 | /**
27 | * Dispatch request
28 | *
29 | * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface
30 | * @throws \Magento\Framework\Exception\NotFoundException
31 | */
32 | public function execute()
33 | {
34 | /** @var Raw $result */
35 | $result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
36 | $result->setHeader('content-type', 'application/json');
37 |
38 | $openHandler = new OpenHandler($this->toolbar);
39 | $data = $openHandler->handle(null, false, false);
40 |
41 | $result->setContents($data);
42 |
43 | return $result;
44 | }
45 | }
--------------------------------------------------------------------------------
/JavascriptRenderer.php:
--------------------------------------------------------------------------------
1 | url = $url;
17 |
18 | parent::__construct($debugBar);
19 | }
20 |
21 | /**
22 | * Renders the html to include needed assets
23 | *
24 | * @return string
25 | */
26 | public function renderHead()
27 | {
28 | $cssUrl = $this->url->getUrl('hackathon_toolbar/assets/css?v=' . $this->getAssetsHash('css'));
29 | $jsUrl = $this->url->getUrl('hackathon_toolbar/assets/js?v=' . $this->getAssetsHash('js'));
30 |
31 | $html = "";
32 | $html .= "";
33 |
34 | return $html;
35 | }
36 |
37 | /**
38 | * Get the hash of the included assets, based on filename and modified time.
39 | *
40 | * @param string $type 'js' or 'css'
41 | * @return string
42 | */
43 | protected function getAssetsHash($type)
44 | {
45 | $assets = [];
46 | foreach ($this->getAssets($type) as $file) {
47 | $assets[$file] = filemtime($file);
48 | }
49 | return md5(serialize($assets));
50 | }
51 | }
--------------------------------------------------------------------------------
/Plugin/EventManagerPlugin.php:
--------------------------------------------------------------------------------
1 | toolbar = $toolbar;
31 | $this->eventCollector = $eventCollector;
32 | $this->config = $config;
33 | }
34 |
35 | public function aroundDispatch(
36 | ManagerInterface $subject,
37 | \Closure $proceed,
38 | $eventName,
39 | array $data = []
40 | ) {
41 | $start = microtime(true);
42 | $res = $proceed($eventName, $data);
43 | $end = microtime(true);
44 |
45 | if ($this->toolbar->shouldCollectorRun($this->eventCollector)) {
46 | if ($observers = $this->config->getObservers($eventName)) {
47 | $data['__observers'] = $observers;
48 | }
49 |
50 | $this->eventCollector->addEvent($eventName, $start, $end, $data);
51 | }
52 |
53 | return $res;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/DataCollector/EventCollector.php:
--------------------------------------------------------------------------------
1 | setDataFormatter(new SimpleFormatter());
13 | }
14 |
15 | public function addEvent($name, $start, $end, $params)
16 | {
17 | $params = $this->prepareParams($params);
18 |
19 | return $this->addMeasure($name, $start, $end, $params);
20 | }
21 |
22 | protected function prepareParams($params)
23 | {
24 | $data = [];
25 | foreach ($params as $key => $value) {
26 | $data[$key] = htmlentities($this->getDataFormatter()->formatVar($value), ENT_QUOTES, 'UTF-8', false);
27 | }
28 | return $data;
29 | }
30 |
31 | public function collect()
32 | {
33 | $data = parent::collect();
34 | $data['nb_measures'] = count($data['measures']);
35 |
36 | return $data;
37 | }
38 |
39 | public function getName()
40 | {
41 | return 'event';
42 | }
43 |
44 | public function getWidgets()
45 | {
46 | return [
47 | "events" => [
48 | "icon" => "tasks",
49 | "widget" => "PhpDebugBar.Widgets.TimelineWidget",
50 | "map" => "event",
51 | "default" => "{}",
52 | ],
53 | 'events:badge' => [
54 | 'map' => 'event.nb_measures',
55 | 'default' => 0,
56 | ],
57 | ];
58 | }
59 | }
--------------------------------------------------------------------------------
/Controller/Assets/Base.php:
--------------------------------------------------------------------------------
1 | toolbar = $toolbar;
20 |
21 | parent::__construct($context);
22 | }
23 |
24 | /**
25 | * @param $contentType
26 | * @param callable $callback
27 | * @return ResultInterface
28 | */
29 | protected function createResponse($contentType, callable $callback)
30 | {
31 | /** @var Raw $result */
32 | $result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
33 | $result->setHeader('content-type', $contentType);
34 |
35 | // Add cache headers
36 | $date = new \DateTime('+1 year');
37 | $date->setTimezone(new \DateTimeZone('UTC'));
38 | $result->setHeader('expires', $date->format('D, d M Y H:i:s').' GMT');
39 | $result->setHeader('shared-max-age', 31536000);
40 | $result->setHeader('max-age', 31536000);
41 | $result->setHeader('cache-control', 'public');
42 | $result->setHeader('pragma', 'cache');
43 |
44 |
45 | // Run the callback, catch the echo'd output to create the response
46 | ob_start();
47 | $callback();
48 | $result->setContents(ob_get_contents());
49 | ob_end_clean();
50 |
51 | return $result;
52 | }
53 | }
--------------------------------------------------------------------------------
/DataCollector/MagentoCollector.php:
--------------------------------------------------------------------------------
1 | productMetadata = $productMetadata;
28 | $this->resolver = $localeResolver;
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public function collect()
35 | {
36 | return array(
37 | "version" => $this->productMetadata->getVersion(),
38 | "locale" => $this->resolver->getLocale(),
39 | );
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public function getName()
46 | {
47 | return 'magento';
48 | }
49 |
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public function getWidgets()
54 | {
55 | return array(
56 | "version" => array(
57 | "icon" => "github",
58 | "tooltip" => "Version",
59 | "map" => "magento.version",
60 | "default" => ""
61 | ),
62 | "locale" => array(
63 | "icon" => "flag",
64 | "tooltip" => "Current locale",
65 | "map" => "magento.locale",
66 | "default" => "",
67 | ),
68 | );
69 | }
70 | }
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Magento\Config\Model\Config\Source\Yesno
10 | Enable the Debugbar on all requests.
11 |
12 |
13 |
14 |
15 |
16 |
17 | Magento\Config\Model\Config\Source\Enabledisable
18 | Shows the Magento version + current locale.
19 |
20 |
21 |
22 | Magento\Config\Model\Config\Source\Enabledisable
23 | Shows messages, can be aggregated from multiple sources.
24 |
25 |
26 |
27 | Magento\Config\Model\Config\Source\Enabledisable
28 | Can be used to display measurements.
29 |
30 |
31 |
32 | Magento\Config\Model\Config\Source\Enabledisable
33 | Show all events.
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Provider/StateProvider.php:
--------------------------------------------------------------------------------
1 | scopeConfig = $scopeConfig;
21 | $this->request = $request;
22 | }
23 |
24 | /**
25 | * Check if the Toolbar should be enabled.
26 | *
27 | * @return bool
28 | */
29 | public function isToolbarEnabled()
30 | {
31 | return $this->getConfigValue('dev/hackathon_toolbar/enabled');
32 | }
33 |
34 | /**
35 | * Check if the Toolbar should run at all.
36 | *
37 | * @return bool
38 | */
39 | public function shouldToolbarRun()
40 | {
41 | return $this->isToolbarEnabled() && ! $this->isInternalToolbarRequest();
42 | }
43 |
44 | /**
45 | * Determine if a specific collector should run.
46 | *
47 | * @param DataCollectorInterface $collector
48 | * @return bool
49 | */
50 | public function shouldCollectorRun(DataCollectorInterface $collector)
51 | {
52 | if ( ! $this->shouldToolbarRun()) {
53 | return false;
54 | }
55 |
56 | $configPath = 'dev/hackathon_toolbar_collectors/' . $collector->getName();
57 |
58 | return (bool) $this->scopeConfig->getValue($configPath);
59 | }
60 |
61 | /**
62 | * Check if the Toolbar should be visible on the frontend.
63 | *
64 | * @return bool
65 | */
66 | public function isToolbarVisible()
67 | {
68 | return true;
69 | }
70 |
71 | /**
72 | * Check if the current request is an ajax request.
73 | *
74 | * @return bool
75 | */
76 | public function isAjaxRequest()
77 | {
78 | return $this->request->isAjax();
79 | }
80 |
81 | /**
82 | * Check if the current request is an internal Toolbar request.
83 | *
84 | * @return bool
85 | */
86 | protected function isInternalToolbarRequest()
87 | {
88 | return $this->request->getModuleName() === 'hackathon_toolbar';
89 | }
90 |
91 | /**
92 | * Get a Config value.
93 | *
94 | * @param $path
95 | * @return mixed
96 | */
97 | protected function getConfigValue($path)
98 | {
99 | return $this->scopeConfig->getValue($path);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/DataFormatter/SimpleFormatter.php:
--------------------------------------------------------------------------------
1 | exportValue($data);
21 | }
22 |
23 | /**
24 | * Converts a PHP value to a string.
25 | *
26 | * @param mixed $value The PHP value
27 | * @param int $depth Only for internal usage
28 | * @param bool $deep Only for internal usage
29 | *
30 | * @return string The string representation of the given value
31 | * @author Bernhard Schussek
32 | */
33 | private function exportValue($value, $depth = 1, $deep = false)
34 | {
35 | if ($value instanceof \__PHP_Incomplete_Class) {
36 | return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value));
37 | }
38 |
39 | if (is_object($value)) {
40 | if ($value instanceof \DateTimeInterface) {
41 | return sprintf('Object(%s) - %s', get_class($value), $value->format(\DateTime::ATOM));
42 | }
43 |
44 | return sprintf('Object(%s)', get_class($value));
45 | }
46 |
47 | if (is_array($value)) {
48 | if (empty($value)) {
49 | return '[]';
50 | }
51 |
52 | $indent = str_repeat(' ', $depth);
53 |
54 | $a = array();
55 | foreach ($value as $k => $v) {
56 | if (is_array($v)) {
57 | $deep = true;
58 | }
59 | $a[] = sprintf('%s => %s', $k, $this->exportValue($v, $depth + 1, $deep));
60 | }
61 |
62 | if ($deep) {
63 | return sprintf("[\n%s%s\n%s]", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1));
64 | }
65 |
66 | $s = sprintf('[%s]', implode(', ', $a));
67 |
68 | if (80 > strlen($s)) {
69 | return $s;
70 | }
71 |
72 | return sprintf("[\n%s%s\n]", $indent, implode(sprintf(",\n%s", $indent), $a));
73 | }
74 |
75 | if (is_resource($value)) {
76 | return sprintf('Resource(%s#%d)', get_resource_type($value), $value);
77 | }
78 |
79 | if (null === $value) {
80 | return 'null';
81 | }
82 |
83 | if (false === $value) {
84 | return 'false';
85 | }
86 |
87 | if (true === $value) {
88 | return 'true';
89 | }
90 |
91 | return (string) $value;
92 | }
93 |
94 | /**
95 | * @param \__PHP_Incomplete_Class $value
96 | * @return mixed
97 | * @author Bernhard Schussek
98 | */
99 | private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
100 | {
101 | $array = new \ArrayObject($value);
102 |
103 | return $array['__PHP_Incomplete_Class_Name'];
104 | }
105 | }
--------------------------------------------------------------------------------
/view/base/web/toolbar.css:
--------------------------------------------------------------------------------
1 | div.phpdebugbar {
2 | font-size: 13px;
3 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
4 | }
5 | div.phpdebugbar-header {
6 | height: 40px;
7 | padding-left: 48px;
8 | }
9 | select.phpdebugbar-datasets-switcher {
10 | max-height: 40px;
11 | }
12 | div.phpdebugbar-header > div > * {
13 | font-size: 15px;
14 | line-height: 30px;
15 | color: #aaa6a0;
16 | }
17 | div.phpdebugbar-header .phpdebugbar-tab,
18 | div.phpdebugbar-header .phpdebugbar-indicator {
19 | padding-left: 12px;
20 | padding-right: 12px;
21 | }
22 | div.phpdebugbar-header .phpdebugbar-indicator {
23 | border: none;
24 | }
25 | div.phpdebugbar-header .phpdebugbar-close-btn,
26 | div.phpdebugbar-header .phpdebugbar-open-btn,
27 | div.phpdebugbar-header .phpdebugbar-minimize-btn,
28 | div.phpdebugbar-header .phpdebugbar-maximize-btn {
29 | width: 40px;
30 | height: 30px;
31 | background-position: center center;
32 | border-right: none;
33 | }
34 | .phpdebugbar-indicator span.phpdebugbar-tooltip {
35 | top: -40px;
36 | background: #eb5202;
37 | color: #fff;
38 | border: none;
39 | opacity: 1;
40 | }
41 | div.phpdebugbar-body {
42 | padding: 10px;
43 | }
44 | div.phpdebugbar-widgets-messages div.phpdebugbar-widgets-toolbar {
45 | width: auto;
46 | left: 15px;
47 | right: 15px;
48 | }
49 | div.phpdebugbar-resize-handle,
50 | div.phpdebugbar-closed,
51 | div.phpdebugbar-minimized {
52 | border: none;
53 | }
54 | a.phpdebugbar-restore-btn.phpdebugbar-restore-btn {
55 | border-right-color: #aaa6a0;
56 | height: 32px;
57 | width: 32px;
58 | background-size: 24px auto;
59 | background-position: center center;
60 | }
61 | div.phpdebugbar-header,
62 | a.phpdebugbar-restore-btn,
63 | div.phpdebugbar-openhandler .phpdebugbar-openhandler-header {
64 | background: #373330 url(data:image/svg+xml;base64,PHN2ZyBiYXNlUHJvZmlsZT0idGlueSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMzUiIGhlaWdodD0iNDEiIHZpZXdCb3g9Ii0wLjE1NCAwIDU0IDYyIj48ZyBmaWxsPSIjRTg1RDIyIj48cGF0aCBkPSJNMjYuODQ1IDguODU3Ii8+PHBhdGggZD0iTTUzLjY5MiAxNS41djMxbC03LjY3IDQuNDN2LTMxTDI2Ljg0NCA4Ljg1NiA3LjY3IDE5LjkyNlY1MC45M0wwIDQ2LjV2LTMxTDI2Ljg0NSAwek0yNi44NDcgNjJMMTUuMzQgNTUuMzU1VjI0LjM1N2w3LjY3LTQuNDNWNTAuOTNsMy44MzUgMi4zMjcgMy44MzctMi4zMjd2LTMxbDcuNjcgNC40Mjd2MzAuOTk4eiIvPjwvZz48L3N2Zz4=) no-repeat;
65 | background-size: 24px auto;
66 | background-position: 16px center;
67 | }
68 | a.phpdebugbar-restore-btn {
69 | width: 18px;
70 | border-right-color: #aaa6a0;
71 | }
72 | a.phpdebugbar-tab:hover,
73 | span.phpdebugbar-indicator:hover,
74 | a.phpdebugbar-indicator:hover,
75 | a.phpdebugbar-close-btn:hover,
76 | a.phpdebugbar-open-btn:hover,
77 | a.phpdebugbar-minimize-btn:hover,
78 | a.phpdebugbar-maximize-btn:hover {
79 | background-color: #eb5202;
80 | transition: background-color .25s linear 0s, color .25s linear 0s;
81 | }
82 | a.phpdebugbar-close-btn,
83 | a.phpdebugbar-open-btn,
84 | a.phpdebugbar-minimize-btn,
85 | a.phpdebugbar-maximize-btn {
86 | background-color: #aaa6a0;
87 | }
88 | a.phpdebugbar-tab.phpdebugbar-active,
89 | a.phpdebugbar-tab:hover,
90 | span.phpdebugbar-indicator:hover,
91 | a.phpdebugbar-indicator:hover {
92 | background: #eb5202;
93 | color: #fff;
94 | }
95 |
96 | a.phpdebugbar-tab span.phpdebugbar-badge {
97 | vertical-align: 0px;
98 | padding: 2px 6px;
99 | background: #eb5202;
100 | font-size: 12px;
101 | color: #fff;
102 | border-radius: 10px;
103 | }
104 | a.phpdebugbar-tab.phpdebugbar-active span.phpdebugbar-badge,
105 | a.phpdebugbar-tab:hover span.phpdebugbar-badge {
106 | background-color: #ffffff;
107 | color: #eb5202;
108 | }
109 |
110 | ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-value {
111 | top: 2px;
112 | height: 16px;
113 | background: #eb5202;
114 | }
115 | ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label,
116 | ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-collector {
117 | color: black;
118 | }
119 | ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label,
120 | ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-collector {
121 | font-size: inherit;
122 | }
123 | ul.phpdebugbar-widgets-timeline table.phpdebugbar-widgets-params td,
124 | ul.phpdebugbar-widgets-timeline table.phpdebugbar-widgets-params th {
125 | padding: 4px 10px;
126 | }
127 |
--------------------------------------------------------------------------------
/Storage/FilesystemStorage.php:
--------------------------------------------------------------------------------
1 | filesystem = $filesystem;
25 | }
26 |
27 | /**
28 | * Saves collected data
29 | *
30 | * @param string $id
31 | * @param string $data
32 | */
33 | public function save($id, $data)
34 | {
35 | $directory = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
36 |
37 | if ($directory->create($this->dirname)) {
38 | $path = $this->makeFilename($id);
39 |
40 | $file = $directory->openFile($path);
41 | try {
42 | $file->write(json_encode($data));
43 | } finally {
44 | $file->close();
45 | }
46 | }
47 | }
48 |
49 | /**
50 | * Returns collected data with the specified id
51 | *
52 | * @param string $id
53 | * @return array
54 | */
55 | public function get($id)
56 | {
57 | $directory = $this->filesystem->getDirectoryRead(DirectoryList::VAR_DIR);
58 |
59 | return $this->loadFile($directory, $this->makeFilename($id));
60 | }
61 |
62 | /**
63 | * Returns a metadata about collected data
64 | *
65 | * @param array $filters
66 | * @param integer $max
67 | * @param integer $offset
68 | * @return array
69 | */
70 | public function find(array $filters = array(), $max = 20, $offset = 0)
71 | {
72 | $directory = $this->filesystem->getDirectoryRead(DirectoryList::VAR_DIR);
73 |
74 | $i = 0;
75 | $results = array();
76 | foreach ($directory->search('*.json', $this->dirname) as $path)
77 | {
78 | if ($i++ < $offset && empty($filters)) {
79 | $results[] = null;
80 | continue;
81 | }
82 |
83 | $data = $this->loadFile($directory, $path);
84 | $meta = $data['__meta'];
85 | unset($data);
86 | if ($this->filter($meta, $filters)) {
87 | $results[] = $meta;
88 | }
89 | if (count($results) >= ($max + $offset)) {
90 | break;
91 | }
92 | }
93 |
94 | return array_slice($results, $offset, $max);
95 | }
96 |
97 | /**
98 | * Filter the metadata for matches.
99 | *
100 | * @param $meta
101 | * @param $filters
102 | * @return bool
103 | */
104 | protected function filter($meta, $filters)
105 | {
106 | foreach ($filters as $key => $value) {
107 | if (!isset($meta[$key]) || fnmatch($value, $meta[$key]) === false) {
108 | return false;
109 | }
110 | }
111 | return true;
112 | }
113 |
114 | /**
115 | * Clears all the collected data
116 | */
117 | public function clear()
118 | {
119 | $directory = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
120 | $directory->delete($this->dirname);
121 | }
122 |
123 | /**
124 | * Create the filename for the data, based on the id.
125 | *
126 | * @param $id
127 | * @return string
128 | */
129 | protected function makeFilename($id)
130 | {
131 | return $this->dirname . DIRECTORY_SEPARATOR . basename($id) . ".json";
132 | }
133 |
134 | /**
135 | * Read a file into a stringß.ß
136 | *
137 | * @param ReadInterface $directory
138 | * @param $path
139 | * @return mixed
140 | */
141 | protected function loadFile(ReadInterface $directory, $path)
142 | {
143 | if ($directory->isExist($path)) {
144 | $file = $directory->openFile($path);
145 |
146 | $contents = '';
147 | while( ! $file->eof()) {
148 | $contents .= $file->read(8192);
149 | }
150 | return json_decode($contents, true);
151 | }
152 | }
153 | }
--------------------------------------------------------------------------------
/Toolbar.php:
--------------------------------------------------------------------------------
1 | url = $url;
44 | $this->state = $state;
45 | $this->appState = $appState;
46 | $this->setStorage($storage);
47 | }
48 |
49 | /**
50 | * @param DataCollectorInterface $collector
51 | * @return bool
52 | */
53 | public function shouldCollectorRun(DataCollectorInterface $collector)
54 | {
55 | return $this->state->shouldCollectorRun($collector);
56 | }
57 |
58 | /**
59 | * @param DataCollectorInterface $collector
60 | * @return $this
61 | * @throws \DebugBar\DebugBarException
62 | */
63 | public function addCollector(DataCollectorInterface $collector)
64 | {
65 | $collectorName = $collector->getName();
66 |
67 | if ($this->shouldCollectorRun($collector) && ! $this->hasCollector($collectorName)) {
68 | return parent::addCollector($collector);
69 | }
70 | }
71 |
72 | /**
73 | * Adds a message to the MessagesCollector
74 | *
75 | * A message can be anything from an object to a string
76 | *
77 | * @param mixed $message
78 | * @param string $label
79 | */
80 | public function addMessage($message, $label = 'info')
81 | {
82 | if ($this->hasCollector('messages')) {
83 | /** @var \MagentoHackathon\Toolbar\DataCollector\MessagesCollector $collector */
84 | $collector = $this->getCollector('messages');
85 | $collector->addMessage($message, $label);
86 | }
87 | }
88 |
89 | /**
90 | * Get the JavascriptRenderer
91 | *
92 | * @param string|null $baseUrl
93 | * @param string|null $basePath
94 | * @return \DebugBar\JavascriptRenderer
95 | */
96 | public function getJavascriptRenderer($baseUrl = null, $basePath = null)
97 | {
98 | if ($this->jsRenderer !== null) {
99 | return $this->jsRenderer;
100 | }
101 |
102 | // Create our own JavascriptRenderer
103 | $this->jsRenderer = new JavascriptRenderer($this, $this->url);
104 | $this->jsRenderer = $this->getJavascriptRenderer();
105 |
106 | // Add our own custom CSS
107 | $this->jsRenderer->addAssets([
108 | 'toolbar.css',
109 | 'font-awesome.css'
110 | ], [], __DIR__ . '/view/base/web');
111 |
112 | // Use RequireJS to include jQuery
113 | $this->jsRenderer->disableVendor('jquery');
114 | $this->jsRenderer->disableVendor('fontawesome');
115 | $this->jsRenderer->setUseRequireJs(true);
116 |
117 | // Enable the openHandler and bind to XHR requests
118 | $this->jsRenderer->setOpenHandlerUrl($this->url->getUrl('hackathon_toolbar/openhandler/handle'));
119 | $this->jsRenderer->setBindAjaxHandlerToXHR(true);
120 |
121 | return $this->jsRenderer;
122 | }
123 |
124 | /**
125 | * @param HttpResponse $response
126 | */
127 | public function modifyResponse(HttpResponse $response)
128 | {
129 | if ( ! $this->state->shouldToolbarRun()) {
130 | // Don't collect or store on internal routes
131 | return;
132 | } elseif ($response->isRedirect()) {
133 | // On redirects, stack the data for the next request
134 | $this->stackData();
135 | } elseif ($this->state->isAjaxRequest() || $response instanceof Json) {
136 | // On XHR requests, send the header so it can be shown by the active toolbar
137 | $this->sendDataInHeaders(true);
138 | } elseif($this->state->isToolbarVisible()) {
139 | // Inject the Toolbar into the HTML
140 | $this->appState->emulateAreaCode('frontend', function() use($response) {
141 | $this->injectToolbar($response);
142 | });
143 | } else {
144 | // Just collect the data without rendering (for later viewing)ß
145 | $this->collect();
146 | }
147 | }
148 |
149 | /**
150 | * Inject the toolbar in the HTML response.
151 | *
152 | * @param HttpResponse $response
153 | */
154 | protected function injectToolbar(HttpResponse $response)
155 | {
156 | $content = (string) $response->getBody();
157 | $renderer = $this->getJavascriptRenderer();
158 |
159 | $pos = strripos($content, '