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

api-platform / core / 20545070147

27 Dec 2025 10:15PM UTC coverage: 28.855% (+3.7%) from 25.192%
20545070147

push

github

soyuka
ci: upgrade to phpunit 12

Remove soyuka/phpunit fork from all composer.json files and upgrade to
PHPUnit 12.2. Update CI workflow to install PHPUnit before other steps
and configure MongoDB conditional execution. Migrate tests from Prophecy
to PHPUnit native mocking in FieldsBuilderTest and Symfony event listener
tests. Remove unused dataprovider and fix warnings.

0 of 84 new or added lines in 8 files covered. (0.0%)

534 existing lines in 34 files now uncovered.

16760 of 58083 relevant lines covered (28.86%)

78.25 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();
2,000✔
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) {
1,985✔
44
            return $this->decorated?->provide($operation, $uriVariables, $context);
×
45
        }
46

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

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

56
        return $this->decorated?->provide($operation, $uriVariables, $context);
1,983✔
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) {
1,985✔
70
            $request->setFormat($format, (array) $mimeTypes);
1,985✔
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 = [];
1,983✔
84
        foreach ($formats as $format => $mimeTypes) {
1,983✔
85
            foreach ($mimeTypes as $mimeType) {
1,983✔
86
                $flattenedMimeTypes[$mimeType] = $format;
1,983✔
87
            }
88
        }
89

90
        return $flattenedMimeTypes;
1,983✔
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())
1,985✔
102
            || (\is_array($input) && null === $input['class'])
1,985✔
103
            || false === $operation->canDeserialize()
1,985✔
104
        ) {
105
            return null;
1,205✔
106
        }
107

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

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

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

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

UNCOV
129
        return null;
5✔
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

© 2026 Coveralls, Inc