├── .codeclimate.yml
├── .github
└── FUNDING.yml
├── .gitignore
├── Api
└── ServiceInterface.php
├── Block
├── Adminhtml
│ └── System
│ │ └── Config
│ │ └── Form
│ │ └── Fieldset
│ │ └── IsEnabled.php
├── Tab
│ ├── Content
│ │ ├── Config.php
│ │ ├── Help.php
│ │ ├── Layout.php
│ │ ├── Log.php
│ │ ├── PhpInfo.php
│ │ ├── Request.php
│ │ ├── Sql.php
│ │ └── Translation.php
│ ├── Panel.php
│ └── Wrapper.php
└── Toolbar.php
├── Console
└── Command
│ ├── AbstractStatusToolbar.php
│ ├── Database.php
│ ├── DisableToolBar.php
│ └── EnableToolBar.php
├── Controller
├── Action
│ ├── Cache.php
│ ├── CacheCss.php
│ ├── ConfigSearch.php
│ ├── ConfigUpdate.php
│ └── Cookie.php
├── Adminhtml
│ ├── Index.php
│ └── Tab
│ │ └── PhpInfo.php
├── Index.php
├── Index
│ └── Ajax.php
├── Log
│ ├── Reset.php
│ └── View.php
└── Tab
│ ├── Ajax.php
│ ├── PhpInfo.php
│ └── Translation.php
├── Helper
├── Cookie.php
├── Data.php
├── Debug.php
├── Register.php
└── Translate.php
├── Model
└── Config
│ └── Source
│ ├── Activate.php
│ ├── Area.php
│ ├── DumperHandler.php
│ └── Ide.php
├── Observer
├── ControllerFrontSendResponseBeforeObserver.php
├── LayoutGenerateBlocksAfterObserver.php
└── UpdateLayoutObserver.php
├── Plugin
├── Framework
│ ├── App
│ │ ├── Cache.php
│ │ ├── FrontController.php
│ │ └── UpdateCookies.php
│ ├── Event
│ │ ├── Invoker.php
│ │ └── Manager.php
│ ├── Form
│ │ └── Element.php
│ └── Http
│ │ └── Response.php
├── PageCache
│ └── FrontController
│ │ └── BuiltinPlugin.php
├── Search
│ ├── ResponseFactory.php
│ └── SearchClient.php
└── Zend
│ └── DbAdapter.php
├── Profiler
├── App.php
└── Db.php
├── README.md
├── Service
├── App
│ └── Cache.php
├── Config.php
├── Dumper.php
├── Elasticsearch.php
├── Event
│ ├── Instance.php
│ └── Manager.php
├── Layout
│ ├── Handle.php
│ └── Hierarchy.php
├── Module.php
├── Observer.php
├── Plugin.php
├── Request.php
└── Sql.php
├── composer.json
├── doc
├── Changelog.md
└── images
│ ├── phpstorm_debugger.png
│ ├── qdb_screen_config_ko.png
│ ├── qdb_screen_dark.png
│ ├── qdb_screen_dispatch.png
│ ├── qdb_screen_dispatch.youtube.png
│ ├── qdb_screen_queries.png
│ └── qdb_screen_request.png
├── etc
├── adminhtml
│ ├── di.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── csp_whitelist.xml
├── di.xml
├── events.xml
├── frontend
│ ├── di.xml
│ └── routes.xml
└── module.xml
├── modman
├── registration.php
└── view
├── base
├── layout
│ ├── default.xml
│ └── quickdevbar.xml
├── templates
│ ├── tab
│ │ ├── action.phtml
│ │ ├── design
│ │ │ ├── block.phtml
│ │ │ ├── handles.phtml
│ │ │ └── layout.phtml
│ │ ├── dumper.phtml
│ │ ├── help.phtml
│ │ ├── info
│ │ │ ├── config.phtml
│ │ │ ├── module.phtml
│ │ │ ├── request.phtml
│ │ │ └── store.phtml
│ │ ├── log.phtml
│ │ ├── profile
│ │ │ ├── cache.phtml
│ │ │ ├── collection.phtml
│ │ │ ├── event.phtml
│ │ │ ├── model.phtml
│ │ │ ├── observer.phtml
│ │ │ ├── plugin.phtml
│ │ │ ├── preference.phtml
│ │ │ └── profiler.phtml
│ │ ├── sql.phtml
│ │ └── translation
│ │ │ ├── file.phtml
│ │ │ └── plain.phtml
│ ├── tabs.phtml
│ └── toolbar.phtml
└── web
│ ├── css
│ └── quickdevbar.css
│ ├── images
│ ├── asc.gif
│ ├── bg.gif
│ ├── config.png
│ ├── database.png
│ ├── desc.gif
│ ├── dump.png
│ ├── help.png
│ ├── info.png
│ ├── lastnode.png
│ ├── layout.png
│ ├── loader-128.gif
│ ├── loader-32.gif
│ ├── loader-64.gif
│ ├── log.png
│ ├── node.png
│ ├── profile.png
│ ├── qdb-icon.png
│ ├── setting.png
│ ├── tools.png
│ ├── translate.png
│ └── vline.png
│ └── js
│ ├── filter-table.js
│ ├── sortable-table.js
│ └── tabbis.js
└── frontend
└── layout
└── quickdevbar.xml
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | languages:
2 | JavaScript: true
3 | PHP: true
4 | engines:
5 | duplication:
6 | enabled: true
7 | config:
8 | languages:
9 | - javascript
10 | - php
11 | eslint:
12 | enabled: true
13 | fixme:
14 | enabled: true
15 | phpmd:
16 | enabled: true
17 | checks:
18 | CleanCode/ElseExpression:
19 | enabled: false
20 | ratings:
21 | paths:
22 | - "**.js"
23 | - "**.php"
24 | exclude_paths:
25 | - "view/base/web/js/tablesorter/"
26 | - "view/base/web/js/sunnywalker/"
27 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: vpietri
2 | custom: ["https://paypal.me/vpietri"]
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .buildpath
2 | .project
3 | .settings/
4 | .idea/
5 |
--------------------------------------------------------------------------------
/Api/ServiceInterface.php:
--------------------------------------------------------------------------------
1 | _qdbHelper = $qdbHelper;
20 | }
21 |
22 | /**
23 | * @param AbstractElement $element
24 | * @return string
25 | */
26 | protected function _getElementHtml(AbstractElement $element)
27 | {
28 | $html = [];
29 | if ($this->_qdbHelper->isToolbarAccessAllowed(true)) {
30 | $html[] = __('Yep');
31 | } else {
32 | $html[] = '' . __('Nope') .' ';
33 | if (!$this->_qdbHelper->isIpAuthorized()) {
34 | $html[] = __('Your Ip "%1 " is not allowed, you should register it in the field below.', $this->_qdbHelper->getClientIp());
35 | }
36 | if (!$this->_qdbHelper->isUserAgentAuthorized()) {
37 | $html[] = __('Your User Agent "%1 " is not allowed, you should add a user-agent pattern', $this->_qdbHelper->getUserAgent());
38 | }
39 | }
40 |
41 |
42 | return implode(' ', $html);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Config.php:
--------------------------------------------------------------------------------
1 | _appConfig = $appConfig;
21 |
22 | parent::__construct($context, $qdbHelper, $qdbHelperRegister, $data);
23 | }
24 |
25 | public function getTitleBadge()
26 | {
27 | return $this->count($this->getConfigValues());
28 | }
29 |
30 | public function getConfigValues()
31 | {
32 | if (is_null($this->_config_values)) {
33 | $this->_config_values = $this->_buildFlatConfig($this->_appConfig->getValue( null, ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
34 | null));
35 | }
36 |
37 | return $this->_config_values;
38 | }
39 |
40 | protected function _buildFlatConfig($scope, $path = '')
41 | {
42 | $flatConfig = [];
43 | if (is_array($scope)) {
44 | foreach ($scope as $scopeKey => $scopeValue) {
45 | $buildedPath = !empty($path) ? $path.'/'.$scopeKey : $scopeKey;
46 | $flatConfig = array_merge($flatConfig, $this->_buildFlatConfig($scopeValue, $buildedPath));
47 | }
48 | } else {
49 | $flatConfig[$path] = ['path' => $path, 'value' => $scope];
50 | }
51 |
52 | return $flatConfig;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Help.php:
--------------------------------------------------------------------------------
1 | componentRegistrar = $componentRegistrar;
28 | $this->readFactory = $readFactory;
29 | }
30 |
31 |
32 | public function getModuleVersion()
33 | {
34 | //return $this->helper->getModuleVersion($this->getModuleName());
35 | return $this->getMagentoModuleVersion($this->getModuleName());
36 | }
37 |
38 |
39 | /**
40 | * @see https://www.rakeshjesadiya.com/get-module-composer-version-programmatically-by-magento/
41 | *
42 | */
43 | public function getMagentoModuleVersion(string $moduleName): string
44 | {
45 | $path = $this->componentRegistrar->getPath(
46 | ComponentRegistrar::MODULE,
47 | $moduleName
48 | );
49 | $directoryRead = $this->readFactory->create($path);
50 | $composerJsonData = '';
51 | if ($directoryRead->isFile('composer.json')) {
52 | $composerJsonData = $directoryRead->readFile('composer.json');
53 | }
54 | $data = json_decode($composerJsonData);
55 |
56 | return !empty($data->version) ? $data->version : '';
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Layout.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister->getLayoutHandles();
14 | }
15 |
16 | public function getHtmlBlocksHierarchy($treeBlocks = [], $level = 0)
17 | {
18 | if (empty($treeBlocks)) {
19 | $treeBlocks = [$this->qdbHelperRegister->getLayoutHierarchy()];
20 | }
21 |
22 | $html = '';
23 | foreach ($treeBlocks as $treeNode) {
24 | if(empty($treeNode)) {
25 | continue;
26 | }
27 |
28 | $openAttr = !empty($treeNode['children']) && $level < 2 ? " open " : "";
29 | $classes = ['type-'.$treeNode['type']];
30 | $classes[] = (!$treeNode['cacheable']) ? ' qdb-warning ' : '';
31 | $classes[] = !empty($treeNode['children']) ? ' haschild ' : '';
32 |
33 |
34 | $blockInfo = [];
35 | if (!empty($treeNode['class_name'])) {
36 | $blockInfo[]= 'Class: ' . $this->helper->getIDELinkForFile($treeNode['class_file'],1, $treeNode['class_name']);
37 | }
38 | if (!empty($treeNode['file'])) {
39 | $blockInfo[]= 'Template: ' . $this->helper->getIDELinkForFile($treeNode['file']);
40 | }
41 | if (empty($treeNode['cacheable'])) {
42 | $blockInfo[]= 'Not cacheable ';
43 | }
44 |
45 | $html .= '' .
50 | '' . $treeNode['name'] . ' ';
51 |
52 | if (!empty($blockInfo)) {
53 | $html .= '' . implode(' ', $blockInfo) . '
';
54 | }
55 |
56 | if (!empty($treeNode['children'])) {
57 | $html .= $this->getHtmlBlocksHierarchy($treeNode['children'], $level+1);
58 | }
59 | $html .= ' ';
60 | }
61 | $html .= '';
62 |
63 | return $html;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Log.php:
--------------------------------------------------------------------------------
1 | _jsonHelper = $jsonHelper;
23 |
24 | parent::__construct($context, $qdbHelper, $qdbHelperRegister, $data);
25 | }
26 |
27 | public function getTailLines()
28 | {
29 | return 20;
30 | }
31 |
32 | public function getLogFiles()
33 | {
34 | return $this->helper->getLogFiles();
35 | }
36 |
37 | public function getJsonLogFiles()
38 | {
39 | return $this->_jsonHelper->jsonEncode($this->helper->getLogFiles());
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Block/Tab/Content/PhpInfo.php:
--------------------------------------------------------------------------------
1 | showPhpInfo();
15 | }
16 |
17 | /**
18 | * Return PHP Info CSS
19 | */
20 | protected function phpInfoCssLambda($value)
21 | {
22 | return ".phpinfodisplay " . preg_replace("/,/", ",.phpinfodisplay ", $value);
23 | }
24 |
25 | public function showPhpInfo()
26 | {
27 | $what = $this->hasShortWhat() ? INFO_VARIABLES|INFO_ENVIRONMENT : INFO_ALL;
28 |
29 | ob_start();
30 | phpinfo($what);
31 | if (preg_match('%.*?
(.*)%s', ob_get_clean(), $matches)) {
32 | return "" . PHP_EOL .
42 | "" . PHP_EOL .
43 | $matches[2]. PHP_EOL .
44 | "
" . PHP_EOL;
45 | } else {
46 | return '';
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Request.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister->getContextData();
17 | return $requestData;
18 | }
19 |
20 | public function formatValue($data)
21 | {
22 | if (is_array($data['value'])) {
23 | return '' . print_r($data['value'], true) . ' ';
24 | } elseif (!empty($data['is_url'])) {
25 | return '' . $data['value'] . ' ';
26 | } else {
27 | return $data['value'];
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Sql.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister = $qdbHelperRegister;
25 | $this->objectFactory = $objectFactory;
26 | $this->cookieHelper = $cookieHelper;
27 | }
28 |
29 |
30 | public function getTitleBadge()
31 | {
32 | if ($this->getSqlProfiler()) {
33 | return $this->getSqlProfiler()->getTotalNumQueries();
34 | }
35 | return false;
36 | }
37 |
38 |
39 |
40 | /**
41 | * @return Zend_Db_Profiler
42 | */
43 | public function getSqlProfiler()
44 | {
45 | return $this->objectFactory->create()->setData($this->qdbHelperRegister->getRegisteredData('sql_profiler'));
46 | }
47 |
48 |
49 | public function getAllQueries()
50 | {
51 | return $this->getSqlProfiler()->getAllQueries();
52 | }
53 |
54 | public function getTotalNumQueries($queryType = null)
55 | {
56 | return $this->getSqlProfiler()->getTotalNumQueries($queryType);
57 | }
58 |
59 | public function getTotalNumQueriesByType($queryType = null)
60 | {
61 | $numQueriesByType = $this->getSqlProfiler()->getTotalNumQueriesByType();
62 | return isset($numQueriesByType[$queryType]) ? $numQueriesByType[$queryType] : 0;
63 | }
64 |
65 | public function getTotalElapsedSecs()
66 | {
67 | return $this->getSqlProfiler()->getTotalElapsedSecs();
68 | }
69 |
70 | public function getAverage()
71 | {
72 | return $this->getSqlProfiler()->getAverage();
73 | }
74 |
75 | public function getLongestQuery()
76 | {
77 | return $this->getSqlProfiler()->getLongestQuery();
78 | }
79 |
80 | public function getLongestQueryTime()
81 | {
82 | return $this->getSqlProfiler()->getLongestQueryTime();
83 | }
84 |
85 | public function getNumQueriesPerSecond()
86 | {
87 |
88 | return $this->getSqlProfiler()->getNumQueriesPerSecond();
89 | }
90 |
91 | public function formatSql($sql)
92 | {
93 | $htmlSql = preg_replace('/\b(SET|AS|ASC|COUNT|DESC|IN|LIKE|DISTINCT|INTO|VALUES|LIMIT)\b/', '\\1 ', $sql);
94 | $htmlSql = preg_replace('/\b(UNION ALL|DESCRIBE|SHOW|connect|begin|commit)\b/', '\\1 ', $htmlSql);
95 | $htmlSql = preg_replace('/\b(UPDATE|SELECT|FROM|WHERE|LEFT JOIN|INNER JOIN|RIGHT JOIN|ORDER BY|GROUP BY|DELETE|INSERT)\b/', '\\1 ', $htmlSql);
96 |
97 | return preg_replace('/^ /', '', $htmlSql);
98 | }
99 |
100 | public function formatParams($params) {
101 | if (is_array($params)) {
102 | ksort($params);
103 |
104 | return \json_encode($params);
105 | }
106 |
107 | return '';
108 | }
109 |
110 |
111 | public function formatSqlTime($time, $decimals = 2)
112 | {
113 | return number_format(round(1000 * $time, $decimals), $decimals) . 'ms';
114 | }
115 |
116 | public function formatSqlTrace($bt)
117 | {
118 | $traceFormated = [];
119 | foreach ($bt as $i=>$traceLine) {
120 | $traceFormated[] = sprintf('#%d %s %s->%s()', $i, $this->helper->getIDELinkForFile($traceLine['file'],$traceLine['line']) , $traceLine['class'], $traceLine['function']);
121 | }
122 | return ''.implode(' ', $traceFormated).'
';
123 | }
124 |
125 | public function getProfilerEnabled()
126 | {
127 | return $this->cookieHelper->isProfilerEnabled();
128 | }
129 |
130 | public function getProfilerBacktraceEnabled()
131 | {
132 | return $this->cookieHelper->isProfilerBacktraceEnabled();
133 | }
134 |
135 |
136 | public function getButtonProfilerLabel()
137 | {
138 | return $this->getProfilerEnabled() ? 'Disable profiler session' : 'Enable profiler session';
139 | }
140 |
141 | public function getButtonProfilerBactraceLabel()
142 | {
143 | return $this->getProfilerBacktraceEnabled() ? 'Disable backtrace' : 'Enable backtrace';
144 |
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/Block/Tab/Content/Translation.php:
--------------------------------------------------------------------------------
1 | translate = $translate;
30 | }
31 |
32 | /**
33 | * @return string
34 | */
35 | public function getType()
36 | {
37 | $type = $this->getTitle();
38 | if (!empty($this->_data['type'])) {
39 | $type = $this->_data['type'];
40 | }
41 |
42 | return strtolower($type);
43 | }
44 |
45 | /**
46 | * Get relevant path to template
47 | *
48 | * @return string
49 | */
50 | public function getTemplate()
51 | {
52 | if (empty($this->_template)) {
53 | if (in_array($this->getType(), ['module','theme'])) {
54 | $this->_template = "tab/translation/file.phtml";
55 | } else {
56 | $this->_template = "tab/translation/plain.phtml";
57 | }
58 | }
59 |
60 | return $this->_template;
61 | }
62 |
63 | /**
64 | * @return array
65 | * @throws LocalizedException
66 | */
67 | public function getTranslations()
68 | {
69 | return $this->translate->getTranslationsByType($this->getType());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Block/Tab/Panel.php:
--------------------------------------------------------------------------------
1 | helper = $helper;
29 | $this->qdbHelperRegister = $qdbHelperRegister;
30 | }
31 |
32 | /**
33 | * @param $key
34 | * @param $index
35 | * @return array|\Magento\Framework\DataObject|string|null
36 | * @throws \Exception
37 | */
38 | public function getData($key = '', $index = null)
39 | {
40 | if(!isset($this->_data[$key]) && $key==$this->getDataKey()) {
41 | return $this->getQdbData();
42 | }
43 | return parent::getData($key, $index);
44 | }
45 |
46 | public function getDataKey()
47 | {
48 | return $this->_data['data_key'] ?? null;
49 | }
50 |
51 |
52 |
53 | public function getTitleBadge()
54 | {
55 | $qdbData = $this->getQdbData();
56 | return $this->count($qdbData);
57 | }
58 |
59 | protected function count($registeredData)
60 | {
61 | return is_countable($registeredData) ? count($registeredData) : 0;
62 | }
63 |
64 |
65 | protected function getQdbData()
66 | {
67 | if(!$this->getDataKey()) {
68 | return '';
69 | }
70 |
71 | if(!$this->getDataKey()) {
72 | throw new \Exception('property qdbDataKey is not defined.');
73 | }
74 |
75 | return $this->qdbHelperRegister->getRegisteredData($this->getDataKey());
76 | }
77 |
78 |
79 | public function getTitle()
80 | {
81 | $title = $this->getData('title');
82 | if(!$title && $title = $this->getDataKey()) {
83 | return ucfirst($title);
84 | }
85 | return $title ?? $this->getNameInLayout();
86 | }
87 |
88 |
89 | public function getId($prefix = '')
90 | {
91 | $id = ($this->getData('id')) ? $this->getData('id') : $this->getNameInLayout();
92 | $id = str_replace('.', '-', $id);
93 | if ($prefix) {
94 | $id = $prefix . $id;
95 | }
96 | return $id;
97 | }
98 |
99 | public function getClass()
100 | {
101 | $class = $this->getId();
102 | if ($this->isAjax(false)) {
103 | $class .= ' use-ajax';
104 | }
105 |
106 | return $class;
107 | }
108 |
109 | public function isAjax($asString = true)
110 | {
111 | $return = (($this->hasData('ajax_url') || $this->hasData('is_ajax'))? true : false);
112 | if ($asString) {
113 | $return = ($return) ? "true" : "false";
114 | }
115 |
116 | return $return;
117 | }
118 |
119 | public function getTabUrl()
120 | {
121 | $tabUrl = '';
122 | if ($this->getData('tab_url')) {
123 | $tabUrl = $this->getData('tab_url');
124 | } else {
125 | if ($this->getData('ajax_url')) {
126 | $tabUrl = $this->getFrontUrl($this->getData('ajax_url'));
127 | } elseif ($this->getData('is_ajax')) {
128 | $tabUrl = $this->getFrontUrl('quickdevbar/tab/ajax', ['block'=>$this->getNameInLayout(), '_query'=>['isAjax'=>1]]);
129 | }
130 | }
131 |
132 | return $tabUrl;
133 | }
134 |
135 |
136 | /**
137 | * Generate url by route and parameters
138 | *
139 | * @param string $route
140 | * @param array $params
141 | * @return string
142 | */
143 | public function getFrontUrl($route = '', $params = [])
144 | {
145 | if ($this->_frontUrl === null) {
146 | $this->_frontUrl = ObjectManager::getInstance()->get('Magento\Framework\Url');
147 | }
148 |
149 | return $this->_frontUrl->getUrl($route, $params);
150 | }
151 |
152 | public function getHtmlLoader($class='')
153 | {
154 | $html = '
';
155 |
156 | return $html;
157 | }
158 |
159 |
160 | // public function getTabBlocks()
161 | // {
162 | // if ($this->_mainTabs === null) {
163 | // $this->_mainTabs = $this->getLayout()->getChildBlocks($this->getNameInLayout());
164 | // }
165 | //
166 | // return $this->_mainTabs;
167 | // }
168 |
169 | public function getStore()
170 | {
171 | return $this->_storeManager->getStore();
172 | }
173 |
174 | public function getWebsite()
175 | {
176 | return $this->_storeManager->getWebsite();
177 | }
178 |
179 | public function getGroup()
180 | {
181 | return $this->_storeManager->getGroup();
182 | }
183 |
184 | /**
185 | * Render block HTML
186 | *
187 | * @return string
188 | */
189 | protected function _toHtml()
190 | {
191 | try {
192 | $buffer = parent::_toHtml();
193 | return $this->sanitizeOutput($buffer);
194 | } catch (\Exception $e) {
195 | return $e->getMessage();
196 | }
197 | }
198 |
199 |
200 | /**
201 | * @see http://stackoverflow.com/a/6225706
202 | * @param $buffer
203 | * @return array|string|string[]|null
204 | */
205 | protected function sanitizeOutput($buffer)
206 | {
207 | if($this->getDoNotMinify()) {
208 | return $buffer;
209 | }
210 |
211 | $search = [
212 | '/\>[^\S ]+/s', // strip whitespaces after tags, except space
213 | '/[^\S ]+\',
219 | '<',
220 | '\\1'
221 | ];
222 |
223 | $buffer = preg_replace($search, $replace, $buffer);
224 |
225 | return $buffer;
226 | }
227 |
228 | public function htmlFormatClass($class)
229 | {
230 | return $this->helper->getIDELinkForClass($class);
231 | }
232 |
233 | /**
234 | * @param array $bt
235 | * @return string
236 | */
237 | public function formatTrace(array $bt)
238 | {
239 | return $this->helper->getIDELinkForFile($bt['file'], $bt['line']);
240 | }
241 |
242 | public function getQdbConfig($key, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null)
243 |
244 | {
245 | return $this->helper->getQdbConfig($key, $scopeType, $scopeCode);
246 | }
247 |
248 | }
249 |
--------------------------------------------------------------------------------
/Block/Tab/Wrapper.php:
--------------------------------------------------------------------------------
1 | _jsonHelper = $jsonHelper;
27 |
28 | parent::__construct($context, $qdbHelper, $qdbHelperRegister, $data);
29 | }
30 |
31 | public function getTabBlocks()
32 | {
33 | if ($this->_mainTabs === null) {
34 | $this->_mainTabs=[];
35 | foreach ($this->getLayout()->getChildBlocks($this->getNameInLayout()) as $alias => $block) {
36 | $this->_mainTabs[$alias]=$block;
37 | }
38 | }
39 |
40 | return $this->_mainTabs;
41 | }
42 |
43 | public function getSubTabSuffix()
44 | {
45 | return SimpleDataObjectConverter::snakeCaseToCamelCase(str_replace('.', '_', $this->getNameInLayout()));
46 | }
47 |
48 | public function getUiTabClass()
49 | {
50 | return ($this->getIsMainTab()) ? 'qdb-ui-tabs' : 'qdb-ui-subtabs';
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Block/Toolbar.php:
--------------------------------------------------------------------------------
1 | _qdnHelper = $qdnHelper;
25 |
26 | parent::__construct($context, $data);
27 | }
28 |
29 | /**
30 | * Determine if action is allowed
31 | *
32 | * @return bool
33 | */
34 | protected function canDisplay()
35 | {
36 | return $this->_qdnHelper->isToolbarAccessAllowed() && $this->_qdnHelper->isToolbarAreaAllowed($this->getArea());
37 | }
38 |
39 | public function getAppearance()
40 | {
41 | return $this->_qdnHelper->defaultAppearance();
42 | }
43 |
44 | public function getBaseUrl()
45 | {
46 | if ($this->_frontUrl === null) {
47 | $this->_frontUrl = ObjectManager::getInstance()->get('Magento\Framework\Url');
48 | }
49 |
50 | return $this->_frontUrl->getUrl();
51 | }
52 |
53 | public function isAjaxLoading()
54 | {
55 | return $this->_qdnHelper->isAjaxLoading() ? "true" : "false";
56 | }
57 |
58 | public function toHtml()
59 | {
60 | return (!$this->canDisplay()) ? '' : parent::toHtml();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Console/Command/AbstractStatusToolbar.php:
--------------------------------------------------------------------------------
1 | resourceConfig = $resourceConfig;
65 | $this->cacheManager = $cacheManager;
66 | $this->eventManager = $eventManager;
67 | $this->writer = $writer;
68 | $this->arrayManager = $arrayManager;
69 | }
70 |
71 | /**
72 | * {@inheritdoc}
73 | */
74 | protected function configure()
75 | {
76 | $this->setName($this->name);
77 | $this->setDescription($this->description);
78 | $this->addOption(
79 | self::CLEAN_HTML,
80 | null,
81 | InputOption::VALUE_NONE,
82 | 'Clear front cache block_html & full_page'
83 | );
84 | $this->addOption(
85 | self::ACTIVATE_SQL_PROFILER,
86 | null,
87 | InputOption::VALUE_NONE,
88 | 'Activate/deactivate SQL profiler'
89 | );
90 | }
91 |
92 | /**
93 | * {@inheritdoc}
94 | */
95 | protected function execute(InputInterface $input, OutputInterface $output)
96 | {
97 |
98 | $this->resourceConfig->saveConfig('dev/quickdevbar/enable', $this->status);
99 | $output->writeln("" . $this->message . " ");
100 |
101 | $this->eventManager->dispatch('adminhtml_cache_flush_system');
102 |
103 | $cachesToClear=['config'];
104 | if ($input->getOption(self::CLEAN_HTML)) {
105 | $cachesToClear = array_merge($cachesToClear, ['block_html', 'full_page']);
106 | }
107 |
108 | $lockTargetPath = ConfigFilePool::APP_ENV;
109 | if(!$this->status) {
110 | $this->writer->saveConfig(
111 | [$lockTargetPath => $this->arrayManager->set('db/connection/default/profiler', [], 0)],
112 | false
113 | );
114 | $output->writeln("SQL profiler is disabled in env.php ");
115 | } elseif ($input->getOption(self::ACTIVATE_SQL_PROFILER) ) {
116 |
117 | $profilerValue = [ 'enabled'=>1];
118 | $this->writer->saveConfig(
119 | [$lockTargetPath => $this->arrayManager->set('db/connection/default/profiler', [], $profilerValue)],
120 | false
121 | );
122 | $output->writeln("SQL profiler is enabled in env.php ");
123 | }
124 |
125 | $this->cacheManager->clean($cachesToClear);
126 | $output->writeln("Cache cleared: ".implode(",", $cachesToClear)." ");
127 |
128 | return \Magento\Framework\Console\Cli::RETURN_SUCCESS;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Console/Command/Database.php:
--------------------------------------------------------------------------------
1 | resource = $resource;
43 | }
44 |
45 | /**
46 | * {@inheritdoc}
47 | */
48 | protected function configure()
49 | {
50 | $this->setName($this->name);
51 | $this->setDescription($this->description);
52 | $this->addArgument(
53 | self::DB_TABLENAME,
54 | \Symfony\Component\Console\Input\InputArgument::REQUIRED,
55 | 'Table name to describe'
56 | );
57 | $this->addOption(
58 | self::DB_TABLE_COMMENT,
59 | 'c',
60 | null,
61 | 'Table name comment'
62 | );
63 | }
64 |
65 | /**
66 | * {@inheritdoc}
67 | */
68 | protected function execute(InputInterface $input, OutputInterface $output)
69 | {
70 |
71 | $connection = $this->resource->getConnection();
72 | $tableName = $input->getArgument(self::DB_TABLENAME);
73 |
74 | $ddl = $connection->describeTable($input->getArgument(self::DB_TABLENAME));
75 |
76 | $createTable = $connection->getCreateTable($input->getArgument(self::DB_TABLENAME));
77 | $createTableComment = [self::DDL_COMMENT_TABLE_KEY => $tableName . ' Table'];
78 |
79 | if(preg_match_all('/.*COMMENT[\s=]\'(.*)\'/', $createTable, $matchComment)) {
80 |
81 | }
82 |
83 | $tableEngine = 'innodb';
84 | $tableComment = $tableName . ' Table';
85 |
86 | $dbSchemaArr = [''];
87 | $dbSchemaArr[] = ' ';
88 |
89 | foreach ($ddl as $ddlColumn) {
90 | $xmlColumn=[];
91 | $xmlColumn['name'] = $ddlColumn['COLUMN_NAME'];
92 | $xmlColumn['xsi:type'] = $ddlColumn['DATA_TYPE'];
93 | $xmlColumn['nullable'] = $ddlColumn['NULLABLE'];
94 | if($ddlColumn['DEFAULT']) {
95 | $xmlColumn['default'] = $ddlColumn['DEFAULT'];
96 | }
97 | $xmlColumn['scale'] = $ddlColumn['SCALE'];
98 | $xmlColumn['precision'] = $ddlColumn['PRECISION'];
99 | $xmlColumn['unsigned'] = $ddlColumn['UNSIGNED'];
100 | if($ddlColumn['PRIMARY']) {
101 | $xmlColumn['primary'] = $ddlColumn['PRIMARY'];
102 | }
103 | if($ddlColumn['IDENTITY']) {
104 | $xmlColumn['identity'] = $ddlColumn['IDENTITY'];
105 | }
106 | $xmlColumn['length'] = $ddlColumn['LENGTH'];
107 | $xmlColumn['comment'] = $ddlColumn['COLUMN_NAME'];
108 | array_filter($xmlColumn, fn($var) => $var !== null);
109 | array_walk($xmlColumn, function(&$item, $key) {
110 | if(!is_string($item)) {
111 | $item = empty($item) ? 'false' : 'true';
112 | }
113 | $item = $key . '="'.$item.'"';
114 | });
115 |
116 | $dbSchemaArr[] = ' ';
117 | }
118 | $dbSchemaArr[] = '
';
119 | $dbSchemaArr[] = ' ';
120 |
121 |
122 | $output->writeln("" . implode(PHP_EOL, $dbSchemaArr) . " ");
123 |
124 | return Cli::RETURN_SUCCESS;
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/Console/Command/DisableToolBar.php:
--------------------------------------------------------------------------------
1 | _qdbHelper->getControllerMessage();
10 | $output = '';
11 | try {
12 |
13 | $cacheFrontEndPool = $this->_qdbHelper->getCacheFrontendPool();
14 | $this->_eventManager->dispatch('adminhtml_cache_flush_all');
15 | foreach ($cacheFrontEndPool as $cacheFrontend) {
16 | $cacheFrontend->clean();
17 | $cacheFrontend->getBackend()->clean();
18 | }
19 |
20 | $output = 'Cache cleaned';
21 |
22 | } catch (\Exception $e) {
23 | $output = $e->getMessage();
24 | $error = true;
25 | }
26 |
27 | if ($ctrlMsg) {
28 | $output = $ctrlMsg . ' (' . $output .')';
29 | }
30 |
31 | $resultRaw = $this->_resultRawFactory->create();
32 | return $resultRaw->setContents($output);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Controller/Action/CacheCss.php:
--------------------------------------------------------------------------------
1 | _mergeService = $mergeService;
28 | }
29 |
30 |
31 |
32 |
33 | public function execute()
34 | {
35 |
36 | try {
37 | $this->_mergeService->cleanMergedJsCss();
38 | $output = 'Cache merged Js and Css cleaned';
39 | } catch (\Exception $e) {
40 | $output = $e->getMessage();
41 | }
42 |
43 | $this->_view->loadLayout();
44 | $resultRaw = $this->_resultRawFactory->create();
45 | return $resultRaw->setContents($output);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Controller/Action/ConfigSearch.php:
--------------------------------------------------------------------------------
1 | _tabs = $configStructure->getTabs();
39 | }
40 |
41 |
42 |
43 | public function execute()
44 | {
45 | $this->_tabs->rewind();
46 | foreach ($this->_tabs as $tab) {
47 | echo $tab->getLabel();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Controller/Action/ConfigUpdate.php:
--------------------------------------------------------------------------------
1 | _resourceConfig = $resourceConfig;
45 | $this->_storeManager = $storeManager;
46 | $this->_resultForwardFactory = $resultForwardFactory;
47 | }
48 |
49 |
50 |
51 | public function execute()
52 | {
53 |
54 | $error = false;
55 | $output = '';
56 | $config = $this->getRequest()->getParam('config');
57 | try {
58 | if (empty($config['key'])) {
59 | throw new \Exception('Key is missing');
60 | } else {
61 | $configKey = $config['key'];
62 | }
63 |
64 |
65 | switch ($configKey) {
66 | case 'template_hints_admin':
67 | case 'template_hints_storefront':
68 | case 'template_hints_blocks':
69 | case 'translate':
70 | $configScope = 'stores';
71 | break;
72 | case 'devadmin':
73 | $configScope = 'default';
74 | break;
75 | default:
76 | throw new \Exception('Scope auto is unrecognized');
77 | break;
78 | }
79 |
80 |
81 | $configValue = 'toggle';
82 | switch ($configScope) {
83 | case 'stores':
84 | $configScopeId = $this->_storeManager->getStore()->getId();
85 | break;
86 | case 'websites':
87 | $configScopeId = $this->_storeManager->getWebsite()->getId();
88 | break;
89 | default:
90 | $configScopeId = 0;
91 | break;
92 | }
93 |
94 |
95 | switch ($configKey) {
96 | case 'template_hints_admin':
97 | case 'template_hints_storefront':
98 | case 'template_hints_blocks':
99 | $configValue = ($this->_qdbHelper->getConfig('dev/debug/' . $configKey, $configScope, $configScopeId)) ? 0 : 1;
100 | $this->_resourceConfig->saveConfig('dev/debug/' . $configKey, $configValue, $configScope, $configScopeId);
101 | $output = ucwords(str_replace('_', ' ', $configKey)) . " set " . ($configValue ? 'On' : 'Off');
102 | break;
103 | case 'translate':
104 | $configValue = ($this->_qdbHelper->getConfig('dev/translate_inline/active', $configScope, $configScopeId)) ? 0 : 1;
105 |
106 | $this->_resourceConfig->saveConfig('dev/translate_inline/active', $configValue, $configScope, $configScopeId);
107 | $output = "Translate set " . ($configValue ? 'On' : 'Off');
108 | break;
109 | case 'devadmin':
110 | $this->_resourceConfig->saveConfig('admin/security/password_lifetime', 0, $configScope, $configScopeId);
111 | $this->_resourceConfig->saveConfig('admin/security/password_is_forced', 0, $configScope, $configScopeId);
112 | $output = "Done";
113 | break;
114 | default:
115 | break;
116 | }
117 |
118 | if ($output) {
119 | $this->_qdbHelper->setControllerMessage($output);
120 | }
121 |
122 |
123 | } catch (\Exception $e) {
124 | $output = $e->getMessage();
125 | $error = true;
126 | }
127 |
128 | if (!$error) {
129 | /** @var \Magento\Framework\Controller\Result\Forward $resultForward */
130 | $resultForward = $this->_resultForwardFactory->create();
131 | $resultForward->forward('cache');
132 | return $resultForward;
133 | } else {
134 | $resultRaw = $this->_resultRawFactory->create();
135 | return $resultRaw->setContents($output);
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Controller/Action/Cookie.php:
--------------------------------------------------------------------------------
1 | cookieManager = $cookieManager;
25 | $this->cookieMetadataFactory = $cookieMetadataFactory;
26 | $this->sessionConfig = $sessionConfig;
27 | }
28 |
29 | public function execute()
30 | {
31 | $cookieName = $this->getRequest()->getParam('qdbName');
32 | $output = 'No cookie name';
33 | try {
34 | if ($cookieName) {
35 | $cookieValue = $this->getRequest()->getParam('qdbValue');
36 | if(is_null($cookieValue)) {
37 | if($this->getRequest()->getParam('qdbToggle')) {
38 | $cookieValue = $this->cookieManager->getCookie($cookieName) ? null : true;
39 | } else {
40 | throw new \Exception('No value to set');
41 | }
42 | }
43 |
44 |
45 | $metadata = $this->cookieMetadataFactory->createPublicCookieMetadata();
46 | $metadata->setPath($this->sessionConfig->getCookiePath());
47 | $metadata->setDomain($this->sessionConfig->getCookieDomain());
48 | $metadata->setDuration($this->sessionConfig->getCookieLifetime());
49 | $metadata->setSecure($this->sessionConfig->getCookieSecure());
50 | $metadata->setHttpOnly($this->sessionConfig->getCookieHttpOnly());
51 | $metadata->setSameSite($this->sessionConfig->getCookieSameSite());
52 |
53 | $this->cookieManager->setPublicCookie(
54 | $cookieName,
55 | $cookieValue,
56 | $metadata
57 | );
58 |
59 | $output = $cookieName.':'.$cookieValue;
60 | }
61 | } catch (\Exception $e) {
62 | $output = $e->getMessage();
63 | }
64 |
65 |
66 | $resultRaw = $this->_resultRawFactory->create();
67 | return $resultRaw->setContents($output);
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Index.php:
--------------------------------------------------------------------------------
1 | _layoutFactory = $layoutFactory;
31 | $this->_resultRawFactory = $resultRawFactory;
32 | parent::__construct($context);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Tab/PhpInfo.php:
--------------------------------------------------------------------------------
1 | _layoutFactory->create()
16 | ->createBlock('ADM\QuickDevBar\Block\Tab\Content\PhpInfo')
17 | ->toHtml();
18 | } catch (Exception $e) {
19 | $output = $e->getMessage();
20 | }
21 |
22 | $resultRaw = $this->_resultRawFactory->create();
23 | return $resultRaw->setContents($output);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Controller/Index.php:
--------------------------------------------------------------------------------
1 | _qdbHelper = $qdbHelper;
40 | $this->_resultRawFactory = $resultRawFactory;
41 | $this->_layoutFactory = $layoutFactory;
42 | }
43 |
44 | /**
45 | * @param \Magento\Framework\App\RequestInterface $request
46 | * @return \Magento\Framework\App\ResponseInterface
47 | */
48 | public function dispatch(\Magento\Framework\App\RequestInterface $request)
49 | {
50 | if (!$this->_isAllowed()) {
51 | throw new NotFoundException(__('Page not found.'));
52 | }
53 |
54 | return parent::dispatch($request);
55 | }
56 |
57 | /**
58 | * Determine if action is allowed
59 | *
60 | * @return bool
61 | */
62 | protected function _isAllowed()
63 | {
64 | return $this->_qdbHelper->isToolbarAccessAllowed();
65 | }
66 |
67 | public function execute()
68 | {
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Controller/Index/Ajax.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister = $qdbHelperRegister;
22 | }
23 |
24 |
25 | /**
26 | * @return \Magento\Framework\Controller\Result\Raw|void
27 | */
28 | public function execute()
29 | {
30 | /** @var \Magento\Framework\Controller\Result\Raw $resultRaw */
31 | $resultRaw = $this->_resultRawFactory->create();
32 |
33 | try {
34 | $this->qdbHelperRegister->loadDataFromFile();
35 |
36 | $this->_view->loadLayout('quickdevbar');
37 | $output = $this->_view->getLayout()->getBlock('quick.dev.maintabs')
38 | //->setNeedHtmlContent(true)
39 | ->toHtml();
40 | } catch (\Exception $e) {
41 | $output = $e->getMessage();
42 | $resultRaw->setStatusHeader(
43 | \Laminas\Http\Response::STATUS_CODE_202,
44 | \Laminas\Http\AbstractMessage::VERSION_11,
45 | 'QDB Error'
46 | );
47 | }
48 |
49 | //We are using HTTP headers to control various page caches (varnish, fastly, built-in php cache)
50 | $resultRaw->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true);
51 |
52 | return $resultRaw->setContents($output);
53 |
54 | }
55 |
56 | /**
57 | * @param \Magento\Framework\App\RequestInterface $request
58 | * @return \Magento\Framework\App\ResponseInterface
59 | */
60 | public function dispatch(\Magento\Framework\App\RequestInterface $request)
61 | {
62 | if (!$this->getRequest()->isXmlHttpRequest()) {
63 | throw new NotFoundException(__('Page not found.'));
64 | }
65 |
66 | return parent::dispatch($request);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Controller/Log/Reset.php:
--------------------------------------------------------------------------------
1 | getRequest()->getParam('log_key', '');
13 | $output = '';
14 |
15 | $file = $this->_qdbHelper->getLogFiles($fileKey);
16 | if ($file) {
17 | if (!empty($file['size'])) {
18 | if (!unlink($file['path'])) {
19 | $output = 'Cannot reset file.';
20 | } else {
21 | $output = 'File empty.';
22 | }
23 | } else {
24 | $output = 'Cannot find file to reset.';
25 | }
26 | } else {
27 | $output = $file['path'];
28 | }
29 |
30 | $this->_view->loadLayout();
31 | $resultRaw = $this->_resultRawFactory->create();
32 | //We are using HTTP headers to control various page caches (varnish, fastly, built-in php cache)
33 | $resultRaw->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true);
34 |
35 | return $resultRaw->setContents($output);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Controller/Log/View.php:
--------------------------------------------------------------------------------
1 | getRequest()->getParam('log_key', '');
13 | $lines = $this->getRequest()->getParam('tail', 20);
14 | $file = $this->_qdbHelper->getLogFiles($fileKey);
15 | if ($file) {
16 | $output = $this->_qdbHelper->tailFile($file['path'], $lines);
17 | } else {
18 | $output = __('No log file.');
19 | }
20 |
21 | $this->_view->loadLayout();
22 |
23 | $resultRaw = $this->_resultRawFactory->create();
24 | //We are using HTTP headers to control various page caches (varnish, fastly, built-in php cache)
25 | $resultRaw->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true);
26 |
27 | return $resultRaw->setContents($output);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Controller/Tab/Ajax.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister = $qdbHelperRegister;
18 | }
19 |
20 |
21 | /**
22 | *
23 | * @return \Magento\Backend\Model\View\Result\Page
24 | */
25 | public function execute()
26 | {
27 | $blockName = $this->getRequest()->getParam('block', '');
28 |
29 | try {
30 | $this->_view->loadLayout('quickdevbar');
31 |
32 | $block = $this->_view->getLayout()->getBlock($blockName);
33 | if ($block) {
34 | if($block->getNeedLoadData()) {
35 | $this->qdbHelperRegister->loadDataFromFile(true);
36 | }
37 | $block->setIsUpdateCall(true);
38 | $output = $block->toHtml();
39 | } else {
40 | $output = 'Cannot found block: '. $blockName;
41 | }
42 | } catch (Exception $e) {
43 | $output = $e->getMessage();
44 | }
45 |
46 | $resultRaw = $this->_resultRawFactory->create();
47 | //We are using HTTP headers to control various page caches (varnish, fastly, built-in php cache)
48 | $resultRaw->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true);
49 |
50 | return $resultRaw->setContents($output);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Controller/Tab/PhpInfo.php:
--------------------------------------------------------------------------------
1 | _layoutFactory->create()
15 | ->createBlock('ADM\QuickDevBar\Block\Tab\Content\PhpInfo')
16 | ->toHtml();
17 | } catch (Exception $e) {
18 | $output = $e->getMessage();
19 | }
20 |
21 | $resultRaw = $this->_resultRawFactory->create();
22 | return $resultRaw->setContents($output);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Controller/Tab/Translation.php:
--------------------------------------------------------------------------------
1 | getRequest()->getParam('type');
15 |
16 | $output = $this->_layoutFactory->create()
17 | ->createBlock('ADM\QuickDevBar\Block\Tab\Content\Translation')
18 | ->setType($type)
19 | ->toHtml();
20 | } catch (Exception $e) {
21 | $output = $e->getMessage();
22 | }
23 |
24 | $resultRaw = $this->_resultRawFactory->create();
25 | //We are using HTTP headers to control various page caches (varnish, fastly, built-in php cache)
26 | $resultRaw->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true);
27 |
28 | return $resultRaw->setContents($output);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Helper/Cookie.php:
--------------------------------------------------------------------------------
1 | cookieManager = $cookieManager;
19 | }
20 |
21 | public function isProfilerEnabled()
22 | {
23 | return (bool)$this->cookieManager->getCookie(self::COOKIE_NAME_PROFILER_ENABLED);
24 | }
25 |
26 | public function isProfilerBacktraceEnabled()
27 | {
28 | return (bool)$this->cookieManager->getCookie(self::COOKIE_NAME_PROFILER_BACKTRACE_ENABLED);
29 | }
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Helper/Debug.php:
--------------------------------------------------------------------------------
1 | $traceLine) {
17 | $traceFormated[] = sprintf('#%d %s(%d) %s->%s()', $i, $traceLine['file'], $traceLine['line'], $traceLine['class'], $traceLine['function']);
18 |
19 | }
20 | return implode($separator, $traceFormated);
21 |
22 | }
23 |
24 | public static function traceHtml()
25 | {
26 | return self::traceString(' ');
27 | }
28 |
29 | /**
30 | * @param array $trace
31 | * @return array
32 | */
33 | public static function trace(array $trace=[], $skipLine = null)
34 | {
35 | if(empty($trace)) {
36 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
37 | is_null($skipLine) && $skipLine=1;
38 | }
39 |
40 | $returnTrace = [];
41 | foreach ($trace as $i => $data) {
42 | if($i<$skipLine) {
43 | continue;
44 | }
45 |
46 | $className = '[class]';
47 | if (isset($data['class']) && isset($data['function'])) {
48 | $className = $data['class'];
49 |
50 | if (isset($data['object']) && get_class($data['object']) != $data['class']) {
51 | $className = get_class($data['object']);
52 | }
53 | }
54 | if(preg_match('/Interceptor$/', $className)) {
55 | $className = '[interceptor]';
56 | }
57 |
58 | $methodName = $data['function'] ?? '[function]';
59 | $fileName = $data['file'] ?? '[file]';
60 | $line = $data['line'] ?? '[line]';
61 |
62 | $returnTrace[]= ['file'=>$fileName, 'line'=> $line, 'class'=>$className, 'function'=>$methodName];
63 | }
64 |
65 | return $returnTrace;
66 | }
67 |
68 | /**
69 | * @see \Magento\Framework\Debug::getRootPath
70 | *
71 | * @return false|string
72 | */
73 | public static function getRootPath()
74 | {
75 | if (self::$_filePath === null) {
76 | if (defined('BP')) {
77 | self::$_filePath = BP;
78 | } else {
79 | self::$_filePath = dirname(__DIR__);
80 | }
81 | }
82 | return self::$_filePath;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Helper/Register.php:
--------------------------------------------------------------------------------
1 | objectFactory = $objectFactory;
37 | $this->qdbHelper = $qdbHelper;
38 | $this->services = $services;
39 | }
40 |
41 |
42 | /**
43 | * @return bool
44 | */
45 | public function dumpToFile()
46 | {
47 | $moduleName = $this->_getRequest()->getModuleName();
48 | if($this->_getRequest() && $moduleName=='quickdevbar') {
49 | return false;
50 | }
51 |
52 | //Test magewire for Hyva calls
53 | $isAjax = ( $this->_getRequest()->isAjax() || $moduleName=='magewire');
54 | foreach ($this->services as $serviceKey => $serviceObj) {
55 | //TODO: Filter keys on $isAjax
56 | if($isAjax && $serviceKey!='dumps') {
57 | continue;
58 | }
59 |
60 | $this->setRegisteredData($serviceKey, $serviceObj->pullData());
61 | }
62 | $content = $this->registeredData->convertToJson();
63 | $this->qdbHelper->setWrapperContent($content, $isAjax);
64 | }
65 |
66 | /**
67 | *
68 | */
69 | public function loadDataFromFile($ajax = false)
70 | {
71 | $wrapperContent = $this->qdbHelper->getWrapperContent($ajax);
72 | $this->setRegisteredData($wrapperContent);
73 | $this->pullDataFromService = false;
74 | }
75 |
76 |
77 |
78 | /**
79 | * @param null $key
80 | * @return \Magento\Framework\DataObject|null
81 | */
82 | public function getRegisteredData($key = '')
83 | {
84 | if($this->pullDataFromService && !empty($this->services[$key])) {
85 | return $this->services[$key]->pullData();
86 | } elseif (empty($this->registeredData)) {
87 | $this->registeredData = $this->objectFactory->create();
88 | }
89 | return $this->registeredData->getData($key);
90 | }
91 |
92 | public function setRegisteredData($key, $value = null)
93 | {
94 | if(is_null($this->registeredData)) {
95 | $this->registeredData = $this->objectFactory->create();
96 | }
97 |
98 | $this->registeredData->setData($key, $value);
99 | }
100 |
101 | public function getContextData()
102 | {
103 | return $this->getRegisteredData('request_data');
104 | }
105 |
106 | /**
107 | * @return \Magento\Framework\DataObject|null
108 | */
109 | public function getObservers()
110 | {
111 | return $this->getRegisteredData('observers');
112 | }
113 |
114 | /**
115 | * @return \Magento\Framework\DataObject|null
116 | */
117 | public function getEvents()
118 | {
119 | return $this->getRegisteredData('events');
120 | }
121 |
122 | /**
123 | * @return \Magento\Framework\DataObject|null
124 | */
125 | public function getCollections()
126 | {
127 | return $this->getRegisteredData('collections');
128 | }
129 |
130 | /**
131 | * @return \Magento\Framework\DataObject|null
132 | */
133 | public function getModels()
134 | {
135 | return $this->getRegisteredData('models');
136 | }
137 |
138 | /**
139 | * @return \Magento\Framework\DataObject|null
140 | */
141 | public function getBlocks()
142 | {
143 | return $this->getRegisteredData('blocks');
144 | }
145 |
146 | /**
147 | * @return \Magento\Framework\DataObject|null
148 | */
149 | public function getLayoutHandles()
150 | {
151 | return $this->getRegisteredData('layout_handles');
152 | }
153 |
154 | /**
155 | * @return \Magento\Framework\DataObject|null
156 | */
157 | public function getLayoutHierarchy()
158 | {
159 | return $this->getRegisteredData('layout_tree_blocks_hierarchy');
160 | }
161 |
162 | }
163 |
164 |
--------------------------------------------------------------------------------
/Helper/Translate.php:
--------------------------------------------------------------------------------
1 | directoryList = $directoryList;
83 | }
84 |
85 | /**
86 | * Gets relative file path for absolute path.
87 | *
88 | * @param string $absolutePath
89 | * @return string
90 | */
91 | protected function _getRelativeFilePath($absolutePath)
92 | {
93 | return str_replace($this->directoryList->getRoot() . DIRECTORY_SEPARATOR, '', $absolutePath);
94 | }
95 |
96 | /**
97 | * Load current theme translation
98 | *
99 | * @return $this
100 | */
101 | protected function _loadThemeTranslation()
102 | {
103 | $file = $this->_getThemeTranslationFile($this->getLocale());
104 | if ($file) {
105 | $relativePath = $this->_getRelativeFilePath($file);
106 | foreach ($this->_getFileData($file) as $key => $value) {
107 | if ($key === $value) {
108 | continue;
109 | }
110 | $this->_data['theme'][htmlspecialchars($key)] = [
111 | 'file' => $relativePath,
112 | 'translation' => htmlspecialchars((string)$value)
113 | ];
114 | }
115 | }
116 | return $this;
117 | }
118 |
119 | /**
120 | * Load translation dictionary from language packages.
121 | *
122 | * @todo It's also possible to get the filename of the language pack here, but generally only a single
123 | * language pack will be installed for a given locale.
124 | * @return $this
125 | * @throws LocalizedException
126 | */
127 | protected function _loadPackTranslation()
128 | {
129 | $this->_data['pack'] = $this->packDictionary->getDictionary($this->getLocale());
130 | return $this;
131 | }
132 |
133 | /**
134 | * Loading current translation from DB
135 | *
136 | * @return $this
137 | */
138 | protected function _loadDbTranslation()
139 | {
140 | $this->_data['db'] = $this->_translateResource->getTranslationArray(null, $this->getLocale());
141 | return $this;
142 | }
143 |
144 |
145 | /**
146 | * Load data from module translation files by list of modules
147 | *
148 | * @param array $modules
149 | * @return $this
150 | */
151 | protected function loadModuleTranslationByModulesList(array $modules)
152 | {
153 | foreach ($modules as $module) {
154 | $moduleFilePath = $this->_getModuleTranslationFile($module, $this->getLocale());
155 | $relativePath = $this->_getRelativeFilePath($moduleFilePath);
156 | foreach ($this->_getFileData($moduleFilePath) as $key => $value) {
157 | if ($key === $value) {
158 | continue;
159 | }
160 | $this->_data['module'][htmlspecialchars($key)] = [
161 | 'file' => $relativePath,
162 | 'translation' => htmlspecialchars((string)$value)
163 | ];
164 | }
165 | }
166 | return $this;
167 | }
168 |
169 | /**
170 | * Gets translation data by type.
171 | *
172 | * @param string $type
173 | * @return array
174 | * @throws LocalizedException
175 | */
176 | public function getTranslationsByType($type)
177 | {
178 | if ($this->_hasLoaded === false) {
179 | $this->loadData(null, true);
180 | $this->_hasLoaded = true;
181 | }
182 | return isset($this->_data[$type]) ? $this->_data[$type] : [];
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/Model/Config/Source/Activate.php:
--------------------------------------------------------------------------------
1 | 0, 'label' => __('No')],
16 | ['value' => 1, 'label' => __('Yes')],
17 | ['value' => 2, 'label' => __('Yes with restriction')]
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Model/Config/Source/Area.php:
--------------------------------------------------------------------------------
1 | \Magento\Framework\App\Area::AREA_GLOBAL, 'label' => __('All')],
15 | ['value' => \Magento\Framework\App\Area::AREA_FRONTEND, 'label' => __('Frontend only')],
16 | ['value' => \Magento\Framework\App\Area::AREA_ADMINHTML, 'label' => __('Adminhtml only')]
17 | ];
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Model/Config/Source/DumperHandler.php:
--------------------------------------------------------------------------------
1 | 0, 'label' => __('No')],
16 | ['value' => 1, 'label' => __('Current page')],
17 | ['value' => 2, 'label' => __('Current page and ajax calls')]
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Model/Config/Source/Ide.php:
--------------------------------------------------------------------------------
1 | helper = $helper;
14 | }
15 |
16 | /**
17 | * Options getter
18 | *
19 | * @return array
20 | */
21 | public function toOptionArray()
22 | {
23 | $ides = [['value' => '', 'label' => __('None')]];
24 | foreach ($this->helper->getIdeList() as $ide=>$ideREgex) {
25 | $ides[] = ['value' => $ide, 'label' => __($ide)];
26 | }
27 | $ides[] = ['value' => 'Custom', 'label' => __('Custom ...')];
28 |
29 | return $ides;
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Observer/ControllerFrontSendResponseBeforeObserver.php:
--------------------------------------------------------------------------------
1 | qdbHelperRegister = $qdbHelperRegister;
27 | $this->qdbHelper = $qdbHelper;
28 | }
29 |
30 | /**
31 | * @inheritDoc
32 | */
33 | public function execute(Observer $observer)
34 | {
35 | /** @var RequestHttp $request */
36 | //TODO: Show $request = $observer->getRequest();
37 |
38 | /** @var ResponseHttp $response */
39 | //TODO: Show $response = $observer->getResponse();
40 | $response = $observer->getResponse();
41 |
42 | /** @var Headers $header */
43 | //TODO: Show $response->getHeaders()
44 |
45 | //Remove QDB trace
46 | if(!$this->qdbHelper->isToolbarAccessAllowed()) {
47 | $newContent = preg_replace('//', '', $response->getContent());
48 | $response->setContent($newContent);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Observer/LayoutGenerateBlocksAfterObserver.php:
--------------------------------------------------------------------------------
1 | serviceHandle = $serviceHandle;
32 | $this->serviceHierarchy = $serviceHierarchy;
33 | }
34 |
35 | /**
36 | * @inheritDoc
37 | */
38 | public function execute(Observer $observer)
39 | {
40 | /** @var \Magento\Framework\View\LayoutInterface $layout */
41 | $layout = $observer->getLayout();
42 |
43 | $this->serviceHandle->addLayoutHandles($this->getHandles($layout));
44 | $this->serviceHierarchy->addLayoutHierarchy($this->getTreeBlocksHierarchy($layout));
45 | }
46 |
47 |
48 | /**
49 | * @param \Magento\Framework\View\LayoutInterface $layout
50 | * @return array
51 | */
52 | protected function getHandles($layout)
53 | {
54 | return $layout->getUpdate()->getHandles();
55 | }
56 |
57 |
58 |
59 | /**
60 | * TODO: Find a better way to access the layout structure
61 | * @see: https://github.com/balloz/magento2-developer-toolbar/blob/master/Block/Panel/Layout.php
62 | *
63 | * But by now seems no other way
64 | * @see: https://github.com/magento/magento2/issues/748
65 | *
66 | * @param \Magento\Framework\View\LayoutInterface $layout
67 | * @return array|null
68 | * @throws \ReflectionException
69 | */
70 | public function getTreeBlocksHierarchy($layout)
71 | {
72 | //$layout = $this->getLayout();
73 |
74 | $reflection = new \ReflectionClass($layout);
75 |
76 | /** @var \Magento\Framework\View\Layout\Data\Structure $structure */
77 | $structure = $reflection->getProperty('structure');
78 | $structure->setAccessible(true);
79 | $structure = $structure->getValue($layout);
80 |
81 | if($elements = $layout->getXpath('//' . Element::TYPE_BLOCK . '[@cacheable="false"]')) {
82 | foreach ($elements as $element) {
83 | $blockName = $element->getBlockName();
84 | if ($blockName !== false && $structure->hasElement($blockName)) {
85 | $this->nonCacheableBlocks[$blockName] = $blockName;
86 | }
87 | }
88 | }
89 |
90 | $this->_elements = $structure->exportElements();
91 | if ($this->_elements) {
92 | $treeBlocks = $this->buildTreeBlocks($layout);
93 | } else {
94 | $treeBlocks = [];
95 | }
96 |
97 | return $treeBlocks;
98 | }
99 |
100 | /**
101 | * @param \Magento\Framework\View\LayoutInterface $layout
102 | * @param $name
103 | * @param $alias
104 | * @return array|void
105 | * @throws \ReflectionException
106 | */
107 | protected function buildTreeBlocks($layout, $name = 'root', $alias = '')
108 | {
109 | $element = $this->getElementByName($name);
110 | if ($element) {
111 | $treeBlocks = [
112 | 'name' =>$name,
113 | 'alias' =>$alias,
114 | 'type' => $element['type'],
115 | 'label' => isset($element['label']) ? $element['label'] : '',
116 | 'file' => '',
117 | 'class_name' => '',
118 | 'class_file' => '',
119 | 'cacheable' => empty($this->nonCacheableBlocks[$name])
120 | ];
121 |
122 | /** @var \Magento\Framework\View\Element\AbstractBlock|bool $block */
123 | $block = $layout->getBlock($name);
124 | if (false !== $block) {
125 |
126 | $templateFile = '';
127 | if($block->getTemplate()) {
128 | $templateFile = $block->getTemplateFile();
129 | }
130 |
131 |
132 | $treeBlocks['file'] = $templateFile;
133 | $treeBlocks['class_name'] = get_class($block);
134 | if (!empty($treeBlocks['class_name'])) {
135 | $reflectionClass = new \ReflectionClass($block);
136 | $treeBlocks['class_file'] = $reflectionClass->getFileName();
137 | }
138 | }
139 |
140 | if (isset($element['children'])) {
141 | foreach ($element['children'] as $childName => $childAlias) {
142 | $treeBlocks['children'][] = $this->buildTreeBlocks($layout, $childName, $childAlias);
143 | }
144 | }
145 | } else {
146 | $treeBlocks = [];
147 | }
148 |
149 | return $treeBlocks;
150 | }
151 |
152 | /**
153 | *
154 | * @param unknown_type $name
155 | *
156 | * @return Ambigous
157 | */
158 | protected function getElementByName($name)
159 | {
160 | return (!empty($this->_elements[$name])) ? $this->_elements[$name] : false;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/Observer/UpdateLayoutObserver.php:
--------------------------------------------------------------------------------
1 | qdbHelper = $qdbHelper;
21 | }
22 |
23 | /**
24 | * @inheritDoc
25 | */
26 | public function execute(Observer $observer)
27 | {
28 | if(!$this->qdbHelper->isAjaxLoading()) {
29 | /** @var \Magento\Framework\View\Layout $layout */
30 | $layout = $observer->getData('layout');
31 | $layout->getUpdate()->addHandle('quickdevbar');
32 | }
33 | return $this;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Plugin/Framework/App/Cache.php:
--------------------------------------------------------------------------------
1 | cacheService = $cacheService;
16 | }
17 |
18 |
19 | /**
20 | * @param CacheInterface $subject
21 | * @param string $identifier
22 | */
23 | public function beforeLoad(CacheInterface $subject, string $identifier)
24 | {
25 | $this->cacheService->addCache('load', $identifier);
26 | }
27 |
28 | /**
29 | * @param CacheInterface $subject
30 | * @param string $data
31 | * @param string $identifier
32 | * @param array $tags
33 | * @param $lifeTime
34 | * @return void
35 | */
36 | public function beforeSave(
37 | CacheInterface $subject,
38 | string $data,
39 | string $identifier,
40 | array $tags = [],
41 | $lifeTime = null
42 | ) {
43 |
44 | $this->cacheService->addCache('save', $identifier);
45 | }
46 |
47 |
48 | /**
49 | * @param CacheInterface $subject
50 | * @param string $identifier
51 | * @return void
52 | */
53 | public function beforeRemove(CacheInterface $subject, string $identifier)
54 | {
55 | $this->cacheService->addCache('remove', $identifier);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Plugin/Framework/App/FrontController.php:
--------------------------------------------------------------------------------
1 | request = $request;
33 | $this->qdbHelper = $qdbHelper;
34 | $this->register = $register;
35 | $this->dumper = $dumper;
36 | }
37 |
38 | /**
39 | * Be careful, two usage:
40 | * - dumpToFile
41 | * - VarDumper::setHandler
42 | *
43 | * @param \Magento\Framework\AppInterface $subject
44 | * @return void
45 | */
46 | public function beforeDispatch(\Magento\Framework\App\FrontControllerInterface $subject)
47 | {
48 |
49 |
50 | if(!$this->qdbHelper->isToolbarAccessAllowed()) {
51 | return;
52 | }
53 |
54 | if($this->qdbHelper->isAjaxLoading()) {
55 | register_shutdown_function([$this->register, 'dumpToFile']);
56 | }
57 |
58 | if($enabledHandler = $this->qdbHelper->getQdbConfig('handle_vardumper')) {
59 | if($this->request->isAjax() && $enabledHandler<2) {
60 | return;
61 | }
62 | $prevHandler = \Symfony\Component\VarDumper\VarDumper::setHandler($this->dumperHandler(...));
63 | }
64 | }
65 |
66 | /**
67 | * @param $var
68 | * @return void
69 | */
70 | protected function dumperHandler($var)
71 | {
72 | $cloner = new \Symfony\Component\VarDumper\Cloner\VarCloner();
73 | $dumper = new \Symfony\Component\VarDumper\Dumper\HtmlDumper();
74 |
75 | $dumper->setTheme('dark');
76 | $dumpBt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[2];
77 |
78 | $ajaxReq = $this->request->isAjax() ? $this->request->getActionName() : null;
79 |
80 | $output = $dumpBt['function'] != 'dd';
81 | $dumpOutput = $dumper->dump($cloner->cloneVar($var), $output);
82 | if($output) {
83 | $this->dumper->addDump($dumpOutput, $dumpBt, $ajaxReq);
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Plugin/Framework/App/UpdateCookies.php:
--------------------------------------------------------------------------------
1 | cookieManager = $cookieManager;
32 | $this->cookieMetadataFactory = $cookieMetadataFactory;
33 | }
34 |
35 | /**
36 | * Set form key from the cookie.
37 | *
38 | * @return void
39 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
40 | */
41 | public function beforeDispatch(): void
42 | {
43 |
44 | $cookieValue = $this->cookieManager->getCookie(Cookie::COOKIE_NAME_PROFILER_ENABLED);
45 | if ($cookieValue) {
46 | //TODO: Update cookie lifetime
47 |
48 | // $metadata = $this->cookieMetadataFactory
49 | // ->createPublicCookieMetadata()
50 | // ->setDuration(Cookie::COOKIE_DURATION);
51 | //
52 | // $this->cookieManager->setPublicCookie(
53 | // DbAdapter::COOKIE_NAME_PROFILER_ENABLED,
54 | // $cookieValue,
55 | // $metadata
56 | // );
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Plugin/Framework/Event/Invoker.php:
--------------------------------------------------------------------------------
1 | serviceObserver = $serviceObserver;
20 | }
21 |
22 | public function beforeDispatch($class, $observerConfig, $wrapper)
23 | {
24 | $this->serviceObserver->addObserver($observerConfig, $wrapper);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Plugin/Framework/Event/Manager.php:
--------------------------------------------------------------------------------
1 | serviceManager = $serviceManager;
19 | }
20 |
21 | /**
22 | * Before dispatch event
23 | *
24 | * Calls all observer callbacks registered for this event
25 | * and multiple observers matching event name pattern
26 | *
27 | * @param \Magento\Framework\Event\Manager $interceptor
28 | * @param string $eventName
29 | * @param array $data
30 | */
31 | public function beforeDispatch($interceptor, $eventName, $data = [])
32 | {
33 | $this->serviceManager->addEvent($eventName, $data);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Plugin/Framework/Form/Element.php:
--------------------------------------------------------------------------------
1 | getOriginalData('path')
16 | && $subject->getOriginalData('id')) {
17 | $html .= '' . $subject->getOriginalData('path') . '/' .$subject->getOriginalData('id') . '
';
18 | }
19 | return $html;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Plugin/Framework/Http/Response.php:
--------------------------------------------------------------------------------
1 | _qdbHelperRegister = $qdbHelperRegister;
22 | }
23 |
24 |
25 | public function afterSendResponse(\Magento\Framework\HTTP\PhpEnvironment\Response $subject) {
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Plugin/PageCache/FrontController/BuiltinPlugin.php:
--------------------------------------------------------------------------------
1 | cacheService = $cacheService;
25 | }
26 |
27 | /**
28 | * @param PageCache $subject
29 | * @param string $identifier
30 | */
31 | public function beforeLoad(PageCache $subject, string $identifier)
32 | {
33 | $this->cacheService->addCache('load', $identifier);
34 | }
35 |
36 | /**
37 | * @param PageCache $subject
38 | * @param string $data
39 | * @param string $identifier
40 | * @param array $tags
41 | * @param $lifeTime
42 | * @return void
43 | */
44 | public function beforeSave(
45 | PageCache $subject,
46 | string $data,
47 | string $identifier,
48 | array $tags = [],
49 | $lifeTime = null
50 | ) {
51 |
52 | $this->cacheService->addCache('save', $identifier);
53 | }
54 |
55 |
56 | /**
57 | * @param PageCache $subject
58 | * @param string $identifier
59 | * @return void
60 | */
61 | public function beforeRemove(PageCache $subject, string $identifier)
62 | {
63 | $this->cacheService->addCache('remove', $identifier);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Plugin/Search/ResponseFactory.php:
--------------------------------------------------------------------------------
1 | elasticsearchService = $elasticsearchService;
15 | }
16 |
17 | /**
18 | * @param \Magento\Elasticsearch\SearchAdapter\ResponseFactory $subject
19 | * @param $result
20 | * @param $response
21 | * @return mixed
22 | */
23 | public function afterCreate(\Magento\Elasticsearch\SearchAdapter\ResponseFactory $subject, $result, $response)
24 | {
25 |
26 | //dd($result);
27 |
28 | return $result;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Plugin/Search/SearchClient.php:
--------------------------------------------------------------------------------
1 | cookieHelper = $cookieHelper;
16 | }
17 |
18 |
19 | /**
20 | * @param Zend_Db_Adapter_Abstract $subject
21 | * @param array|bool|Zend_Config|Zend_Db_Profiler $profiler
22 | * @return array
23 | */
24 | public function beforeSetProfiler(Zend_Db_Adapter_Abstract $subject, $profiler): array
25 | {
26 | if($this->cookieHelper->isProfilerEnabled()) {
27 | $profiler = [
28 | 'enabled'=>1,
29 | 'class' => \ADM\QuickDevBar\Profiler\Db::class
30 | ];
31 | }
32 |
33 | return [$profiler];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Profiler/App.php:
--------------------------------------------------------------------------------
1 | cookieHelper)) {
22 | //Mea culpa, mea maxima culpa
23 | $objectManager = ObjectManager::getInstance();
24 | $this->cookieHelper = $objectManager->create(\ADM\QuickDevBar\Helper\Cookie::class);
25 | }
26 |
27 | return $this->cookieHelper->isProfilerBacktraceEnabled();
28 | }
29 |
30 |
31 | /**
32 | * {@inheritdoc }
33 | */
34 | public function queryStart($queryText, $queryType = null)
35 | {
36 | $keyQuery = parent::queryStart($queryText, $queryType);
37 | if($keyQuery && $this->getBacktraceQuery()) {
38 | $this->queryBacktrace[$keyQuery] = Debug::trace([], 5);
39 | }
40 | return $keyQuery;
41 | }
42 |
43 | public function getQueryBt($keyQuery)
44 | {
45 | return $this->queryBacktrace[$keyQuery] ?? [];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Developer Toolbar for Magento2 🚀
2 |
3 | ----
4 |
5 | [](https://codeclimate.com/github/vpietri/magento2-developer-quickdevbar)
6 | [](https://packagist.org/packages/vpietri/adm-quickdevbar)
7 |
8 | ## Table of Content
9 |
10 | * [Overview](#Overview)
11 | * [Requirement](#Requirement)
12 | * [About](#About)
13 | * [Panels](#Panels)
14 | * [Screenshots](#Screenshots)
15 | * [Installation](#Installation)
16 | * [Manual](#Manual)
17 | * [Composer](#Composer)
18 | * [Modman](#Modman)
19 | * [Setup](#Setup)
20 | * [URI File to IDE](#URI-File-to-IDE)
21 | * [Sponsors](#Sponsors)
22 | * [Documentation](#Documentation)
23 | * [Credits](#Credits)
24 |
25 | ## Overview
26 |
27 | ✨ With the Magento 2.4.7 compatibility, and the vanilla javascript refactoring comes the compatibility with Hyvä and Breeze themes.
28 |
29 | 🎁 Till compatible with Full page cache and fit coding standard :sparkles:
30 | Functionalities like VarDumper are unforced and SQL profiler backtrace is only on demand. See more [Changelog](doc/Changelog.md) .
31 |
32 | ## Requirement
33 |
34 | Supported versions: Magento 2.4.x till 2.4.7 but should work with lower version.
35 | See composer.json for other requirements.
36 |
37 | ## About
38 |
39 | Hope this debug toolbar can speed up Magento2 development module. Any feedback and idea to improve this toolbar will be appreciated :beers: so get in touch via the [issue tracker on GitHub](https://github.com/vpietri/magento2-developer-quickdevbar/issues). Feel free to fork and pull request.
40 | The structure of this toolbar is extremely simple you just need to add a new block in the layout to get your tab running.
41 |
42 | ### Panels
43 |
44 | - Info : Main informations about controller, route, action and store. Search on core config data. Dedicated tab output for local and global phpinfo.
45 | - Design : List handles called and display layout structure of nested blocks and containers
46 | - Profile : View current observers, all events dispatched, collections and models loaded, plugins instanciated, preferences, cache hits
47 | - Queries : Statistics about executed queries and detailed query listing with syntax highlighting of main SQL keywords
48 | - Logs : Display log files with ability to reset these files
49 | - Dump : Catch all dump() in code
50 | - Actions : Easily toggle template hints and inline translation and flush cache
51 | - Translation : Quickly see module, pack,theme and DB translations
52 | - Help : Show module version and link to github
53 |
54 | ### Screenshots
55 |
56 | - Info tab
57 | 
58 |
59 | - Queries Tab
60 | 
61 |
62 | - Profile Tab
63 | 
64 |
65 | - Theme chooser
66 | 
67 |
68 | ## Installation
69 |
70 | ### Manual
71 |
72 | - Download zip file of the last version of this extension under release tab
73 | - Extract files in the Magento root directory in the folder app/code/ADM/QuickDevBar
74 | - Enable the extension
75 | ```
76 | php bin/magento --clear-static-content module:enable ADM_QuickDevBar
77 | ```
78 | - Upgrade Magento setup
79 | ```
80 | php bin/magento setup:upgrade
81 | ```
82 |
83 | ### Composer
84 |
85 | In the Magento root directory
86 |
87 | - Install the module
88 | ```
89 | composer require vpietri/adm-quickdevbar --dev
90 | php bin/magento module:enable ADM_QuickDevBar
91 | php bin/magento setup:upgrade
92 | ```
93 |
94 | ### Modman
95 |
96 | In the Magento root directory
97 |
98 | - Install the module
99 | ```
100 | modman clone git@github.com:vpietri/magento2-developer-quickdevbar.git
101 | php bin/magento module:enable ADM_QuickDevBar
102 | php bin/magento setup:upgrade
103 | ```
104 |
105 | ### Setup
106 |
107 | The toolbar is displayed by default if your web server is on your local development environment.
108 |
109 | You can force activation via command line
110 | ```
111 | php bin/magento dev:quickdevbar:enable
112 | ```
113 | and activate full sql backtrace
114 | ```
115 | php bin/magento dev:quickdevbar:enable --sql-qdb-profiler
116 | ```
117 |
118 | Or via the standard configuration in the Advanced/Developer/Quick dev bar section.
119 |
120 | If you do not see the toolbar you should either force activation by filling your IP in the field "Allowed IPs" and fill a matching pattern of you user-agent in the field "Allowed user-agent pattern" if it's needed.
121 | 
122 |
123 |
124 | #### URI File to IDE
125 |
126 | (Beta) In PhpStorm you can use **IDE Remote Control** to open file
127 |
128 | https://plugins.jetbrains.com/plugin/19991-ide-remote-control
129 |
130 | 
131 |
132 | ## Sponsors
133 |
134 | [](https://www.sansec.io/)
135 |
136 | Add your logo on Github Sponsors
137 |
138 | ## Documentation
139 |
140 | - [Changelog](doc/Changelog.md)
141 | - ~~You can extend this toolbar with your own tabs, a [sample module](https://github.com/vpietri/magento2-brandnew_quikdevsample) is available.~~ (refactoring coming soon)
142 |
143 | ## Credits
144 |
145 | - [Jens Törnell](https://github.com/jenstornell)
146 |
--------------------------------------------------------------------------------
/Service/App/Cache.php:
--------------------------------------------------------------------------------
1 | cacheEvents[$identifier] = ['load'=>0, 'save'=>0, 'remove'=>0];
17 | }
18 | $this->cacheEvents[$identifier][$event]++;
19 | }
20 |
21 | public function pullData()
22 | {
23 | return $this->cacheEvents;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Service/Config.php:
--------------------------------------------------------------------------------
1 | config = $config;
19 | }
20 |
21 | /**
22 | * @inheritDoc
23 | */
24 | public function pullData()
25 | {
26 | $preferences = array();
27 | foreach ($this->config->getPreferences() as $type => $preference) {
28 | if(preg_match('/^(\w+\\\\\w+)/', $type, $matches)) {
29 | if(strpos($preference, $matches[1]) === false) {
30 | $preferences[$type] = $preference;
31 | }
32 | }
33 | }
34 |
35 | return $preferences;
36 | }
37 | }
--------------------------------------------------------------------------------
/Service/Dumper.php:
--------------------------------------------------------------------------------
1 | dumps;
17 | }
18 |
19 | public function addDump(string $output, array $bt, $ajaxReq = null)
20 | {
21 | $this->dumps[] = ['dump'=>$output, 'bt'=> $bt, 'ajaxReq'=> $ajaxReq];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Service/Elasticsearch.php:
--------------------------------------------------------------------------------
1 | classType = $classType;
21 | }
22 |
23 | public function addClassToRegisterData($data)
24 | {
25 | $class = !empty($data[$this->classType]) ? get_class($data[$this->classType]) : false;
26 |
27 | if($class) {
28 | if (empty($this->listByClass[$class])) {
29 | $this->listByClass[$class] = ['class'=>$class, 'nbr'=>0];
30 | }
31 | $this->listByClass[$class]['nbr']++;
32 | }
33 | }
34 |
35 | /**
36 | * @inheritDoc
37 | */
38 | public function pullData()
39 | {
40 | return $this->listByClass;
41 | }
42 | }
--------------------------------------------------------------------------------
/Service/Event/Manager.php:
--------------------------------------------------------------------------------
1 | services = $services;
22 | }
23 |
24 | /**
25 | * @param $eventName
26 | * @param $data
27 | */
28 | public function addEvent($eventName, $data)
29 | {
30 | if (!isset($this->events[$eventName])) {
31 | $this->events[$eventName] = ['event'=>$eventName,
32 | 'nbr'=>0,
33 | 'args'=>array_keys($data)
34 | ];
35 | }
36 | $this->events[$eventName]['nbr']++;
37 | if(!empty($this->services[$eventName])) {
38 | $this->services[$eventName]->addClassToRegisterData($data);
39 | }
40 | }
41 |
42 | /**
43 | * @inheritDoc
44 | */
45 | public function pullData()
46 | {
47 | return $this->events;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Service/Layout/Handle.php:
--------------------------------------------------------------------------------
1 | handles;
19 | }
20 |
21 | public function addLayoutHandles(array $getHandles)
22 | {
23 | $this->handles = $getHandles;
24 | }
25 | }
--------------------------------------------------------------------------------
/Service/Layout/Hierarchy.php:
--------------------------------------------------------------------------------
1 | treeBlocksHierarchy;
18 | }
19 |
20 | public function addLayoutHierarchy(array $getTreeBlocksHierarchy)
21 | {
22 | $this->treeBlocksHierarchy = $getTreeBlocksHierarchy;
23 | }
24 | }
--------------------------------------------------------------------------------
/Service/Module.php:
--------------------------------------------------------------------------------
1 | moduleList = $moduleList;
16 | }
17 |
18 |
19 | public function pullData()
20 | {
21 | return $this->moduleList->getAll();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Service/Observer.php:
--------------------------------------------------------------------------------
1 | observers;
20 | }
21 |
22 | public function addObserver($observerConfig, $wrapper)
23 | {
24 | $data = $observerConfig;
25 |
26 | if (isset($data['disabled']) && true === $data['disabled']) {
27 | return;
28 | }
29 |
30 |
31 | $data['event'] = $wrapper->getEvent()->getName();
32 |
33 | $key = crc32(json_encode($data));
34 | if (isset($this->observers[$key])) {
35 | $this->observers[$key]['call_number']++;
36 | } else {
37 | $data['call_number']=1;
38 | $this->observers[$key] = $data;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Service/Plugin.php:
--------------------------------------------------------------------------------
1 | pluginList = $pluginList;
22 | }
23 |
24 | public function pullData()
25 | {
26 | if ($this->pluginsByTypes === null) {
27 | $this->pluginsByTypes = [];
28 |
29 | $reflection = new \ReflectionClass($this->pluginList);
30 |
31 | $processed = $reflection->getProperty('_processed');
32 | $processed->setAccessible(true);
33 | $processed = $processed->getValue($this->pluginList);
34 |
35 | $inherited = $reflection->getProperty('_inherited');
36 | $inherited->setAccessible(true);
37 | $inherited = $inherited->getValue($this->pluginList);
38 |
39 |
40 | $types = [DefinitionInterface::LISTENER_BEFORE=>'before',
41 | DefinitionInterface::LISTENER_AROUND=>'around',
42 | DefinitionInterface::LISTENER_AFTER=>'after'];
43 |
44 | /**
45 | * @see: Magento/Framework/Interception/PluginList/PluginList::_inheritPlugins($type)
46 | */
47 | foreach ($processed as $currentKey => $processDef) {
48 | if (preg_match('/^(.*)_(.*)___self$/', $currentKey, $matches) or preg_match('/^(.*?)_(.*?)_(.*)$/', $currentKey, $matches)) {
49 | $type= $matches[1];
50 | $method= $matches[2];
51 | if (!empty($inherited[$type])) {
52 | foreach ($processDef as $keyType => $pluginsNames) {
53 | if (!is_array($pluginsNames)) {
54 | $pluginsNames = [$pluginsNames];
55 | }
56 |
57 | foreach ($pluginsNames as $pluginName) {
58 | if (!empty($inherited[$type][$pluginName])) {
59 | $this->pluginsByTypes[] = ['type'=>$type, 'plugin'=>$inherited[$type][$pluginName]['instance'], 'plugin_name'=>$pluginName, 'sort_order'=> $inherited[$type][$pluginName]['sortOrder'], 'method'=>$types[$keyType].ucfirst($method)];
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 | }
67 |
68 | return $this->pluginsByTypes;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Service/Request.php:
--------------------------------------------------------------------------------
1 | requestHttp = $requestHttp;
47 | $this->appState = $appState;
48 | $this->productMetadata = $productMetadata;
49 | $this->frontNameResolver = $frontNameResolver;
50 | $this->session = $session;
51 | }
52 |
53 | /**
54 | * @inheritDoc
55 | */
56 | public function pullData()
57 | {
58 | $request = $this->requestHttp;
59 | $requestData = [];
60 | $requestData[] = ['name' => 'Date sys', 'value' => date("Y-m-d H:i:s")];
61 | $requestData[] = ['name' => 'Base Url', 'value' => $request->getDistroBaseUrl(), 'is_url' => true];
62 | $requestData[] = ['name' => 'Path Info', 'value' => $request->getPathInfo()];
63 | $requestData[] = ['name' => 'Module Name', 'value' => $request->getControllerModule() ?: self::LABEL_CACHE_HIDDEN];
64 | $requestData[] = ['name' => 'Controller', 'value' => $request->getControllerName() ?: self::LABEL_CACHE_HIDDEN];
65 | $requestData[] = ['name' => 'Action', 'value' => $request->getActionName() ?: self::LABEL_CACHE_HIDDEN];
66 | $requestData[] = ['name' => 'Full Action', 'value' => $request->getFullActionName() ?: self::LABEL_CACHE_HIDDEN];
67 | $requestData[] = ['name' => 'Route', 'value' => $request->getRouteName() ?: self::LABEL_CACHE_HIDDEN];
68 | $requestData[] = ['name' => 'Area', 'value' => $this->appState->getAreaCode()];
69 |
70 | if ($this->session->isLoggedIn()) {
71 | $requestData[] = ['name' => 'Logged user', 'value' => $this->session->getCustomer()->getEmail()];
72 | $requestData[] = ['name' => 'Group id', 'value' => $this->session->getCustomer()->getGroupId()];
73 | }
74 | $requestData[] = ['name' => 'Session Id', 'value' => $this->session->getSessionId()];
75 |
76 | if ($request->getBeforeForwardInfo()) {
77 | $requestData[] = ['name' => 'Before Forward', 'value' => $request->getBeforeForwardInfo()];
78 | }
79 |
80 | if ($request->getParams()) {
81 | $requestData[] = ['name' => 'Params', 'value' => $request->getParams()];
82 | }
83 | $requestData[] = ['name' => 'Client IP', 'value' => $request->getClientIp()];
84 | $requestData[] = ['name' => 'Magento', 'value' => $this->productMetadata->getVersion()];
85 | $requestData[] = ['name' => 'Mage Mode', 'value' => $this->appState->getMode()];
86 |
87 | $requestData[] = ['name' => 'Backend', 'value' => $request->getDistroBaseUrl() . $this->frontNameResolver->getFrontName(), 'is_url' => true];
88 |
89 | return $requestData;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Service/Sql.php:
--------------------------------------------------------------------------------
1 | resource = $resource;
32 | }
33 |
34 | public function pullData()
35 | {
36 | if(is_null($this->sqlProfilerData)) {
37 | $this->sqlProfilerData = $this->initSqlProfilerData();
38 | }
39 | return $this->sqlProfilerData;
40 | }
41 |
42 | protected function initSqlProfilerData()
43 | {
44 | $longestQueryTime = 0;
45 | $shortestQueryTime = 100000;
46 | $longestQuery = '';
47 | $allQueries = [];
48 | if ($this->sqlProfiler === null) {
49 | $this->sqlProfiler = new \Zend_Db_Profiler();
50 | if ($this->resource !== null) {
51 | $this->sqlProfiler = $this->resource->getConnection('read')->getProfiler();
52 |
53 | $this->useQdbProfiler = method_exists($this->sqlProfiler, 'getQueryBt');
54 |
55 |
56 | if ($this->sqlProfiler->getQueryProfiles() && is_array($this->sqlProfiler->getQueryProfiles())) {
57 | foreach ($this->sqlProfiler->getQueryProfiles() as $key => $query) {
58 | if ($query->getElapsedSecs() > $longestQueryTime) {
59 | $longestQueryTime = $query->getElapsedSecs();
60 | $longestQuery = $query->getQuery();
61 | }
62 | if ($query->getElapsedSecs() < $shortestQueryTime) {
63 | $shortestQueryTime = $query->getElapsedSecs();
64 | }
65 |
66 | $allQueries[] = ['sql' => $query->getQuery(),
67 | 'params' => $query->getQueryParams(),
68 | 'time' => $query->getElapsedSecs(),
69 | 'grade' => 'medium',
70 | 'bt' => $this->useQdbProfiler ? $this->sqlProfiler->getQueryBt($key) : null
71 | ];
72 | }
73 | }
74 | }
75 | }
76 |
77 | if(!$this->sqlProfiler->getTotalNumQueries()) {
78 | return [];
79 | }
80 |
81 | $numQueriesByType = [];
82 | foreach( [$this->sqlProfiler::INSERT,
83 | $this->sqlProfiler::UPDATE,
84 | $this->sqlProfiler::DELETE,
85 | $this->sqlProfiler::SELECT,
86 | $this->sqlProfiler::QUERY] as $type) {
87 | $numQueriesByType[$type] = $this->sqlProfiler->getTotalNumQueries($type);
88 |
89 | }
90 |
91 | $totalNumQueries = $this->sqlProfiler->getTotalNumQueries();
92 | $totalElapsedSecs = $this->sqlProfiler->getTotalElapsedSecs();
93 | $average = $totalElapsedSecs/$totalNumQueries;
94 |
95 | return [
96 | 'all_queries' => $this->computeQueryGrade($allQueries, $shortestQueryTime, $longestQueryTime, $totalNumQueries, $average),
97 | 'longest_query_time' => $longestQueryTime,
98 | 'shortest_query_time' => $shortestQueryTime,
99 | 'longest_query' => $longestQuery,
100 | 'total_elapsed_secs' => $totalElapsedSecs,
101 | 'total_num_queries' => $totalNumQueries,
102 | 'num_queries_per_second' => floor($totalNumQueries/$totalElapsedSecs),
103 | 'average' => $average,
104 | 'total_num_queries_by_type' => $numQueriesByType,
105 | // 'show_backtrace' => $this->useQdbProfiler
106 | ];
107 | }
108 |
109 | protected function computeQueryGrade($allQueries, $shortestQueryTime, $longestQueryTime, $totalNumQueries, $average)
110 | {
111 | $squareSum = 0;
112 | foreach ($allQueries as $index => $query) {
113 | $squareSum = pow($query['time'] - $average, 2);
114 | }
115 |
116 | $standardDeviation = 0;
117 | if ($squareSum and $totalNumQueries) {
118 | $standardDeviation = sqrt($squareSum/$totalNumQueries);
119 | }
120 |
121 | foreach ($allQueries as $index => $query) {
122 | if ($query['time']<($shortestQueryTime+2*$standardDeviation)) {
123 | $allQueries[$index]['grade'] = 'good';
124 | } elseif ($query['time']>($longestQueryTime-2*$standardDeviation)) {
125 | $allQueries[$index]['grade'] = 'bad';
126 | }
127 | }
128 |
129 | return $allQueries;
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vpietri/adm-quickdevbar",
3 | "description": "QuickDevBar is a developer toolbar for magento 2",
4 | "type": "magento2-module",
5 | "license": [
6 | "OSL-3.0",
7 | "AFL-3.0"
8 | ],
9 | "version": "0.3.2",
10 | "require": {
11 | "magento/magento-composer-installer": "*"
12 | },
13 | "authors": [
14 | {
15 | "name": "Vincent Pietri",
16 | "homepage": "http://www.vincent-pietri.fr/",
17 | "role": "Developer"
18 | }
19 | ],
20 | "autoload": {
21 | "files": [
22 | "registration.php"
23 | ],
24 | "psr-4": {
25 | "ADM\\QuickDevBar\\": ""
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/doc/Changelog.md:
--------------------------------------------------------------------------------
1 | Changelog: Quick Developer Toolbar for Magento2
2 | ====================================
3 | 0.3.2
4 | * Fix adminhtml renderer
5 | * Add doc screenshots
6 |
7 |
8 | 0.3.1
9 | * Fix the typo in the XML closing tag within the comment, thanks to [hgati](https://github.com/vpietri/magento2-developer-quickdevbar/pull/86)
10 |
11 | 0.3.0
12 | * Compatibility Magento 2.4.7 with strict CSP policy
13 | * Hyva and Breeze compatibility (vanilla JS)
14 | * Dynamic SQL profiling with backtrace
15 | * Code refactoring
16 |
17 | 0.2.3
18 | * Catch VarDumper in ajax calls
19 | * Code refactoring
20 |
21 | 0.2.2
22 | * Use config to handle VarDumper
23 | * Move handler for VarDumper
24 | * Do not catch dd()
25 |
26 | 0.2.1
27 | * Remove hard log /tmp/debug.log
28 |
29 | 0.2.0
30 | * Full compatibility with FPC
31 | * Full code refactoring
32 | * Handle Symfony VarDumper
33 | * Command to activate SQL backtrace
34 | * New tabs added: Preferences, Cache (PageCache) hits, Debug
35 | * Skin chooser
36 | * Css cleaning
37 | * Remove module fingerprint from page is not allowed
38 | * Open file from url to IDE
39 |
40 |
41 | 0.1.20
42 | * Add command to enable/disable toolbar and activate sql profiler
43 | * Remove Deprecated Warning in Translate Helper, thanks [lefte](https://github.com/vpietri/magento2-developer-quickdevbar/pull/69) and [josue-rmoya](https://github.com/vpietri/magento2-developer-quickdevbar/pull/66)
44 | * Fix must be of type Countable, thanks @bbakalov, closes #70
45 |
46 | 0.1.19
47 | * Fix M244 compatibility, removed legacy text from readme, thanks [asannikov](https://github.com/vpietri/magento2-developer-quickdevbar/pull/63)
48 | * Compatibility 2.4.4, Closes #60, closes #62
49 |
50 | 0.1.18.1
51 | * Remove version from composer
52 |
53 | 0.1.18
54 | * Fix js error 'base is not a constructor', thanks to @asalgado0391, closes #53
55 | * Fix call appConfig->getValue, closes #26
56 |
57 | 0.1.17
58 | * Fixed report from Content Security Policies module. Thanks to [pikulsky and r-martins](https://github.com/vpietri/magento2-developer-quickdevbar/pull/47)
59 |
60 | 0.1.16
61 | * Replace Deprecated Function. Thanks to [lefte](https://github.com/vpietri/magento2-developer-quickdevbar/pull/42)
62 |
63 | 0.1.15
64 | * Replace Deprecated Function. Thanks to [lefte](https://github.com/vpietri/magento2-developer-quickdevbar/pull/40)
65 | * Support for modman. Thanks to [MagePsycho](https://github.com/vpietri/magento2-developer-quickdevbar/pull/37)
66 | * PHP < 7.0 backward compatible. Thanks to [tuyennn](https://github.com/vpietri/magento2-developer-quickdevbar/pull/33)
67 |
68 | 0.1.14
69 | * Specify area where display toolbar. Thanks to [zzarazza] and [tuyennn]
70 | * Small bug fix for users using a proxy with Magento 2. Thanks to [NateSwanson7](https://github.com/vpietri/magento2-developer-quickdevbar/pull/31)
71 | * Fix jquery error dependency in Admin. Thanks to [hoangnm89](https://github.com/vpietri/magento2-developer-quickdevbar/pull/29)
72 | * Update jquery.tablesorter.min.js. Thanks to [sebfie](https://github.com/vpietri/magento2-developer-quickdevbar/pull/27)
73 |
74 | 0.1.13
75 | * Memorize toolbar state
76 | * Fix on require_js
77 | * Add translation tab. Thanks to [danslo](https://github.com/vpietri/magento2-developer-quickdevbar/pull/23)
78 | * Check whether event observer is disabled. Thanks to [tufahu](https://github.com/vpietri/magento2-developer-quickdevbar/pull/24)
79 |
80 |
81 | 0.1.12
82 | * Fix Wbug when profiler is disabled. Thanks to [rakibabu](https://github.com/vpietri/magento2-developer-quickdevbar/pull/16)
83 |
84 | 0.1.11
85 | * Improve layout view with a js tree
86 | * Add css lazy load to keep toolbar completly hidden when disabled
87 | * Fix compatibility with Magento 2.1.3. Thanks to [Koc](https://github.com/vpietri/magento2-developer-quickdevbar/pull/15)
88 | * Fix ajax tab load bug
89 |
90 | 0.1.10
91 | * Fix conflicts in backend with magento tabs widget
92 | * Improve profiler detection
93 |
94 | 0.1.9
95 | * Add config list tab
96 | * Use common ajax controller
97 |
98 | 0.1.8 - 22 Jul 2016
99 | * Add plugin list tab
100 | * Fix bug on action hints. Thanks to [adpeate](https://github.com/vpietri/magento2-developer-quickdevbar/pull/7)
101 |
102 | 0.1.7 - 7 Jul 2016
103 | * Configuration section improvement
104 | * Code refactoring
105 | * Authorize IPv6 localhost. Thanks to [Dayssam](https://github.com/vpietri/magento2-developer-quickdevbar/pull/5)
106 |
107 | 0.1.6.1 - 30 Jun 2016
108 | * Fix compatibility bugs with Magento 2.1
109 |
110 | 0.1.6 - 17 Jun 2016
111 | * UI improvement
112 | * Add Block subtab
113 | * Add icon from [iconsdb.com](http://www.iconsdb.com/)
114 |
115 | 0.1.5.2 - 22 Apr 2016
116 | * Fit to PHP coding standards
117 |
118 | 0.1.5.1 - 25 Feb 2016
119 | * Fix tab bug in backoffice
120 |
121 | 0.1.5 - 12 Dec 2015
122 | * Back office toolbar
123 | * Reorganize tabs
124 | * Add list of collection and model instanciated
125 | * Add [Christian Bach's tablesorter plugin](https://github.com/christianbach/tablesorter)
126 |
127 | 0.1.4 - 6 Dec 2015
128 | * Fix bug on composer.json with registration.php
129 | * Clean layout display
130 |
131 | 0.1.3 - 4 Dec 2015
132 | * Compatibility with Magento 2.0.0 Publication
133 | * Add action tab (Template hints, Translate inline, Flush Cache Storage)
134 | * Controller structure cleaning
135 |
136 | 0.1.2 - 29 Jun 2015
137 | * Add sub-tab and reorganize existing tabs
138 |
139 | 0.1.1 - 19 Jun 2015
140 | * Javascript cleaning to meet coding standards
141 | * Add [sunnywalker/filterTable](https://github.com/sunnywalker/jQuery.FilterTable)
142 | * Fix bugs on the log screen
143 | * Css improvements
144 |
145 | 0.0.1 - 18 Jun 2015
146 | * module initialization
147 |
--------------------------------------------------------------------------------
/doc/images/phpstorm_debugger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/phpstorm_debugger.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_config_ko.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_config_ko.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_dark.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_dispatch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_dispatch.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_dispatch.youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_dispatch.youtube.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_queries.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_queries.png
--------------------------------------------------------------------------------
/doc/images/qdb_screen_request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/doc/images/qdb_screen_request.png
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quick dev bar configuration
7 |
8 | Activate
9 | ADM\QuickDevBar\Model\Config\Source\Activate
10 | "Yes with restriction" means that your web server is your localhost or your ip is in "Allowed ips" or your user-agent is matching "Allowed user-agent pattern"
11 |
12 |
13 | Is enabled for you?
14 | ADM\QuickDevBar\Block\Adminhtml\System\Config\Form\Fieldset\IsEnabled
15 |
16 | 2
17 |
18 |
19 |
20 | Allowed IPs
21 | Comma separated list. If empty check only localhost IPs.
22 | Magento\Developer\Model\Config\Backend\AllowedIps
23 |
24 | 2
25 |
26 |
27 |
34 |
35 | Area
36 | ADM\QuickDevBar\Model\Config\Source\Area
37 |
38 | 1,2
39 |
40 |
41 |
42 | Link files to IDE
43 | Some files can be open via hyperlink by your IDE
44 | ADM\QuickDevBar\Model\Config\Source\Ide
45 |
46 | 1,2
47 |
48 |
49 |
50 | Custom link
51 |
52 | %1$s absolute path of magento root
53 | %2$s relative file path from magento root (magento may run in a docker and have a mapped path on host)
54 | %3$d line number
55 | Sample for phpstorm, with standard path: http://127.0.0.1:63342/api/file/%2$s:%3$d]]>
56 |
57 | 1,2
58 | Custom
59 |
60 |
61 |
62 |
63 | Handle VarDumper
64 | ADM\QuickDevBar\Model\Config\Source\DumperHandler
65 |
66 | 1,2
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 2
7 | global
8 | memorize
9 | 1
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/etc/csp_whitelist.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | github.blog
7 |
8 |
9 |
10 |
11 |
12 | http://127.0.0.1:63342
13 | http://127.0.0.1:34567
14 |
15 |
16 |
17 |
18 |
19 | SgvvFr+EuIbNctHUihu7npbOfmUqDK4M7sA5gSEUN48=
20 | hnovV8f+WhZ9ebCoXRqdN5AB0kK8XLdG0m1A1iJwEnY=
21 | qNCjKiE6ytQPnSBywIMEXvzw+Ar3jDurzNb87EqtM5E=
22 | cGE9z/R3oV10mtE4AQPzTjSc5JWIKk4tMjDOs+W5Y+Q=
23 | cGE9z/R3oV10mtE4AQPzTjSc5JWIKk4tMjDOs+W5Y+Q=
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | - ADM\QuickDevBar\Service\Plugin
45 | - ADM\QuickDevBar\Service\Sql
46 | - ADM\QuickDevBar\Service\Event\Manager
47 | - ADM\QuickDevBar\Service\Collection
48 | - ADM\QuickDevBar\Service\Model
49 | - ADM\QuickDevBar\Service\Block
50 | - ADM\QuickDevBar\Service\Request
51 | - ADM\QuickDevBar\Service\Observer
52 | - ADM\QuickDevBar\Service\Layout\Handle
53 | - ADM\QuickDevBar\Service\Layout\Hierarchy
54 | - ADM\QuickDevBar\Service\Config
55 | - ADM\QuickDevBar\Service\Module
56 | - ADM\QuickDevBar\Service\Dumper
57 | - ADM\QuickDevBar\Service\App\Cache
58 | - ADM\QuickDevBar\Service\Elasticsearch
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | - ADM\QuickDevBar\Service\Collection
67 | - ADM\QuickDevBar\Service\Model
68 | - ADM\QuickDevBar\Service\Block
69 |
70 |
71 |
72 |
73 |
74 |
75 | collection
76 |
77 |
78 |
79 |
80 | object
81 |
82 |
83 |
84 |
85 | block
86 |
87 |
88 |
89 |
90 |
91 |
92 | - ADM\QuickDevBar\Console\Command\EnableToolBar
93 | - ADM\QuickDevBar\Console\Command\DisableToolBar
94 | - ADM\QuickDevBar\Console\Command\Database
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/etc/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/etc/frontend/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
21 |
22 |
--------------------------------------------------------------------------------
/etc/frontend/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/modman:
--------------------------------------------------------------------------------
1 | ./ app/code/ADM/QuickDevBar
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/view/base/templates/tab/action.phtml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | Change QDB theme
10 |
11 |
12 | Standard
13 | Dark
14 | Kawaii UwU
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Template Path Hints for Storefront
23 | Toggle
24 |
25 |
26 |
27 | Template Path Hints for Admin
28 | Toggle
29 |
30 |
31 |
32 | Add Block Names to Hints
33 | Toggle
34 |
35 |
36 |
37 | Translate inline
38 | Toggle
39 |
40 |
41 |
42 | Flush Cache Storage
43 | Flush
44 |
45 |
46 |
47 |
48 |
49 |
60 |
--------------------------------------------------------------------------------
/view/base/templates/tab/design/block.phtml:
--------------------------------------------------------------------------------
1 |
4 | getBlocks()):?>
5 |
6 |
7 |
8 | Block
9 | Call Number
10 |
11 |
12 |
13 | getBlocks() as $blockInfo): ?>
16 |
17 | = $block->htmlFormatClass($blockInfo['class']); ?>
18 | = $blockInfo['nbr']; ?>
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/tab/design/handles.phtml:
--------------------------------------------------------------------------------
1 |
4 | getHandles()):?>
5 |
6 |
7 | = __('Handles'); ?>
8 |
9 | getHandles() as $handle): ?>
10 | = $handle; ?>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/view/base/templates/tab/design/layout.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | = __('Blocks hierarchy'); ?>
7 |
8 | = $block->getHtmlBlocksHierarchy(); ?>
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/view/base/templates/tab/dumper.phtml:
--------------------------------------------------------------------------------
1 |
4 | getQdbConfig('handle_vardumper')):?>
5 | You need to install VarDumper Component, see github.com/symfony/var-dumper
6 |
7 |
8 |
9 |
10 | getDumps()): ?>
11 |
12 |
13 | getDumps() as $dump):?>
14 |
15 | = $block->formatTrace($dump['bt']) ?>
16 | = $dump['dump'] ?>
17 |
18 |
19 |
20 |
21 |
22 |
23 | getIsUpdateCall() && $block->getQdbConfig('handle_vardumper')>1): ?>
24 |
74 |
75 |
--------------------------------------------------------------------------------
/view/base/templates/tab/help.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | = $block->getModuleName()?> (version = $block->getModuleVersion()?>)
8 |
9 |
10 | In order to use this toolbar on a remote server you should either specify allowed IP or set a part of your http header in the config.
11 | Any feedback and idea to improve this toolbar will be appreciate so get in touch via the issue tracker on GitHub.
12 |
--------------------------------------------------------------------------------
/view/base/templates/tab/info/config.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | = __('List config for default scope')?>
6 |
7 | getConfigValues()):?>
8 |
9 |
10 |
11 | Path
12 | Value
13 |
14 |
15 |
16 | getConfigValues() as $config): ?>
19 |
20 | = $config['path']; ?>
21 | = $block->escapeHtml($config['value']); ?>
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/view/base/templates/tab/info/module.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Name
9 | Version
10 | Sequence
11 |
12 |
13 |
14 | getModuleList() as $index => $module): ?>
15 |
16 |
17 | = $module['name']; ?>
18 | = $module['setup_version']; ?>
19 | = json_encode($module['sequence']); ?>
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/view/base/templates/tab/info/request.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | getRequestData()) {
6 |
7 | echo 'An error occurred generating toolbar data';
8 | return;
9 | }
10 | ?>
11 |
12 |
13 |
14 | getRequestData() as $data):?>
15 |
16 | = $data['name'];?>
17 | = $block->formatValue($data);?>
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/view/base/templates/tab/info/store.phtml:
--------------------------------------------------------------------------------
1 | getWebsite();
5 | $_store = $block->getStore();
6 | ?>
7 |
8 |
9 |
10 | = __('Website Id'); ?>
11 | = $_website->getId(); ?>
12 |
13 |
14 | = __('Website Name'); ?>
15 | = $_website->getName(); ?>
16 |
17 |
18 | = __('Store Id'); ?>
19 | = $_store->getId(); ?>
20 |
21 |
22 | = __('Store Name'); ?>
23 | = $_store->getName(); ?>
24 |
25 |
26 | = __('Store Code'); ?>
27 | = $_store->getCode(); ?>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/view/base/templates/tab/log.phtml:
--------------------------------------------------------------------------------
1 |
4 | Reset all Logs
5 |
6 |
7 | getLogFiles() as $logKey => $logFile):?>
8 | = $logFile['name'] ?> Reset
9 | Tail the = $block->getTailLines() ?> last lines
10 |
11 |
12 |
13 |
14 | = $block->getHtmlLoader()?>
15 |
16 |
59 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/cache.phtml:
--------------------------------------------------------------------------------
1 |
7 | getCacheEvents()):?>
8 |
9 |
10 |
11 | Identifier
12 | Save
13 | Load
14 | Remove
15 |
16 |
17 |
18 | getCacheEvents() as $identifier=>$events): ?>
19 |
20 | = $identifier; ?>
21 | = $events['save']; ?>
22 | = $events['load']; ?>
23 | = $events['remove']; ?>
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/collection.phtml:
--------------------------------------------------------------------------------
1 |
4 | getCollections()):?>
5 |
6 |
7 |
8 | Collection
9 | Call Number
10 |
11 |
12 |
13 | getCollections() as $collection): ?>
16 |
17 | = $block->htmlFormatClass($collection['class']); ?>
18 | = $collection['nbr']; ?>
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/event.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | = __('List only events dispatched when Magento generate this page')?>
6 |
7 | getEvents()):?>
8 |
9 |
10 |
11 | Event
12 | Data
13 | Call Number
14 |
15 |
16 |
17 | getEvents() as $event): ?>
18 |
19 | = $event['event']; ?>
20 | = (!empty($event['args']) ? ''.implode(' ', $event['args']).' ' : ''); ?>
21 | = $event['nbr']; ?>
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/model.phtml:
--------------------------------------------------------------------------------
1 |
4 | getModels()):?>
5 |
6 |
7 |
8 | Event
9 | Call Number
10 |
11 |
12 |
13 | getModels() as $model): ?>
16 |
17 | = $block->htmlFormatClass($model['class']); ?>
18 | = $model['nbr']; ?>
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/observer.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | = __('List only observer that intercept dispatched events when Magento generate this page')?>
6 |
7 | getObservers()):?>
8 |
9 |
10 |
11 | Event
12 | Name
13 | Call Number
14 | Instance
15 |
16 |
17 |
18 | getObservers() as $observer): ?>
21 |
22 | = $observer['event']; ?>
23 | = $observer['name']; ?>
24 | = $observer['call_number']; ?>
25 | = $block->htmlFormatClass($observer['instance']); ?>
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/plugin.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | Types
8 | Plugin
9 | Sort Order
10 | Method
11 |
12 |
13 |
14 | getPluginList() as $type): ?>
16 |
17 | = $block->htmlFormatClass($type['type']); ?>
18 | = $block->htmlFormatClass($type['plugin']); ?>
19 | = $type['sort_order']; ?>
20 | = $type['method']; ?>
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/preference.phtml:
--------------------------------------------------------------------------------
1 |
4 | Display only preferences cross modules
5 |
6 |
7 |
8 | Types
9 | Preferences
10 |
11 |
12 |
13 | getObjectManagerConfig() as $type =>$preference): ?>
15 |
16 | = $block->htmlFormatClass($type) ?>
17 | = $block->htmlFormatClass($preference) ?>
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/view/base/templates/tab/profile/profiler.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | = __('Cannot find profiler table or profiler is not enabled.'); ?>
6 |
7 | Since 2.3 you can enable the profiler with the following command
8 |
bin/magento dev:profiler:enable html
9 | You have to add a SetEnv MAGE_PROFILER "html" to your .htaccess (do not use "csvfile" nor "firebug" to have profiler displayed in tab).
10 | Be careful with .htacces directives an redirection you can have
11 |
$_SERVER['REDIRECT_MAGE_PROFILER']
12 | setted instead of
13 |
$_SERVER['MAGE_PROFILER']
14 | prefer apache2.conf.
15 |
16 | You can read the official documentation
Enable profiling (MAGE_PROFILER)
17 |
18 |
19 |
36 |
--------------------------------------------------------------------------------
/view/base/templates/tab/sql.phtml:
--------------------------------------------------------------------------------
1 |
8 | getAllQueries()): ?>
9 |
10 |
11 |
12 |
13 |
14 |
15 | = sprintf(
16 | '%s queries in %s (average time: %s) - %s queries/second',
17 | $block->getTotalNumQueries(),
18 | $block->formatSqlTime($block->getTotalElapsedSecs()),
19 | $block->formatSqlTime($block->getAverage()),
20 | $block->getNumQueriesPerSecond()
21 | ); ?>
22 |
23 |
24 |
25 |
26 |
27 |
28 | = sprintf(
29 | '%s SELECT - %s INSERT - %s UPDATE - %s DELETE - %s TRANSACTION',
30 | $block->getTotalNumQueriesByType(Zend_Db_Profiler::SELECT),
31 | $block->getTotalNumQueriesByType(Zend_Db_Profiler::INSERT),
32 | $block->getTotalNumQueriesByType(Zend_Db_Profiler::UPDATE),
33 | $block->getTotalNumQueriesByType(Zend_Db_Profiler::DELETE),
34 | $block->getTotalNumQueriesByType(Zend_Db_Profiler::TRANSACTION)
35 | ); ?>
36 |
37 |
38 |
39 | = __('Longest'); ?>
40 |
41 | = $block->formatSql($block->getLongestQuery()); ?>
42 |
43 |
44 |
45 |
46 |
47 | (= $block->formatSqlTime($block->getLongestQueryTime()); ?>)
48 |
49 |
50 |
51 |
52 | = $block->getButtonProfilerLabel() ?>
53 |
54 |
55 | getProfilerEnabled()):?>
56 | = $block->getButtonProfilerBactraceLabel() ?>
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | #
68 | SQL
69 | Args
70 | getProfilerBacktraceEnabled()): ?>
71 | Bt
72 |
73 | Time
74 |
75 |
76 |
77 |
78 | getAllQueries() as $i => $query): ?>
81 |
82 |
83 | formatSql($query['sql']); ?>
84 | formatParams($query['params']); ?>
85 |
86 | getProfilerBacktraceEnabled()): ?>
87 | formatSqlTrace($query['bt']) ?>
88 |
89 | formatSqlTime($query['time']); ?>
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | SQL profiler is not active
99 | You can use command line
100 | bin/magento dev:quickdevbar:enable
101 | and use a specific profiler with backtrace
102 | bin/magento dev:quickdevbar:enable --sql-profiler
103 | OR
104 | set a new key for $config array in file app/etc/env.php
105 | $config[db][connection][default][profiler] = 1
106 | OR
107 | Dynamically enable profiler for your session (cookie qdb_db_profiler_ebnabled)
108 | = $block->getButtonProfilerLabel() ?>
109 | Page need to be refresh
110 |
111 |
--------------------------------------------------------------------------------
/view/base/templates/tab/translation/file.phtml:
--------------------------------------------------------------------------------
1 |
4 | getTranslations()):?>
5 |
6 |
7 |
8 | File
9 | Original
10 | Translation
11 |
12 |
13 |
14 | getTranslations() as $original => $translation): ?>
17 |
18 | = $translation['file']; ?>
19 | = $original; ?>
20 | = $translation['translation']; ?>
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/tab/translation/plain.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 | getTranslations()):?>
6 |
7 |
8 |
9 | Original
10 | Translation
11 |
12 |
13 |
14 | getTranslations() as $original => $translation): ?>
17 |
18 | = $original; ?>
19 | = $translation; ?>
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/view/base/templates/tabs.phtml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
24 |
25 |
26 | getTabBlocks() as $tabBlock): ?>
27 |
28 | = ($tabBlock->isAjax(false)) ? $tabBlock->getHtmlLoader('big') : $tabBlock->toHtml(); ?>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/view/base/web/images/asc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/asc.gif
--------------------------------------------------------------------------------
/view/base/web/images/bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/bg.gif
--------------------------------------------------------------------------------
/view/base/web/images/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/config.png
--------------------------------------------------------------------------------
/view/base/web/images/database.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/database.png
--------------------------------------------------------------------------------
/view/base/web/images/desc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/desc.gif
--------------------------------------------------------------------------------
/view/base/web/images/dump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/dump.png
--------------------------------------------------------------------------------
/view/base/web/images/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/help.png
--------------------------------------------------------------------------------
/view/base/web/images/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/info.png
--------------------------------------------------------------------------------
/view/base/web/images/lastnode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/lastnode.png
--------------------------------------------------------------------------------
/view/base/web/images/layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/layout.png
--------------------------------------------------------------------------------
/view/base/web/images/loader-128.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/loader-128.gif
--------------------------------------------------------------------------------
/view/base/web/images/loader-32.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/loader-32.gif
--------------------------------------------------------------------------------
/view/base/web/images/loader-64.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/loader-64.gif
--------------------------------------------------------------------------------
/view/base/web/images/log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/log.png
--------------------------------------------------------------------------------
/view/base/web/images/node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/node.png
--------------------------------------------------------------------------------
/view/base/web/images/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/profile.png
--------------------------------------------------------------------------------
/view/base/web/images/qdb-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/qdb-icon.png
--------------------------------------------------------------------------------
/view/base/web/images/setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/setting.png
--------------------------------------------------------------------------------
/view/base/web/images/tools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/tools.png
--------------------------------------------------------------------------------
/view/base/web/images/translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/translate.png
--------------------------------------------------------------------------------
/view/base/web/images/vline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vpietri/magento2-developer-quickdevbar/960d7df6e72a316533c4ab08ce4aca482eea445b/view/base/web/images/vline.png
--------------------------------------------------------------------------------
/view/base/web/js/filter-table.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Vanilla JS table filter
3 | * https://blog.pagesd.info/2019/10/01/search-filter-table-javascript/
4 | *
5 | */
6 |
7 |
8 | 'use strict';
9 |
10 | class FilterTable {
11 |
12 | constructor(tableNode) {
13 | this.tableNode = tableNode;
14 |
15 | this.input= document.createElement("input")
16 | this.input.setAttribute("type","search");//, placeholder:"search this table", name:""});
17 | this.input.addEventListener(
18 | "input",
19 | () => {
20 | this.onInputEvent(this.tableNode);
21 | },
22 | false,
23 | );
24 |
25 | let container = document.createElement("p");
26 | container.classList.add("filter-table");
27 | container.appendChild(document.createTextNode('Search filter: '));
28 | container.appendChild(this.input);
29 | tableNode.insertAdjacentElement('beforeBegin', container);
30 | }
31 |
32 |
33 | onInputEvent(table) {
34 | for (let row of table.rows)
35 | {
36 | this.filter(row)
37 | }
38 | }
39 |
40 | filter(row) {
41 | var text = row.textContent.toLowerCase();
42 | var val = this.input.value.toLowerCase();
43 | row.style.display = text.indexOf(val) === -1 ? 'none' : 'table-row';
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/view/base/web/js/sortable-table.js:
--------------------------------------------------------------------------------
1 | /*
2 | * https://www.w3.org/WAI/ARIA/apg/patterns/table/examples/sortable-table/
3 | *
4 | * This content is licensed according to the W3C Software License at
5 | * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
6 | *
7 | *
8 | * File: sortable-table.js
9 | *
10 | * Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices
11 | */
12 |
13 | 'use strict';
14 |
15 | class SortableTable {
16 | constructor(tableNode) {
17 | this.tableNode = tableNode;
18 |
19 | this.columnHeaders = tableNode.querySelectorAll('thead th');
20 |
21 | this.sortColumns = [];
22 |
23 | for (var i = 0; i < this.columnHeaders.length; i++) {
24 | var ch = this.columnHeaders[i];
25 | this.sortColumns.push(i);
26 | ch.setAttribute('data-column-index', i);
27 | ch.addEventListener('click', this.handleClick.bind(this));
28 | }
29 |
30 | this.optionCheckbox = document.querySelector(
31 | 'input[type="checkbox"][value="show-unsorted-icon"]'
32 | );
33 |
34 | if (this.optionCheckbox) {
35 | this.optionCheckbox.addEventListener(
36 | 'change',
37 | this.handleOptionChange.bind(this)
38 | );
39 | if (this.optionCheckbox.checked) {
40 | this.tableNode.classList.add('show-unsorted-icon');
41 | }
42 | }
43 | }
44 |
45 | setColumnHeaderSort(columnIndex) {
46 | if (typeof columnIndex === 'string') {
47 | columnIndex = parseInt(columnIndex);
48 | }
49 |
50 | for (var i = 0; i < this.columnHeaders.length; i++) {
51 | var ch = this.columnHeaders[i];
52 | if (i === columnIndex) {
53 | var value = ch.getAttribute('aria-sort');
54 | if (value === 'descending') {
55 | ch.setAttribute('aria-sort', 'ascending');
56 | this.sortColumn(
57 | columnIndex,
58 | 'ascending',
59 | ch.classList.contains('num')
60 | );
61 | } else {
62 | ch.setAttribute('aria-sort', 'descending');
63 | this.sortColumn(
64 | columnIndex,
65 | 'descending',
66 | ch.classList.contains('num')
67 | );
68 | }
69 | }
70 | }
71 | }
72 |
73 | sortColumn(columnIndex, sortValue, isNumber) {
74 | function compareValues(a, b) {
75 | if (sortValue === 'ascending') {
76 | if (a.value === b.value) {
77 | return 0;
78 | } else {
79 | if (isNumber) {
80 | return a.value - b.value;
81 | } else {
82 | return a.value < b.value ? -1 : 1;
83 | }
84 | }
85 | } else {
86 | if (a.value === b.value) {
87 | return 0;
88 | } else {
89 | if (isNumber) {
90 | return b.value - a.value;
91 | } else {
92 | return a.value > b.value ? -1 : 1;
93 | }
94 | }
95 | }
96 | }
97 |
98 | if (typeof isNumber !== 'boolean') {
99 | isNumber = false;
100 | }
101 |
102 | var tbodyNode = this.tableNode.querySelector('tbody');
103 | var rowNodes = [];
104 | var dataCells = [];
105 |
106 | var rowNode = tbodyNode.firstElementChild;
107 |
108 | var index = 0;
109 | while (rowNode) {
110 | rowNodes.push(rowNode);
111 | var rowCells = rowNode.querySelectorAll('th, td');
112 | var dataCell = rowCells[columnIndex];
113 |
114 | var data = {};
115 | data.index = index;
116 | data.value = dataCell.textContent.toLowerCase().trim();
117 | if (isNumber) {
118 | data.value = parseFloat(data.value);
119 | }
120 | dataCells.push(data);
121 | rowNode = rowNode.nextElementSibling;
122 | index += 1;
123 | }
124 |
125 | dataCells.sort(compareValues);
126 |
127 | // remove rows
128 | while (tbodyNode.firstChild) {
129 | tbodyNode.removeChild(tbodyNode.lastChild);
130 | }
131 |
132 | // add sorted rows
133 | for (var i = 0; i < dataCells.length; i += 1) {
134 | tbodyNode.appendChild(rowNodes[dataCells[i].index]);
135 | }
136 | }
137 |
138 | /* EVENT HANDLERS */
139 |
140 | handleClick(event) {
141 | var tgt = event.currentTarget;
142 | this.setColumnHeaderSort(tgt.getAttribute('data-column-index'));
143 | }
144 |
145 | handleOptionChange(event) {
146 | var tgt = event.currentTarget;
147 |
148 | if (tgt.checked) {
149 | this.tableNode.classList.add('show-unsorted-icon');
150 | } else {
151 | this.tableNode.classList.remove('show-unsorted-icon');
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/view/base/web/js/tabbis.js:
--------------------------------------------------------------------------------
1 | class tabbisClass {
2 | tabOptions ={}
3 |
4 | constructor(options) {
5 | this.thisOptions(options);
6 | this.thisMemory();
7 | this.setup();
8 | }
9 |
10 | getOption(key, groupIndex) {
11 | if(typeof groupIndex !== "undefined" && this.tabOptions.hasOwnProperty(groupIndex) && this.tabOptions[groupIndex].hasOwnProperty(key)) {
12 | return this.tabOptions[groupIndex][key];
13 | }
14 | return this.options[key];
15 | }
16 |
17 | // Setup
18 | setup() {
19 | const panes = document.querySelectorAll(this.getOption('paneGroup'));
20 | const tabs = document.querySelectorAll(this.getOption('tabGroup'));
21 |
22 | tabs.forEach((tabGroups, groupIndex) => {
23 | const paneGroups = panes[groupIndex];
24 | const activeIndex = this.getActiveIndex(tabGroups, groupIndex);
25 |
26 | tabGroups.setAttribute('role', 'tablist');
27 | this.tabOptions[groupIndex] = JSON.parse(tabGroups.getAttribute('tabbis-options'));
28 |
29 | // Reset items
30 | this.resetTabs([ ...tabGroups.children ]);
31 | this.resetPanes([ ...paneGroups.children ]);
32 |
33 | [ ...tabGroups.children ].forEach((tabItem, tabIndex) => {
34 | const paneItem = paneGroups.children[tabIndex];
35 |
36 | // Add attributes
37 | this.addTabAttributes(tabItem, groupIndex);
38 | this.addPaneAttributes(tabItem, paneItem);
39 |
40 | tabItem.groupIndex = groupIndex;
41 |
42 | // Trigger event
43 | tabItem.addEventListener(this.getOption('trigger'), (e) => {
44 | this.toggle(e.currentTarget, tabItem.groupIndex);
45 | });
46 |
47 | // Key event
48 | if (this.getOption('keyboardNavigation')) {
49 | tabItem.addEventListener('keydown', (e) => {
50 | this.eventKey(e);
51 | });
52 | }
53 | });
54 |
55 | if (activeIndex !== null) {
56 | this.toggle([ ...tabGroups.children ][activeIndex]);
57 | }
58 | });
59 | }
60 |
61 | // Event key
62 | eventKey(e) {
63 | if ([ 13, 37, 38, 39, 40 ].includes(e.keyCode)) {
64 | e.preventDefault();
65 | }
66 |
67 | if (e.keyCode == 13) {
68 | e.currentTarget.click();
69 | } else if ([ 39, 40 ].includes(e.keyCode)) {
70 | this.step(e, 1);
71 | } else if ([ 37, 38 ].includes(e.keyCode)) {
72 | this.step(e, -1);
73 | }
74 | }
75 |
76 | // Index
77 | index(el) {
78 | return [ ...el.parentElement.children ].indexOf(el);
79 | }
80 |
81 | // Step
82 | step(e, direction) {
83 | const children = e.currentTarget.parentElement.children;
84 | this.resetTabindex(children);
85 |
86 | let el = children[this.pos(e.currentTarget, children, direction)];
87 | el.focus();
88 | el.setAttribute('tabindex', 0);
89 | }
90 |
91 | resetTabindex(children) {
92 | [ ...children ].forEach((child) => {
93 | child.setAttribute('tabindex', '-1');
94 | });
95 | }
96 |
97 | // Pos
98 | pos(tab, children, direction) {
99 | let pos = this.index(tab);
100 | pos += direction;
101 |
102 | if (children.length <= pos) {
103 | pos = 0;
104 | } else if (pos == -1) {
105 | pos = children.length - 1;
106 | }
107 |
108 | return pos;
109 | }
110 |
111 | // Emit event
112 | emitEvent(eventName, tab, pane) {
113 | let event = new CustomEvent(eventName, {
114 | bubbles: true,
115 | detail: {
116 | tab: tab,
117 | pane: pane
118 | }
119 | });
120 |
121 | tab.dispatchEvent(event);
122 | }
123 |
124 | // Set active
125 | getActiveIndex(groupTabs, groupIndex) {
126 | const memory = this.loadMemory(groupIndex);
127 |
128 | if (typeof memory !== 'undefined') {
129 | return memory;
130 | } else {
131 | let element = groupTabs.querySelector(this.getOption('tabActive'));
132 |
133 | if (!element) {
134 | element = groupTabs.querySelector('[aria-selected="true"]');
135 | }
136 |
137 | if (element) {
138 | return this.index(element);
139 | } else if (this.getOption('tabActiveFallback') !== false) {
140 | return this.getOption('tabActiveFallback');
141 | } else {
142 | return null;
143 | }
144 | }
145 | }
146 |
147 | // ATTRIBUTES
148 |
149 | // Add tab attributes
150 | addTabAttributes(tab, groupIndex) {
151 | const tabIndex = this.index(tab);
152 | const prefix = this.getOption('prefix');
153 |
154 | tab.setAttribute('role', 'tab');
155 | tab.setAttribute('aria-controls', `${prefix}tabpanel-${groupIndex}-${tabIndex}`);
156 | }
157 |
158 | // Add tabpanel attributes
159 | addPaneAttributes(tab, pane) {
160 | pane.setAttribute('role', 'tabpanel');
161 | pane.setAttribute('aria-labelledby', tab.getAttribute('id'));
162 | pane.setAttribute('aria-controled-by', tab.getAttribute('aria-controls'));
163 | pane.setAttribute('tabindex', '0');
164 | }
165 |
166 | toggle(tab, groupIndex) {
167 | if(this.isActiveTab(tab, groupIndex) && this.getOption('collapsible', groupIndex)) {
168 | this.resetForTab(tab);
169 | this.resetMemoryGroup(groupIndex);
170 | } else {
171 | this.activate(tab,groupIndex);
172 | }
173 | }
174 |
175 | resetForTab(tab) {
176 | const pane = this.getPaneForTab(tab);
177 | this.resetTabs([ ...tab.parentNode.children ]);
178 | this.resetPanes([ ...pane.parentElement.children ]);
179 | }
180 |
181 | getPaneForTab(tab) {
182 | return document.querySelector('[aria-controled-by="'+tab.getAttribute('aria-controls')+'"]');
183 | }
184 |
185 | // Activate
186 | activate(tab, i) {
187 | this.resetForTab(tab)
188 |
189 | const pane = this.getPaneForTab(tab);
190 | let memorize = true;
191 | if(tab.getAttribute('data-ajax')) {
192 | this.loadPaneContent(tab, pane);
193 | tab.removeAttribute('data-ajax');
194 | memorize = false;
195 | }
196 |
197 | this.activateTab(tab);
198 | this.activatePane(pane);
199 |
200 | if(memorize) {
201 | this.saveMemory(tab, i);
202 | }
203 |
204 | this.emitEvent('tabbis', tab, pane);
205 | this.emitEvent('tabbis_pane_activate', tab, pane);
206 |
207 | }
208 |
209 | isActiveTab(tab) {
210 | return tab.getAttribute('aria-selected') === "true";
211 | }
212 |
213 | // Activate tab
214 | activateTab(tab) {
215 |
216 | tab.setAttribute('aria-selected', 'true');
217 | tab.setAttribute('tabindex', '0');
218 | tab.classList.add(this.getOption('tabActiveClass'));
219 | }
220 |
221 | // Activate pane
222 | activatePane(pane) {
223 | pane.removeAttribute('hidden');
224 | }
225 |
226 | loadPaneContent(tab, pane) {
227 | let paneXhrUri = tab.getAttribute('data-ajax');
228 | if(!paneXhrUri) {
229 | throw new Error("No data-ajax attribute");
230 | }
231 |
232 | fetch(paneXhrUri, {
233 | //To be compliant with \Laminas\Http\Request::isXmlHttpRequest
234 | headers: {
235 | "X-Requested-With": "XMLHttpRequest",
236 | }
237 | }
238 | )
239 | .then(response => {
240 | if (!response.ok) {
241 | throw new Error(response.status + " Failed Fetch ");
242 | }
243 | return response.text()
244 | })
245 | .then(function (html) {
246 | // console.log(html);
247 | pane.innerHTML = html;
248 | this.emitEvent('tabbis_pane_ajax_loaded', tab, pane);
249 | }.bind(this))
250 | .catch((err) =>
251 | console.log("Can’t access " + url + " response. Blocked by browser?" + err)
252 | );
253 |
254 | }
255 |
256 | // Remove tab attributes
257 | resetTabs(tabs) {
258 | tabs.forEach((el) => {
259 | el.setAttribute('aria-selected', 'false')
260 | el.classList.remove(this.getOption('tabActiveClass'));
261 | });
262 | this.resetTabindex(tabs);
263 | }
264 |
265 | // Reset pane attributes
266 | resetPanes(panes) {
267 | panes.forEach((el) => el.setAttribute('hidden', ''));
268 | }
269 |
270 | // MEMORY
271 |
272 | // Load memory
273 | loadMemory(groupIndex) {
274 | if (!this.options.memory) return;
275 | if (typeof this.memory[groupIndex] === 'undefined') return;
276 | if (this.memory[groupIndex] === null) return;
277 |
278 | return parseInt(this.memory[groupIndex]);
279 | }
280 |
281 | // Save memory
282 | saveMemory(tab, groupIndex) {
283 | if (!this.getOption('memory')) return;
284 | this.memory[groupIndex] = this.index(tab);
285 | localStorage.setItem(this.options.memory, JSON.stringify(this.memory));
286 | }
287 |
288 | resetMemoryGroup(groupIndex) {
289 | this.memory[groupIndex] = null;
290 | localStorage.setItem(this.options.memory, JSON.stringify(this.memory));
291 | }
292 |
293 |
294 | // This memory
295 | thisMemory() {
296 | if (!this.getOption('memory')) return;
297 | const store = localStorage.getItem(this.options.memory);
298 | this.memory = store !== null ? JSON.parse(store) : [];
299 | }
300 |
301 | // OPTIONS
302 |
303 | // Defaults
304 | defaults() {
305 | return {
306 | keyboardNavigation: true,
307 | memory: false,
308 | paneGroup: '[data-panes]',
309 | prefix: '',
310 | tabActive: '[data-active]',
311 | tabActiveClass: 'ui-tabs-active',
312 | tabActiveFallback: 0,
313 | tabGroup: '[data-tabs]',
314 | trigger: 'click',
315 | collapsible: false
316 | };
317 | }
318 |
319 | // This options
320 | thisOptions(options) {
321 | this.options = Object.assign(this.defaults(), options);
322 | if (this.options.memory !== true) return;
323 | this.options.memory = 'tabbis';
324 | }
325 | }
326 |
327 | // Function call
328 | function tabbis(options = {}) {
329 | const tabs = new tabbisClass(options);
330 | }
331 |
--------------------------------------------------------------------------------
/view/frontend/layout/quickdevbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Store
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------