Completed
Pull Request — master (#47)
by Robbie
01:27
created

DatabaseCollector   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 166
Duplicated Lines 5.42 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 7
dl 9
loc 166
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A collect() 0 23 3
A explodeFields() 0 4 1
C collectData() 0 69 8
A getName() 0 4 1
A getWidgets() 0 15 1
A getAssets() 9 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace LeKoala\DebugBar\Collector;
4
5
use DebugBar\DataCollector\AssetProvider;
6
use DebugBar\DataCollector\DataCollector;
7
use DebugBar\DataCollector\Renderable;
8
use DebugBar\DataCollector\TimeDataCollector as BaseTimeDataCollector;
9
use LeKoala\DebugBar\DebugBar;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\ORM\DB;
12
13
/**
14
 * Collects data about SQL statements executed through the DatabaseProxy
15
 */
16
class DatabaseCollector extends DataCollector implements Renderable, AssetProvider
17
{
18
    /**
19
     * @var TimeDataCollector
20
     */
21
    protected $timeCollector;
22
23
    /**
24
     * @var SS_Database
25
     */
26
    protected $db;
27
28
    /**
29
     * @return array
30
     */
31
    public function collect()
32
    {
33
        // Gather the database connector at the last minute in case it has been replaced by other modules
34
        $this->db = DB::get_conn();
0 ignored issues
show
Documentation Bug introduced by
It seems like \SilverStripe\ORM\DB::get_conn() of type object<SilverStripe\ORM\Connect\Database> is incompatible with the declared type object<LeKoala\DebugBar\Collector\SS_Database> of property $db.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
35
        $this->timeCollector = DebugBar::getDebugBar()->getCollector('time');
36
37
        $data = $this->collectData($this->timeCollector);
38
39
        // Check for excessive number of queries
40
        $dbQueryWarningLevel = DebugBar::config()->warn_query_limit;
41
        if ($dbQueryWarningLevel && $data['nb_statements'] > $dbQueryWarningLevel) {
42
            DebugBar::getDebugBar()
43
                ->getCollector('messages')
44
                ->addMessage(
45
                    'This page ran more than ' . $dbQueryWarningLevel . ' database queries. You could reduce this by '
46
                    . 'implementing caching. For more information, <a href="https://docs.silverstripe.org/en/'
47
                    . 'developer_guides/performance/" target="_blank">click here.</a>',
48
                    'warning'
49
                );
50
        }
51
52
        return $data;
53
    }
54
55
    /**
56
     * Explode comma separated elements not within parenthesis or quotes
57
     *
58
     * @param string $str
59
     * @return array
60
     */
61
    protected static function explodeFields($str)
62
    {
63
        return preg_split("/(?![^(]*\)),/", $str);
64
    }
65
66
    /**
67
     * Collects data
68
     *
69
     * @param TimeDataCollector $timeCollector
70
     * @return array
71
     */
72
    protected function collectData(TimeDataCollector $timeCollector = null)
73
    {
74
        $stmts = array();
75
76
        $total_duration = 0;
77
        $total_mem      = 0;
78
79
        $failed = 0;
80
81
        $i       = 0;
82
        $queries = $this->db->getQueries();
83
84
        $limit   = DebugBar::config()->query_limit;
85
        $warnDurationThreshold = Config::inst()->get(DebugBar::class, 'warn_dbqueries_threshold_seconds');
86
87
        $showDb = count(array_unique(array_map(function ($stmt) {
88
                return $stmt['database'];
89
        }, $queries))) > 1;
90
91
        foreach ($queries as $stmt) {
92
            $i++;
93
94
            $total_duration += $stmt['duration'];
95
            $total_mem += $stmt['memory'];
96
97
            if (!$stmt['success']) {
98
                $failed++;
99
            }
100
101
            if ($limit && $i > $limit) {
102
                $stmts[] = array(
103
                    'sql' => "Only the first $limit queries are shown"
104
                );
105
                break;
106
            }
107
108
            $stmts[] = array(
109
                'sql' => $stmt['short_query'],
110
                'row_count' => $stmt['rows'],
111
                'params' => $stmt['select'] ? $stmt['select'] : null,
112
                'duration' => $stmt['duration'],
113
                'duration_str' => $this->getDataFormatter()->formatDuration($stmt['duration']),
114
                'memory' => $stmt['memory'],
115
                'memory_str' => $this->getDataFormatter()->formatBytes($stmt['memory']),
116
                'is_success' => $stmt['success'],
117
                'database' => $showDb ? $stmt['database'] : null,
118
                'source' => $stmt['source'],
119
                'warn' => $stmt['duration'] > $warnDurationThreshold
120
            );
121
122
            if ($timeCollector !== null) {
123
                $timeCollector->addMeasure(
124
                    $stmt['short_query'],
125
                    $stmt['start_time'],
126
                    $stmt['end_time']
127
                );
128
            }
129
        }
130
131
        return array(
132
            'nb_statements' => count($queries),
133
            'nb_failed_statements' => $failed,
134
            'statements' => $stmts,
135
            'accumulated_duration' => $total_duration,
136
            'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($total_duration),
137
            'memory_usage' => $total_mem,
138
            'memory_usage_str' => $this->getDataFormatter()->formatBytes($total_mem),
139
        );
140
    }
141
142
    /**
143
     * @return string
144
     */
145
    public function getName()
146
    {
147
        return 'db';
148
    }
149
150
    /**
151
     * @return array
152
     */
153
    public function getWidgets()
154
    {
155
        return array(
156
            "database" => array(
157
                "icon" => "inbox",
158
                "widget" => "PhpDebugBar.Widgets.SQLQueriesWidget",
159
                "map" => "db",
160
                "default" => "[]"
161
            ),
162
            "database:badge" => array(
163
                "map" => "db.nb_statements",
164
                "default" => 0
165
            )
166
        );
167
    }
168
169
    /**
170
     * @return array
171
     */
172 View Code Duplication
    public function getAssets()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
    {
174
        return array(
175
            'base_path' => '/' . DEBUGBAR_DIR . '/javascript',
176
            'base_url' => DEBUGBAR_DIR.'/javascript',
177
            'css' => 'sqlqueries/widget.css',
178
            'js' => 'sqlqueries/widget.js'
179
        );
180
    }
181
}
182