Passed
Push — master ( c78459...485dda )
by Thomas
02:41
created

code/Collector/DatabaseCollector.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace LeKoala\DebugBar\Collector;
4
5
use LeKoala\DebugBar\DebugBar;
6
use SilverStripe\Control\Director;
7
use DebugBar\DataCollector\Renderable;
8
use DebugBar\DataCollector\AssetProvider;
9
use DebugBar\DataCollector\DataCollector;
10
use LeKoala\DebugBar\Extension\ProxyDBExtension;
11
12
/**
13
 * Collects data about SQL statements executed through the proxied behaviour
14
 */
15
class DatabaseCollector extends DataCollector implements Renderable, AssetProvider
16
{
17
    /**
18
     * @var TimeDataCollector
19
     */
20
    protected $timeCollector;
21
22
    /**
23
     * @return array
24
     */
25
    public function collect()
26
    {
27
        $this->timeCollector = DebugBar::getDebugBar()->getCollector('time');
28
29
        $data = $this->collectData($this->timeCollector);
30
31
        // Check for excessive number of queries
32
        $dbQueryWarningLevel = DebugBar::config()->get('warn_query_limit');
33
        if ($dbQueryWarningLevel && $data['nb_statements'] > $dbQueryWarningLevel) {
34
            $helpLink = DebugBar::config()->get('performance_guide_link');
35
            $messages = DebugBar::getDebugBar()->getCollector('messages');
36
            $messages->addMessage(
0 ignored issues
show
The method addMessage() does not exist on DebugBar\DataCollector\DataCollectorInterface. It seems like you code against a sub-type of DebugBar\DataCollector\DataCollectorInterface such as DebugBar\DataCollector\MessagesCollector. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

36
            $messages->/** @scrutinizer ignore-call */ 
37
                       addMessage(
Loading history...
37
                "This page ran more than $dbQueryWarningLevel database queries." .
38
                    "\nYou could reduce this by implementing caching." .
39
                    "\nYou can find more info here: $helpLink",
40
                'warning',
41
                true
42
            );
43
        }
44
45
        return $data;
46
    }
47
48
    /**
49
     * Explode comma separated elements not within parenthesis or quotes
50
     *
51
     * @param string $str
52
     * @return array
53
     */
54
    protected static function explodeFields($str)
55
    {
56
        return preg_split("/(?![^(]*\)),/", $str);
57
    }
58
59
    /**
60
     * Collects data
61
     *
62
     * @param TimeDataCollector $timeCollector
63
     * @return array
64
     */
65
    protected function collectData(TimeDataCollector $timeCollector = null)
66
    {
67
        $stmts = array();
68
69
        $total_duration = 0;
70
        $total_mem      = 0;
71
72
        $failed = 0;
73
74
        $i       = 0;
75
76
        // Get queries gathered by proxy
77
        $queries = ProxyDBExtension::getQueries();
78
79
        $limit   = DebugBar::config()->get('query_limit');
80
        $warnDurationThreshold = DebugBar::config()->get('warn_dbqueries_threshold_seconds');
81
82
        $showDb = count(array_unique(array_map(function ($stmt) {
83
            return $stmt['database'];
84
        }, $queries))) > 1;
85
86
        foreach ($queries as $stmt) {
87
            $i++;
88
89
            $total_duration += $stmt['duration'];
90
            $total_mem += $stmt['memory'];
91
92
            if (!$stmt['success']) {
93
                $failed++;
94
            }
95
96
            if ($limit && $i > $limit) {
97
                $stmts[] = array(
98
                    'sql' => "Only the first $limit queries are shown"
99
                );
100
                break;
101
            }
102
103
            $stmts[] = array(
104
                'sql' => $stmt['short_query'],
105
                'row_count' => $stmt['rows'],
106
                'params' => $stmt['select'] ? $stmt['select'] : null,
107
                'duration' => $stmt['duration'],
108
                'duration_str' => $this->getDataFormatter()->formatDuration($stmt['duration']),
109
                'memory' => $stmt['memory'],
110
                'memory_str' => $this->getDataFormatter()->formatBytes($stmt['memory']),
111
                'is_success' => $stmt['success'],
112
                'database' => $showDb ? $stmt['database'] : null,
113
                'source' => $stmt['source'],
114
                'warn' => $stmt['duration'] > $warnDurationThreshold
115
            );
116
117
            if ($timeCollector !== null) {
118
                $timeCollector->addMeasure(
119
                    $stmt['short_query'],
120
                    $stmt['start_time'],
121
                    $stmt['end_time']
122
                );
123
            }
124
        }
125
126
        return array(
127
            'nb_statements' => count($queries),
128
            'nb_failed_statements' => $failed,
129
            'statements' => $stmts,
130
            'accumulated_duration' => $total_duration,
131
            'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($total_duration),
132
            'memory_usage' => $total_mem,
133
            'memory_usage_str' => $this->getDataFormatter()->formatBytes($total_mem),
134
        );
135
    }
136
137
    /**
138
     * @return string
139
     */
140
    public function getName()
141
    {
142
        return 'db';
143
    }
144
145
    /**
146
     * @return array
147
     */
148
    public function getWidgets()
149
    {
150
        return array(
151
            "database" => array(
152
                "icon" => "database",
153
                "widget" => "PhpDebugBar.Widgets.SQLQueriesWidget",
154
                "map" => "db",
155
                "default" => "[]"
156
            ),
157
            "database:badge" => array(
158
                "map" => "db.nb_statements",
159
                "default" => 0
160
            )
161
        );
162
    }
163
164
    /**
165
     * @return array
166
     */
167
    public function getAssets()
168
    {
169
        return array(
170
            'base_path' => '/' . DebugBar::moduleResource('javascript')->getRelativePath(),
171
            'base_url' => Director::makeRelative(DebugBar::moduleResource('javascript')->getURL()),
172
            'css' => 'sqlqueries/widget.css',
173
            'js' => 'sqlqueries/widget.js'
174
        );
175
    }
176
}
177