Completed
Pull Request — master (#44)
by Robbie
01:37
created

DebugBar::initDebugBar()   C

Complexity

Conditions 11
Paths 97

Size

Total Lines 72
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 72
rs 5.6331
c 0
b 0
f 0
cc 11
eloc 41
nc 97
nop 0

How to fix   Long Method    Complexity   

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
/**
4
 * A simple helper
5
 */
6
class DebugBar extends Object
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
7
{
8
9
    /**
10
     * @var DebugBar\StandardDebugBar
11
     */
12
    protected static $debugbar = null;
13
14
    /**
15
     *
16
     * @var bool
17
     */
18
    public static $bufferingEnabled = false;
19
20
    /**
21
     * @var DebugBar\JavascriptRenderer
22
     */
23
    protected static $renderer = null;
24
25
    /**
26
     *
27
     * @var bool
28
     */
29
    protected static $showQueries = false;
30
31
    /**
32
     * Get the Debug Bar instance
33
     * @return \DebugBar\StandardDebugBar
34
     * @throws Exception
35
     * @global array $databaseConfig
36
     */
37
    public static function getDebugBar()
38
    {
39
        if (self::$debugbar !== null) {
40
            return self::$debugbar;
41
        }
42
43
        if (!Director::isDev() || self::isDisabled() || self::vendorNotInstalled() ||
44
            self::notLocalIp() || Director::is_cli() || self::isDevUrl() ||
45
            (self::isAdminUrl() && !self::config()->enabled_in_admin)
46
        ) {
47
            self::$debugbar = false; // No need to check again
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object<DebugBar\StandardDebugBar> of property $debugbar.

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...
48
            return;
49
        }
50
51
        self::initDebugBar();
52
53
        if (!self::$debugbar) {
54
            throw new Exception("Failed to initialize the DebugBar");
55
        }
56
57
        return self::$debugbar;
58
    }
59
60
    /**
61
     * Init the debugbar instance
62
     *
63
     * @global array $databaseConfig
64
     * @return DebugBar\StandardDebugBar
65
     */
66
    public static function initDebugBar()
0 ignored issues
show
Coding Style introduced by
initDebugBar uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
67
    {
68
        // Prevent multiple inits
69
        if (self::$debugbar) {
70
            return self::$debugbar;
71
        }
72
73
        // Add the controller extension programmaticaly because it might not be added properly through yml
74
        Controller::add_extension('DebugBarControllerExtension');
75
76
        // Add a custom logger that logs everything under the Messages tab
77
        SS_Log::add_writer(new DebugBarLogWriter(), SS_Log::DEBUG, '<=');
78
79
        self::$debugbar = $debugbar = new DebugBar\DebugBar();
0 ignored issues
show
Documentation Bug introduced by
$debugbar = new \DebugBar\DebugBar() is of type object<DebugBar\DebugBar>, but the property $debugbar was declared to be of type object<DebugBar\StandardDebugBar>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
80
81
        if (isset($_REQUEST['showqueries'])) {
82
            self::setShowQueries(true);
83
            echo "The queries above have been run before we started DebugBar";
84
            echo '<hr>';
85
            unset($_REQUEST['showqueries']);
86
        }
87
88
        $debugbar->addCollector(new DebugBar\DataCollector\PhpInfoCollector());
89
        $debugbar->addCollector(new DebugBarTimeDataCollector());
90
        $debugbar->addCollector(new DebugBar\DataCollector\MemoryCollector());
91
92
        if (!DB::get_conn()) {
93
            global $databaseConfig;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
94
            if ($databaseConfig) {
95
                DB::connect($databaseConfig);
96
            }
97
        }
98
99
        $connector = DB::get_connector();
100
        if (!self::config()->force_proxy && $connector instanceof PDOConnector) {
101
            // Use a little bit of magic to replace the pdo instance
102
            $refObject = new ReflectionObject($connector);
103
            $refProperty = $refObject->getProperty('pdoConnection');
104
            $refProperty->setAccessible(true);
105
            $traceablePdo = new DebugBar\DataCollector\PDO\TraceablePDO($refProperty->getValue($connector));
106
            $refProperty->setValue($connector, $traceablePdo);
107
108
            $debugbar->addCollector(new DebugBar\DataCollector\PDO\PDOCollector($traceablePdo));
109
        } else {
110
            DB::set_conn($db = new DebugBarDatabaseNewProxy(DB::get_conn()));
0 ignored issues
show
Documentation introduced by
\DB::get_conn() is of type object<SS_Database>, but the function expects a object<MySQLDatabase>|array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
111
            $db->setShowQueries(self::getShowQueries());
112
            $debugbar->addCollector(new DebugBarDatabaseCollector($db));
113
        }
114
115
        // Add message collector last so other collectors can send messages to the console using it
116
        $debugbar->addCollector(new DebugBar\DataCollector\MessagesCollector());
117
118
        // Add some SilverStripe specific infos
119
        $debugbar->addCollector(new DebugBarSilverStripeCollector());
120
121
        if (self::config()->enable_storage) {
122
            $debugbar->setStorage(new DebugBar\Storage\FileStorage(TEMP_FOLDER . '/debugbar'));
123
        }
124
125
        // Since we buffer everything, why not enable all dev options ?
126
        if (self::config()->auto_debug) {
127
            $_REQUEST['debug'] = true;
128
            $_REQUEST['debug_request'] = true;
129
        }
130
131
        if (isset($_REQUEST['debug']) || isset($_REQUEST['debug_request'])) {
132
            self::$bufferingEnabled = true;
133
            ob_start(); // We buffer everything until we have called an action
134
        }
135
136
        return $debugbar;
137
    }
138
139
    public static function clearDebugBar()
140
    {
141
        self::$debugbar = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object<DebugBar\StandardDebugBar> of property $debugbar.

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...
142
    }
143
144
    public static function getShowQueries()
145
    {
146
        return self::$showQueries;
147
    }
148
149
    public static function setShowQueries($showQueries)
150
    {
151
        self::$showQueries = $showQueries;
152
    }
153
154
    public static function includeRequirements()
155
    {
156
        $debugbar = self::getDebugBar();
157
158
        if (!$debugbar) {
159
            return;
160
        }
161
162
        // Already called
163
        if (self::$renderer) {
164
            return;
165
        }
166
167
        $renderer = $debugbar->getJavascriptRenderer();
168
169
        // We don't need the true path since we are going to use Requirements API that appends the BASE_PATH
170
        $renderer->setBasePath(DEBUGBAR_DIR . '/assets');
171
        $renderer->setBaseUrl(DEBUGBAR_DIR . '/assets');
172
173
        $includeJquery = self::config()->include_jquery;
174
        // In CMS, jQuery is already included
175
        if (self::isAdminController()) {
176
            $includeJquery = false;
177
        }
178
        // If jQuery is already included, set to false
179
        $js = Requirements::backend()->get_javascript();
180
        foreach ($js as $url) {
181
            $name = basename($url);
182
            if ($name == 'jquery.js' || $name == 'jquery.min.js') {
183
                $includeJquery = false;
184
                break;
185
            }
186
        }
187
188
        if ($includeJquery) {
189
            $renderer->setEnableJqueryNoConflict(true);
190
        } else {
191
            $renderer->disableVendor('jquery');
192
            $renderer->setEnableJqueryNoConflict(false);
193
        }
194
195
        if (DebugBar::config()->enable_storage) {
196
            $renderer->setOpenHandlerUrl('__debugbar');
197
        }
198
199
        foreach ($renderer->getAssets('css') as $cssFile) {
200
            Requirements::css(ltrim($cssFile, '/'));
201
        }
202
203
        foreach ($renderer->getAssets('js') as $jsFile) {
204
            Requirements::javascript(ltrim($jsFile, '/'));
205
        }
206
207
        self::$renderer = $renderer;
208
    }
209
210
    public static function renderDebugBar()
211
    {
212
        if (!self::$renderer) {
213
            return;
214
        }
215
216
        // Requirements may have been cleared (CMS iframes...) or not set (Security...)
217
        $js = Requirements::backend()->get_javascript();
218
        if (!in_array('debugbar/assets/debugbar.js', $js)) {
219
            return;
220
        }
221
        $initialize = true;
222
        if (Director::is_ajax()) {
223
            $initialize = false;
224
        }
225
226
        $script = self::$renderer->render($initialize);
227
        return $script;
228
    }
229
230
    /**
231
     * Determine why DebugBar is disabled
232
     *
233
     * @return string
234
     */
235
    public static function whyDisabled()
236
    {
237
        if (!Director::isDev()) {
238
            return 'Not in dev mode';
239
        }
240
        if (self::isDisabled()) {
241
            return 'Disabled by a constant or configuration';
242
        }
243
        if (self::vendorNotInstalled()) {
244
            return 'DebugBar is not installed in vendors';
245
        }
246
        if (self::notLocalIp()) {
247
            return 'Not a local ip';
248
        }
249
        if (Director::is_cli()) {
250
            return 'In CLI mode';
251
        }
252
        if (self::isDevUrl()) {
253
            return 'Dev tools';
254
        }
255
        if (self::isAdminUrl() && !self::config()->enabled_in_admin) {
256
            return 'In admin';
257
        }
258
        return "I don't know why";
259
    }
260
261
    public static function vendorNotInstalled()
262
    {
263
        return !class_exists('DebugBar\\StandardDebugBar');
264
    }
265
266
    public static function notLocalIp()
0 ignored issues
show
Coding Style introduced by
notLocalIp uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
267
    {
268
        if (!self::config()->check_local_ip) {
269
            return false;
270
        }
271
        if (isset($_SERVER['REMOTE_ADDR'])) {
272
            return !in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1', '1'));
273
        }
274
        return false;
275
    }
276
277
    public static function isDisabled()
278
    {
279
        if ((defined('DEBUGBAR_DISABLE') && DEBUGBAR_DISABLE) || static::config()->disabled) {
280
            return true;
281
        }
282
        return false;
283
    }
284
285
    public static function isDevUrl()
286
    {
287
        return strpos(self::getRequestUrl(), '/dev/') === 0;
288
    }
289
290
    public static function isAdminUrl()
291
    {
292
        return strpos(self::getRequestUrl(), '/admin/') === 0;
293
    }
294
295
    public static function isAdminController()
296
    {
297
        if (Controller::curr()) {
298
            return Controller::curr() instanceof LeftAndMain;
299
        }
300
        return self::isAdminUrl();
301
    }
302
303
    /**
304
     * Avoid triggering data collection for open handler
305
     *
306
     * @return boolean
307
     */
308
    public static function isDebugBarRequest()
309
    {
310
        if ($url = self::getRequestUrl()) {
311
            return strpos($url, '/__debugbar') === 0;
312
        }
313
        return true;
314
    }
315
316
    /**
317
     * Get request url
318
     *
319
     * @return string
320
     */
321
    public static function getRequestUrl()
0 ignored issues
show
Coding Style introduced by
getRequestUrl uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getRequestUrl uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
322
    {
323
        if (isset($_REQUEST['url'])) {
324
            return $_REQUEST['url'];
325
        }
326
        if (isset($_SERVER['REQUEST_URI'])) {
327
            return $_SERVER['REQUEST_URI'];
328
        }
329
        return '';
330
    }
331
332
    /**
333
     * Helper to make code cleaner
334
     *
335
     * @param callable $callback
336
     */
337
    public static function withDebugBar($callback)
338
    {
339
        if (self::getDebugBar() && !self::isDebugBarRequest()) {
340
            $callback(self::getDebugBar());
341
        }
342
    }
343
}
344