1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Charcoal\App\Handler; |
4
|
|
|
|
5
|
|
|
// Dependencies from PSR-7 (HTTP Messaging) |
6
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
7
|
|
|
use Psr\Http\Message\ResponseInterface; |
8
|
|
|
|
9
|
|
|
// Local Dependencies |
10
|
|
|
use Charcoal\App\Handler\AbstractHandler; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Not Allowed Handler |
14
|
|
|
* |
15
|
|
|
* Enhanced version of {@see \Slim\Handlers\NotAllowed}. |
16
|
|
|
* |
17
|
|
|
* It outputs a simple message in either JSON, XML, |
18
|
|
|
* or HTML based on the Accept header. |
19
|
|
|
*/ |
20
|
|
|
class NotAllowed extends AbstractHandler |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* HTTP methods allowed by the current request. |
24
|
|
|
* |
25
|
|
|
* @var string $methods |
26
|
|
|
*/ |
27
|
|
|
protected $methods; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Invoke "Not Allowed" Handler |
31
|
|
|
* |
32
|
|
|
* @param ServerRequestInterface $request The most recent Request object. |
33
|
|
|
* @param ResponseInterface $response The most recent Response object. |
34
|
|
|
* @param string[] $methods Allowed HTTP methods. |
35
|
|
|
* @return ResponseInterface |
36
|
|
|
*/ |
37
|
|
|
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $methods) |
38
|
|
|
{ |
39
|
|
|
$this->setMethods($methods); |
40
|
|
|
|
41
|
|
|
if ($request->getMethod() === 'OPTIONS') { |
42
|
|
|
$status = 200; |
43
|
|
|
$contentType = 'text/plain'; |
44
|
|
|
$output = $this->renderPlainOutput(); |
45
|
|
View Code Duplication |
} else { |
|
|
|
|
46
|
|
|
$status = 405; |
47
|
|
|
$contentType = $this->determineContentType($request); |
48
|
|
|
switch ($contentType) { |
49
|
|
|
case 'application/json': |
50
|
|
|
$output = $this->renderJsonOutput(); |
51
|
|
|
break; |
52
|
|
|
|
53
|
|
|
case 'text/xml': |
54
|
|
|
case 'application/xml': |
55
|
|
|
$output = $this->renderXmlOutput(); |
56
|
|
|
break; |
57
|
|
|
|
58
|
|
|
case 'text/html': |
59
|
|
|
default: |
60
|
|
|
$output = $this->renderHtmlOutput(); |
61
|
|
|
break; |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
$response->getBody()->write($output); |
66
|
|
|
$allow = implode(', ', $methods); |
67
|
|
|
|
68
|
|
|
return $response |
69
|
|
|
->withStatus($status) |
70
|
|
|
->withHeader('Content-type', $contentType) |
71
|
|
|
->withHeader('Allow', $allow); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Set the HTTP methods allowed by the current request. |
76
|
|
|
* |
77
|
|
|
* @param array $methods Case-sensitive array of methods. |
78
|
|
|
* @return NotAllowed Chainable |
79
|
|
|
*/ |
80
|
|
|
protected function setMethods(array $methods) |
81
|
|
|
{ |
82
|
|
|
$this->methods = implode(', ', $methods); |
83
|
|
|
|
84
|
|
|
return $this; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Retrieves the HTTP methods allowed by the current request. |
89
|
|
|
* |
90
|
|
|
* @return string Returns the allowed request methods. |
91
|
|
|
*/ |
92
|
|
|
public function methods() |
93
|
|
|
{ |
94
|
|
|
return $this->methods; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Render Plain/Text Error |
99
|
|
|
* |
100
|
|
|
* @return string |
101
|
|
|
*/ |
102
|
|
|
protected function renderPlainOutput() |
103
|
|
|
{ |
104
|
|
|
$message = $this->translator()->translate('Allowed methods:').' '.$this->methods(); |
105
|
|
|
|
106
|
|
|
return $this->render($message); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Render JSON Error |
111
|
|
|
* |
112
|
|
|
* @return string |
113
|
|
|
*/ |
114
|
|
|
protected function renderJsonOutput() |
115
|
|
|
{ |
116
|
|
|
$message = $this->translator()->translate('Method not allowed. Must be one of:').' '.$this->methods(); |
117
|
|
|
|
118
|
|
|
return $this->render('{"message":"'.$message.'"}'); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Render XML Error |
123
|
|
|
* |
124
|
|
|
* @return string |
125
|
|
|
*/ |
126
|
|
|
protected function renderXmlOutput() |
127
|
|
|
{ |
128
|
|
|
$message = $this->translator()->translate('Method not allowed. Must be one of:').' '.$this->methods(); |
129
|
|
|
|
130
|
|
|
return $this->render('<root><message>'.$message.'</message></root>'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Render title of error |
135
|
|
|
* |
136
|
|
|
* @return string |
137
|
|
|
*/ |
138
|
|
|
public function messageTitle() |
139
|
|
|
{ |
140
|
|
|
return $this->translator()->translate('Method not allowed.'); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Render body of HTML error |
145
|
|
|
* |
146
|
|
|
* @return string |
147
|
|
|
*/ |
148
|
|
|
public function renderHtmlMessage() |
149
|
|
|
{ |
150
|
|
|
$title = $this->messageTitle(); |
151
|
|
|
$notice = $this->translator()->entry('Method not allowed. Must be one of:'); |
|
|
|
|
152
|
|
|
$methods = $this->methods(); |
153
|
|
|
$message = '<h1>'.$title."</h1>\n\t\t<p>".$notice.' <strong>'.$methods."</strong></p>\n"; |
154
|
|
|
|
155
|
|
|
return $message; |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.