DebugBarMiddleware::afterRequest()   F
last analyzed

Complexity

Conditions 22
Paths 141

Size

Total Lines 97
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 0 Features 3
Metric Value
cc 22
eloc 53
c 9
b 0
f 3
nc 141
nop 2
dl 0
loc 97
rs 3.825

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\Middleware;
4
5
use LeKoala\DebugBar\DebugBar;
6
use LeKoala\DebugBar\Extension\ControllerExtension;
7
use SilverStripe\Control\Middleware\HTTPMiddleware;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Control\HTTPRequest;
10
use SilverStripe\Control\HTTPResponse;
11
use SilverStripe\View\Requirements;
12
13
class DebugBarMiddleware implements HTTPMiddleware
14
{
15
    public function process(HTTPRequest $request, callable $delegate)
16
    {
17
        $this->beforeRequest($request);
18
        $response = $delegate($request);
19
        if ($response) {
20
            $this->afterRequest($request, $response);
21
        }
22
        return $response;
23
    }
24
25
    /**
26
     * Track the start up of the framework boot
27
     *
28
     * @param HTTPRequest $request
29
     * @return void
30
     */
31
    protected function beforeRequest(HTTPRequest $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

31
    protected function beforeRequest(/** @scrutinizer ignore-unused */ HTTPRequest $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
32
    {
33
        DebugBar::withDebugBar(function (\DebugBar\DebugBar $debugbar) {
34
            /** @var \DebugBar\DataCollector\TimeDataCollector|null $timeData */
35
            $timeData = $debugbar->getCollector('time');
36
37
            if (!$timeData) {
0 ignored issues
show
introduced by
$timeData is of type DebugBar\DataCollector\TimeDataCollector, thus it always evaluated to true.
Loading history...
38
                return;
39
            }
40
41
            // Allows a more realistic view
42
            // Define FRAMEWORK_BOOT_TIME in your index.php after composer autoload
43
            if (defined('FRAMEWORK_BOOT_TIME')) {
44
                if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
45
                    $timeData = $debugbar['time'];
46
                    $timeData->addMeasure(
0 ignored issues
show
Bug introduced by
The method addMeasure() does not exist on DebugBar\DataCollector\DataCollectorInterface. It seems like you code against a sub-type of DebugBar\DataCollector\DataCollectorInterface such as DebugBar\DataCollector\TimeDataCollector. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
                    $timeData->/** @scrutinizer ignore-call */ 
47
                               addMeasure(
Loading history...
47
                        'php boot',
48
                        $_SERVER['REQUEST_TIME_FLOAT'],
49
                        constant('FRAMEWORK_BOOT_TIME')
50
                    );
51
                    $timeData->addMeasure(
52
                        'framework boot',
53
                        constant('FRAMEWORK_BOOT_TIME'),
54
                        microtime(true)
55
                    );
56
                } else {
57
                    $timeData = $debugbar['time'];
58
                    $timeData->addMeasure(
59
                        'framework boot',
60
                        constant('FRAMEWORK_BOOT_TIME'),
61
                        microtime(true)
62
                    );
63
                }
64
            } elseif (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
65
                $timeData = $debugbar['time'];
66
                $timeData->addMeasure(
67
                    'framework boot',
68
                    $_SERVER['REQUEST_TIME_FLOAT'],
69
                    microtime(true)
70
                );
71
            }
72
73
            DebugBar::closeExtraTime();
74
            $timeData->startMeasure('pre_request', 'pre request');
0 ignored issues
show
Bug introduced by
The method startMeasure() does not exist on DebugBar\DataCollector\DataCollectorInterface. It seems like you code against a sub-type of DebugBar\DataCollector\DataCollectorInterface such as DebugBar\DataCollector\TimeDataCollector. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
            $timeData->/** @scrutinizer ignore-call */ 
75
                       startMeasure('pre_request', 'pre request');
Loading history...
75
        });
76
    }
77
78
    /**
79
     * Inject DebugBar requirements for the frontend
80
     *
81
     * @param HTTPRequest  $request
82
     * @param HTTPResponse $response
83
     * @return void
84
     */
85
    protected function afterRequest(HTTPRequest $request, HTTPResponse $response)
86
    {
87
        $debugbar = DebugBar::getDebugBar();
88
        if (!$debugbar) {
0 ignored issues
show
introduced by
$debugbar is of type DebugBar\DebugBar, thus it always evaluated to true.
Loading history...
89
            return;
90
        }
91
92
        // Should not alter xml or json, only html
93
        $contentType = $response->getHeader('Content-Type');
94
        if (!str_contains($contentType, 'text/html')) {
95
            // We need to strip <link> and <script> tags added to the body
96
            // Calling DebugBar::excludeRequirements(); won't work since the response is already generated
97
            $body = (string)$response->getBody();
98
            if (str_contains($body, '/debugbar/')) {
99
                $regex = '/^[ \t]*<(?:link|script)[^>]*?debugbar[^>]*?>(?:.*?<\/script>)?.*(?:\r?\n)?/mi';
100
                $cleanedBody = preg_replace($regex, '', $body);
101
                $response->setBody($cleanedBody);
102
            }
103
            return;
104
        }
105
106
        // Don't apply to assets
107
        $dir = defined('ASSETS_DIR') ? ASSETS_DIR : 'assets';
108
        if (strpos($request->getURL(), "$dir/") === 0) {
109
            return;
110
        }
111
112
        DebugBar::setRequest($request);
113
114
        // All queries have been displayed
115
        if (DebugBar::getShowQueries()) {
116
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
117
        }
118
        $script = DebugBar::renderDebugBar();
119
120
        // If the bar is not renderable, return early
121
        if (!$script) {
122
            return;
123
        }
124
125
        // Use module to make sure it's deferred and does not cause side effects
126
        $script = str_replace('<script type="text/javascript">', '<script type="module">', $script);
127
128
        // Inject init script into the HTML response
129
        $body = (string)$response->getBody();
130
131
        if (strpos($body, '</body>') !== false) {
132
            $customScripts = '';
133
            if (DebugBar::$suppressJquery) {
134
                // Move scripts after the latest script
135
                $matches = [];
136
                preg_match_all('/<script(.*) src="(.*)\/debugbar\/(.*)"><\/script>/', $body, $matches);
137
                $body = preg_replace('/<script(.*) src="(.*)\/debugbar\/(.*)"><\/script>\n/', '', $body);
138
                $customScripts = implode("\n", $matches[0]);
139
            }
140
141
            $scriptsToInsert = $customScripts . "\n" . $script;
142
            // You can use a placeholder if somehow you have a </body> string somewhere else in the body
143
            // @link https://github.com/lekoala/silverstripe-debugbar/issues/154
144
            $debugbarPlaceholder = "<!-- debugbar -->";
145
            if (strpos((string) $body, $debugbarPlaceholder) !== false) {
146
                $body = str_replace($debugbarPlaceholder, $scriptsToInsert, $body);
147
            } else {
148
                if (Requirements::get_write_js_to_body()) {
149
                    // Replace the last occurence of </body>
150
                    $pos = strrpos((string) $body, '</body>');
151
                    if ($pos !== false) {
152
                        $body = substr_replace($body, $scriptsToInsert . '</body>', $pos, strlen('</body>'));
153
                    }
154
                } else {
155
                    // Replace the first occurence of </head>
156
                    $pos = strpos((string) $body, '</head>');
157
                    if ($pos !== false) {
158
                        $body = substr_replace($body, $scriptsToInsert . '</head>', $pos, strlen('</head>'));
159
                    }
160
                }
161
            }
162
            $response->setBody($body);
0 ignored issues
show
Bug introduced by
It seems like $body can also be of type array; however, parameter $body of SilverStripe\Control\HTTPResponse::setBody() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
            $response->setBody(/** @scrutinizer ignore-type */ $body);
Loading history...
163
        }
164
165
        // Ajax support
166
        if (Director::is_ajax() && !headers_sent()) {
167
            if (DebugBar::isAdminUrl() && !DebugBar::config()->get('enabled_in_admin')) {
168
                return;
169
            }
170
            // Skip anything that is not a GET request
171
            if (!$request->isGET()) {
172
                return;
173
            }
174
            // Always enable in admin because everything is mostly loaded through ajax
175
            if (DebugBar::config()->get('ajax') || DebugBar::isAdminUrl()) {
176
                $headers = $debugbar->getDataAsHeaders();
177
178
                // Prevent throwing js errors in case header size is too large
179
                if (is_array($headers)) {
0 ignored issues
show
introduced by
The condition is_array($headers) is always true.
Loading history...
180
                    $maxHeaderLength = DebugBar::config()->get('max_header_length');
181
                    $debugbar->sendDataInHeaders(null, 'phpdebugbar', $maxHeaderLength);
182
                }
183
            }
184
        }
185
    }
186
}
187