Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
DeveloperToolbar
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
3 / 3
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getRouters
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
8
 getPostProcessors
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace Miniframe\Toolbar\Middleware;
4
5use Miniframe\Toolbar\Service\DeveloperToolbar as DeveloperToolbarService;
6use Miniframe\Toolbar\Controller\DeveloperToolbar as DeveloperToolbarController;
7use Miniframe\Toolbar\Response\DeveloperToolbar as DeveloperToolbarResponse;
8use Miniframe\Core\AbstractMiddleware;
9use Miniframe\Core\Config;
10use Miniframe\Core\Registry;
11use Miniframe\Core\Request;
12use Miniframe\Core\Response;
13
14class DeveloperToolbar extends AbstractMiddleware
15{
16    /**
17     * Reference to the Developer Toolbar service
18     *
19     * @var DeveloperToolbarService
20     */
21    protected $developerToolbar;
22
23    /**
24     * Prefix URL for the developer toolbar
25     *
26     * @var string
27     */
28    protected $debugPrefixUrl;
29
30    /**
31     * Initiates the Developer Toolbar middleware; binding to the framework and starting the service.
32     *
33     * @param Request $request Reference to the Request object.
34     * @param Config  $config  Reference to the Config object.
35     */
36    public function __construct(Request $request, Config $config)
37    {
38        if (!$config->has('developer-toolbar', 'log_path')) {
39            throw new \RuntimeException('No log path configured for the developer toolbar');
40        }
41
42        // Creates and registers the Developer Toolbar service
43        $this->developerToolbar = new DeveloperToolbarService(
44            $request,
45            $config->getPath('developer-toolbar', 'log_path')
46        );
47        Registry::register(DeveloperToolbarService::class, $this->developerToolbar);
48
49        // Generates the URL
50        $this->debugPrefixUrl = $config->get('framework', 'base_href') . '_DEBUG';
51
52        parent::__construct($request, $config);
53    }
54
55    /**
56     * Adds the Developer Toolbar routes
57     *
58     * @return array
59     */
60    public function getRouters(): array
61    {
62        return [function (): ?callable {
63            $comparePath = explode('/', trim($this->debugPrefixUrl, '/'));
64            foreach ($comparePath as $index => $path) {
65                if ($this->request->getPath($index) != $path) {
66                    return null;
67                }
68            }
69
70            // Is the hash valid?
71            $hash = $this->request->getPath(count($comparePath));
72            if ($hash === 'bugicon.svg') {
73                $this->developerToolbar->setDisabled(true);
74                return [new DeveloperToolbarController($this->request, $this->config), 'bugicon'];
75            }
76            if (!preg_match('/^[a-zA-Z0-9_\-.]+$/', $hash)) {
77                return null;
78            }
79            $requestData = $this->developerToolbar->getDataByHash($hash);
80            if ($requestData === null) {
81                return null;
82            }
83
84            // Is the subcommand valid?
85            $subCommand = $this->request->getPath(count($comparePath) + 1);
86            if ($subCommand && !method_exists(DeveloperToolbarController::class, $subCommand)) {
87                return null;
88            }
89
90            $this->developerToolbar->setDisabled(true);
91            return [new DeveloperToolbarController($this->request, $this->config, $requestData), $subCommand ?? 'view'];
92        }];
93    }
94
95    /**
96     * Modifies output to append the Developer Toolbar URL in headers and HTML pages
97     *
98     * @todo Modify HTML pages
99     *
100     * @return array
101     */
102    public function getPostProcessors(): array
103    {
104        return [function (Response $response, bool $thrown): Response {
105            // When disabled, return actual response
106            if ($this->developerToolbar->isDisabled()) {
107                return $response;
108            }
109
110            // Make the URL absolute
111            $hostPrefix = 'http';
112            if ($this->request->isHttpsRequest()) {
113                $hostPrefix .= 's';
114            }
115            $hostPrefix .= '://' . $this->request->getServer('HTTP_HOST');
116
117            // Combine all URL parts
118            $debugUrl = $hostPrefix . $this->debugPrefixUrl . '/' . $this->developerToolbar->getRequestHash();
119
120            $response->addHeader('X-Debug-URL: ' . $debugUrl);
121            $this->developerToolbar->addData('responseHeaders', $response->getHeaders());
122            $this->developerToolbar->addData('responseCode', $response->getResponseCode());
123            $this->developerToolbar->addData('responseType', get_class($response));
124            $this->developerToolbar->addData('exitCode', $response->getExitCode());
125
126            // Add exception data
127            $exception = $response->getPrevious() ?? $response;
128            $this->developerToolbar->addData('exceptionThrown', $thrown);
129            $this->developerToolbar->addData('exceptionType', get_class($exception));
130            $this->developerToolbar->addData('exceptionCode', $exception->getCode());
131            $this->developerToolbar->addData('exceptionMessage', $exception->getMessage());
132            $this->developerToolbar->addData('exceptionFile', $exception->getFile());
133            $this->developerToolbar->addData('exceptionLine', $exception->getLine());
134            $this->developerToolbar->addData('exceptionTrace', $exception->getTraceAsString());
135
136            return new DeveloperToolbarResponse($response, $debugUrl);
137        }];
138    }
139}