GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

YiiDebugToolbarPanelSql   F
last analyzed

Complexity

Total Complexity 68

Size/Duplication

Total Lines 438
Duplicated Lines 5.02 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 0
Metric Value
dl 22
loc 438
rs 2.96
c 0
b 0
f 0
wmc 68
lcom 2
cbo 3

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 2
A getCountLimit() 0 4 1
A setCountLimit() 0 4 1
A getTimeLimit() 0 4 1
A setTimeLimit() 0 4 1
A getDbConnectionsCount() 0 8 2
A getDbConnections() 0 16 5
A getMenuTitle() 0 4 1
A getMenuSubTitle() 0 9 2
A getTitle() 0 9 2
A getSubTitle() 0 6 2
A init() 0 4 1
A run() 0 16 2
A duration() 0 21 4
B getServerInfo() 0 26 7
B processCallstack() 0 49 9
B processSummary() 10 55 10
B formatLogEntry() 0 39 6
A getTextHighlighter() 0 12 2
A aggregateResult() 0 22 3
A filterLogs() 12 12 4

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like YiiDebugToolbarPanelSql often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use YiiDebugToolbarPanelSql, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * YiiDebugToolbarPanelSql class file.
4
 *
5
 * @author Sergey Malyshev <[email protected]>
6
 */
7
8
9
/**
10
 * YiiDebugToolbarPanelSql class.
11
 *
12
 * Description of YiiDebugToolbarPanelSql
13
 *
14
 * @author Sergey Malyshev <[email protected]>
15
 * @author Igor Golovanov <[email protected]>
16
 * @package YiiDebugToolbar
17
 * @since 1.1.7
18
 */
