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

DebugBar::setRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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