1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the FOSRestBundle package. |
5
|
|
|
* |
6
|
|
|
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace FOS\RestBundle\View; |
13
|
|
|
|
14
|
|
|
use FOS\RestBundle\Context\Adapter\SerializationContextAdapterInterface; |
15
|
|
|
use FOS\RestBundle\Context\Adapter\SerializerAwareInterface; |
16
|
|
|
use FOS\RestBundle\Context\ContextInterface; |
17
|
|
|
use FOS\RestBundle\Context\GroupableContextInterface; |
18
|
|
|
use FOS\RestBundle\Context\SerializeNullContextInterface; |
19
|
|
|
use FOS\RestBundle\Context\VersionableContextInterface; |
20
|
|
|
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; |
21
|
|
|
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference; |
22
|
|
|
use Symfony\Component\Form\FormInterface; |
23
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse; |
24
|
|
|
use Symfony\Component\HttpFoundation\Request; |
25
|
|
|
use Symfony\Component\HttpFoundation\RequestStack; |
26
|
|
|
use Symfony\Component\HttpFoundation\Response; |
27
|
|
|
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; |
28
|
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* View may be used in controllers to build up a response in a format agnostic way |
32
|
|
|
* The View class takes care of encoding your data in json, xml, or renders a |
33
|
|
|
* template for html via the Serializer component. |
34
|
|
|
* |
35
|
|
|
* @author Jordi Boggiano <[email protected]> |
36
|
|
|
* @author Lukas K. Smith <[email protected]> |
37
|
|
|
*/ |
38
|
|
|
class ViewHandler implements ConfigurableViewHandlerInterface |
39
|
|
|
{ |
40
|
|
|
/** |
41
|
|
|
* Key format, value a callable that returns a Response instance. |
42
|
|
|
* |
43
|
|
|
* @var array |
44
|
|
|
*/ |
45
|
|
|
protected $customHandlers = []; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* The supported formats as keys and if the given formats |
49
|
|
|
* uses templating is denoted by a true value. |
50
|
|
|
* |
51
|
|
|
* @var array |
52
|
|
|
*/ |
53
|
|
|
protected $formats; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* HTTP response status code for a failed validation. |
57
|
|
|
* |
58
|
|
|
* @var int |
59
|
|
|
*/ |
60
|
|
|
protected $failedValidationCode; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* HTTP response status code when the view data is null. |
64
|
|
|
* |
65
|
|
|
* @var int |
66
|
|
|
*/ |
67
|
|
|
protected $emptyContentCode; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Whether or not to serialize null view data. |
71
|
|
|
* |
72
|
|
|
* @var bool |
73
|
|
|
*/ |
74
|
|
|
protected $serializeNull; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* If to force a redirect for the given key format, |
78
|
|
|
* with value being the status code to use. |
79
|
|
|
* |
80
|
|
|
* @var array |
81
|
|
|
*/ |
82
|
|
|
protected $forceRedirects; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @var string |
86
|
|
|
*/ |
87
|
|
|
protected $defaultEngine; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @var array |
91
|
|
|
*/ |
92
|
|
|
protected $exclusionStrategyGroups = []; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @var string |
96
|
|
|
*/ |
97
|
|
|
protected $exclusionStrategyVersion; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @var bool |
101
|
|
|
*/ |
102
|
|
|
protected $serializeNullStrategy; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @var SerializationContextAdapterInterface |
106
|
|
|
*/ |
107
|
|
|
protected $contextAdapter; |
108
|
|
|
|
109
|
|
|
private $urlGenerator; |
110
|
|
|
private $serializer; |
111
|
|
|
private $templating; |
112
|
|
|
private $requestStack; |
113
|
|
|
private $exceptionWrapperHandler; |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Constructor. |
117
|
|
|
* |
118
|
|
|
* @param UrlGeneratorInterface $urlGenerator The URL generator |
119
|
|
|
* @param object $serializer An object implementing a serialize() method |
120
|
|
|
* @param EngineInterface $templating The configured templating engine |
121
|
|
|
* @param RequestStack $requestStack The request stack |
122
|
|
|
* @param ExceptionWrapperHandlerInterface $exceptionWrapperHandler An exception wrapper handler |
123
|
|
|
* @param array $formats the supported formats as keys and if the given formats uses templating is denoted by a true value |
124
|
|
|
* @param int $failedValidationCode The HTTP response status code for a failed validation |
125
|
|
|
* @param int $emptyContentCode HTTP response status code when the view data is null |
126
|
|
|
* @param bool $serializeNull Whether or not to serialize null view data |
127
|
|
|
* @param array $forceRedirects If to force a redirect for the given key format, with value being the status code to use |
128
|
|
|
* @param string $defaultEngine default engine (twig, php ..) |
129
|
|
|
*/ |
130
|
75 |
|
public function __construct( |
131
|
|
|
UrlGeneratorInterface $urlGenerator, |
132
|
|
|
$serializer, |
133
|
|
|
EngineInterface $templating, |
134
|
|
|
RequestStack $requestStack, |
135
|
|
|
ExceptionWrapperHandlerInterface $exceptionWrapperHandler, |
136
|
|
|
array $formats = null, |
137
|
|
|
$failedValidationCode = Response::HTTP_BAD_REQUEST, |
138
|
|
|
$emptyContentCode = Response::HTTP_NO_CONTENT, |
139
|
|
|
$serializeNull = false, |
140
|
|
|
array $forceRedirects = null, |
141
|
|
|
$defaultEngine = 'twig' |
142
|
|
|
) { |
143
|
75 |
|
if (!method_exists($serializer, 'serialize')) { |
144
|
|
|
throw new \InvalidArgumentException('The $serializer argument must implement a serialize() method.'); |
145
|
|
|
} |
146
|
|
|
|
147
|
75 |
|
$this->urlGenerator = $urlGenerator; |
148
|
75 |
|
$this->serializer = $serializer; |
149
|
75 |
|
$this->templating = $templating; |
150
|
75 |
|
$this->requestStack = $requestStack; |
151
|
75 |
|
$this->exceptionWrapperHandler = $exceptionWrapperHandler; |
152
|
75 |
|
$this->formats = (array) $formats; |
153
|
75 |
|
$this->failedValidationCode = $failedValidationCode; |
154
|
75 |
|
$this->emptyContentCode = $emptyContentCode; |
155
|
75 |
|
$this->serializeNull = $serializeNull; |
156
|
75 |
|
$this->forceRedirects = (array) $forceRedirects; |
157
|
75 |
|
$this->defaultEngine = $defaultEngine; |
158
|
75 |
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Sets the default serialization groups. |
162
|
|
|
* |
163
|
|
|
* @param array|string $groups |
164
|
|
|
*/ |
165
|
1 |
|
public function setExclusionStrategyGroups($groups) |
166
|
|
|
{ |
167
|
1 |
|
$this->exclusionStrategyGroups = $groups; |
|
|
|
|
168
|
1 |
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Sets the default serialization version. |
172
|
|
|
* |
173
|
|
|
* @param string $version |
174
|
|
|
*/ |
175
|
5 |
|
public function setExclusionStrategyVersion($version) |
176
|
|
|
{ |
177
|
5 |
|
$this->exclusionStrategyVersion = $version; |
178
|
5 |
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* If nulls should be serialized. |
182
|
|
|
* |
183
|
|
|
* @param bool $isEnabled |
184
|
|
|
*/ |
185
|
16 |
|
public function setSerializeNullStrategy($isEnabled) |
186
|
|
|
{ |
187
|
16 |
|
$this->serializeNullStrategy = $isEnabled; |
188
|
16 |
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* Sets context adapter. |
192
|
|
|
* |
193
|
|
|
* @param SerializationContextAdapterInterface $contextAdapter |
194
|
|
|
*/ |
195
|
44 |
|
public function setSerializationContextAdapter(SerializationContextAdapterInterface $contextAdapter) |
196
|
|
|
{ |
197
|
44 |
|
$this->contextAdapter = $contextAdapter; |
198
|
44 |
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* {@inheritdoc} |
202
|
|
|
*/ |
203
|
32 |
|
public function supports($format) |
204
|
|
|
{ |
205
|
32 |
|
return isset($this->customHandlers[$format]) || isset($this->formats[$format]); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Registers a custom handler. |
210
|
|
|
* |
211
|
|
|
* The handler must have the following signature: handler(ViewHandler $viewHandler, View $view, Request $request, $format) |
212
|
|
|
* It can use the public methods of this class to retrieve the needed data and return a |
213
|
|
|
* Response object ready to be sent. |
214
|
|
|
* |
215
|
|
|
* @param string $format |
216
|
|
|
* @param callable $callable |
217
|
|
|
* |
218
|
|
|
* @throws \InvalidArgumentException |
219
|
|
|
*/ |
220
|
16 |
|
public function registerHandler($format, $callable) |
221
|
|
|
{ |
222
|
16 |
|
if (!is_callable($callable)) { |
223
|
1 |
|
throw new \InvalidArgumentException('Registered view callback must be callable.'); |
224
|
|
|
} |
225
|
|
|
|
226
|
15 |
|
$this->customHandlers[$format] = $callable; |
227
|
15 |
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Gets a response HTTP status code from a View instance. |
231
|
|
|
* |
232
|
|
|
* By default it will return 200. However if there is a FormInterface stored for |
233
|
|
|
* the key 'form' in the View's data it will return the failed_validation |
234
|
|
|
* configuration if the form instance has errors. |
235
|
|
|
* |
236
|
|
|
* @param View $view |
237
|
|
|
* @param mixed $content |
238
|
|
|
* |
239
|
|
|
* @return int HTTP status code |
240
|
|
|
*/ |
241
|
43 |
|
protected function getStatusCode(View $view, $content = null) |
242
|
|
|
{ |
243
|
43 |
|
$form = $this->getFormFromView($view); |
244
|
|
|
|
245
|
43 |
|
if ($form && $form->isSubmitted() && !$form->isValid()) { |
246
|
7 |
|
return $this->failedValidationCode; |
247
|
|
|
} |
248
|
|
|
|
249
|
36 |
|
if (200 !== ($code = $view->getStatusCode())) { |
250
|
9 |
|
return $code; |
251
|
|
|
} |
252
|
|
|
|
253
|
27 |
|
return null !== $content ? Response::HTTP_OK : $this->emptyContentCode; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* If the given format uses the templating system for rendering. |
258
|
|
|
* |
259
|
|
|
* @param string $format |
260
|
|
|
* |
261
|
|
|
* @return bool |
262
|
|
|
*/ |
263
|
34 |
|
public function isFormatTemplating($format) |
264
|
|
|
{ |
265
|
34 |
|
return !empty($this->formats[$format]); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Gets or creates a JMS\Serializer\SerializationContext and initializes it with |
270
|
|
|
* the view exclusion strategies, groups & versions if a new context is created. |
271
|
|
|
* |
272
|
|
|
* @param View $view |
273
|
|
|
* |
274
|
|
|
* @return ContextInterface |
275
|
|
|
*/ |
276
|
24 |
|
protected function getSerializationContext(View $view) |
277
|
|
|
{ |
278
|
24 |
|
$context = $view->getSerializationContext(); |
279
|
|
|
|
280
|
24 |
|
if ($context instanceof GroupableContextInterface) { |
281
|
24 |
|
$groups = $context->getGroups(); |
282
|
24 |
|
if (empty($groups) && $this->exclusionStrategyGroups) { |
|
|
|
|
283
|
1 |
|
$context->addGroups((array) $this->exclusionStrategyGroups); |
284
|
1 |
|
} |
285
|
24 |
|
} |
286
|
|
|
|
287
|
24 |
|
if ($context instanceof VersionableContextInterface && null === $context->getVersion() && $this->exclusionStrategyVersion) { |
288
|
1 |
|
$context->setVersion($this->exclusionStrategyVersion); |
289
|
1 |
|
} |
290
|
|
|
|
291
|
24 |
|
if ($context instanceof SerializeNullContextInterface && null === $context->getSerializeNull()) { |
292
|
24 |
|
$context->setSerializeNull($this->serializeNullStrategy); |
293
|
24 |
|
} |
294
|
|
|
|
295
|
24 |
|
return $context; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Handles a request with the proper handler. |
300
|
|
|
* |
301
|
|
|
* Decides on which handler to use based on the request format. |
302
|
|
|
* |
303
|
|
|
* @param View $view |
304
|
|
|
* @param Request $request |
305
|
|
|
* |
306
|
|
|
* @throws UnsupportedMediaTypeHttpException |
307
|
|
|
* |
308
|
|
|
* @return Response |
309
|
|
|
*/ |
310
|
28 |
|
public function handle(View $view, Request $request = null) |
311
|
|
|
{ |
312
|
28 |
|
if (null === $request) { |
313
|
7 |
|
$request = $this->requestStack->getCurrentRequest(); |
314
|
7 |
|
} |
315
|
|
|
|
316
|
28 |
|
$format = $view->getFormat() ?: $request->getRequestFormat(); |
|
|
|
|
317
|
|
|
|
318
|
28 |
|
if (!$this->supports($format)) { |
319
|
1 |
|
$msg = "Format '$format' not supported, handler must be implemented"; |
320
|
1 |
|
throw new UnsupportedMediaTypeHttpException($msg); |
321
|
|
|
} |
322
|
|
|
|
323
|
27 |
|
if (isset($this->customHandlers[$format])) { |
324
|
10 |
|
return call_user_func($this->customHandlers[$format], $this, $view, $request, $format); |
325
|
|
|
} |
326
|
|
|
|
327
|
17 |
|
return $this->createResponse($view, $request, $format); |
|
|
|
|
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Creates the Response from the view. |
332
|
|
|
* |
333
|
|
|
* @param View $view |
334
|
|
|
* @param string $location |
335
|
|
|
* @param string $format |
336
|
|
|
* |
337
|
|
|
* @return Response |
338
|
|
|
*/ |
339
|
7 |
|
public function createRedirectResponse(View $view, $location, $format) |
340
|
|
|
{ |
341
|
7 |
|
$content = null; |
342
|
7 |
|
if (($view->getStatusCode() == Response::HTTP_CREATED || $view->getStatusCode() == Response::HTTP_ACCEPTED) && $view->getData() != null) { |
343
|
1 |
|
$response = $this->initResponse($view, $format); |
344
|
1 |
|
} else { |
345
|
6 |
|
$response = $view->getResponse(); |
346
|
6 |
|
if ('html' === $format && isset($this->forceRedirects[$format])) { |
347
|
1 |
|
$redirect = new RedirectResponse($location); |
348
|
1 |
|
$content = $redirect->getContent(); |
349
|
1 |
|
$response->setContent($content); |
350
|
1 |
|
} |
351
|
|
|
} |
352
|
|
|
|
353
|
7 |
|
$code = isset($this->forceRedirects[$format]) |
354
|
7 |
|
? $this->forceRedirects[$format] : $this->getStatusCode($view, $content); |
355
|
|
|
|
356
|
7 |
|
$response->setStatusCode($code); |
357
|
7 |
|
$response->headers->set('Location', $location); |
358
|
|
|
|
359
|
7 |
|
return $response; |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
/** |
363
|
|
|
* Renders the view data with the given template. |
364
|
|
|
* |
365
|
|
|
* @param View $view |
366
|
|
|
* @param string $format |
367
|
|
|
* |
368
|
|
|
* @return string |
369
|
|
|
*/ |
370
|
11 |
|
public function renderTemplate(View $view, $format) |
371
|
|
|
{ |
372
|
11 |
|
$data = $this->prepareTemplateParameters($view); |
373
|
|
|
|
374
|
11 |
|
$template = $view->getTemplate(); |
375
|
11 |
|
if ($template instanceof TemplateReference) { |
376
|
|
|
if (null === $template->get('format')) { |
377
|
|
|
$template->set('format', $format); |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
if (null === $template->get('engine')) { |
381
|
|
|
$engine = $view->getEngine() ?: $this->defaultEngine; |
382
|
|
|
$template->set('engine', $engine); |
383
|
|
|
} |
384
|
|
|
} |
385
|
|
|
|
386
|
11 |
|
return $this->templating->render($template, $data); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Prepares view data for use by templating engine. |
391
|
|
|
* |
392
|
|
|
* @param View $view |
393
|
|
|
* |
394
|
|
|
* @return array |
395
|
|
|
*/ |
396
|
18 |
|
public function prepareTemplateParameters(View $view) |
397
|
|
|
{ |
398
|
18 |
|
$data = $view->getData(); |
399
|
|
|
|
400
|
18 |
|
if ($data instanceof FormInterface) { |
401
|
2 |
|
$data = [$view->getTemplateVar() => $data->getData(), 'form' => $data]; |
402
|
18 |
|
} elseif (empty($data) || !is_array($data) || is_numeric((key($data)))) { |
403
|
10 |
|
$data = [$view->getTemplateVar() => $data]; |
404
|
10 |
|
} |
405
|
|
|
|
406
|
18 |
|
if (isset($data['form']) && $data['form'] instanceof FormInterface) { |
407
|
2 |
|
$data['form'] = $data['form']->createView(); |
408
|
2 |
|
} |
409
|
|
|
|
410
|
18 |
|
$templateData = $view->getTemplateData(); |
411
|
18 |
|
if (is_callable($templateData)) { |
412
|
2 |
|
$templateData = call_user_func($templateData, $this, $view); |
413
|
2 |
|
} |
414
|
|
|
|
415
|
18 |
|
return array_merge($data, $templateData); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
/** |
419
|
|
|
* Handles creation of a Response using either redirection or the templating/serializer service. |
420
|
|
|
* |
421
|
|
|
* @param View $view |
422
|
|
|
* @param Request $request |
423
|
|
|
* @param string $format |
424
|
|
|
* |
425
|
|
|
* @return Response |
426
|
|
|
*/ |
427
|
39 |
|
public function createResponse(View $view, Request $request, $format) |
428
|
|
|
{ |
429
|
39 |
|
$route = $view->getRoute(); |
430
|
|
|
$location = $route |
431
|
39 |
|
? $this->urlGenerator->generate($route, (array) $view->getRouteParameters(), UrlGeneratorInterface::ABSOLUTE_URL) |
432
|
39 |
|
: $view->getLocation(); |
433
|
|
|
|
434
|
39 |
|
if ($location) { |
|
|
|
|
435
|
7 |
|
return $this->createRedirectResponse($view, $location, $format); |
436
|
|
|
} |
437
|
|
|
|
438
|
32 |
|
$response = $this->initResponse($view, $format); |
439
|
|
|
|
440
|
32 |
|
if (!$response->headers->has('Content-Type')) { |
441
|
32 |
|
$response->headers->set('Content-Type', $request->getMimeType($format)); |
442
|
32 |
|
} |
443
|
|
|
|
444
|
32 |
|
return $response; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Initializes a response object that represents the view and holds the view's status code. |
449
|
|
|
* |
450
|
|
|
* @param View $view |
451
|
|
|
* @param string $format |
452
|
|
|
* |
453
|
|
|
* @return Response |
454
|
|
|
*/ |
455
|
33 |
|
private function initResponse(View $view, $format) |
456
|
|
|
{ |
457
|
33 |
|
$content = null; |
458
|
33 |
|
if ($this->isFormatTemplating($format)) { |
459
|
11 |
|
$content = $this->renderTemplate($view, $format); |
460
|
33 |
|
} elseif ($this->serializeNull || null !== $view->getData()) { |
461
|
21 |
|
$data = $this->getDataFromView($view); |
462
|
|
|
|
463
|
21 |
|
$standardContext = $this->getSerializationContext($view); |
464
|
21 |
|
if ($this->contextAdapter instanceof SerializerAwareInterface) { |
465
|
8 |
|
$this->contextAdapter->setSerializer($this->serializer); |
466
|
8 |
|
} |
467
|
21 |
|
$context = $this->contextAdapter->convertSerializationContext($standardContext); |
468
|
21 |
|
$content = $this->serializer->serialize($data, $format, $context); |
469
|
21 |
|
} |
470
|
|
|
|
471
|
33 |
|
$response = $view->getResponse(); |
472
|
33 |
|
$response->setStatusCode($this->getStatusCode($view, $content)); |
473
|
|
|
|
474
|
33 |
|
if (null !== $content) { |
475
|
27 |
|
$response->setContent($content); |
476
|
27 |
|
} |
477
|
|
|
|
478
|
33 |
|
return $response; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Returns the form from the given view if present, false otherwise. |
483
|
|
|
* |
484
|
|
|
* @param View $view |
485
|
|
|
* |
486
|
|
|
* @return bool|FormInterface |
487
|
|
|
*/ |
488
|
43 |
|
protected function getFormFromView(View $view) |
489
|
|
|
{ |
490
|
43 |
|
$data = $view->getData(); |
491
|
|
|
|
492
|
43 |
|
if ($data instanceof FormInterface) { |
493
|
7 |
|
return $data; |
494
|
|
|
} |
495
|
|
|
|
496
|
36 |
|
if (is_array($data) && isset($data['form']) && $data['form'] instanceof FormInterface) { |
497
|
4 |
|
return $data['form']; |
498
|
|
|
} |
499
|
|
|
|
500
|
32 |
|
return false; |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* Returns the data from a view. If the data is form with errors, it will return it wrapped in an ExceptionWrapper. |
505
|
|
|
* |
506
|
|
|
* @param View $view |
507
|
|
|
* |
508
|
|
|
* @return mixed|null |
509
|
|
|
*/ |
510
|
21 |
|
private function getDataFromView(View $view) |
511
|
|
|
{ |
512
|
21 |
|
$form = $this->getFormFromView($view); |
513
|
|
|
|
514
|
21 |
|
if (false === $form) { |
515
|
15 |
|
return $view->getData(); |
516
|
|
|
} |
517
|
|
|
|
518
|
6 |
|
if ($form->isValid() || !$form->isSubmitted()) { |
519
|
|
|
return $form; |
520
|
|
|
} |
521
|
|
|
|
522
|
6 |
|
return $this->exceptionWrapperHandler->wrap( |
523
|
|
|
[ |
524
|
6 |
|
'status_code' => $this->failedValidationCode, |
525
|
6 |
|
'message' => 'Validation Failed', |
526
|
6 |
|
'errors' => $form, |
527
|
|
|
] |
528
|
6 |
|
); |
529
|
|
|
} |
530
|
|
|
} |
531
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.