├── .github
└── workflows
│ └── ci.yaml
├── .gitignore
├── .phpcs.xml.dist
├── Api
├── Data
│ └── ProfileInterface.php
└── ProfileRepositoryInterface.php
├── Console
└── Command
│ ├── DatabaseProfilerDisableCommand.php
│ └── DatabaseProfilerEnableCommand.php
├── Controller
├── Adminhtml
│ └── Profiler
│ │ └── Config.php
├── Cache.php
├── Cache
│ ├── Clean.php
│ ├── Disable.php
│ ├── Enable.php
│ └── Flush.php
└── Profiler
│ ├── Info.php
│ ├── PHPInfo.php
│ ├── Purge.php
│ ├── Search.php
│ └── Toolbar.php
├── Exception
└── CollectorNotFoundException.php
├── Helper
├── Config.php
├── Database.php
├── Debug.php
├── File.php
├── Formatter.php
├── Injector.php
└── Url.php
├── Logger
├── DataLogger.php
├── Handler.php
├── LoggableInterface.php
└── Logger.php
├── Model
├── Collector
│ ├── AjaxCollector.php
│ ├── CacheCollector.php
│ ├── CollectorInterface.php
│ ├── ConfigCollector.php
│ ├── CustomerCollector.php
│ ├── DatabaseCollector.php
│ ├── EventCollector.php
│ ├── LateCollectorInterface.php
│ ├── LayoutCollector.php
│ ├── LoggerCollectorInterface.php
│ ├── MemoryCollector.php
│ ├── ModelCollector.php
│ ├── PluginCollector.php
│ ├── RequestCollector.php
│ ├── TimeCollector.php
│ └── TranslationCollector.php
├── Config
│ ├── Database
│ │ └── ProfilerWriter.php
│ └── Source
│ │ └── ErrorHandler.php
├── DataCollector.php
├── Indexer
│ └── ProfileIndexer.php
├── Info
│ ├── CacheInfo.php
│ ├── CustomerInfo.php
│ ├── DatabaseInfo.php
│ ├── ExtensionInfo.php
│ ├── LayoutInfo.php
│ ├── MagentoInfo.php
│ ├── MemoryInfo.php
│ ├── PluginInfo.php
│ └── RequestInfo.php
├── Profile.php
├── Profile
│ └── Criteria.php
├── ProfileRepository.php
├── Profiler.php
├── Profiler
│ └── Driver
│ │ └── StopwatchDriver.php
├── Serializer
│ ├── CollectorSerializer.php
│ └── ProfileSerializer.php
├── Session.php
├── Storage
│ ├── HttpStorage.php
│ ├── ProfileFileStorage.php
│ └── ProfileMemoryStorage.php
├── ValueObject
│ ├── Block.php
│ ├── CacheAction.php
│ ├── EventObserver.php
│ ├── LayoutNode.php
│ ├── LoopModelAction.php
│ ├── ModelAction.php
│ ├── Plugin.php
│ ├── Redirect.php
│ ├── SearchResult.php
│ └── Translation.php
└── View
│ ├── Menu.php
│ ├── Profiler.php
│ ├── Renderer
│ ├── LayoutGraphRenderer.php
│ ├── LayoutNodeRenderer.php
│ ├── ParametersRenderer.php
│ ├── QueryListRenderer.php
│ ├── QueryParametersRenderer.php
│ ├── QueryRenderer.php
│ ├── RedirectRenderer.php
│ ├── RendererInterface.php
│ ├── TableRenderer.php
│ ├── TraceCallRenderer.php
│ ├── TraceRenderer.php
│ └── VarRenderer.php
│ ├── Search.php
│ ├── Summary.php
│ └── Toolbar.php
├── Observer
├── AllowedIP.php
├── BeforeSendResponse.php
├── Collector
│ ├── LayoutCollectorAfterToHtml.php
│ └── LayoutCollectorBeforeToHtml.php
├── Config
│ └── DatabaseProfiler.php
├── DebugHandle.php
└── ValidateRedirect.php
├── Plugin
├── Collector
│ ├── CacheCollectorPlugin.php
│ ├── EventCollectorPlugin.php
│ ├── ModelCollectorPlugin.php
│ ├── TimeCollectorPlugin.php
│ └── TranslationCollectorPlugin.php
├── ErrorHandler
│ └── WhoopsPlugin.php
├── PageCache
│ └── KernelPlugin.php
├── PreventMessageBlockInitByToolbarPlugin.php
├── ProfileRepository
│ └── RequestTimePlugin.php
└── UseMagentoBackendThemeOnDebugFrontendViewPlugin.php
├── Readme.md
├── Serializer
├── Serializer.php
└── SerializerInterface.php
├── Test
└── Unit
│ ├── Console
│ └── Command
│ │ ├── DatabaseProfilerDisableCommandTest.php
│ │ └── DatabaseProfilerEnableCommandTest.php
│ ├── Controller
│ ├── Adminhtml
│ │ └── Profiler
│ │ │ └── ConfigTest.php
│ ├── Cache
│ │ ├── CacheControllerTestCase.php
│ │ ├── CleanTest.php
│ │ ├── DisableTest.php
│ │ ├── EnableTest.php
│ │ └── FlushTest.php
│ └── Profiler
│ │ ├── InfoTest.php
│ │ ├── PHPInfoTest.php
│ │ ├── PurgeTest.php
│ │ ├── SearchTest.php
│ │ └── ToolbarTest.php
│ ├── Helper
│ ├── ConfigTest.php
│ └── DatabaseTest.php
│ ├── Logger
│ └── DataLoggerTest.php
│ ├── Model
│ ├── Storage
│ │ ├── HttpStorageTest.php
│ │ ├── ProfileFileStorageTest.php
│ │ └── ProfileMemoryStorageTest.php
│ └── ValueObject
│ │ ├── BlockTest.php
│ │ ├── CacheActionTest.php
│ │ ├── EventObserverTest.php
│ │ ├── LayoutNodeTest.php
│ │ ├── LoopModelActionTest.php
│ │ ├── ModelActionTest.php
│ │ ├── PluginTest.php
│ │ ├── RedirectTest.php
│ │ ├── SearchResultTest.php
│ │ └── TranslationTest.php
│ ├── Observer
│ ├── AllowedIPTest.php
│ ├── BeforeSendResponseTest.php
│ ├── Collector
│ │ ├── LayoutCollectorAfterToHtmlTest.php
│ │ └── LayoutCollectorBeforeToHtmlTest.php
│ ├── Config
│ │ └── DatabaseProfilerTest.php
│ ├── DebugHandleTest.php
│ └── ValidateRedirectTest.php
│ ├── Plugin
│ ├── Collector
│ │ ├── CacheCollectorPluginTest.php
│ │ ├── EventCollectorPluginTest.php
│ │ ├── ModelCollectorPluginTest.php
│ │ ├── TimeCollectorPluginTest.php
│ │ └── TranslationCollectorPluginTest.php
│ ├── ErrorHandler
│ │ └── WhoopsPluginTest.php
│ ├── PageCache
│ │ └── KernelPluginTest.php
│ └── ProfileRepository
│ │ └── RequestTimePluginTest.php
│ └── Serializer
│ └── SerializerTest.php
├── composer.json
├── etc
├── adminhtml
│ ├── di.xml
│ ├── events.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── di.xml
├── events.xml
├── frontend
│ ├── di.xml
│ └── routes.xml
└── module.xml
├── phpmd.xml
├── phpstan.neon.dist
├── phpunit.xml.dist
├── registration.php
└── view
└── base
├── layout
├── clawrock_debug.xml
├── debug_panel_cache.xml
├── debug_panel_config.xml
├── debug_panel_database.xml
├── debug_panel_event.xml
├── debug_panel_layout.xml
├── debug_panel_model.xml
├── debug_panel_plugin.xml
├── debug_panel_request.xml
├── debug_panel_time.xml
├── debug_panel_translation.xml
├── debug_profiler_info.xml
├── debug_profiler_search.xml
└── debug_profiler_toolbar.xml
├── page_layout
├── profiler.xml
└── toolbar.xml
├── templates
├── menu
│ ├── cache.phtml
│ ├── config.phtml
│ ├── database.phtml
│ ├── event.phtml
│ ├── layout.phtml
│ ├── model.phtml
│ ├── plugin.phtml
│ ├── request.phtml
│ ├── settings.phtml
│ ├── time.phtml
│ └── translation.phtml
├── panel
│ ├── cache.phtml
│ ├── config.phtml
│ ├── database.phtml
│ ├── event.phtml
│ ├── layout.phtml
│ ├── model.phtml
│ ├── plugin.phtml
│ ├── request.phtml
│ ├── time.phtml
│ └── translation.phtml
├── profiler.phtml
├── profiler
│ ├── js.phtml
│ ├── summary.phtml
│ └── toolbar
│ │ └── js.phtml
├── renderer
│ ├── layout
│ │ ├── graph.phtml
│ │ └── node.phtml
│ ├── parameters.phtml
│ ├── query.phtml
│ ├── query
│ │ └── list.phtml
│ ├── redirect.phtml
│ ├── table.phtml
│ ├── trace.phtml
│ └── trace
│ │ └── call.phtml
├── search
│ ├── input.phtml
│ └── results.phtml
├── toolbar.phtml
└── toolbar
│ ├── ajax.phtml
│ ├── cache.phtml
│ ├── config.phtml
│ ├── customer.phtml
│ ├── database.phtml
│ ├── event.phtml
│ ├── layout.phtml
│ ├── memory.phtml
│ ├── model.phtml
│ ├── plugin.phtml
│ ├── request.phtml
│ ├── time.phtml
│ └── translation.phtml
└── web
├── css
├── profiler.css
└── toolbar.css
└── images
├── clawrock.svg
├── collector
├── ajax.svg
├── cache.svg
├── config.svg
├── customer.svg
├── database.svg
├── event.svg
├── layout.svg
├── logs.svg
├── memory.svg
├── model.svg
├── models.svg
├── plugin.svg
├── redirect.svg
├── time.svg
└── translation.svg
├── icon
├── close.svg
├── menu.svg
├── no.svg
├── search.svg
├── settings.svg
└── yes.svg
└── magento.svg
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: "Build"
2 | on: ["push", "pull_request"]
3 | jobs:
4 | static-analysis:
5 | name: "Static analysis"
6 | runs-on: "ubuntu-latest"
7 | strategy:
8 | fail-fast: false
9 | matrix:
10 | php:
11 | - "8.1"
12 | - "8.2"
13 | steps:
14 | - name: "Checkout"
15 | uses: "actions/checkout@v3"
16 |
17 | - name: "Setup PHP"
18 | uses: "shivammathur/setup-php@v2"
19 | with:
20 | php-version: ${{ matrix.php }}
21 | extensions: bcmath, gd, intl, soap, sockets, xsl, zip
22 | ini-values: memory_limit=-1
23 | tools: composer:v2
24 |
25 | - name: "Cache Composer dependencies"
26 | uses: "actions/cache@v2"
27 | with:
28 | path: "/tmp/composer-cache"
29 | key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
30 | restore-keys: |
31 | php${{ matrix.php }}-composer-
32 |
33 | - name: Create auth.json
34 | run: echo '${{ secrets.COMPOSER_AUTH_JSON }}' > $GITHUB_WORKSPACE/auth.json
35 |
36 | - name: Composer install
37 | run: composer install --no-interaction --prefer-dist
38 |
39 | - name: Remove auth.json
40 | run: rm -f $GITHUB_WORKSPACE/auth.json
41 |
42 | - name: PHPUnit
43 | run: vendor/bin/phpunit -c phpunit.xml.dist Test --no-interaction
44 |
45 | - name: PHPCS
46 | run: vendor/bin/phpcs
47 |
48 | - name: PHPMD
49 | run: vendor/bin/phpmd . text phpmd.xml
50 |
51 | - name: PHPCPD
52 | run: vendor/bin/phpcpd --exclude vendor .
53 |
54 | - name: PHPStan
55 | run: vendor/bin/phpstan analyse --ansi --no-interaction
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | /vendor
3 | .phpunit.result.cache
4 |
--------------------------------------------------------------------------------
/.phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 | .
4 |
5 |
6 | *.xml
7 | */vendor/*
8 | */Test/.generated/tmp/generated/code/*
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | *.phtml
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Api/Data/ProfileInterface.php:
--------------------------------------------------------------------------------
1 | profilerWriter = $profilerWriter;
21 | }
22 |
23 | protected function configure(): void
24 | {
25 | parent::configure();
26 |
27 | $this->setDescription('Disable database profiler required for database collector.');
28 | }
29 |
30 | /**
31 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
32 | *
33 | * @param \Symfony\Component\Console\Input\InputInterface $input
34 | * @param \Symfony\Component\Console\Output\OutputInterface $output
35 | * @return int
36 | */
37 | protected function execute(InputInterface $input, OutputInterface $output): int
38 | {
39 | $this->profilerWriter->save(false);
40 |
41 | $output->writeLn('Database profiler disabled!');
42 |
43 | return Cli::RETURN_SUCCESS;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Console/Command/DatabaseProfilerEnableCommand.php:
--------------------------------------------------------------------------------
1 | profilerWriter = $profilerWriter;
21 | }
22 |
23 | protected function configure(): void
24 | {
25 | parent::configure();
26 |
27 | $this->setDescription('Enable database profiler required for database collector.');
28 | }
29 |
30 | /**
31 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
32 | *
33 | * @param \Symfony\Component\Console\Input\InputInterface $input
34 | * @param \Symfony\Component\Console\Output\OutputInterface $output
35 | * @return int
36 | */
37 | protected function execute(InputInterface $input, OutputInterface $output): int
38 | {
39 | $this->profilerWriter->save(true);
40 |
41 | $output->writeLn('Database profiler enabled!');
42 |
43 | return Cli::RETURN_SUCCESS;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Profiler/Config.php:
--------------------------------------------------------------------------------
1 | resultRedirectFactory->create();
22 |
23 | return $resultRedirect->setPath('admin/system_config/edit', [
24 | 'section' => 'clawrock_debug',
25 | 'key' => $this->_url->getSecretKey('adminhtml', 'system_config', 'edit'), // @phpstan-ignore-line
26 | ]);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Controller/Cache.php:
--------------------------------------------------------------------------------
1 | resultFactory = $resultFactory;
20 | $this->request = $request;
21 | $this->cacheManager = $cacheManager;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Controller/Cache/Clean.php:
--------------------------------------------------------------------------------
1 | resultFactory->create(ResultFactory::TYPE_JSON);
14 | $types = $this->request->getParam('type');
15 |
16 | if (!$types) {
17 | $types = $this->cacheManager->getAvailableTypes();
18 | }
19 |
20 | $this->cacheManager->clean((array) $types);
21 |
22 | return $result;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Controller/Cache/Disable.php:
--------------------------------------------------------------------------------
1 | resultFactory->create(ResultFactory::TYPE_JSON);
14 | $types = $this->request->getParam('type');
15 |
16 | $this->cacheManager->setEnabled((array) $types, false);
17 |
18 | return $result;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Controller/Cache/Enable.php:
--------------------------------------------------------------------------------
1 | resultFactory->create(ResultFactory::TYPE_JSON);
14 | $types = $this->request->getParam('type');
15 |
16 | $this->cacheManager->setEnabled((array) $types, true);
17 |
18 | return $result;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Controller/Cache/Flush.php:
--------------------------------------------------------------------------------
1 | resultFactory->create(ResultFactory::TYPE_JSON);
15 | $types = $this->request->getParam('type');
16 |
17 | if (!$types) {
18 | $types = $this->cacheManager->getAvailableTypes();
19 | }
20 |
21 | $this->cacheManager->flush((array) $types);
22 |
23 | return $result;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Controller/Profiler/PHPInfo.php:
--------------------------------------------------------------------------------
1 | resultFactory = $resultFactory;
18 | }
19 |
20 | public function execute(): ?ResultInterface
21 | {
22 | phpinfo();
23 |
24 | return $this->resultFactory->create(ResultFactory::TYPE_RAW);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Controller/Profiler/Purge.php:
--------------------------------------------------------------------------------
1 | resultFactory = $resultFactory;
25 | $this->redirect = $redirect;
26 | $this->profileFileStorage = $profileFileStorage;
27 | $this->logger = $logger;
28 | }
29 |
30 | public function execute(): ?ResultInterface
31 | {
32 | try {
33 | $this->profileFileStorage->purge();
34 | } catch (FileSystemException $e) {
35 | $this->logger->error('ClawRock_Debug: failed to purge file storage', ['exception' => $e]);
36 | }
37 |
38 | /** @var \Magento\Framework\Controller\Result\Redirect $result */
39 | $result = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
40 | $result->setUrl($this->redirect->getRefererUrl());
41 |
42 | return $result;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Controller/Profiler/Toolbar.php:
--------------------------------------------------------------------------------
1 | resultFactory = $resultFactory;
24 | $this->request = $request;
25 | $this->profileMemoryStorage = $profileMemoryStorage;
26 | $this->profileRepository = $profileRepository;
27 | }
28 |
29 | public function execute(): ?\Magento\Framework\Controller\ResultInterface
30 | {
31 | $token = $this->request->getParam(Profiler::URL_TOKEN_PARAMETER);
32 | $profile = $this->profileRepository->getById($token);
33 | $this->profileMemoryStorage->write($profile);
34 |
35 | return $this->resultFactory->create(ResultFactory::TYPE_PAGE);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Exception/CollectorNotFoundException.php:
--------------------------------------------------------------------------------
1 | isBacktraceItemValid($item, $functions)) {
23 | array_shift($backtrace);
24 | $item = reset($backtrace);
25 | }
26 |
27 | $backtrace = array_map(function ($item) {
28 | unset($item['object'], $item['args'], $item['type']);
29 |
30 | return $item;
31 | }, $backtrace);
32 |
33 | return $backtrace;
34 | }
35 |
36 | private function isBacktraceItemValid(array $data, array $functions): bool
37 | {
38 | if (!isset($data['class'], $data['function'])) {
39 | return false;
40 | }
41 |
42 | if (empty($functions)) {
43 | return true;
44 | }
45 |
46 | if (!in_array($data['function'], $functions)) {
47 | return false;
48 | }
49 |
50 | return true;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Helper/File.php:
--------------------------------------------------------------------------------
1 | directoryList = $directoryList;
14 | }
15 |
16 | public function getProfileDirectory(): string
17 | {
18 | return $this->directoryList->getPath('var') . DIRECTORY_SEPARATOR . 'debug';
19 | }
20 |
21 | public function getProfileIndex(): string
22 | {
23 | return $this->directoryList->getPath('var') . DIRECTORY_SEPARATOR . 'debug' . DIRECTORY_SEPARATOR . 'index.csv';
24 | }
25 |
26 | public function getProfileTempIndex(): string
27 | {
28 | return $this->directoryList->getPath('var') . DIRECTORY_SEPARATOR . 'debug' . DIRECTORY_SEPARATOR . 'tmp'
29 | . DIRECTORY_SEPARATOR . 'index.csv';
30 | }
31 |
32 | public function getProfileFilename(string $token): string
33 | {
34 | return $this->getProfileDirectory() . DIRECTORY_SEPARATOR
35 | . substr($token, -2, 2) . DIRECTORY_SEPARATOR
36 | . substr($token, -4, 2) . DIRECTORY_SEPARATOR
37 | . $token;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Helper/Formatter.php:
--------------------------------------------------------------------------------
1 | config = $config;
14 | }
15 |
16 | public function microtime(float $value, ?int $precision = null): string
17 | {
18 | if ($precision === null) {
19 | $precision = $this->config->getTimePrecision();
20 | }
21 |
22 | return sprintf('%0.' . $precision . 'f', $value * 1000);
23 | }
24 |
25 | public function revertMicrotime(string $value): float
26 | {
27 | return (float) $value / 1000;
28 | }
29 |
30 | public function toMegaBytes(int $value, int $precision = 0): string
31 | {
32 | return sprintf('%0.' . $precision . 'f', $value / 1024 /1024);
33 | }
34 |
35 | public function percentage(float $value, int $precision = 5): string
36 | {
37 | return sprintf('%.' . $precision . 'f%%', $value * 100);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Helper/Url.php:
--------------------------------------------------------------------------------
1 | url = $url;
23 | $this->backendUrl = $backendUrl;
24 | }
25 |
26 | public function getAdminUrl(): string
27 | {
28 | return $this->backendUrl->getRouteUrl(Area::AREA_ADMINHTML);
29 | }
30 |
31 | public function getConfigurationUrl(): string
32 | {
33 | return $this->backendUrl->getUrl(self::CONFIGURATION_URL_PATH);
34 | }
35 |
36 | public function getProfilerUrl(?string $token = null, ?string $panel = null): string
37 | {
38 | $params = [];
39 | if ($token) {
40 | $params[Profiler::URL_TOKEN_PARAMETER] = $token;
41 | }
42 | if ($panel) {
43 | $params[Profiler::URL_PANEL_PARAMETER] = $panel;
44 | }
45 |
46 | return $this->url->getUrl(self::PROFILER_URL_PATH, $params);
47 | }
48 |
49 | public function getToolbarUrl(string $token): string
50 | {
51 | return $this->url->getUrl('_debug/profiler/toolbar', [
52 | Profiler::URL_TOKEN_PARAMETER => $token,
53 | '_nosid' => true,
54 | ]);
55 | }
56 |
57 | public function getRequestFullActionName(Request $request): string
58 | {
59 | try {
60 | // @phpstan-ignore-next-line
61 | return $request->getRouteName() . '_' . $request->getControllerName() . '_' . $request->getActionName();
62 | } catch (\Exception $e) {
63 | return 'unknown';
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Logger/DataLogger.php:
--------------------------------------------------------------------------------
1 | data[$value->getId()] = $value;
13 |
14 | return $this;
15 | }
16 |
17 | public function getLogs(): array
18 | {
19 | return $this->data;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Logger/Handler.php:
--------------------------------------------------------------------------------
1 | config = $config;
16 | }
17 |
18 | public function collect(): CollectorInterface
19 | {
20 | // Nothing to collect here
21 | return $this;
22 | }
23 |
24 | /**
25 | * @return bool
26 | */
27 | public function isEnabled(): bool
28 | {
29 | return $this->config->isAjaxCollectorEnabled();
30 | }
31 |
32 | public function getData(): array
33 | {
34 | return [];
35 | }
36 |
37 | public function setData(array $data): CollectorInterface
38 | {
39 | return $this;
40 | }
41 |
42 | public function getName(): string
43 | {
44 | return self::NAME;
45 | }
46 |
47 | public function getStatus(): string
48 | {
49 | return self::STATUS_DEFAULT;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Model/Collector/CollectorInterface.php:
--------------------------------------------------------------------------------
1 | configWriter = $configWriter;
18 | }
19 |
20 | public function save(bool $flag): void
21 | {
22 | $configGroup = [
23 | ConfigOptionsListConstants::CONFIG_PATH_DB => [
24 | 'connection' => [
25 | 'default' => [
26 | 'profiler' => [
27 | 'class' => Profiler::class,
28 | 'enabled' => $flag,
29 | ],
30 | ],
31 | ],
32 | ],
33 | ];
34 |
35 | $this->configWriter->saveConfig([ConfigFilePool::APP_ENV => $configGroup]);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Model/Config/Source/ErrorHandler.php:
--------------------------------------------------------------------------------
1 | self::MAGENTO, 'label' => __('Default')],
17 | ['value' => self::WHOOPS, 'label' => __('Whoops')],
18 | ];
19 | }
20 |
21 | public function toArray(): array
22 | {
23 | return [
24 | self::MAGENTO => __('Default'),
25 | self::WHOOPS => __('Whoops'),
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Model/DataCollector.php:
--------------------------------------------------------------------------------
1 | $value) {
13 | $this->data[$key] = $value;
14 | }
15 |
16 | return $this;
17 | }
18 |
19 | /**
20 | * @param string $key
21 | * @return mixed
22 | */
23 | public function getData(string $key = '')
24 | {
25 | if ($key) {
26 | return $this->data[$key] ?? null;
27 | }
28 |
29 | return $this->data;
30 | }
31 |
32 | /**
33 | * @param string $key
34 | * @param mixed $value
35 | * @return $this
36 | */
37 | public function addData(string $key, $value): DataCollector
38 | {
39 | $this->data[$key] = $value;
40 |
41 | return $this;
42 | }
43 |
44 | /**
45 | * @param string $key
46 | * @param mixed $value
47 | * @return $this
48 | */
49 | public function appendData(string $key, $value): DataCollector
50 | {
51 | if (!isset($this->data[$key])) {
52 | $this->data[$key] = [];
53 | }
54 | $this->data[$key][] = $value;
55 |
56 | return $this;
57 | }
58 |
59 | public function removeData(string $key): DataCollector
60 | {
61 | unset($this->data[$key]);
62 |
63 | return $this;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Model/Indexer/ProfileIndexer.php:
--------------------------------------------------------------------------------
1 | fileSystem = $fileSystem;
22 | $this->fileWriteFactory = $fileWriteFactory;
23 | $this->logger = $logger;
24 | $this->fileHelper = $fileHelper;
25 | }
26 |
27 | public function index(ProfileInterface $profile): void
28 | {
29 | try {
30 | $tmpIndexPath = $this->fileHelper->getProfileTempIndex();
31 | $this->fileSystem->createDirectory($this->fileSystem->getParentDirectory($tmpIndexPath));
32 | $tmpIndex = $this->fileWriteFactory->create($tmpIndexPath, $this->fileSystem, 'w');
33 |
34 | $tmpIndex->writeCsv($profile->getIndex());
35 | $index = $tmpIndex->readAll();
36 | $tmpIndex->close();
37 | $index .= $this->fileSystem->isExists($this->fileHelper->getProfileIndex())
38 | ? $this->fileSystem->fileGetContents($this->fileHelper->getProfileIndex())
39 | : '';
40 |
41 | $this->fileSystem->filePutContents($this->fileHelper->getProfileIndex(), $index);
42 | } catch (\Exception $e) {
43 | $this->logger->error('ClawRock_Debug: Error during profile indexation', ['exception' => $e]);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Model/Info/CustomerInfo.php:
--------------------------------------------------------------------------------
1 | session = $session;
21 | $this->groupRepository = $groupRepository;
22 | $this->groupInterfaceFactory = $groupInterfaceFactory;
23 | }
24 |
25 | public function isLoggedIn(): bool
26 | {
27 | return $this->session->isLoggedIn();
28 | }
29 |
30 | public function getCustomer(): Customer
31 | {
32 | return $this->session->getCustomer();
33 | }
34 |
35 | public function getGroup(): GroupInterface
36 | {
37 | try {
38 | $group = $this->groupRepository->getById($this->getCustomer()->getGroupId());
39 | } catch (\Exception $e) {
40 | $group = $this->groupInterfaceFactory->create();
41 | }
42 |
43 | return $group;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Model/Info/ExtensionInfo.php:
--------------------------------------------------------------------------------
1 | layout = $layout;
17 | }
18 |
19 | public function getHandles(): array
20 | {
21 | return $this->layout->getUpdate()->getHandles();
22 | }
23 |
24 | public function getCreatedBlocks(): array
25 | {
26 | $blocks = [];
27 | foreach ($this->layout->getAllBlocks() as $block) {
28 | $blocks[] = new Block($block);
29 | }
30 |
31 | return $blocks;
32 | }
33 |
34 | public function getNotRenderedBlocks(): array
35 | {
36 | $blocks = [];
37 | foreach ($this->layout->getAllBlocks() as $block) {
38 | /** @var \Magento\Framework\View\Element\AbstractBlock $block */
39 | if (!$block->getData(LayoutCollector::BLOCK_PROFILER_ID_KEY)) {
40 | $blocks[] = new Block($block);
41 | }
42 | }
43 |
44 | return $blocks;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Model/Info/MemoryInfo.php:
--------------------------------------------------------------------------------
1 | convertToBytes((string) ini_get('memory_limit'));
11 | }
12 |
13 | public function getCurrentPeakMemoryUsage(): int
14 | {
15 | return memory_get_peak_usage(true);
16 | }
17 |
18 | private function convertToBytes(string $memoryLimit): int
19 | {
20 | if ('-1' === $memoryLimit) {
21 | return -1;
22 | }
23 |
24 | $memoryLimit = strtolower($memoryLimit);
25 | $max = $this->readValue($memoryLimit);
26 |
27 | switch (substr($memoryLimit, -1)) {
28 | case 't':
29 | $max *= 1024;
30 | // no break
31 | case 'g':
32 | $max *= 1024;
33 | // no break
34 | case 'm':
35 | $max *= 1024;
36 | // no break
37 | case 'k':
38 | $max *= 1024;
39 | }
40 |
41 | return $max;
42 | }
43 |
44 | private function readValue(string $memoryLimit): int
45 | {
46 | $value = ltrim($memoryLimit, '+');
47 | if (0 === strpos($value, '0x')) {
48 | // phpcs:ignore Magento2.Functions.DiscouragedFunction.DiscouragedWithAlternative
49 | return intval($value, 16);
50 | }
51 |
52 | if (0 === strpos($value, '0')) {
53 | // phpcs:ignore Magento2.Functions.DiscouragedFunction.DiscouragedWithAlternative
54 | return intval($value, 8);
55 | }
56 |
57 | return (int) $value;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Model/Serializer/CollectorSerializer.php:
--------------------------------------------------------------------------------
1 | objectManager = $objectManager;
20 | $this->logger = $logger;
21 | $this->config = $config;
22 | }
23 |
24 | /**
25 | * @param \ClawRock\Debug\Model\Collector\CollectorInterface[] $collectors
26 | * @return array
27 | */
28 | public function serialize(array $collectors): array
29 | {
30 | foreach ($collectors as &$collector) {
31 | $collector = $collector->getData();
32 | }
33 |
34 | return $collectors;
35 | }
36 |
37 | public function unserialize(array $data): array
38 | {
39 | $collectors = [];
40 | foreach ($data as $name => $collector) {
41 | try {
42 | $collectorClass = $this->config->getCollectorClass($name);
43 | $collectors[$name] = $this->objectManager->create($collectorClass)->setData($collector);
44 | } catch (CollectorNotFoundException $e) {
45 | $this->logger->error(sprintf('ClawRock_Debug: collector "%s" not found', $name), ['exception' => $e]);
46 | continue;
47 | }
48 | }
49 |
50 | return $collectors;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Model/Serializer/ProfileSerializer.php:
--------------------------------------------------------------------------------
1 | serializer = $serializer;
20 | $this->collectorSerializer = $collectorSerializer;
21 | $this->profileFactory = $profileFactory;
22 | }
23 |
24 | public function serialize(ProfileInterface $profile): string
25 | {
26 | return $this->serializer->serialize(array_merge(
27 | $profile->getData(),
28 | ['collectors' => $this->collectorSerializer->serialize($profile->getCollectors())]
29 | ));
30 | }
31 |
32 | public function unserialize(string $data): ProfileInterface
33 | {
34 | $profileData = $this->serializer->unserialize($data);
35 | $collectors = $this->collectorSerializer->unserialize($profileData['collectors']);
36 | unset($profileData['collectors']);
37 |
38 | /** @var \ClawRock\Debug\Model\Profile $profile */
39 | $profile = $this->profileFactory->create(['token' => $profileData['token']])->setData($profileData);
40 | $profile->setCollectors($collectors);
41 |
42 | return $profile;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Model/Session.php:
--------------------------------------------------------------------------------
1 | request;
18 | }
19 |
20 | public function setRequest(Request $request): HttpStorage
21 | {
22 | $this->request = $request;
23 |
24 | return $this;
25 | }
26 |
27 | public function getResponse(): Response
28 | {
29 | return $this->response;
30 | }
31 |
32 | public function setResponse(Response $response): HttpStorage
33 | {
34 | $this->response = $response;
35 |
36 | return $this;
37 | }
38 |
39 | public function markAsFPCRequest(): HttpStorage
40 | {
41 | $this->fpc = true;
42 |
43 | return $this;
44 | }
45 |
46 | public function isFPCRequest(): bool
47 | {
48 | return $this->fpc;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Model/Storage/ProfileMemoryStorage.php:
--------------------------------------------------------------------------------
1 | profile;
15 | }
16 |
17 | public function write(ProfileInterface $profile): void
18 | {
19 | $this->profile = $profile;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Model/ValueObject/Block.php:
--------------------------------------------------------------------------------
1 | id = (string) $block->getData(LayoutCollector::BLOCK_PROFILER_ID_KEY);
23 | $this->name = (string) $block->getNameInLayout();
24 | $this->class = get_class($block);
25 | $this->module = $block->getModuleName();
26 | $this->renderTime = (float) $block->getData(LayoutCollector::RENDER_TIME);
27 | $this->template = (string) $block->getTemplate();
28 | $this->children = $block->getChildNames();
29 | $this->parentId = $block->getParentBlock() instanceof \Magento\Framework\View\Element\AbstractBlock
30 | ? (string) $block->getParentBlock()->getData(LayoutCollector::BLOCK_PROFILER_ID_KEY)
31 | : '';
32 | }
33 |
34 | public function getId(): string
35 | {
36 | return $this->id;
37 | }
38 |
39 | public function getName(): string
40 | {
41 | return $this->name;
42 | }
43 |
44 | public function getClass(): string
45 | {
46 | return $this->class;
47 | }
48 |
49 | public function getModule(): string
50 | {
51 | return $this->module;
52 | }
53 |
54 | public function getRenderTime(): float
55 | {
56 | return $this->renderTime;
57 | }
58 |
59 | public function getTemplate(): string
60 | {
61 | return $this->template;
62 | }
63 |
64 | public function getChildren(): array
65 | {
66 | return $this->children;
67 | }
68 |
69 | public function getParentId(): string
70 | {
71 | return $this->parentId;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Model/ValueObject/CacheAction.php:
--------------------------------------------------------------------------------
1 | id = $id;
30 | $this->name = $name;
31 | $this->time = $time;
32 | $this->info = $info;
33 | }
34 |
35 | public function getId(): string
36 | {
37 | return $this->id;
38 | }
39 |
40 | public function getName(): string
41 | {
42 | return $this->name;
43 | }
44 |
45 | public function isLoad(): bool
46 | {
47 | return $this->name === self::LOAD;
48 | }
49 |
50 | public function getTime(): float
51 | {
52 | return $this->time;
53 | }
54 |
55 | public function getInfo(): array
56 | {
57 | return $this->info;
58 | }
59 |
60 | public function isHit(): bool
61 | {
62 | return $this->info[self::CACHE_HIT] ?? false;
63 | }
64 |
65 | public function getTags(): array
66 | {
67 | return $this->info[self::CACHE_TAGS] ?? [];
68 | }
69 |
70 | public function hasTags(): bool
71 | {
72 | return !empty($this->getTags());
73 | }
74 |
75 | public function getTTL(): int
76 | {
77 | return (int) ($this->info[self::CACHE_TTL] ?? 0);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Model/ValueObject/EventObserver.php:
--------------------------------------------------------------------------------
1 | id = uniqid();
23 | $this->name = $name;
24 | $this->class = $class;
25 | $this->event = $event;
26 | $this->time = $time;
27 | }
28 |
29 | public function getId(): string
30 | {
31 | return $this->getName() . '_' . $this->id;
32 | }
33 |
34 | public function getName(): string
35 | {
36 | return $this->name;
37 | }
38 |
39 | public function getClass(): string
40 | {
41 | return $this->class;
42 | }
43 |
44 | public function getEvent(): string
45 | {
46 | return $this->event;
47 | }
48 |
49 | public function getTime(): float
50 | {
51 | return $this->time;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Model/ValueObject/LayoutNode.php:
--------------------------------------------------------------------------------
1 | block = $block;
20 | $this->layoutRenderTime = $layoutRenderTime;
21 | $this->prefix = $prefix;
22 | $this->children = $children;
23 | }
24 |
25 | public function getName(): string
26 | {
27 | return $this->block->getName();
28 | }
29 |
30 | public function getClass(): string
31 | {
32 | return $this->block->getClass();
33 | }
34 |
35 | public function getModule(): string
36 | {
37 | return $this->block->getModule();
38 | }
39 |
40 | public function getRenderTime(): float
41 | {
42 | return $this->block->getRenderTime();
43 | }
44 |
45 | public function getPrefix(): string
46 | {
47 | return (string) $this->prefix;
48 | }
49 |
50 | public function getTemplate(): string
51 | {
52 | return $this->block->getTemplate();
53 | }
54 |
55 | public function getChildren(): array
56 | {
57 | return $this->children;
58 | }
59 |
60 | public function hasChildren(): bool
61 | {
62 | return !empty($this->children);
63 | }
64 |
65 | public function getParentId(): string
66 | {
67 | return (string) $this->block->getParentId();
68 | }
69 |
70 | public function getRenderPercent(): float
71 | {
72 | if (empty($this->layoutRenderTime)) {
73 | return 0.0;
74 | }
75 |
76 | return $this->getRenderTime() / $this->layoutRenderTime;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Model/ValueObject/LoopModelAction.php:
--------------------------------------------------------------------------------
1 | modelAction = $modelAction;
15 | $this->time = $time;
16 | $this->count = $count;
17 | }
18 |
19 | public function getModelAction(): ModelAction
20 | {
21 | return $this->modelAction;
22 | }
23 |
24 | public function getName(): string
25 | {
26 | return $this->modelAction->getName();
27 | }
28 |
29 | public function getModel(): string
30 | {
31 | return $this->modelAction->getModel();
32 | }
33 |
34 | public function getTrace(): array
35 | {
36 | return $this->modelAction->getTrace();
37 | }
38 |
39 | public function getTime(): float
40 | {
41 | return $this->time;
42 | }
43 |
44 | public function getCount(): int
45 | {
46 | return $this->count;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Model/ValueObject/ModelAction.php:
--------------------------------------------------------------------------------
1 | id = uniqid();
24 | $this->name = $name;
25 | $this->model = $model;
26 | $this->time = $time;
27 | $this->trace = $trace;
28 | }
29 |
30 | public function getId(): string
31 | {
32 | return $this->name . '::' . $this->id . '::' . $this->model;
33 | }
34 |
35 | public function getName(): string
36 | {
37 | return $this->name;
38 | }
39 |
40 | public function getModel(): string
41 | {
42 | return $this->model;
43 | }
44 |
45 | public function getTime(): float
46 | {
47 | return $this->time;
48 | }
49 |
50 | public function getTrace(): array
51 | {
52 | return $this->trace;
53 | }
54 |
55 | public function getTraceHash(): string
56 | {
57 | if (empty($this->getTrace())) {
58 | return '';
59 | }
60 |
61 | // phpcs:ignore Magento2.Security.InsecureFunction.FoundWithAlternative
62 | return md5(serialize($this->getTrace()));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Model/ValueObject/Plugin.php:
--------------------------------------------------------------------------------
1 | class = $class;
17 | $this->name = $name;
18 | $this->sortOrder = $sortOrder;
19 | $this->method = $method;
20 | $this->type = $type;
21 | }
22 |
23 | public function getClass(): string
24 | {
25 | return $this->class;
26 | }
27 |
28 | public function getName(): string
29 | {
30 | return $this->name;
31 | }
32 |
33 | public function getSortOrder(): int
34 | {
35 | return $this->sortOrder;
36 | }
37 |
38 | public function getMethod(): string
39 | {
40 | return $this->method;
41 | }
42 |
43 | public function getType(): string
44 | {
45 | return $this->type;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Model/ValueObject/Translation.php:
--------------------------------------------------------------------------------
1 | phrase = $phrase;
17 | $this->translation = $translation;
18 | $this->defined = $defined;
19 | }
20 |
21 | public function getId(): string
22 | {
23 | return $this->phrase;
24 | }
25 |
26 | public function getPhrase(): string
27 | {
28 | return $this->phrase;
29 | }
30 |
31 | public function getTranslation(): string
32 | {
33 | return $this->translation;
34 | }
35 |
36 | public function isDefined(): bool
37 | {
38 | return $this->defined;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Model/View/Menu.php:
--------------------------------------------------------------------------------
1 | request = $request;
33 | $this->profileMemoryStorage = $profileMemoryStorage;
34 | $this->url = $url;
35 | }
36 |
37 | public function isActive(string $collectorName): bool
38 | {
39 | return $this->getProfile()->hasCollector($collectorName);
40 | }
41 |
42 | public function isCurrentPanel(string $collectorName): bool
43 | {
44 | return $this->request->getParam('panel') === $collectorName;
45 | }
46 |
47 | public function getCollector(string $collectorName): CollectorInterface
48 | {
49 | return $this->getProfile()->getCollector($collectorName);
50 | }
51 |
52 | public function getProfilerUrl(string $collectorName): string
53 | {
54 | return $this->url->getProfilerUrl($this->getProfile()->getToken(), $collectorName);
55 | }
56 |
57 | public function getConfigurationUrl(): string
58 | {
59 | return $this->url->getConfigurationUrl();
60 | }
61 |
62 | private function getProfile(): ProfileInterface
63 | {
64 | return $this->profileMemoryStorage->read();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Model/View/Renderer/LayoutNodeRenderer.php:
--------------------------------------------------------------------------------
1 | node = $node;
24 | $this->layout = $layout;
25 | $this->layoutNodeRendererFactory = $layoutNodeRendererFactory;
26 | $this->formatter = $formatter;
27 | }
28 |
29 | public function render(): string
30 | {
31 | /** @var \Magento\Framework\View\Element\Template $block */
32 | $block = $this->layout->createBlock(
33 | Template::class,
34 | '',
35 | [
36 | 'data' => [
37 | 'template' => self::TEMPLATE,
38 | 'node' => $this->node,
39 | 'formatter' => $this->formatter,
40 | 'layout_node_renderer' => $this->layoutNodeRendererFactory,
41 | ],
42 | ]
43 | );
44 |
45 | return $block->toHtml();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Model/View/Renderer/ParametersRenderer.php:
--------------------------------------------------------------------------------
1 | parameters = $parameters;
22 | $this->layout = $layout;
23 | $this->varRenderer = $varRenderer;
24 | }
25 |
26 | public function render(): string
27 | {
28 | /** @var \Magento\Framework\View\Element\Template $block */
29 | $block = $this->layout->createBlock(
30 | Template::class,
31 | '',
32 | [
33 | 'data' => [
34 | 'template' => self::TEMPLATE,
35 | 'parameters' => $this->parameters,
36 | 'var_renderer' => $this->varRenderer,
37 | ],
38 | ]
39 | );
40 |
41 | return $block->toHtml();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Model/View/Renderer/QueryListRenderer.php:
--------------------------------------------------------------------------------
1 | queries = $queries;
27 | $this->layout = $layout;
28 | $this->mathRandom = $mathRandom;
29 | $this->queryRendererFactory = $queryRendererFactory;
30 | $this->formatter = $formatter;
31 | }
32 |
33 | public function render(): string
34 | {
35 | /** @var \Magento\Framework\View\Element\Template $block */
36 | $block = $this->layout->createBlock(
37 | Template::class,
38 | '',
39 | [
40 | 'data' => [
41 | 'template' => self::TEMPLATE,
42 | 'queries' => $this->queries,
43 | 'query_renderer' => $this->queryRendererFactory,
44 | 'prefix' => $this->mathRandom->getUniqueHash(),
45 | 'formatter' => $this->formatter,
46 | ],
47 | ]
48 | );
49 |
50 | return $block->toHtml();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Model/View/Renderer/QueryParametersRenderer.php:
--------------------------------------------------------------------------------
1 | query = $query;
18 | $this->parameters = $parameters;
19 | $this->resource = $resource;
20 | }
21 |
22 | public function render(): string
23 | {
24 | $parameters = $this->parameters;
25 | $i = !array_key_exists(0, $parameters) && array_key_exists(1, $parameters) ? 1 : 0;
26 |
27 | $result = preg_replace_callback('/\?|((?resource->getConnection()->quote($value);
35 | $i++;
36 |
37 | return $result;
38 | }, $this->query);
39 |
40 | return (string) $result;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Model/View/Renderer/RedirectRenderer.php:
--------------------------------------------------------------------------------
1 | redirect = $redirect;
33 | $this->layout = $layout;
34 | $this->url = $url;
35 | }
36 |
37 | public function render(): string
38 | {
39 | /** @var \Magento\Framework\View\Element\Template $block */
40 | $block = $this->layout->createBlock(
41 | Template::class,
42 | '',
43 | [
44 | 'data' => [
45 | 'template' => self::TEMPLATE,
46 | ],
47 | ]
48 | );
49 |
50 | return $block->setProfilerUrl($this->url->getProfilerUrl($this->redirect->getToken()))
51 | ->setRedirect($this->redirect)
52 | ->toHtml();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Model/View/Renderer/RendererInterface.php:
--------------------------------------------------------------------------------
1 | items = $items;
24 | $this->layout = $layout;
25 | $this->varRenderer = $varRenderer;
26 | $this->labels = $labels;
27 | }
28 |
29 | public function render(): string
30 | {
31 | /** @var \Magento\Framework\View\Element\Template $block */
32 | $block = $this->layout->createBlock(
33 | Template::class,
34 | '',
35 | [
36 | 'data' => [
37 | 'template' => self::TEMPLATE,
38 | 'items' => $this->items,
39 | 'labels' => $this->labels,
40 | 'var_renderer' => $this->varRenderer,
41 | 'key_label' => $this->labels[0] ?? 'Key',
42 | 'value_label' => $this->labels[1] ?? 'Value',
43 | ],
44 | ]
45 | );
46 |
47 | return $block->toHtml();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Model/View/Renderer/TraceCallRenderer.php:
--------------------------------------------------------------------------------
1 | call = $call;
23 | $this->layout = $layout;
24 | $this->directoryList = $directoryList;
25 | }
26 |
27 | public function render(): string
28 | {
29 | /** @var \Magento\Framework\View\Element\Template $block */
30 | $block = $this->layout->createBlock(
31 | Template::class,
32 | '',
33 | [
34 | 'data' => [
35 | 'template' => self::TEMPLATE,
36 | ],
37 | ]
38 | );
39 |
40 | foreach (self::CALL_INFO as $info) {
41 | if (isset($this->call[$info])) {
42 | $block->setData($info, $this->call[$info]);
43 | }
44 | }
45 | if ($block->hasFile()) {
46 | $block->setFile($this->relativizePath($block->getFile()));
47 | }
48 |
49 | return $block->toHtml();
50 | }
51 |
52 | private function relativizePath(string $path): string
53 | {
54 | $rootDirectory = $this->directoryList->getRoot();
55 |
56 | return (string) (strpos($path, $rootDirectory) === 0 ? substr($path, strlen($rootDirectory)) : $path);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Model/View/Renderer/TraceRenderer.php:
--------------------------------------------------------------------------------
1 | id = uniqid();
23 | $this->trace = $trace;
24 | $this->layout = $layout;
25 | $this->traceCallRendererFactory = $traceCallRendererFactory;
26 | }
27 |
28 | public function render(): string
29 | {
30 | /** @var \Magento\Framework\View\Element\Template $block */
31 | $block = $this->layout->createBlock(
32 | Template::class,
33 | '',
34 | [
35 | 'data' => [
36 | 'template' => self::TEMPLATE,
37 | 'trace' => $this->trace,
38 | 'trace_id' => $this->id,
39 | 'trace_call_renderer' => $this->traceCallRendererFactory,
40 | ],
41 | ]
42 | );
43 |
44 | return $block->toHtml();
45 | }
46 |
47 | public function getId(): string
48 | {
49 | return $this->id;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Model/View/Renderer/VarRenderer.php:
--------------------------------------------------------------------------------
1 | cloner = new VarCloner();
17 | $this->dumper = new HtmlDumper();
18 | }
19 |
20 | /**
21 | * @param mixed $value
22 | * @return string
23 | */
24 | public function render($value): string
25 | {
26 | return (string) $this->dumper->dump($this->cloner->cloneVar($value), true);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Model/View/Search.php:
--------------------------------------------------------------------------------
1 | request = $request;
24 | $this->profileMemoryStorage = $profileMemoryStorage;
25 | $this->formatter = $formatter;
26 | $this->url = $url;
27 | }
28 |
29 | public function isParamSelected(string $param, string $expected): bool
30 | {
31 | return $this->request->getParam($param) === $expected;
32 | }
33 |
34 | public function getParam(string $param): ?string
35 | {
36 | return $this->request->getParam($param);
37 | }
38 |
39 | public function getLimits(): array
40 | {
41 | return ['10', '50', '100'];
42 | }
43 |
44 | public function getMethods(): array
45 | {
46 | return ['GET', 'POST', 'DELETE', 'PUT', 'PATCH', 'HEAD'];
47 | }
48 |
49 | public function getToken(): string
50 | {
51 | if ($this->token === null) {
52 | $this->token = $this->profileMemoryStorage->read()->getToken();
53 | }
54 |
55 | return $this->token;
56 | }
57 |
58 | public function toMegaBytes(int $value): string
59 | {
60 | return $this->formatter->toMegaBytes($value, 2);
61 | }
62 |
63 | public function getProfilerUrl(string $token): string
64 | {
65 | return $this->url->getProfilerUrl($token, RequestCollector::NAME);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Model/View/Summary.php:
--------------------------------------------------------------------------------
1 | profileMemoryStorage = $profileMemoryStorage;
22 | $this->url = $url;
23 | $this->redirectRendererFactory = $redirectRendererFactory;
24 | }
25 |
26 | public function getProfile(): ProfileInterface
27 | {
28 | return $this->profileMemoryStorage->read();
29 | }
30 |
31 | public function getProfilerUrl(string $token): string
32 | {
33 | return $this->url->getProfilerUrl($token);
34 | }
35 |
36 | public function renderRedirect(Redirect $redirect): string
37 | {
38 | return $this->redirectRendererFactory->create(['redirect' => $redirect])->render();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Observer/AllowedIP.php:
--------------------------------------------------------------------------------
1 | config = $config;
17 | }
18 |
19 | public function execute(Observer $observer)
20 | {
21 | if ($this->config->isAllowedIP()) {
22 | return;
23 | }
24 |
25 | /** @var \Magento\Framework\App\Request\Http $request */
26 | $request = $observer->getRequest();
27 | $request->initForward();
28 | $request->setControllerName('noroute');
29 | $request->setModuleName('cms');
30 | $request->setActionName('index');
31 | $request->setDispatched(false);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Observer/BeforeSendResponse.php:
--------------------------------------------------------------------------------
1 | config = $config;
19 | $this->profiler = $profiler;
20 | }
21 |
22 | public function execute(Observer $observer)
23 | {
24 | $request = $observer->getRequest();
25 | $response = $observer->getResponse();
26 | if ($this->isProfilerAction($request) || !$this->config->isEnabled()) {
27 | return;
28 | }
29 |
30 | $this->profiler->run($request, $response);
31 | }
32 |
33 | private function isProfilerAction(\Magento\Framework\HTTP\PhpEnvironment\Request $request): bool
34 | {
35 | return $request->getModuleName() === '_debug' || $request->getModuleName() === 'debug';
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Observer/Collector/LayoutCollectorAfterToHtml.php:
--------------------------------------------------------------------------------
1 | layoutCollector = $layoutCollector;
19 | }
20 |
21 | public function execute(Observer $observer)
22 | {
23 | /** @var \Magento\Framework\View\Element\AbstractBlock $block */
24 | $block = $observer->getBlock();
25 |
26 | $renderedTimestamp = microtime(true);
27 | $renderTime = $renderedTimestamp - $block->getData(LayoutCollector::BLOCK_START_RENDER_KEY);
28 |
29 | $block->addData([
30 | LayoutCollector::BLOCK_STOP_RENDER_KEY => $renderedTimestamp,
31 | LayoutCollector::RENDER_TIME => $renderTime,
32 | ]);
33 |
34 | $this->layoutCollector->log(new Block($block));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Observer/Collector/LayoutCollectorBeforeToHtml.php:
--------------------------------------------------------------------------------
1 | getBlock();
16 | $id = uniqid();
17 | $block->addData([
18 | LayoutCollector::BLOCK_PROFILER_ID_KEY => $id,
19 | LayoutCollector::BLOCK_START_RENDER_KEY => microtime(true),
20 | LayoutCollector::BLOCK_HASH_KEY => spl_object_hash($block),
21 | ]);
22 |
23 | if ($block->getParentBlock() instanceof \Magento\Framework\View\Element\AbstractBlock) {
24 | $block->addData([
25 | LayoutCollector::BLOCK_PARENT_PROFILER_ID_KEY => $block->getParentBlock()
26 | ->getData(LayoutCollector::BLOCK_PROFILER_ID_KEY),
27 | ]);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Observer/Config/DatabaseProfiler.php:
--------------------------------------------------------------------------------
1 | messageManager = $messageManager;
23 | $this->dbProfilerWriter = $dbProfilerWriter;
24 | $this->config = $config;
25 | }
26 |
27 | public function execute(Observer $observer): void
28 | {
29 | if (!$this->isDBProfilerDependentConfigChanged($observer->getChangedPaths())) {
30 | return;
31 | }
32 |
33 | $flag = $this->config->isDatabaseCollectorEnabled() && $this->config->isActive();
34 |
35 | try {
36 | $this->dbProfilerWriter->save($flag);
37 | } catch (FileSystemException $e) {
38 | $this->messageManager->addExceptionMessage($e);
39 | }
40 | }
41 |
42 | private function isDBProfilerDependentConfigChanged(array $paths): bool
43 | {
44 | return in_array(Config::CONFIG_COLLECTOR_DATABASE, $paths) || in_array(Config::CONFIG_ENABLED, $paths);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Observer/DebugHandle.php:
--------------------------------------------------------------------------------
1 | config = $config;
18 | }
19 |
20 | public function execute(Observer $observer)
21 | {
22 | if ($this->config->isEnabled()) {
23 | $observer->getLayout()->getUpdate()->addHandle('clawrock_debug');
24 | }
25 |
26 | if ($observer->getFullActionName() === Profiler::TOOLBAR_FULL_ACTION_NAME) {
27 | $observer->getLayout()->getUpdate()->removeHandle('default');
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Observer/ValidateRedirect.php:
--------------------------------------------------------------------------------
1 | session = $session;
18 | }
19 |
20 | public function execute(Observer $observer)
21 | {
22 | if ($this->session->getData(RequestInfo::REDIRECT_PARAM)) {
23 | $observer->getRequest()->setParam('_redirected', true);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Plugin/Collector/EventCollectorPlugin.php:
--------------------------------------------------------------------------------
1 | eventCollector = $eventCollector;
21 | }
22 |
23 | public function aroundDispatch(
24 | InvokerDefault $subject,
25 | callable $proceed,
26 | array $configuration,
27 | Observer $observer
28 | ): void {
29 | $start = microtime(true);
30 | $proceed($configuration, $observer);
31 | $end = microtime(true);
32 |
33 | $this->eventCollector->log(new EventObserver(
34 | $configuration['name'],
35 | $configuration['instance'],
36 | $observer->getEvent()->getName(),
37 | $end - $start
38 | ));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Plugin/Collector/TimeCollectorPlugin.php:
--------------------------------------------------------------------------------
1 | stopwatchDriver = $stopwatchDriver;
16 | }
17 |
18 | public function beforeLaunch(): void
19 | {
20 | Profiler::reset();
21 | Profiler::add($this->stopwatchDriver);
22 | Profiler::start($this->stopwatchDriver::ROOT_EVENT);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Plugin/Collector/TranslationCollectorPlugin.php:
--------------------------------------------------------------------------------
1 | translate = $translate;
23 | $this->translationCollector = $translationCollector;
24 | }
25 |
26 | public function beforeRender(Translate $subject, array $source, array $arguments): void
27 | {
28 | /** @var string $text */
29 | $text = end($source);
30 | $text = str_replace('\"', '"', $text);
31 | $text = str_replace("\\'", "'", $text);
32 |
33 | $data = $this->getTranslations();
34 | $translation = '';
35 |
36 | if ($isDefined = array_key_exists($text, $data)) {
37 | $translation = $data[$text];
38 | }
39 |
40 | $this->translationCollector->log(new Translation(end($source), $translation, $isDefined));
41 | }
42 |
43 | private function getTranslations(): array
44 | {
45 | if ($this->translations === null) {
46 | $this->translations = $this->translate->getData();
47 | }
48 |
49 | return $this->translations;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Plugin/ErrorHandler/WhoopsPlugin.php:
--------------------------------------------------------------------------------
1 | config = $config;
22 | $this->whoopsFactory = $whoopsFactory;
23 | $this->prettyPageHandlerFactory = $prettyPageHandlerFactory;
24 | }
25 |
26 | /**
27 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
28 | *
29 | * @param \Magento\Framework\App\Http $subject
30 | * @param \Magento\Framework\App\Bootstrap $bootstrap
31 | * @param \Exception $exception
32 | * @return array
33 | */
34 | public function beforeCatchException(Http $subject, Bootstrap $bootstrap, \Exception $exception): array
35 | {
36 | if ($this->config->getErrorHandler() === ErrorHandler::WHOOPS) {
37 | $whoops = $this->whoopsFactory->create();
38 | $whoops->pushHandler($this->prettyPageHandlerFactory->create());
39 | $whoops->handleException($exception);
40 | }
41 |
42 | return [$bootstrap, $exception];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Plugin/PageCache/KernelPlugin.php:
--------------------------------------------------------------------------------
1 | httpStorage = $httpStorage;
17 | }
18 |
19 | /**
20 | * @param \Magento\Framework\App\PageCache\Kernel $subject
21 | * @param \Magento\Framework\App\Response\Http|false $result
22 | * @return \Magento\Framework\App\Response\Http|false
23 | */
24 | public function afterLoad(\Magento\Framework\App\PageCache\Kernel $subject, $result)
25 | {
26 | if ($result !== false) {
27 | $this->httpStorage->markAsFPCRequest();
28 | }
29 |
30 | return $result;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Plugin/PreventMessageBlockInitByToolbarPlugin.php:
--------------------------------------------------------------------------------
1 | getUpdate()->getHandles();
19 | if ($handles === ['clawrock_debug']) {
20 | // Block is initialized by layout collector, messages can't be initialized
21 | // because there will be no messages during block rendering
22 | return;
23 | }
24 |
25 | $proceed($messageGroups);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Plugin/ProfileRepository/RequestTimePlugin.php:
--------------------------------------------------------------------------------
1 | getCollector(TimeCollector::NAME);
24 | } catch (\InvalidArgumentException $e) {
25 | return [$profile];
26 | }
27 |
28 | $profile->setRequestTime($timeCollector->getDuration());
29 |
30 | return [$profile];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Plugin/UseMagentoBackendThemeOnDebugFrontendViewPlugin.php:
--------------------------------------------------------------------------------
1 | design = $design;
16 | }
17 |
18 | public function beforeExecute(): void
19 | {
20 | $this->design->setArea(Area::AREA_ADMINHTML);
21 | $this->design->setDesignTheme('Magento/backend');
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | [](https://packagist.org/packages/clawrock/magento2-debug)
2 | [](https://packagist.org/packages/clawrock/magento2-debug)
3 | [](https://github.com/clawrock/magento2-debug/actions)
4 |
5 | # Magento 2 - Debug module
6 | Module for debugging Magento 2 performance. It works without overwriting any core files and it can be installed with composer.
7 |
8 | ## Installation
9 | 1. Enable developer mode `php bin/magento deploy:mode:set developer`
10 | 2. Install module via composer `composer require clawrock/magento2-debug`
11 | 3. Register module `php bin/magento setup:upgrade`
12 | 4. Enable profiler in configuration: `Stores -> Configuration -> Advanced -> Debug`
13 | 5. Enable DB profiler `php bin/magento debug:db-profiler:enable`
14 |
15 | ## Configuration
16 | All settings have only default scope and config type pool is set to environment for better integration with `php bin/magento app:config:dump`
17 |
18 | ## Compatibility
19 | * Magento >= 2.4.4
20 | * PHP 8.1, 8.2
21 |
22 | ## Profiler collectors
23 | - Ajax
24 | - Cache
25 | - Config
26 | - Customer
27 | - Database
28 | - Events
29 | - Layout
30 | - Memory
31 | - Models
32 | - Plugins
33 | - Request/Response
34 | - Performance
35 | - Translations
36 |
37 | ## Additional features
38 | - [Whoops error handler](http://filp.github.io/whoops/)
39 |
40 | ## Credits
41 | - [Magento 1.x Web Profiler](https://github.com/ecoco/magento_profiler)
42 | - [Symfony WebProfilerBundle](https://github.com/symfony/web-profiler-bundle)
43 |
--------------------------------------------------------------------------------
/Serializer/Serializer.php:
--------------------------------------------------------------------------------
1 | profilerWriterMock = $this->getMockBuilder(\ClawRock\Debug\Model\Config\Database\ProfilerWriter::class)
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 |
31 | $this->application = new Application();
32 | $this->commandObject = new DatabaseProfilerDisableCommand($this->profilerWriterMock);
33 | $this->application->add($this->commandObject);
34 | $this->command = $this->application->find('debug:db-profiler:disable');
35 | $this->commandTester = new CommandTester($this->command);
36 | }
37 |
38 | public function testExecute(): void
39 | {
40 | $this->profilerWriterMock->expects($this->once())->method('save')->with(false);
41 | $this->commandTester->execute(['command' => $this->command->getName()]);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Test/Unit/Console/Command/DatabaseProfilerEnableCommandTest.php:
--------------------------------------------------------------------------------
1 | profilerWriterMock = $this->getMockBuilder(\ClawRock\Debug\Model\Config\Database\ProfilerWriter::class)
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 |
31 | $this->application = new Application();
32 | $this->commandObject = new DatabaseProfilerEnableCommand($this->profilerWriterMock);
33 | $this->application->add($this->commandObject);
34 | $this->command = $this->application->find('debug:db-profiler:enable');
35 | $this->commandTester = new CommandTester($this->command);
36 | }
37 |
38 | public function testExecute(): void
39 | {
40 | $this->profilerWriterMock->expects($this->once())->method('save')->with(true);
41 | $this->commandTester->execute(['command' => $this->command->getName()]);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Cache/CacheControllerTestCase.php:
--------------------------------------------------------------------------------
1 | resultFactoryMock = $this->createMock(\Magento\Framework\Controller\ResultFactory::class);
22 | $this->resultMock = $this->createMock(\Magento\Framework\Controller\ResultInterface::class);
23 | $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class);
24 | $this->cacheManagerMock = $this->createMock(\Magento\Framework\App\Cache\Manager::class);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Cache/CleanTest.php:
--------------------------------------------------------------------------------
1 | controller = new Clean($this->resultFactoryMock, $this->requestMock, $this->cacheManagerMock);
17 | }
18 |
19 | public function testExecute(): void
20 | {
21 | $this->resultFactoryMock->expects($this->once())->method('create')
22 | ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
23 | ->willReturn($this->resultMock);
24 | $this->requestMock->expects($this->once())->method('getParam')
25 | ->with('type')
26 | ->willReturn(null);
27 | $this->cacheManagerMock->expects($this->once())->method('getAvailableTypes')
28 | ->willReturn(['cache_type_1', 'cache_type_2']);
29 | $this->cacheManagerMock->expects($this->once())->method('clean')->with(['cache_type_1', 'cache_type_2']);
30 |
31 | $this->assertInstanceOf(\Magento\Framework\Controller\ResultInterface::class, $this->controller->execute());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Cache/DisableTest.php:
--------------------------------------------------------------------------------
1 | controller = new Disable($this->resultFactoryMock, $this->requestMock, $this->cacheManagerMock);
17 | }
18 |
19 | public function testExecute(): void
20 | {
21 | $this->resultFactoryMock->expects($this->once())->method('create')
22 | ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
23 | ->willReturn($this->resultMock);
24 | $this->requestMock->expects($this->once())->method('getParam')->with('type')->willReturn('cache_type');
25 | $this->cacheManagerMock->expects($this->once())->method('setEnabled')->with(['cache_type'], false);
26 |
27 | $this->assertInstanceOf(\Magento\Framework\Controller\ResultInterface::class, $this->controller->execute());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Cache/EnableTest.php:
--------------------------------------------------------------------------------
1 | controller = new Enable($this->resultFactoryMock, $this->requestMock, $this->cacheManagerMock);
17 | }
18 |
19 | public function testExecute(): void
20 | {
21 | $this->resultFactoryMock->expects($this->once())->method('create')
22 | ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
23 | ->willReturn($this->resultMock);
24 | $this->requestMock->expects($this->once())->method('getParam')->with('type')->willReturn('cache_type');
25 | $this->cacheManagerMock->expects($this->once())->method('setEnabled')->with(['cache_type'], true);
26 |
27 | $this->assertInstanceOf(\Magento\Framework\Controller\ResultInterface::class, $this->controller->execute());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Cache/FlushTest.php:
--------------------------------------------------------------------------------
1 | controller = new Flush($this->resultFactoryMock, $this->requestMock, $this->cacheManagerMock);
17 | }
18 |
19 | public function testExecute(): void
20 | {
21 | $this->resultFactoryMock->expects($this->once())->method('create')
22 | ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
23 | ->willReturn($this->resultMock);
24 | $this->requestMock->expects($this->once())->method('getParam')
25 | ->with('type')
26 | ->willReturn(null);
27 | $this->cacheManagerMock->expects($this->once())->method('getAvailableTypes')
28 | ->willReturn(['cache_type1', 'cache_type2']);
29 | $this->cacheManagerMock->expects($this->once())->method('flush')
30 | ->with(['cache_type1', 'cache_type2']);
31 |
32 | $this->assertInstanceOf(\Magento\Framework\Controller\ResultInterface::class, $this->controller->execute());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Profiler/PHPInfoTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(ResultFactory::class)
17 | ->disableOriginalConstructor()
18 | ->getMock();
19 |
20 | $resultMock = $this->getMockBuilder(Raw::class)
21 | ->disableOriginalConstructor()
22 | ->getMock();
23 |
24 | $resultFactoryMock->expects($this->once())->method('create')
25 | ->with(ResultFactory::TYPE_RAW)
26 | ->willReturn($resultMock);
27 |
28 | $controller = new PHPInfo($resultFactoryMock);
29 |
30 | ob_start();
31 | $result = $controller->execute();
32 | ob_end_clean();
33 |
34 | $this->assertInstanceOf(ResultInterface::class, $result);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Test/Unit/Logger/DataLoggerTest.php:
--------------------------------------------------------------------------------
1 | loggableMock = $this->getMockForAbstractClass(LoggableInterface::class);
21 | $this->logger = new DataLogger();
22 | }
23 |
24 | public function testGetLogs(): void
25 | {
26 | $this->assertEquals([], $this->logger->getLogs());
27 | }
28 |
29 | public function testLog(): void
30 | {
31 | $this->loggableMock->expects($this->once())->method('getId')->willReturn('ID');
32 | $this->assertInstanceOf(DataLogger::class, $this->logger->log($this->loggableMock));
33 | $this->assertEquals(['ID' => $this->loggableMock], $this->logger->getLogs());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Storage/HttpStorageTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(\Magento\Framework\HTTP\PhpEnvironment\Request::class)
14 | ->disableOriginalConstructor()
15 | ->getMock();
16 |
17 | $responseMock = $this->getMockBuilder(\Magento\Framework\HTTP\PhpEnvironment\Response::class)
18 | ->disableOriginalConstructor()
19 | ->getMock();
20 |
21 | $storage = new HttpStorage();
22 | $storage->setRequest($requestMock);
23 | $storage->setResponse($responseMock);
24 | $this->assertFalse($storage->isFPCRequest());
25 | $this->assertTrue($storage->markAsFPCRequest()->isFPCRequest());
26 | $this->assertEquals($requestMock, $storage->getRequest());
27 | $this->assertEquals($responseMock, $storage->getResponse());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Storage/ProfileMemoryStorageTest.php:
--------------------------------------------------------------------------------
1 | getMockForAbstractClass(\ClawRock\Debug\Api\Data\ProfileInterface::class);
14 |
15 | $storage = new ProfileMemoryStorage();
16 | $storage->write($profileMock);
17 | $this->assertEquals($profileMock, $storage->read());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/CacheActionTest.php:
--------------------------------------------------------------------------------
1 | true,
18 | CacheAction::CACHE_TAGS => ['tag1', 'tag2'],
19 | CacheAction::CACHE_TTL => 3600,
20 | ];
21 | $cacheAction = new CacheAction($id, $name, $time, $info);
22 |
23 | $this->assertEquals($id, $cacheAction->getId());
24 | $this->assertEquals($name, $cacheAction->getName());
25 | $this->assertEquals($time, $cacheAction->getTime());
26 | $this->assertTrue($cacheAction->isHit());
27 | $this->assertTrue($cacheAction->isLoad());
28 | $this->assertEquals($info, $cacheAction->getInfo());
29 | $this->assertEquals($info[CacheAction::CACHE_TAGS], $cacheAction->getTags());
30 | $this->assertTrue($cacheAction->hasTags());
31 | $this->assertEquals($info[CacheAction::CACHE_TTL], $cacheAction->getTTL());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/EventObserverTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($name, $eventObserver->getName());
21 | $this->assertEquals($class, $eventObserver->getClass());
22 | $this->assertEquals($event, $eventObserver->getEvent());
23 | $this->assertEquals($time, $eventObserver->getTime());
24 | $this->assertStringStartsWith($name, $eventObserver->getId());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/LoopModelActionTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(\ClawRock\Debug\Model\ValueObject\ModelAction::class)
19 | ->disableOriginalConstructor()
20 | ->getMock();
21 |
22 | $modelActionMock->expects($this->once())->method('getName')->willReturn($name);
23 | $modelActionMock->expects($this->once())->method('getModel')->willReturn($model);
24 | $modelActionMock->expects($this->once())->method('getTrace')->willReturn($trace);
25 |
26 | $loopAction = new LoopModelAction($modelActionMock, $time, $count);
27 | $this->assertEquals($modelActionMock, $loopAction->getModelAction());
28 | $this->assertEquals($name, $loopAction->getName());
29 | $this->assertEquals($model, $loopAction->getModel());
30 | $this->assertEquals($trace, $loopAction->getTrace());
31 | $this->assertEquals($time, $loopAction->getTime());
32 | $this->assertEquals($count, $loopAction->getCount());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/ModelActionTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($name, $modelAction->getName());
20 | $this->assertEquals($model, $modelAction->getModel());
21 | $this->assertEquals($time, $modelAction->getTime());
22 | $this->assertEquals($trace, $modelAction->getTrace());
23 | $this->assertNotEmpty($modelAction->getTraceHash());
24 | $this->assertStringStartsWith($name, $modelAction->getId());
25 | $this->assertStringEndsWith($model, $modelAction->getId());
26 |
27 | $modelAction = new ModelAction($name, $model, $time, []);
28 | $this->assertEquals('', $modelAction->getTraceHash());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/PluginTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($class, $plugin->getClass());
22 | $this->assertEquals($name, $plugin->getName());
23 | $this->assertEquals($sortOrder, $plugin->getSortOrder());
24 | $this->assertEquals($method, $plugin->getMethod());
25 | $this->assertEquals($type, $plugin->getType());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Test/Unit/Model/ValueObject/TranslationTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($phrase, $object->getPhrase());
20 | $this->assertEquals($phrase, $object->getId());
21 | $this->assertEquals($translation, $object->getTranslation());
22 | $this->assertTrue($object->isDefined());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/Collector/LayoutCollectorBeforeToHtmlTest.php:
--------------------------------------------------------------------------------
1 | blockMock = $this->getMockBuilder(\Magento\Framework\View\Element\AbstractBlock::class)
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 |
23 | $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class)
24 | ->setMethods(['getBlock'])
25 | ->disableOriginalConstructor()
26 | ->getMock();
27 |
28 | $this->observer = new LayoutCollectorBeforeToHtml();
29 | }
30 |
31 | public function testExecute(): void
32 | {
33 | $this->observerMock->expects($this->once())->method('getBlock')->willReturn($this->blockMock);
34 | $this->blockMock->expects($this->exactly(2))->method('addData');
35 | $this->blockMock->expects($this->exactly(2))->method('getParentBlock')->willReturn($this->blockMock);
36 |
37 | $this->observer->execute($this->observerMock);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/ValidateRedirectTest.php:
--------------------------------------------------------------------------------
1 | sessionMock = $this->getMockBuilder(\ClawRock\Debug\Model\Session::class)
22 | ->setMethods(['getData'])
23 | ->disableOriginalConstructor()
24 | ->getMock();
25 |
26 | $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class)
27 | ->setMethods(['getRequest'])
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 |
31 | $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
32 | ->setMethods(['setParam'])
33 | ->getMockForAbstractClass();
34 |
35 | $this->observer = new ValidateRedirect($this->sessionMock);
36 | }
37 |
38 | public function testExecute(): void
39 | {
40 | $this->sessionMock->expects($this->once())->method('getData')->willReturn('1');
41 | $this->observerMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock);
42 | $this->requestMock->expects($this->once())->method('setParam');
43 |
44 | $this->observer->execute($this->observerMock);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Test/Unit/Plugin/Collector/TimeCollectorPluginTest.php:
--------------------------------------------------------------------------------
1 | createMock(\ClawRock\Debug\Model\Profiler\Driver\StopwatchDriver::class);
14 | $plugin = new TimeCollectorPlugin($stopwatchDriverMock);
15 | $plugin->beforeLaunch();
16 |
17 | $this->assertTrue(\Magento\Framework\Profiler::isEnabled());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Test/Unit/Plugin/Collector/TranslationCollectorPluginTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(\Magento\Framework\Phrase\Renderer\Translate::class)
14 | ->disableOriginalConstructor()
15 | ->getMock();
16 |
17 | $translateMock = $this->getMockForAbstractClass(\Magento\Framework\TranslateInterface::class);
18 |
19 | $translationCollectorMock = $this->getMockBuilder(\ClawRock\Debug\Model\Collector\TranslationCollector::class)
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 |
23 | $plugin = new TranslationCollectorPlugin($translateMock, $translationCollectorMock);
24 |
25 | $translateMock->expects($this->once())->method('getData')->willReturn(['text' => 'translation']);
26 |
27 | $source = ['text'];
28 | $args = [];
29 |
30 | $plugin->beforeRender($subjectMock, $source, $args);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Test/Unit/Plugin/PageCache/KernelPluginTest.php:
--------------------------------------------------------------------------------
1 | httpStorageMock = $this->getMockBuilder(\ClawRock\Debug\Model\Storage\HttpStorage::class)
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 |
23 | $this->subjectMock = $this->getMockBuilder(\Magento\Framework\App\PageCache\Kernel::class)
24 | ->disableOriginalConstructor()
25 | ->getMock();
26 |
27 | $this->plugin = new KernelPlugin($this->httpStorageMock);
28 | }
29 |
30 | public function testAfterLoad(): void
31 | {
32 | $this->httpStorageMock->expects($this->never())->method('markAsFPCRequest');
33 | $this->assertFalse($this->plugin->afterLoad($this->subjectMock, false));
34 | }
35 |
36 | public function testAfterLoadFPC(): void
37 | {
38 | $result = $this->createMock(\Magento\Framework\App\Response\Http::class);
39 | $this->httpStorageMock->expects($this->once())->method('markAsFPCRequest');
40 | $this->assertEquals($result, $this->plugin->afterLoad($this->subjectMock, $result));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Test/Unit/Serializer/SerializerTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($input, $serializer->unserialize($serializer->serialize($input)));
21 | }
22 |
23 | public function serializationProvider(): array
24 | {
25 | return [
26 | ['1', 2, 3],
27 | [new \stdClass()],
28 | ['
some html
'],
29 | [['foo' => 'bar', new \stdClass(), 'Hello', 'double' => 2.44]],
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clawrock/magento2-debug",
3 | "description": "Magento 2 debug module based on Magento 1 Profiler with some extra features.",
4 | "type": "magento2-module",
5 | "license": [
6 | "OSL-3.0",
7 | "AFL-3.0"
8 | ],
9 | "require": {
10 | "php": ">=8.1",
11 | "magento/framework": "~103.0",
12 | "magento/module-backend": "~102.0",
13 | "magento/module-developer": "^100.4",
14 | "filp/whoops": "^2.1",
15 | "jdorn/sql-formatter": "^1.2",
16 | "symfony/var-dumper": "*",
17 | "symfony/stopwatch": "^2.8 || ^3.0 || ^4.0 || ^5.0"
18 | },
19 | "require-dev": {
20 | "bitexpert/phpstan-magento": "^0.30.0",
21 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
22 | "magento/magento-coding-standard": "*",
23 | "phpcompatibility/php-compatibility": "^9.3",
24 | "phpmd/phpmd": "^2.9.1",
25 | "phpstan/phpstan": "~1.10.0",
26 | "phpunit/phpunit": "~9.5.0",
27 | "sebastian/phpcpd": "^6.0.3",
28 | "slevomat/coding-standard": "~6.4.1",
29 | "squizlabs/php_codesniffer": "~3.7.2",
30 | "phpstan/phpstan-phpunit": "^1.1.1"
31 | },
32 | "repositories": [
33 | {
34 | "type": "composer",
35 | "url": "https://repo.magento.com/"
36 | }
37 | ],
38 | "autoload": {
39 | "files": [
40 | "registration.php"
41 | ],
42 | "psr-4": {
43 | "ClawRock\\Debug\\": ""
44 | }
45 | },
46 | "config": {
47 | "allow-plugins": {
48 | "magento/composer-dependency-version-audit-plugin": true,
49 | "dealerdirect/phpcodesniffer-composer-installer": true
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/etc/adminhtml/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/etc/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/etc/frontend/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/etc/frontend/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 | Magento 2 Debug module ruleset
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | etc
17 | Test
18 | view
19 | vendor
20 |
21 |
--------------------------------------------------------------------------------
/phpstan.neon.dist:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 8
3 | checkMissingIterableValueType: false
4 | checkGenericClassInNonGenericObjectType: false
5 | excludePaths:
6 | - vendor/*
7 | paths:
8 | - .
9 | bootstrapFiles:
10 | - vendor/bitexpert/phpstan-magento/autoload.php
11 | includes:
12 | - vendor/bitexpert/phpstan-magento/extension.neon
13 | - vendor/phpstan/phpstan-phpunit/extension.neon
14 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Console
6 | Controller
7 | Helper
8 | Logger
9 | Model
10 | Observer
11 | Plugin
12 | Serializer
13 |
14 |
15 | Test
16 |
17 |
18 |
19 |
20 | Test/Unit
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_database.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_event.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_request.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_time.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_panel_translation.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 | ClawRock\Debug\Model\View\Profiler
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/view/base/layout/debug_profiler_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/view/base/layout/debug_profiler_search.xml:
--------------------------------------------------------------------------------
1 |
2 | >
4 |
5 |
6 |
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 | ClawRock\Debug\Model\View\Search
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/view/base/page_layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 | ClawRock\Debug\Model\View\Toolbar
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/view/base/templates/menu/cache.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 |
14 |
15 |
16 |
21 |
22 | = $escaper->escapeHtml(__('Cache')); ?>
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/menu/config.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 |
14 |
15 |
16 |
21 |
22 | = $escaper->escapeHtml(__('Config')); ?>
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/menu/database.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Database')); ?>
25 | getDuplicatedQueries())): ?>
26 |
27 | = count($collector->getDuplicatedQueries()) ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/view/base/templates/menu/event.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 |
14 |
15 |
16 |
21 |
22 | = $escaper->escapeHtml(__('Events')); ?>
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/menu/layout.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Layout')); ?>
25 | getNotRenderedBlocks())): ?>
26 |
27 | = count($collector->getNotRenderedBlocks()) ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/view/base/templates/menu/model.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Models')); ?>
25 | getLoopLoadMetric()): ?>
26 |
27 | = /* @noEscape */ $collector->getLoopLoadMetric() ?>
28 |
29 | getLoadMetric() && $collector->isThresholdExceeded()): ?>
30 |
31 | = /* @noEscape */ $collector->getLoadMetric() ?>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/view/base/templates/menu/plugin.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Plugins')); ?>
25 |
26 | = /* @noEscape */ $collector->getPluginsCount() ?>
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/view/base/templates/menu/request.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 |
14 |
15 |
16 |
21 |
22 | = $escaper->escapeHtml(__('Request / Response')); ?>
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/menu/settings.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 |
12 |
13 |
14 |
15 |
20 |
21 | = $escaper->escapeHtml(__('Settings')); ?>
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/menu/time.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Performance')); ?>
25 |
26 | = /* @noEscape */ $collector->getDuration() ?> ms
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/view/base/templates/menu/translation.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | isActive($block->getCollectorName())): ?>
12 |
13 | getCollector($block->getCollectorName()); ?>
14 |
15 |
16 |
17 |
18 |
23 |
24 | = $escaper->escapeHtml(__('Translation')); ?>
25 | getMissingTranslations())): ?>
26 |
27 | = count($collector->getMissingTranslations()) ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/view/base/templates/profiler.phtml:
--------------------------------------------------------------------------------
1 |
9 |
26 |
27 | = $block->getChildHtml('debug_profiler_summary'); ?>
28 |
29 |
30 |
31 |
32 |
33 | = $block->getChildHtml('debug_profiler_panel'); ?>
34 |
35 |
36 | = $block->getChildHtml('debug_profiler_sidebar'); ?>
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/view/base/templates/profiler/summary.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | ?>
11 | getProfile()): ?>
12 |
13 |
14 |
17 | hasRedirect()): ?>
18 | = /* @noEscape */ $viewModel->renderRedirect($profile->getRedirect()); ?>
19 |
20 |
21 | - = $escaper->escapeHtml(__('Method')) ?>
22 | - = /* @noEscape */ $profile->getMethod() ?>
23 | getRoute()): ?>
24 | - = $escaper->escapeHtml(__('Route')) ?>
25 | - @= /* @noEscape */ $profile->getRoute(); ?>
26 |
27 | - = $escaper->escapeHtml(__('HTTP Status')) ?>
28 | - = /* @noEscape */ $profile->getStatusCode() ?>
29 | - = $escaper->escapeHtml(__('IP')) ?>
30 | - = /* @noEscape */ $profile->getIp() ?>
31 | - = $escaper->escapeHtml(__('Profiled on')) ?>
32 | - = /* @noEscape */ $profile->getTime() ?>
33 | - = $escaper->escapeHtml(__('Token')) ?>
34 | - = /* @noEscape */ $profile->getToken(); ?>
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/layout/graph.phtml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | getNodes() as $node): ?>
11 | = /* @noEscape */ $block->getLayoutNodeRenderer()->create(['node' => $node])->render(); ?>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/layout/node.phtml:
--------------------------------------------------------------------------------
1 | getNode();
9 | ?>
10 |
11 | getParentId()): ?>
12 | getName()): ?>
13 | = /* @noEscape */ $node->getClass() ?> | = /* @noEscape */ $node->getTemplate() ?>
14 |
15 |
16 | = /* @noEscape */ $node->getName(); ?>
17 |
18 |
19 |
20 | = /* @noEscape */ $node->getPrefix() ?>└
21 | getTemplate()): ?>
22 |
23 | = /* @noEscape */ $node->getName() ?>
24 | = /* @noEscape */ $node->getClass() ?> | = /* @noEscape */ $node->getTemplate() ?>
25 |
26 |
27 |
28 | = /* @noEscape */ $node->getName() ?>
29 | = /* @noEscape */ $node->getClass() ?>
30 |
31 |
32 |
33 |
34 |
35 | = /* @noEscape */ $block->getFormatter()->microtime($node->getRenderTime()) ?> ms
36 | getParentId()): ?>
37 | (= /* @noEscape */ $block->getFormatter()->percentage($node->getRenderPercent()) ?>)
38 |
39 |
40 |
41 | getChildren() as $child): ?>
42 | = /* @noEscape */ $block->getLayoutNodeRenderer()->create(['node' => $child])->render(); ?>
43 |
44 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/parameters.phtml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 | = $escaper->escapeHtml(__('Key')); ?> |
13 | = $escaper->escapeHtml(__('Value')); ?> |
14 |
15 |
16 |
17 |
18 | getParameters()): ?>
19 | $value): ?>
20 |
21 | = /* @noEscape */ $key ?> |
22 | = /* @noEscape */ $block->getVarRenderer()->render($value); ?> |
23 |
24 |
25 |
26 |
27 | = $escaper->escapeHtml(__('No data')); ?> |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/query.phtml:
--------------------------------------------------------------------------------
1 | getQuery();
10 | ?>
11 | = /* @noEscape */ $block->getHighlightedQuery(); ?>
12 | getQueryParams())): ?>
13 |
14 | = $escaper->escapeHtml(__('Parameters')) ?>:
15 | = /* @noEscape */ $block->getVarRenderer()->render($query->getQueryParams()); ?>
16 |
17 |
18 |
30 |
31 | = /* @noEscape */ $block->getFormattedQuery(); ?>
32 |
33 |
34 | = /* @noEscape */ $block->getRunnableQuery(); ?>
35 |
36 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/query/list.phtml:
--------------------------------------------------------------------------------
1 | getPrefix();
9 | ?>
10 |
11 |
12 |
13 | # |
14 | = $escaper->escapeHtml(__('Time')) ?> |
15 | = $escaper->escapeHtml(__('Info')) ?> |
16 |
17 |
18 |
19 |
20 | getQueries() as $index => $query): ?>
21 |
22 | = /* @noEscape */ ++$index ?> |
23 |
24 | = /* @noEscape */ $block->getFormatter()->microtime($query->getElapsedSecs()); ?> ms
25 | |
26 | = /* @noEscape */ $block->getQueryRenderer()->create(['query' => $query])->render(); ?> |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/redirect.phtml:
--------------------------------------------------------------------------------
1 | getRedirect();
10 | ?>
11 |
12 | -
13 |
14 | = /* @noEscape */ $redirect->getStatusCode() ?>
15 |
16 | = $escaper->escapeHtml(__('Redirect from')) ?>
17 |
18 | -
19 | = /* @noEscape */ $redirect->getMethod() ?>
20 |
21 | = /* @noEscape */ $redirect->getToken() ?>
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/table.phtml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 | = $escaper->escapeHtml(__($block->getKeyLabel())); ?> |
13 | = $escaper->escapeHtml(__($block->getValueLabel())); ?> |
14 |
15 |
16 |
17 | getItems() as $key => $value): ?>
18 |
19 | = /* @noEscape */ $key ?> |
20 | = /* @noEscape */ $block->getVarRenderer()->render($value); ?> |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/trace.phtml:
--------------------------------------------------------------------------------
1 | getTrace();
9 | ?>
10 |
11 |
13 | = $escaper->escapeHtml(__('Show trace')) ?>
14 |
15 |
16 |
= $escaper->escapeHtml(__('Trace')) ?>:
17 |
18 |
19 | - = /* @noEscape */ $block->getTraceCallRenderer()->create(['call' => $call])->render(); ?>
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/view/base/templates/renderer/trace/call.phtml:
--------------------------------------------------------------------------------
1 |
8 |
9 | hasClass()): ?>
10 | = /* @noEscape */ $block->getClass() ?>
11 |
12 | hasClass() && $block->hasFunction()): ?>
13 | ::
14 |
15 | hasFunction()): ?>
16 | = /* @noEscape */ $block->getFunction() ?>
17 |
18 |
19 |
20 | hasLine()): ?>
21 | #= /* @noEscape */ $block->getLine() ?>
22 |
23 | hasFile()): ?>
24 | = /* @noEscape */ $block->getFile() ?>
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar.phtml:
--------------------------------------------------------------------------------
1 | getViewModel();
10 | $token = $viewModel->getToken();
11 | ?>
12 |
22 |
23 |
46 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/ajax.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
41 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/database.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
41 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/event.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
41 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/memory.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
37 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/plugin.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
40 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/time.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | $token = $block->getToken();
11 | ?>
12 |
32 |
--------------------------------------------------------------------------------
/view/base/templates/toolbar/translation.phtml:
--------------------------------------------------------------------------------
1 | getCollector();
10 | ?>
11 |
41 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/ajax.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/cache.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/config.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/customer.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/database.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/event.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/layout.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/logs.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/memory.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/model.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/models.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/plugin.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/redirect.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/time.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/view/base/web/images/collector/translation.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/close.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/menu.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/no.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/search.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/settings.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/view/base/web/images/icon/yes.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/view/base/web/images/magento.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------