• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 18338852783

08 Oct 2025 08:37AM UTC coverage: 24.561% (+0.001%) from 24.56%
18338852783

push

github

web-flow
fix(symfony): ensure the kernel is booted before using `KernelBrowser::loginUser()` (#7446)

1 of 1 new or added line in 1 file covered. (100.0%)

329 existing lines in 15 files now uncovered.

14003 of 57012 relevant lines covered (24.56%)

26.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.14
/src/State/Provider/ContentNegotiationProvider.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.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
declare(strict_types=1);
13

14
namespace ApiPlatform\State\Provider;
15

16
use ApiPlatform\Metadata\Error as ErrorOperation;
17
use ApiPlatform\Metadata\HttpOperation;
18
use ApiPlatform\Metadata\Operation;
19
use ApiPlatform\Metadata\Util\ContentNegotiationTrait;
20
use ApiPlatform\State\ProviderInterface;
21
use ApiPlatform\State\StopwatchAwareInterface;
22
use ApiPlatform\State\StopwatchAwareTrait;
23
use Negotiation\Negotiator;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
26

27
final class ContentNegotiationProvider implements ProviderInterface, StopwatchAwareInterface
28
{
29
    use ContentNegotiationTrait;
30
    use StopwatchAwareTrait;
31

32
    /**
33
     * @param array<string, string[]> $formats
34
     * @param array<string, string[]> $errorFormats
35
     */
36
    public function __construct(private readonly ?ProviderInterface $decorated = null, ?Negotiator $negotiator = null, private readonly array $formats = [], private readonly array $errorFormats = [])
37
    {
38
        $this->negotiator = $negotiator ?? new Negotiator();
677✔
39
    }
40

41
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
42
    {
43
        if (!($request = $context['request'] ?? null) || !$operation instanceof HttpOperation) {
664✔
44
            return $this->decorated?->provide($operation, $uriVariables, $context);
×
45
        }
46

47
        $this->stopwatch?->start('api_platform.provider.content_negotiation');
664✔
48
        $isErrorOperation = $operation instanceof ErrorOperation;
664✔
49

50
        $formats = $operation->getOutputFormats() ?? ($isErrorOperation ? $this->errorFormats : $this->formats);
664✔
51
        $this->addRequestFormats($request, $formats);
664✔
52
        $request->attributes->set('input_format', $this->getInputFormat($operation, $request));
664✔
53
        $request->setRequestFormat($this->getRequestFormat($request, $formats, !$isErrorOperation));
662✔
54
        $this->stopwatch?->stop('api_platform.provider.content_negotiation');
662✔
55

56
        return $this->decorated?->provide($operation, $uriVariables, $context);
662✔
57
    }
58

59
    /**
60
     * Adds the supported formats to the request.
61
     *
62
     * This is necessary for {@see Request::getMimeType} and {@see Request::getMimeTypes} to work.
63
     * Note that this replaces default mime types configured at {@see Request::initializeFormats}
64
     *
65
     * @param array<string, string|string[]> $formats
66
     */
67
    private function addRequestFormats(Request $request, array $formats): void
68
    {
69
        foreach ($formats as $format => $mimeTypes) {
664✔
70
            $request->setFormat($format, (array) $mimeTypes);
664✔
71
        }
72
    }
73

74
    /**
75
     * Flattened the list of MIME types.
76
     *
77
     * @param array<string, string|string[]> $formats
78
     *
79
     * @return array<string, string>
80
     */
81
    private function flattenMimeTypes(array $formats): array
82
    {
83
        $flattenedMimeTypes = [];
662✔
84
        foreach ($formats as $format => $mimeTypes) {
662✔
85
            foreach ($mimeTypes as $mimeType) {
662✔
86
                $flattenedMimeTypes[$mimeType] = $format;
662✔
87
            }
88
        }
89

90
        return $flattenedMimeTypes;
662✔
91
    }
92

93
    /**
94
     * Extracts the format from the Content-Type header and check that it is supported.
95
     *
96
     * @throws UnsupportedMediaTypeHttpException
97
     */
98
    private function getInputFormat(HttpOperation $operation, Request $request): ?string
99
    {
100
        if (
101
            false === ($input = $operation->getInput())
664✔
102
            || (\is_array($input) && null === $input['class'])
664✔
103
            || false === $operation->canDeserialize()
664✔
104
        ) {
105
            return null;
294✔
106
        }
107

108
        $contentType = $request->headers->get('CONTENT_TYPE');
380✔
109
        if (null === $contentType || '' === $contentType) {
380✔
110
            return null;
345✔
111
        }
112

113
        $formats = $operation->getInputFormats() ?? [];
37✔
114
        if ($format = $this->getMimeTypeFormat($contentType, $formats)) {
37✔
115
            return $format;
33✔
116
        }
117

118
        if (!$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) {
6✔
119
            $supportedMimeTypes = [];
4✔
120
            foreach ($formats as $mimeTypes) {
4✔
121
                foreach ($mimeTypes as $mimeType) {
2✔
122
                    $supportedMimeTypes[] = $mimeType;
2✔
123
                }
124
            }
125

126
            throw new UnsupportedMediaTypeHttpException(\sprintf('The content-type "%s" is not supported. Supported MIME types are "%s".', $contentType, implode('", "', $supportedMimeTypes)));
4✔
127
        }
128

UNCOV
129
        return null;
2✔
130
    }
131
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc