Issues (40)

src/Service/RenderService.php (9 issues)

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
        // pdf
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
The type Phauthentic\Presentation\Renderer\ViewInterface was not found. Maybe you did not declare it correctly or list all dependencies?

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:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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 ignore-type  annotation

127
        if (!$this->canRender(/** @scrutinizer ignore-type */ $renderAs)) {
Loading history...
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
The type Phauthentic\Presentation\Service\A was not found. Did you mean A? If so, make sure to prefix the type with \.
Loading history...
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
Bug Best Practice introduced by
The expression return $mimeTypes returns the type string[] which is incompatible with the documented return type Phauthentic\Presentation\Service\A.
Loading history...
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
Bug Best Practice introduced by
The property outPutMimeType does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
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
The variable $mimeType seems to be defined by a foreach iteration on line 170. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
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
The assignment to $response is dead and can be removed.
Loading history...
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 ignore-type  annotation

218
        return $this->renderToResponse($view, /** @scrutinizer ignore-type */ $outputMimeType);
Loading history...
$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 ignore-type  annotation

218
        return $this->renderToResponse(/** @scrutinizer ignore-type */ $view, $outputMimeType);
Loading history...
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