19
class YiiDebugToolbarPanelSql extends YiiDebugToolbarPanel
20
{
21
    /**
22
     * If true, the sql query in the list will use syntax highlighting.
23
     * 
24
     * @var boolean
25
     */
26
    public $highlightSql = true;
27
28
    private $_countLimit = 1;
29
30
    private $_timeLimit = 0.01;
31
32
    private $_groupByToken = true;
33
34
    private $_dbConnections;
35
36
    private $_dbConnectionsCount;
37
38
    private $_textHighlighter;
39
40
    public function  __construct($owner = null)
41
    {
42
        parent::__construct($owner);
43
44
        try
45
        {
46
            Yii::app()->db;
47
        }
48
        catch (Exception $e)
49
        {
50
            $this->_dbConnections = false;
51
        }
52
    }
53
54
    public function getCountLimit()
55
    {
56
        return $this->_countLimit;
57
    }
58
59
    public function setCountLimit($value)
60
    {
61
        $this->_countLimit = CPropertyValue::ensureInteger($value);
62
    }
63
64
    public function getTimeLimit()
65
    {
66
        return $this->_timeLimit;
67
    }
68
69
    public function setTimeLimit($value)
70
    {
71
        $this->_timeLimit = CPropertyValue::ensureFloat($value);
72
    }
73
74
    public function getDbConnectionsCount()
75
    {
76
        if (null === $this->_dbConnectionsCount)
77
        {
78
            $this->_dbConnectionsCount = count($this->getDbConnections());
79
        }
80
        return $this->_dbConnectionsCount;
81
    }
82
83
    public function getDbConnections()
84
    {
85
        if (null === $this->_dbConnections)
86
        {
87
            $this->_dbConnections = array();
88
            foreach (Yii::app()->components as $id=>$component)
89
            {
90
                if (false !== is_object($component)
91
                        && false !== ($component instanceof CDbConnection))
0 ignored issues
show
Bug introduced by
The class CDbConnection does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
92
                {
93
                    $this->_dbConnections[$id] = $component;
94
                }
95
            }
96
        }
97
        return $this->_dbConnections;
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function getMenuTitle()
104
    {
105
        return YiiDebug::t('SQL');
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function getMenuSubTitle($f=4)
112
    {
113
        if (false !== $this->_dbConnections)
114
        {
115
            $st = Yii::app()->db->getStats();
116
            return YiiDebug::t('{n} query in {s} s.|{n} queries in {s} s.', array($st[0], '{s}'=>vsprintf('%0.'.$f.'F', $st[1])));
117
        }
118
        return YiiDebug::t('No active connections');
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function getTitle()
125
    {
126
        if (false !== $this->_dbConnections)
127
        {
128
            $conn=$this->getDbConnectionsCount();
129
            return YiiDebug::t('SQL Queries from {n} connection|SQL Queries from {n} connections', array($conn));
130
        }
131
        return YiiDebug::t('No active connections');
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function getSubTitle()
138
    {
139
        return  false !== $this->_dbConnections
140
                ?  ('(' . self::getMenuSubTitle(6) . ')')
141
                : null;
142
    }
143
144
    /**
145
     * Initialize panel
146
     */
147
    public function init()
148
    {
149
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function run()
156
    {
157
        if (false === $this->_dbConnections)
158
        {
159
            return;
160
        }
161
162
        $logs = $this->filterLogs();
163
164
        $this->render('sql', array(
165
            'connections'       => $this->getDbConnections(),
166
            'connectionsCount'  => $this->getDbConnectionsCount(),
167
            'summary'           => $this->processSummary($logs),
168
            'callstack'         => $this->processCallstack($logs)
169
        ));
170
    }
171
172
    private function duration($secs)
173
    {
174
        $vals = array(
175
            'w' => (int) ($secs / 86400 / 7),
176
            'd' => $secs / 86400 % 7,
177
            'h' => $secs / 3600 % 24,
178
            'm' => $secs / 60 % 60,
179
            's' => $secs % 60
180
        );
181
        $result = array();
182
        $added = false;
183
        foreach ($vals as $k => $v)
184
        {
185
            if ($v > 0 || false !== $added)
186
            {
187
                $added = true;
188
                $result[] = $v . $k;
189
            }
190
        }
191
        return implode(' ', $result);
192
    }
193
194
    /**
195
     * Returns the DB server info by connection ID.
196
     * @param string $connectionId
197
     * @return mixed
198
     */
199
    public function getServerInfo($connectionId)
200
    {
201
        if (null !== ($connection = Yii::app()->getComponent($connectionId))
202
            && false !== ($connection instanceof CDbConnection)
0 ignored issues
show
Bug introduced by
The class CDbConnection does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
203
            && !in_array($connection->driverName, array('sqlite', 'oci', 'dblib'))
204
            && '' !== ($serverInfo = $connection->getServerInfo()))
205
        {
206
            $info = array(
207
                YiiDebug::t('Driver') => $connection->getDriverName(),
208
                YiiDebug::t('Server Version') => $connection->getServerVersion()
209
            );
210
            
211
            $lines = explode('  ', $serverInfo);
212
            foreach($lines as $line) {
213
                list($key, $value) = explode(': ', $line, 2);
214
                $info[YiiDebug::t($key)] = $value;
215
            }
216
            
217
            if(!empty($info[YiiDebug::t('Uptime')])) {
218
                $info[YiiDebug::t('Uptime')] = $this->duration($info[YiiDebug::t('Uptime')]);
219
            }
220
            
221
            return $info;
222
        }
223
        return null;
224
    }
225
226
    /**
227
     * Processing callstack.
228
     *
229
     * @param array $logs Logs.
230
     * @return array
231
     */
232
    protected function processCallstack(array $logs)
233
    {
234
        if (empty($logs))
235
        {
236
            return $logs;
237
        }
238
239
        $stack   = array();
240
        $results = array();
241
        $n       = 0;
242
243
        foreach ($logs as $log)
244
        {
245
            if(CLogger::LEVEL_PROFILE !== $log[1])
246
                continue;
247
248
            $message = $log[0];
249
250
            if (0 === strncasecmp($message,'begin:',6))
251
            {
252
                $log[0]  = substr($message,6);
253
                $log[4]  = $n;
254
                $stack[] = $log;
255
                $n++;
256
            }
257
            else if (0 === strncasecmp($message, 'end:', 4))
258
            {
259
                $token = substr($message,4);
260
                if(null !== ($last = array_pop($stack)) && $last[0] === $token)
261
                {
262
                    $delta = $log[3] - $last[3];
263
                    $results[$last[4]] = array($token, $delta, count($stack));
264
                }
265
                else
266
                    throw new CException(Yii::t('yii-debug-toolbar',
267
                            'Mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
268
                            array('{token}' => $token)
269
                        ));
270
            }
271
        }
272
        // remaining entries should be closed here
273
        $now = microtime(true);
274
        while (null !== ($last = array_pop($stack))){
275
            $results[$last[4]] = array($last[0], $now - $last[3], count($stack));
276
        }
277
278
        ksort($results);
279
        return  array_map(array($this, 'formatLogEntry'), $results);
280
    }
281
282
    /**
283
     * Processing summary.
284
     *
285
     * @param array $logs Logs.
286
     * @return array
287
     */
288
    protected function processSummary(array $logs)
289
    {
290
        if (empty($logs))
291
        {
292
            return $logs;
293
        }
294
        $stack = array();
295
        foreach($logs as $log)
296
        {
297
            $message = $log[0];
298
            if(0 === strncasecmp($message, 'begin:', 6))
299
            {
300
                $log[0]  =substr($message, 6);
301
                $stack[] =$log;
302
            }
303
            else if(0 === strncasecmp($message,'end:',4))
304
            {
305
                $token = substr($message,4);
306
                if(null !== ($last = array_pop($stack)) && $last[0] === $token)
307
                {
308
                    $delta = $log[3] - $last[3];
309
310 View Code Duplication
                    if(isset($results[$token]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
311
                        $results[$token] = $this->aggregateResult($results[$token], $delta);
312
                    else{
313
                        $results[$token] = array($token, 1, $delta, $delta, $delta);
0 ignored issues
show
Bug introduced by
The variable $results does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
314
                    }
315
                }
316
                else
317
                    throw new CException(Yii::t('yii-debug-toolbar',
318
                        'Mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
319
                        array('{token}' => $token)));
320
            }
321
        }
322
323
        $now = microtime(true);
324
        while(null !== ($last = array_pop($stack)))
325
        {
326
            $delta = $now - $last[3];
327
            $token = $last[0];
328
329 View Code Duplication
            if(isset($results[$token]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
330
                $results[$token] = $this->aggregateResult($results[$token], $delta);
331
            else{
332
                $results[$token] = array($token, 1, $delta, $delta, $delta);
333
            }
334
        }
335
336
        $entries = array_values($results);
337
        $func    = create_function('$a,$b','return $a[4]<$b[4]?1:0;');
338
339
        usort($entries, $func);
340
341
        return array_map(array($this, 'formatLogEntry'), $entries);
342
    }
343
344
    /**
345
     * Format log entry
346
     *
347
     * @param array $entry
348
     * @return array
349
     */
350
    public function formatLogEntry(array $entry)
351
    {
352
        // extract query from the entry
353
        $queryString = $entry[0];
354
        $sqlStart = strpos($queryString, '(') + 1;
355
        $sqlEnd = strrpos($queryString , ')');
356
        $sqlLength = $sqlEnd - $sqlStart;
357
        
358
        $queryString = substr($queryString, $sqlStart, $sqlLength);
359
360
        if (false !== strpos($queryString, '. Bound with '))
361
        {
362
            list($query, $params) = explode('. Bound with ', $queryString);
363
364
	        $binds  = array();
365
	        $matchResult = preg_match_all("/(?<key>[a-z0-9\.\_\-\:]+)=(?<value>[\d\.e\-\+]+|''|'.+?(?<!\\\)')/ims", $params, $paramsMatched, PREG_SET_ORDER);
366
367
            if ($matchResult) {
368
                foreach ($paramsMatched as $paramsMatch)
369
	                if (isset($paramsMatch['key'], $paramsMatch['value']))
370
                        $binds[trim($paramsMatch['key'])] = trim($paramsMatch['value']);
371
            }
372
373
374
            $entry[0] = strtr($query, $binds);
375
        }
376
        else
377
        {
378
            $entry[0] = $queryString;
379
        }
380
381
        if(false !== CPropertyValue::ensureBoolean($this->highlightSql))
382
        {
383
            $entry[0] = $this->getTextHighlighter()->highlight($entry[0]);
384
        }
385
386
        $entry[0] = strip_tags($entry[0], '<div>,<span>');
387
        return $entry;
388
    }
389
390
391
    /**
392
     * @return CTextHighlighter the text highlighter
393
     */
394
    private function getTextHighlighter()
395
    {
396
        if (null === $this->_textHighlighter)
397
        {
398
            $this->_textHighlighter = Yii::createComponent(array(
399
                'class' => 'CTextHighlighter',
400
                'language' => 'sql',
401
                'showLineNumbers' => false,
402
            ));
403
        }
404
        return $this->_textHighlighter;
405
    }
406
407
408
    /**
409
     * Aggregates the report result.
410
     *
411
     * @param array $result log result for this code block
412
     * @param float $delta time spent for this code block
413
     * @return array
414
     */
415
    protected function aggregateResult($result, $delta)
416
    {
417
        list($token, $calls, $min, $max, $total) = $result;
418
419
        switch (true)
420
        {
421
            case ($delta < $min):
422
                $min = $delta;
423
                break;
424
            case ($delta > $max):
425
                $max = $delta;
426
                break;
427
            default:
428
                // nothing
429
                break;
430
        }
431
432
        $calls++;
433
        $total += $delta;
434
435
        return array($token, $calls, $min, $max, $total);
436
    }
437
438
    /**
439
     * Get filter logs.
440
     *
441
     * @return array
442
     */
443 View Code Duplication
    protected function filterLogs()
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...
444
    {
445
        $logs = array();
446
        foreach ($this->owner->getLogs() as $entry)
447
        {
448
            if (CLogger::LEVEL_PROFILE === $entry[1] && 0 === strpos($entry[2], 'system.db.CDbCommand'))
449
            {
450
                $logs[] = $entry;
451
            }
452
        }
453
        return $logs;
454
    }
455
456
}
457