QueryInformation.php 4.44 KB
Newer Older
1
<?php
2

3
declare(strict_types=1);
4
5
6
7
8
9
10
11
12
13
14
15
16
17

/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

18
19
namespace TYPO3\CMS\Adminpanel\Modules\Debug;

20
use Psr\Http\Message\ServerRequestInterface;
21
use TYPO3\CMS\Adminpanel\Log\DoctrineSqlLogger;
22
23
24
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
25
26
27
28
29
30
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;

/**
 * Admin Panel Query Information module for showing SQL Queries
31
32
 *
 * @internal
33
 */
34
class QueryInformation extends AbstractSubModule implements DataProviderInterface
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
{
    /**
     * Identifier for this Sub-module,
     * for example "preview" or "cache"
     *
     * @return string
     */
    public function getIdentifier(): string
    {
        return 'debug_queryinformation';
    }

    /**
     * Sub-Module label
     *
     * @return string
     */
    public function getLabel(): string
    {
        return $this->getLanguageService()->sL(
            'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.queryInformation.label'
        );
    }

    /**
60
61
     * @param ServerRequestInterface $request
     * @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData
62
63
     * @throws \Doctrine\DBAL\DBALException
     */
64
    public function getDataToStore(ServerRequestInterface $request): ModuleData
65
66
67
68
    {
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
        $connection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
        $logger = $connection->getConfiguration()->getSQLLogger();
69
        $data = [];
70
71
        if ($logger instanceof DoctrineSqlLogger) {
            $queries = $logger->getQueries();
72
73
            $data['queries'] = $this->groupQueries($queries) ?? [];
            $data['totalTime'] = array_sum(array_column($queries, 'executionMS')) * 1000;
74
        }
75
76
77
78
79
80
81
82
83
84
85
        return new ModuleData($data);
    }

    /**
     * @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
     * @return string Returns content of admin panel
     */
    public function getContent(ModuleData $data): string
    {
        $view = new StandaloneView();
        $view->setTemplatePathAndFilename(
86
            'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/QueryInformation.html'
87
88
89
        );
        $this->getLanguageService()->includeLLFile('EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf');
        $view->assignMultiple($data->getArrayCopy());
90
91
92
93
94
95
96
97
98
99
100
        return $view->render();
    }

    /**
     * @param array $queries
     * @return array
     */
    protected function groupQueries(array $queries): array
    {
        $groupedQueries = [];
        foreach ($queries as $query) {
101
102
103
104
105
106
            $backtraceString = json_encode($query['backtrace']);
            if ($backtraceString === false) {
                // skip entry if it can't be encoded
                continue;
            }
            $identifier = sha1($query['sql']) . sha1($backtraceString);
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
            if (is_array($query['params'])) {
                foreach ($query['params'] as $k => $param) {
                    if (is_array($param)) {
                        $query['params'][$k] = implode(',', $param);
                    }
                }
            }
            if (isset($groupedQueries[$identifier])) {
                $groupedQueries[$identifier]['count']++;
                $groupedQueries[$identifier]['time'] += ($query['executionMS'] * 1000);
                $groupedQueries[$identifier]['queries'][] = $query;
            } else {
                $groupedQueries[$identifier] = [
                    'sql' => $query['sql'],
                    'time' => $query['executionMS'] * 1000,
                    'count' => 1,
                    'queries' => [
                        $query,
                    ],
                ];
            }
        }
        uasort(
            $groupedQueries,
131
            static function ($a, $b) {
132
133
134
135
136
137
                return $b['time'] <=> $a['time'];
            }
        );
        return $groupedQueries;
    }
}