Passed
Push — master ( 2bb6f9...3a8224 )
by Kévin
06:14 queued 02:58
created

DeserializeListener::onKernelRequest()   B

Complexity

Conditions 11
Paths 6

Size

Total Lines 39
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 25
nc 6
nop 1
dl 0
loc 39
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Api\FormatMatcher;
17
use ApiPlatform\Core\Api\FormatsProviderInterface;
18
use ApiPlatform\Core\Exception\InvalidArgumentException;
19
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
20
use ApiPlatform\Core\Util\RequestAttributesExtractor;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
23
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
24
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
25
use Symfony\Component\Serializer\SerializerInterface;
26
27
/**
28
 * Updates the entity retrieved by the data provider with data contained in the request body.
29
 *
30
 * @author Kévin Dunglas <[email protected]>
31
 */
32
final class DeserializeListener
33
{
34
    private $serializer;
35
    private $serializerContextBuilder;
36
    private $formats = [];
37
    private $formatsProvider;
38
    private $formatMatcher;
39
40
    /**
41
     * @throws InvalidArgumentException
42
     */
43
    public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */ $formatsProvider)
44
    {
45
        $this->serializer = $serializer;
46
        $this->serializerContextBuilder = $serializerContextBuilder;
47
        if (\is_array($formatsProvider)) {
48
            @trigger_error('Using an array as formats provider is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3', E_USER_DEPRECATED);
49
            $this->formats = $formatsProvider;
50
        } else {
51
            if (!$formatsProvider instanceof FormatsProviderInterface) {
52
                throw new InvalidArgumentException(sprintf('The "$formatsProvider" argument is expected to be an implementation of the "%s" interface.', FormatsProviderInterface::class));
53
            }
54
55
            $this->formatsProvider = $formatsProvider;
56
        }
57
    }
58
59
    /**
60
     * Deserializes the data sent in the requested format.
61
     */
62
    public function onKernelRequest(GetResponseEvent $event)
63
    {
64
        $request = $event->getRequest();
65
        $method = $request->getMethod();
66
67
        if (
68
            'DELETE' === $method
69
            || $request->isMethodSafe(false)
70
            || !($attributes = RequestAttributesExtractor::extractAttributes($request))
71
            || !$attributes['receive']
72
            || (
73
                    '' === ($requestContent = $request->getContent())
74
                    && ('POST' === $method || 'PUT' === $method)
75
               )
76
        ) {
77
            return;
78
        }
79
80
        $context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes);
81
        if (false === $context['input_class']) {
82
            return;
83
        }
84
85
        // BC check to be removed in 3.0
86
        if (null !== $this->formatsProvider) {
87
            $this->formats = $this->formatsProvider->getFormatsFromAttributes($attributes);
88
        }
89
        $this->formatMatcher = new FormatMatcher($this->formats);
90
        $format = $this->getFormat($request);
91
92
        $data = $request->attributes->get('data');
93
        if (null !== $data) {
94
            $context[AbstractNormalizer::OBJECT_TO_POPULATE] = $data;
95
        }
96
97
        $request->attributes->set(
98
            'data',
99
            $this->serializer->deserialize(
100
                $requestContent, $context['input_class'], $format, $context
101
            )
102
        );
103
    }
104
105
    /**
106
     * Extracts the format from the Content-Type header and check that it is supported.
107
     *
108
     * @throws NotAcceptableHttpException
109
     */
110
    private function getFormat(Request $request): string
111
    {
112
        /**
113
         * @var string|null
114
         */
115
        $contentType = $request->headers->get('CONTENT_TYPE');
116
        if (null === $contentType) {
0 ignored issues
show
introduced by
The condition null === $contentType is always false.
Loading history...
117
            throw new NotAcceptableHttpException('The "Content-Type" header must exist.');
118
        }
119
120
        $format = $this->formatMatcher->getFormat($contentType);
121
        if (null === $format || !isset($this->formats[$format])) {
122
            $supportedMimeTypes = [];
123
            foreach ($this->formats as $mimeTypes) {
124
                foreach ($mimeTypes as $mimeType) {
125
                    $supportedMimeTypes[] = $mimeType;
126
                }
127
            }
128
129
            throw new NotAcceptableHttpException(sprintf(
130
                'The content-type "%s" is not supported. Supported MIME types are "%s".',
131
                $contentType,
132
                implode('", "', $supportedMimeTypes)
133
            ));
134
        }
135
136
        return $format;
137
    }
138
}
139