Completed
Pull Request — master (#60)
by Robbie
01:36
created

DebugBar::includeRequirements()   C

Complexity

Conditions 11
Paths 98

Size

Total Lines 55
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 55
rs 6.6153
c 0
b 0
f 0
cc 11
eloc 30
nc 98
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
namespace LeKoala\DebugBar;
4
5
use DebugBar\Bridge\MonologCollector;
6
use DebugBar\DebugBar as BaseDebugBar;
7
use DebugBar\DataCollector\MemoryCollector;
8
use DebugBar\DataCollector\PDO\PDOCollector;
9
use DebugBar\DataCollector\PDO\TraceablePDO;
10
use DebugBar\DataCollector\PhpInfoCollector;
11
use DebugBar\Storage\FileStorage;
12
use Exception;
13
use LeKoala\DebugBar\Collector\ConfigCollector;
14
use LeKoala\DebugBar\Collector\DatabaseCollector;
15
use LeKoala\DebugBar\Collector\SilverStripeCollector;
16
use LeKoala\DebugBar\Collector\TimeDataCollector;
17
use LeKoala\DebugBar\Messages\LogFormatter;
18
use LeKoala\DebugBar\Proxy\ConfigManifestProxy;
19
use LeKoala\DebugBar\Proxy\DatabaseProxy;
20
use Psr\Log\LoggerInterface;
21
use Monolog\Logger;
22
use ReflectionObject;
23
use SilverStripe\Admin\LeftAndMain;
24
use SilverStripe\Config\Collections\CachedConfigCollection;
25
use SilverStripe\Control\Director;
26
use SilverStripe\Control\HTTPRequest;
27
use SilverStripe\Core\Config\Configurable;
28
use SilverStripe\Core\Injector\Injectable;
29
use SilverStripe\Core\Injector\Injector;
30
use SilverStripe\Core\Kernel;
31
use SilverStripe\ORM\Connect\PDOConnector;
32
use SilverStripe\ORM\DB;
33
use SilverStripe\View\Requirements;
34
35
/**
36
 * A simple helper
37
 */
38
class DebugBar
39
{
40
    use Configurable;
41
    use Injectable;
42
43
    /**
44
     * @var DebugBar\DebugBar
45
     */
46
    protected static $debugbar;
47
48
    /**
49
     * @var bool
50
     */
51
    public static $bufferingEnabled = false;
52
53
    /**
54
     * @var DebugBar\JavascriptRenderer
55
     */
56
    protected static $renderer;
57
58
    /**
59
     * @var bool
60
     */
61
    protected static $showQueries = false;
62
63
    /**
64
     * @var HTTPRequest
65
     */
66
    protected static $request;
67
68
    /**
69
     * Get the Debug Bar instance
70
     * @return \DebugBar\StandardDebugBar
71
     * @throws Exception
72
     * @global array $databaseConfig
73
     */
74
    public static function getDebugBar()
75
    {
76
        if (self::$debugbar !== null) {
77
            return self::$debugbar;
78
        }
79
80
        if (!Director::isDev() || self::isDisabled() || self::vendorNotInstalled() ||
81
            self::notLocalIp() || Director::is_cli() || self::isDevUrl() ||
82
            (self::isAdminUrl() && !self::config()->enabled_in_admin)
83
        ) {
84
            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<LeKoala\DebugBar\DebugBar\DebugBar> 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...
85
            return;
86
        }
87
88
        self::initDebugBar();
89
90
        if (!self::$debugbar) {
91
            throw new Exception("Failed to initialize the DebugBar");
92
        }
93
94
        return self::$debugbar;
95
    }
96
97
    /**
98
     * Init the debugbar instance
99
     *
100
     * @global array $databaseConfig
101
     * @return DebugBar\StandardDebugBar
102
     */
103
    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...
104
    {
105
        // Prevent multiple inits
106
        if (self::$debugbar) {
107
            return self::$debugbar;
108
        }
109
110
        self::$debugbar = $debugbar = new BaseDebugBar;
0 ignored issues
show
Documentation Bug introduced by
It seems like $debugbar = new \DebugBar\DebugBar() of type object<DebugBar\DebugBar> is incompatible with the declared type object<LeKoala\DebugBar\DebugBar\DebugBar> 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...
111
112
        if (isset($_REQUEST['showqueries'])) {
113
            self::setShowQueries(true);
114
            echo "The queries above have been run before we started DebugBar";
115
            echo '<hr>';
116
            unset($_REQUEST['showqueries']);
117
        }
118
119
        $debugbar->addCollector(new PhpInfoCollector);
120
        $debugbar->addCollector(new TimeDataCollector);
121
        $debugbar->addCollector(new MemoryCollector);
122
123
        // Add config proxy replacing the core config manifest
124
        /** @var SilverStripe\Core\Config\ConfigLoader $configLoader */
125
        $configLoader = Injector::inst()->get(Kernel::class)->getConfigLoader();
126
        $configManifest = false;
127
        while ($configLoader->hasManifest()) {
128
            $eachManifest = $configLoader->popManifest();
129
            if ($eachManifest instanceof CachedConfigCollection) {
130
                $configManifest = $eachManifest;
131
                break;
132
            }
133
        }
134
        if ($configManifest) {
135
            $configProxy = new ConfigManifestProxy($configManifest);
136
            $configLoader->pushManifest($configProxy);
137
        }
138
139
        $connector = DB::get_connector();
140
        if (!self::config()->force_proxy && $connector instanceof PDOConnector) {
141
            // Use a little bit of magic to replace the pdo instance
142
            $refObject = new ReflectionObject($connector);
143
            $refProperty = $refObject->getProperty('pdoConnection');
144
            $refProperty->setAccessible(true);
145
            $traceablePdo = new TraceablePDO($refProperty->getValue($connector));
146
            $refProperty->setValue($connector, $traceablePdo);
147
148
            $debugbar->addCollector(new PDOCollector($traceablePdo));
149
        } else {
150
            DB::set_conn($db = new DatabaseProxy(DB::get_conn()));
151
            $db->setShowQueries(self::getShowQueries());
152
            $debugbar->addCollector(new DatabaseCollector);
153
        }
154
155
        // Add message collector last so other collectors can send messages to the console using it
156
        $logger = Injector::inst()->get(LoggerInterface::class);
157
        $logCollector = new MonologCollector($logger, Logger::DEBUG, true, 'messages');
158
        $logCollector->setFormatter(new LogFormatter);
159
160
        $debugbar->addCollector($logCollector);
161
162
        // Add some SilverStripe specific infos
163
        $debugbar->addCollector(new SilverStripeCollector);
164
165
        if (self::config()->enable_storage) {
166
            $debugbar->setStorage(new FileStorage(TEMP_FOLDER . '/debugbar'));
167
        }
168
169
        if ($configManifest) {
170
            // Add the config collector
171
            $debugbar->addCollector(new ConfigCollector);
172
        }
173
174
        // Since we buffer everything, why not enable all dev options ?
175
        if (self::config()->auto_debug) {
176
            $_REQUEST['debug'] = true;
177
            $_REQUEST['debug_request'] = true;
178
        }
179
180
        if (isset($_REQUEST['debug']) || isset($_REQUEST['debug_request'])) {
181
            self::$bufferingEnabled = true;
182
            ob_start(); // We buffer everything until we have called an action
183
        }
184
185
        return $debugbar;
186
    }
187
188
    public static function clearDebugBar()
189
    {
190
        self::$debugbar = null;
191
    }
192
193
    public static function getShowQueries()
194
    {
195
        return self::$showQueries;
196
    }
197
198
    public static function setShowQueries($showQueries)
199
    {
200
        self::$showQueries = $showQueries;
201
    }
202
203
    public static function includeRequirements()
204
    {
205
        $debugbar = self::getDebugBar();
206
207
        if (!$debugbar) {
208
            return;
209
        }
210
211
        // Already called
212
        if (self::$renderer) {
213
            return;
214
        }
215
216
        $renderer = $debugbar->getJavascriptRenderer();
217
218
        // We don't need the true path since we are going to use Requirements API that appends the BASE_PATH
219
        $renderer->setBasePath(DEBUGBAR_DIR . '/assets');
220
        $renderer->setBaseUrl(DEBUGBAR_DIR . '/assets');
221
222
        $includeJquery = self::config()->include_jquery;
223
        // In CMS, jQuery is already included
224
        if (self::isAdminController()) {
225
            $includeJquery = false;
226
        }
227
        // If jQuery is already included, set to false
228
        $js = Requirements::backend()->getJavascript();
229
        foreach ($js as $url => $args) {
230
            $name = basename($url);
231
            if ($name == 'jquery.js' || $name == 'jquery.min.js') {
232
                $includeJquery = false;
233
                break;
234
            }
235
        }
236
237
        if ($includeJquery) {
238
            $renderer->setEnableJqueryNoConflict(true);
239
        } else {
240
            $renderer->disableVendor('jquery');
241
            $renderer->setEnableJqueryNoConflict(false);
242
        }
243
244
        if (DebugBar::config()->enable_storage) {
245
            $renderer->setOpenHandlerUrl('__debugbar');
246
        }
247
248
        foreach ($renderer->getAssets('css') as $cssFile) {
249
            Requirements::css(ltrim($cssFile, '/'));
250
        }
251
252
        foreach ($renderer->getAssets('js') as $jsFile) {
253
            Requirements::javascript(ltrim($jsFile, '/'));
254
        }
255
256
        self::$renderer = $renderer;
257
    }
258
259
    public static function renderDebugBar()
260
    {
261
        if (!self::$renderer) {
262
            return;
263
        }
264
265
        // Requirements may have been cleared (CMS iframes...) or not set (Security...)
266
        $js = Requirements::backend()->getJavascript();
267
        if (!array_key_exists('debugbar/assets/debugbar.js', $js)) {
268
            return;
269
        }
270
        $initialize = true;
271
        if (Director::is_ajax()) {
272
            $initialize = false;
273
        }
274
275
        $script = self::$renderer->render($initialize);
276
        return $script;
277
    }
278
279
    /**
280
     * Determine why DebugBar is disabled
281
     *
282
     * @return string
283
     */
284
    public static function whyDisabled()
285
    {
286
        if (!Director::isDev()) {
287
            return 'Not in dev mode';
288
        }
289
        if (self::isDisabled()) {
290
            return 'Disabled by a constant or configuration';
291
        }
292
        if (self::vendorNotInstalled()) {
293
            return 'DebugBar is not installed in vendors';
294
        }
295
        if (self::notLocalIp()) {
296
            return 'Not a local ip';
297
        }
298
        if (Director::is_cli()) {
299
            return 'In CLI mode';
300
        }
301
        if (self::isDevUrl()) {
302
            return 'Dev tools';
303
        }
304
        if (self::isAdminUrl() && !self::config()->enabled_in_admin) {
305
            return 'In admin';
306
        }
307
        return "I don't know why";
308
    }
309
310
    public static function vendorNotInstalled()
311
    {
312
        return !class_exists('DebugBar\\StandardDebugBar');
313
    }
314
315
    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...
316
    {
317
        if (!self::config()->check_local_ip) {
318
            return false;
319
        }
320
        if (isset($_SERVER['REMOTE_ADDR'])) {
321
            return !in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1', '1'));
322
        }
323
        return false;
324
    }
325
326
    public static function isDisabled()
327
    {
328
        if (getenv('DEBUGBAR_DISABLE') || static::config()->disabled) {
329
            return true;
330
        }
331
        return false;
332
    }
333
334
    public static function isDevUrl()
335
    {
336
        return strpos(self::getRequestUrl(), '/dev/') === 0;
337
    }
338
339
    public static function isAdminUrl()
340
    {
341
        return strpos(self::getRequestUrl(), '/admin/') === 0;
342
    }
343
344
    public static function isAdminController()
345
    {
346
        if (Controller::curr()) {
347
            return Controller::curr() instanceof LeftAndMain;
348
        }
349
        return self::isAdminUrl();
350
    }
351
352
    /**
353
     * Avoid triggering data collection for open handler
354
     *
355
     * @return boolean
356
     */
357
    public static function isDebugBarRequest()
358
    {
359
        if ($url = self::getRequestUrl()) {
360
            return strpos($url, '/__debugbar') === 0;
361
        }
362
        return true;
363
    }
364
365
    /**
366
     * Get request url
367
     *
368
     * @return string
369
     */
370
    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...
371
    {
372
        if (isset($_REQUEST['url'])) {
373
            return $_REQUEST['url'];
374
        }
375
        if (isset($_SERVER['REQUEST_URI'])) {
376
            return $_SERVER['REQUEST_URI'];
377
        }
378
        return '';
379
    }
380
381
    /**
382
     * Helper to make code cleaner
383
     *
384
     * @param callable $callback
385
     */
386
    public static function withDebugBar($callback)
387
    {
388
        if (self::getDebugBar() && !self::isDebugBarRequest()) {
389
            $callback(self::getDebugBar());
390
        }
391
    }
392
393
    /**
394
     * Set the current request. Is provided by the DebugBarMiddleware.
395
     *
396
     * @param HTTPRequest $request
397
     */
398
    public static function setRequest(HTTPRequest $request)
399
    {
400
        self::$request = $request;
401
    }
402
403
    /**
404
     * Get the current request
405
     *
406
     * @return HTTPRequest
407
     */
408
    public static function getRequest()
409
    {
410
        if (self::$request) {
411
            return self::$request;
412
        }
413
        // Fall back to trying from the global state
414
        if (Controller::has_curr()) {
415
            return Controller::curr()->getRequest();
416
        }
417
    }
418
}
419