Completed
Push — master ( 2a5654...51739b )
by Gabor
03:24
created

FinalMiddleware   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 15
lcom 0
cbo 4
dl 0
loc 122
ccs 19
cts 19
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B __invoke() 0 31 5
A injectContentLength() 0 8 3
A filterHeaderName() 0 6 1
A sendHttpHeader() 0 10 2
A sendOutputHeaders() 0 11 3
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Middleware;
13
14
use RuntimeException;
15
use WebHemi\Adapter\Http\ResponseInterface;
16
use WebHemi\Adapter\Http\ServerRequestInterface;
17
use WebHemi\Adapter\Renderer\RendererAdapterInterface;
18
19
/**
20
 * Class FinalMiddleware.
21
 */
22
class FinalMiddleware implements MiddlewareInterface
23
{
24
    /** @var RendererAdapterInterface */
25
    private $templateRenderer;
26
27
    /**
28
     * FinalMiddleware constructor.
29
     *
30
     * @param RendererAdapterInterface $templateRenderer
31
     */
32 7
    public function __construct(RendererAdapterInterface $templateRenderer)
33
    {
34 7
        $this->templateRenderer = $templateRenderer;
35 7
    }
36
37
    /**
38
     * Sends out the headers and prints the response body to the output.
39
     *
40
     * @param ServerRequestInterface $request
41
     * @param ResponseInterface      $response
42
     *
43
     * @return ResponseInterface
44
     */
45 2
    public function __invoke(ServerRequestInterface &$request, ResponseInterface $response)
46
    {
47
        // @codeCoverageIgnoreStart
48
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE') && headers_sent()) {
49
            throw new RuntimeException('Unable to emit response; headers already sent');
50
        }
51
        // @codeCoverageIgnoreEnd
52
53 2
        $content = $response->getBody();
54
55
        // Handle errors here.
56 2
        if ($response->getStatusCode() !== ResponseInterface::STATUS_OK) {
57 1
            $errorTemplate = 'error-'.$response->getStatusCode();
58 1
            $exception = $request->getAttribute(ServerRequestInterface::REQUEST_ATTR_MIDDLEWARE_EXCEPTION);
59 1
            $content = $this->templateRenderer->render($errorTemplate, ['exception' => $exception]);
60
        }
61
62 2
        $response = $this->injectContentLength($response);
63
64
        // Skip sending output when PHP Unit is running.
65
        // @codeCoverageIgnoreStart
66
        if (!defined('PHPUNIT_WEBHEMI_TESTSUITE')) {
67
            $this->sendHttpHeader($response);
68
            $this->sendOutputHeaders($response->getHeaders());
69
70
            echo $content;
71
        }
72
        // @codeCoverageIgnoreEnd
73
74
        return $response;
75
    }
76
77
    /**
78
     * Inject the Content-Length header if is not already present.
79
     *
80
     * @param ResponseInterface $response
81
     *
82
     * @return ResponseInterface
83
     */
84
    private function injectContentLength(ResponseInterface $response)
85
    {
86
        if (!$response->hasHeader('Content-Length')&& !is_null($response->getBody()->getSize())) {
87
            $response = $response->withHeader('Content-Length', (string) $response->getBody()->getSize());
88 2
        }
89
90
        return $response;
91
    }
92
93
    /**
94
     * Filter a header name to word case.
95
     *
96
     * @param string $headerName
97
     *
98 2
     * @return string
99
     */
100 2
    private function filterHeaderName($headerName)
101 2
    {
102
        $filtered = str_replace('-', ' ', $headerName);
103
        $filtered = ucwords($filtered);
104 2
        return str_replace(' ', '-', $filtered);
105
    }
106
107
    /**
108
     * Sends the HTTP header.
109
     *
110
     * @param ResponseInterface $response
111
     *
112
     * @codeCoverageIgnore - vendor and core function calls
113
     */
114 5
    private function sendHttpHeader(ResponseInterface $response)
115
    {
116 5
        $reasonPhrase = $response->getReasonPhrase();
117 5
        header(sprintf(
118 5
            'HTTP/%s %d%s',
119
            $response->getProtocolVersion(),
120
            $response->getStatusCode(),
121
            ($reasonPhrase ? ' '.$reasonPhrase : '')
122
        ));
123
    }
124
125
    /**
126
     * Sends out output headers.
127
     *
128
     * @param array $headers
129
     *
130
     * @codeCoverageIgnore - vendor and core function calls in loop
131
     */
132
    private function sendOutputHeaders(array $headers)
133
    {
134
        foreach ($headers as $headerName => $values) {
135
            $name  = $this->filterHeaderName($headerName);
136
            $first = true;
137
            foreach ($values as $value) {
138
                header(sprintf('%s: %s', $name, $value), $first);
139
                $first = false;
140
            }
141
        }
142
    }
143
}
144