Completed
Push — master ( a5a9aa...44b8ec )
by Oscar
02:26
created

FormatNegotiator::__invoke()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 16
rs 8.8571
c 1
b 1
f 0
cc 5
eloc 8
nc 16
nop 3
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Middleware;
6
use Psr7Middlewares\Utils;
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Negotiation\Negotiator;
10
11
/**
12
 * Middleware returns the client preferred format.
13
 */
14
class FormatNegotiator
15
{
16
    use Utils\NegotiateTrait;
17
18
    const KEY = 'FORMAT';
19
20
    /**
21
     * @var string Default format
22
     */
23
    private $default = 'html';
24
25
    /**
26
     * @var array Available formats with the mime types
27
     */
28
    private $formats = [
29
        'html' => ['text/html', 'application/xhtml+xml'],
30
        'css' => ['text/css'],
31
        'gif' => ['image/gif'],
32
        'png' => ['image/png', 'image/x-png'],
33
        'jpg' => ['image/jpeg', 'image/jpg'],
34
        'jpeg' => ['image/jpeg', 'image/jpg'],
35
        'json' => ['application/json', 'text/json', 'application/x-json'],
36
        'jsonp' => ['text/javascript', 'application/javascript', 'application/x-javascript'],
37
        'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'],
38
        'pdf' => ['application/pdf', 'application/x-download'],
39
        'rdf' => ['application/rdf+xml'],
40
        'rss' => ['application/rss+xml'],
41
        'atom' => ['application/atom+xml'],
42
        'xml' => ['text/xml', 'application/xml', 'application/x-xml'],
43
        'txt' => ['text/plain'],
44
        'mp4' => ['video/mp4'],
45
        'otf' => ['font/opentype'],
46
        'ttf' => ['font/ttf', 'application/font-ttf', 'application/x-font-ttf'],
47
        'ogg' => ['audio/ogg'],
48
        'ogv' => ['video/ogg'],
49
        'webm' => ['video/webm'],
50
        'woff' => ['font/woff', 'application/font-woff', 'application/x-font-woff'],
51
        'webp' => ['image/webp'],
52
        'svg' => ['image/svg+xml'],
53
        'zip' => ['application/zip', 'application/x-zip', 'application/x-zip-compressed'],
54
    ];
55
56
    /**
57
     * Returns the format.
58
     *
59
     * @param ServerRequestInterface $request
60
     *
61
     * @return string|null
62
     */
63
    public static function getFormat(ServerRequestInterface $request)
64
    {
65
        return Middleware::getAttribute($request, self::KEY);
66
    }
67
68
    /**
69
     * Add a new format.
70
     *
71
     * @param string $format
72
     * @param array  $mimeTypes
73
     *
74
     * @return self
75
     */
76
    public function addFormat($format, array $mimeTypes)
77
    {
78
        $this->formats[$format] = $mimeTypes;
79
80
        return $this;
81
    }
82
83
    /**
84
     * Set the default format.
85
     *
86
     * @param string $format
87
     *
88
     * @return self
89
     */
90
    public function defaultFormat($format)
91
    {
92
        $this->default = $format;
93
94
        return $this;
95
    }
96
97
    /**
98
     * Execute the middleware.
99
     *
100
     * @param ServerRequestInterface $request
101
     * @param ResponseInterface      $response
102
     * @param callable               $next
103
     *
104
     * @return ResponseInterface
105
     */
106
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
107
    {
108
        $format = $this->getFromExtension($request) ?: $this->getFromHeader($request) ?: $this->default;
109
110
        if ($format) {
111
            $request = Middleware::setAttribute($request, self::KEY, $format);
112
        }
113
114
        $response = $next($request, $response);
115
116
        if ($format) {
117
            $response = $response->withHeader('Content-Type', $this->formats[$format][0].'; charset=utf-8');
118
        }
119
120
        return $response;
121
    }
122
123
    /**
124
     * Returns the format using the file extension.
125
     *
126
     * @return null|string
127
     */
128
    private function getFromExtension(ServerRequestInterface $request)
129
    {
130
        $format = strtolower(pathinfo($request->getUri()->getPath(), PATHINFO_EXTENSION));
131
132
        return isset($this->formats[$format]) ? $format : null;
133
    }
134
135
    /**
136
     * Returns the format using the Accept header.
137
     *
138
     * @return null|string
139
     */
140
    private function getFromHeader(ServerRequestInterface $request)
141
    {
142
        $format = $this->negotiateHeader($request->getHeaderLine('Accept'), new Negotiator(), call_user_func_array('array_merge', array_values($this->formats)));
143
144
        if ($format !== null) {
145
            foreach ($this->formats as $extension => $headers) {
146
                if (in_array($format, $headers)) {
147
                    return $extension;
148
                }
149
            }
150
        }
151
    }
152
}
153