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

DatabaseCollector::collectData()   C

Complexity

Conditions 8
Paths 11

Size

Total Lines 69
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 69
rs 6.5437
c 0
b 0
f 0
cc 8
eloc 47
nc 11
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, LeKoala\DebugBar\Collector\TimeDataCollector.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
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('monolog')
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