1 | <?php |
||||||
2 | declare(strict_types = 1); |
||||||
3 | |||||||
4 | namespace Phauthentic\Presentation\Service; |
||||||
5 | |||||||
6 | use Phauthentic\Presentation\Renderer\NativePHPRenderer; |
||||||
7 | use Phauthentic\Presentation\Renderer\RendererInterface; |
||||||
8 | use Phauthentic\Presentation\Renderer\WkhtmlToPdfRenderer; |
||||||
9 | use Phauthentic\Presentation\View\ViewInterface; |
||||||
10 | use Psr\Http\Message\ResponseFactoryInterface; |
||||||
11 | use Psr\Http\Message\ResponseInterface; |
||||||
12 | use Psr\Http\Message\ServerRequestInterface; |
||||||
13 | use RuntimeException; |
||||||
14 | |||||||
15 | /** |
||||||
16 | * Maps mime types to renderer implementations |
||||||
17 | */ |
||||||
18 | class RenderService implements RenderServiceInterface, ResponseRenderServiceInterface |
||||||
19 | { |
||||||
20 | /** |
||||||
21 | * Map of output types to renderers |
||||||
22 | * |
||||||
23 | * @var array |
||||||
24 | */ |
||||||
25 | protected $rendererMap = []; |
||||||
26 | |||||||
27 | /** |
||||||
28 | * Response Factory |
||||||
29 | * |
||||||
30 | * @var \Psr\Http\Message\ResponseFactoryInterface |
||||||
31 | */ |
||||||
32 | protected $responseFactory; |
||||||
33 | |||||||
34 | /** |
||||||
35 | * Map of mime types to output types |
||||||
36 | * |
||||||
37 | * @var array |
||||||
38 | */ |
||||||
39 | protected $mimeTypeMap = [ |
||||||
40 | // html |
||||||
41 | 'text/html' => NativePHPRenderer::class, |
||||||
42 | 'application/xhtml' => NativePHPRenderer::class, |
||||||
43 | 'application/xhtml+xml' => NativePHPRenderer::class, |
||||||
44 | // json |
||||||
45 | 'application/json' => 'json', |
||||||
46 | // xml |
||||||
47 | 'application/xml' => 'xml', |
||||||
48 | |||||||
49 | 'application/pdf' => WkhtmlToPdfRenderer::class |
||||||
50 | ]; |
||||||
51 | |||||||
52 | protected $outputMimeType = 'text/html'; |
||||||
53 | |||||||
54 | /** |
||||||
55 | * Constructor |
||||||
56 | */ |
||||||
57 | public function __construct( |
||||||
58 | ResponseFactoryInterface $responseFactory |
||||||
59 | ) { |
||||||
60 | $this->responseFactory = $responseFactory; |
||||||
61 | } |
||||||
62 | |||||||
63 | /** |
||||||
64 | * Adds a renderer and maps it to an output type |
||||||
65 | * |
||||||
66 | * @return $this |
||||||
67 | */ |
||||||
68 | public function addRenderer(string $outputType, RendererInterface $renderer): RenderServiceInterface |
||||||
69 | { |
||||||
70 | $this->rendererMap[$outputType] = $renderer; |
||||||
71 | |||||||
72 | return $this; |
||||||
73 | } |
||||||
74 | |||||||
75 | /** |
||||||
76 | * Validate Mime Type |
||||||
77 | * |
||||||
78 | * @param string $mimeType Mime Type |
||||||
79 | * @return bool |
||||||
80 | */ |
||||||
81 | protected function validateMimeType(string $mimeType): void |
||||||
82 | { |
||||||
83 | if (!preg_match('#^[-\w+]+/[-\w+]+$#', $mimeType)) { |
||||||
84 | throw new RuntimeException('Invalid mime type string'); |
||||||
85 | } |
||||||
86 | } |
||||||
87 | |||||||
88 | /** |
||||||
89 | * Maps a mime type to an output type |
||||||
90 | * |
||||||
91 | * @param string $mimeType Mime Type |
||||||
92 | * @param string $renderAs Abbreviation for the renderer |
||||||
93 | * @return $this |
||||||
94 | */ |
||||||
95 | public function addMimeTypeMapping(string $mimeType, string $renderAs): RenderServiceInterface |
||||||
96 | { |
||||||
97 | $this->validateMimeType($mimeType); |
||||||
98 | $this->mimeTypeMap[$mimeType] = $renderAs; |
||||||
99 | |||||||
100 | return $this; |
||||||
101 | } |
||||||
102 | |||||||
103 | /** |
||||||
104 | * Checks if the given mime type can be rendered as output |
||||||
105 | * |
||||||
106 | * @param string $type Content type to render |
||||||
107 | * @return bool |
||||||
108 | */ |
||||||
109 | public function canRender(string $type): bool |
||||||
110 | { |
||||||
111 | if (isset($this->mimeTypeMap[$type])) { |
||||||
112 | $type = $this->mimeTypeMap[$type]; |
||||||
113 | } |
||||||
114 | |||||||
115 | return isset($this->rendererMap[$type]); |
||||||
116 | } |
||||||
117 | |||||||
118 | /** |
||||||
119 | * Renders the view to the response |
||||||
120 | * |
||||||
121 | * @param \Phauthentic\Presentation\Renderer\ViewInterface $view |
||||||
0 ignored issues
–
show
|
|||||||
122 | * @param string $renderAs Type of output to render |
||||||
123 | * @return string |
||||||
124 | */ |
||||||
125 | public function render(ViewInterface $view, ?string $renderAs = 'text/html'): string |
||||||
126 | { |
||||||
127 | if (!$this->canRender($renderAs)) { |
||||||
0 ignored issues
–
show
It seems like
$renderAs can also be of type null ; however, parameter $type of Phauthentic\Presentation...derService::canRender() 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
![]() |
|||||||
128 | throw new RuntimeException(sprintf( |
||||||
129 | 'No renderer found for the requested output `%s`', |
||||||
130 | $renderAs |
||||||
131 | )); |
||||||
132 | } |
||||||
133 | |||||||
134 | return $this->rendererMap[$this->mimeTypeMap[$renderAs]]->render($view); |
||||||
135 | } |
||||||
136 | |||||||
137 | public function setOutputMimeType(string $mimeType): RenderServiceInterface |
||||||
138 | { |
||||||
139 | $this->outputMimeType = $mimeType; |
||||||
140 | |||||||
141 | return $this; |
||||||
142 | } |
||||||
143 | |||||||
144 | /** |
||||||
145 | * Gets a list of mime types the client accepts from the request |
||||||
146 | * |
||||||
147 | * @param \Psr\Http\Message\ServerRequestInterface $request Server Request Object |
||||||
148 | * @return A list of mime types the client accepts |
||||||
0 ignored issues
–
show
|
|||||||
149 | */ |
||||||
150 | public function getMimeTypesFromRequest(ServerRequestInterface $request): array |
||||||
151 | { |
||||||
152 | $mimeTypes = $request->getHeader('Accept'); |
||||||
153 | |||||||
154 | if (empty($mimeTypes)) { |
||||||
155 | throw new RuntimeException( |
||||||
156 | 'Could not get an accept header from the request' |
||||||
157 | ); |
||||||
158 | } |
||||||
159 | |||||||
160 | return $mimeTypes; |
||||||
0 ignored issues
–
show
|
|||||||
161 | } |
||||||
162 | |||||||
163 | /** |
||||||
164 | * @todo Should this return an immutable instance? |
||||||
165 | */ |
||||||
166 | public function setOutputMimeTypeByRequest(ServerRequestInterface $request): self |
||||||
167 | { |
||||||
168 | $mimeTypes = $this->getMimeTypesFromRequest($request); |
||||||
169 | |||||||
170 | foreach ($mimeTypes as $mimeType) { |
||||||
171 | if ($this->canRender($mimeType)) { |
||||||
172 | $this->outPutMimeType = $mimeType; |
||||||
0 ignored issues
–
show
|
|||||||
173 | |||||||
174 | return $this; |
||||||
175 | } |
||||||
176 | } |
||||||
177 | |||||||
178 | throw new RuntimeException(sprintf( |
||||||
179 | 'No renderer found for the requested output `%s`', |
||||||
180 | $mimeType |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
181 | )); |
||||||
182 | } |
||||||
183 | |||||||
184 | /** |
||||||
185 | * Renders the output to the response object |
||||||
186 | * |
||||||
187 | * @param \Psr\Http\Message\ResponseInterface $response Response object |
||||||
188 | * @param \Phauthentic\Presentation\Renderer\ViewInterface $view View DTO |
||||||
189 | * @param string $outputMimeType Output format |
||||||
190 | * @return \Psr\Http\Message\ResponseInterface |
||||||
191 | */ |
||||||
192 | public function renderToResponse( |
||||||
193 | ResponseInterface $response, |
||||||
194 | ViewInterface $view, |
||||||
195 | ?string $outputMimeType = null |
||||||
196 | ): ResponseInterface { |
||||||
197 | $outputMimeType = $outputMimeType === null ? $this->outputMimeType : $outputMimeType; |
||||||
198 | |||||||
199 | $stream = $response->getBody(); |
||||||
200 | $stream->write($this->render($view, $outputMimeType)); |
||||||
201 | |||||||
202 | return $response |
||||||
203 | ->withBody($stream) |
||||||
204 | ->withHeader('content-type', $outputMimeType); |
||||||
205 | } |
||||||
206 | |||||||
207 | /** |
||||||
208 | * @param \Phauthentic\Presentation\Renderer\ViewInterface $view View DTO |
||||||
209 | * @param string $outputMimeType Output format |
||||||
210 | * @return \Psr\Http\Message\ResponseInterface |
||||||
211 | */ |
||||||
212 | public function renderResponse( |
||||||
213 | ViewInterface $view, |
||||||
214 | ?string $outputMimeType = null |
||||||
215 | ): ResponseInterface { |
||||||
216 | $response = $this->responseFactory->createResponse(); |
||||||
0 ignored issues
–
show
|
|||||||
217 | |||||||
218 | return $this->renderToResponse($view, $outputMimeType); |
||||||
0 ignored issues
–
show
$outputMimeType of type null|string is incompatible with the type Phauthentic\Presentation\View\ViewInterface expected by parameter $view of Phauthentic\Presentation...ice::renderToResponse() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() $view of type Phauthentic\Presentation\View\ViewInterface is incompatible with the type Psr\Http\Message\ResponseInterface expected by parameter $response of Phauthentic\Presentation...ice::renderToResponse() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
219 | } |
||||||
220 | } |
||||||
221 | |||||||
222 | /* |
||||||
223 | $view = new View(); |
||||||
224 | $renderService = new RenderService(); |
||||||
225 | $templateMapperService = new RequestToTemplateMapperService(); |
||||||
226 | |||||||
227 | $view = $templateMapperService->requestToViewTemplate($request, $view); |
||||||
228 | |||||||
229 | $response = $renderService |
||||||
230 | ->addRenderer('html', new NativePhpRenderer()) |
||||||
231 | ->addMimeTypeMapping('text/html', 'html') |
||||||
232 | ->addMimeTypeMapping('application/xhtml') |
||||||
233 | ->addRenderer('json', new NativeJsonRenderer()) |
||||||
234 | ->addMimeTypeMapping('application/json', 'json') |
||||||
235 | ->setOutputMimeTypeByRequest($request) |
||||||
236 | ->renderToResponse($response, $view); |
||||||
237 | */ |
||||||
238 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths