Completed
Push — master ( acec7d...a3b62e )
by Antoine
06:05 queued 02:58
created

DeserializeListener::onKernelRequest()   C

Complexity

Conditions 8
Paths 3

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 18
nc 3
nop 1
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
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
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\EventListener;
15
16
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
17
use ApiPlatform\Core\Util\RequestAttributesExtractor;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
20
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
21
use Symfony\Component\Serializer\SerializerInterface;
22
23
/**
24
 * Updates the entity retrieved by the data provider with data contained in the request body.
25
 *
26
 * @author Kévin Dunglas <[email protected]>
27
 */
28
final class DeserializeListener
29
{
30
    private $serializer;
31
    private $serializerContextBuilder;
32
    private $formats;
33
34
    public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, array $formats)
35
    {
36
        $this->serializer = $serializer;
37
        $this->serializerContextBuilder = $serializerContextBuilder;
38
        $this->formats = $formats;
39
    }
40
41
    /**
42
     * Deserializes the data sent in the requested format.
43
     *
44
     * @param GetResponseEvent $event
45
     */
46
    public function onKernelRequest(GetResponseEvent $event)
47
    {
48
        $request = $event->getRequest();
49
        if (
50
            $request->isMethodSafe(false)
51
            || $request->isMethod(Request::METHOD_DELETE)
52
            || !($attributes = RequestAttributesExtractor::extractAttributes($request))
53
            || !$attributes['receive']
54
            || ('' === ($requestContent = $request->getContent()) && $request->isMethod(Request::METHOD_PUT))
55
        ) {
56
            return;
57
        }
58
59
        $format = $this->getFormat($request);
60
        $context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes);
61
62
        $data = $request->attributes->get('data');
63
        if (null !== $data) {
64
            $context['object_to_populate'] = $data;
65
        }
66
67
        $request->attributes->set(
68
            'data',
69
            $this->serializer->deserialize(
70
                $requestContent, $attributes['resource_class'], $format, $context
71
            )
72
        );
73
    }
74
75
    /**
76
     * Extracts the format from the Content-Type header and check that it is supported.
77
     *
78
     * @param Request $request
79
     *
80
     * @throws NotAcceptableHttpException
81
     *
82
     * @return string
83
     */
84
    private function getFormat(Request $request): string
85
    {
86
        $contentType = $request->headers->get('CONTENT_TYPE');
87
        if (null === $contentType) {
88
            throw new NotAcceptableHttpException('The "Content-Type" header must exist.');
89
        }
90
91
        $format = $request->getFormat($contentType);
92
        if (null === $format || !isset($this->formats[$format])) {
93
            $supportedMimeTypes = [];
94
            foreach ($this->formats as $mimeTypes) {
95
                foreach ($mimeTypes as $mimeType) {
96
                    $supportedMimeTypes[] = $mimeType;
97
                }
98
            }
99
100
            throw new NotAcceptableHttpException(sprintf(
101
                'The content-type "%s" is not supported. Supported MIME types are "%s".',
102
                $contentType,
103
                implode('", "', $supportedMimeTypes)
104
            ));
105
        }
106
107
        return $format;
108
    }
109
}
110