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

api-platform / core / 17327553156

29 Aug 2025 03:13PM UTC coverage: 22.588% (-0.03%) from 22.622%
17327553156

push

github

web-flow
fix(laravel): serialization issue with camelCase relation (#7356)

fixes #7344

0 of 76 new or added lines in 9 files covered. (0.0%)

11415 existing lines in 372 files now uncovered.

11181 of 49499 relevant lines covered (22.59%)

23.68 hits per line

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

93.94
/src/Validator/Exception/ValidationException.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\Validator\Exception;
15

16
use ApiPlatform\Metadata\ApiProperty;
17
use ApiPlatform\Metadata\Error as ErrorOperation;
18
use ApiPlatform\Metadata\ErrorResource;
19
use ApiPlatform\Metadata\Exception\HttpExceptionInterface;
20
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
21
use ApiPlatform\Metadata\Exception\RuntimeException;
22
use ApiPlatform\Metadata\Util\CompositeIdentifierParser;
23
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface as SymfonyHttpExceptionInterface;
24
use Symfony\Component\Serializer\Annotation\Groups;
25
use Symfony\Component\Serializer\Annotation\SerializedName;
26
use Symfony\Component\Validator\ConstraintViolationList;
27
use Symfony\Component\Validator\ConstraintViolationListInterface;
28
use Symfony\Component\WebLink\Link;
29

30
/**
31
 * Thrown when a validation error occurs.
32
 *
33
 * @author Kévin Dunglas <dunglas@gmail.com>
34
 */
35
#[ErrorResource(
UNCOV
36
    uriTemplate: '/validation_errors/{id}',
UNCOV
37
    status: 422,
UNCOV
38
    uriVariables: ['id'],
UNCOV
39
    openapi: false,
UNCOV
40
    outputFormats: [
UNCOV
41
        'jsonapi' => ['application/vnd.api+json'],
UNCOV
42
        'jsonld' => ['application/ld+json'],
UNCOV
43
        'json' => ['application/problem+json', 'application/json'],
UNCOV
44
        'xml' => ['application/xml', 'text/xml'],
UNCOV
45
    ],
UNCOV
46
    provider: 'api_platform.validator.state.error_provider',
UNCOV
47
    shortName: 'ConstraintViolation',
UNCOV
48
    description: 'Unprocessable entity',
UNCOV
49
    operations: [
UNCOV
50
        new ErrorOperation(
UNCOV
51
            name: '_api_validation_errors_problem',
UNCOV
52
            outputFormats: [
UNCOV
53
                'json' => ['application/problem+json'],
UNCOV
54
            ],
UNCOV
55
            normalizationContext: [
UNCOV
56
                'groups' => ['json'],
UNCOV
57
                'ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString', 'previous'],
UNCOV
58
                'skip_null_values' => true,
UNCOV
59
            ]
UNCOV
60
        ),
UNCOV
61
        new ErrorOperation(
UNCOV
62
            name: '_api_validation_errors_hydra',
UNCOV
63
            outputFormats: ['jsonld' => ['application/problem+json', 'application/ld+json']],
UNCOV
64
            links: [new Link(rel: 'http://www.w3.org/ns/json-ld#error', href: 'http://www.w3.org/ns/hydra/error')],
UNCOV
65
            normalizationContext: [
UNCOV
66
                'groups' => ['jsonld'],
UNCOV
67
                'ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString', 'previous'],
UNCOV
68
                'skip_null_values' => true,
UNCOV
69
            ]
UNCOV
70
        ),
UNCOV
71
        new ErrorOperation(
UNCOV
72
            name: '_api_validation_errors_jsonapi',
UNCOV
73
            outputFormats: ['jsonapi' => ['application/vnd.api+json']],
UNCOV
74
            normalizationContext: [
UNCOV
75
                'disable_json_schema_serializer_groups' => false,
UNCOV
76
                'groups' => ['jsonapi'],
UNCOV
77
                'skip_null_values' => true,
UNCOV
78
                'ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString', 'previous'],
UNCOV
79
            ]
UNCOV
80
        ),
UNCOV
81
        new ErrorOperation(
UNCOV
82
            name: '_api_validation_errors_xml',
UNCOV
83
            outputFormats: [
UNCOV
84
                'xml' => ['application/xml', 'text/xml'],
UNCOV
85
            ],
UNCOV
86
            normalizationContext: [
UNCOV
87
                'groups' => ['json'],
UNCOV
88
                'ignored_attributes' => ['trace', 'file', 'line', 'code', 'message', 'traceAsString', 'previous'],
UNCOV
89
                'skip_null_values' => true,
UNCOV
90
            ]
UNCOV
91
        ),
UNCOV
92
    ],
UNCOV
93
    graphQlOperations: []
UNCOV
94
)]
95
#[ApiProperty(property: 'traceAsString', hydra: false)]
96
#[ApiProperty(property: 'string', hydra: false)]
97
class ValidationException extends RuntimeException implements ConstraintViolationListAwareExceptionInterface, \Stringable, ProblemExceptionInterface, HttpExceptionInterface, SymfonyHttpExceptionInterface
98
{
99
    private int $status = 422;
100
    protected ?string $errorTitle = null;
101
    private array|ConstraintViolationListInterface $constraintViolationList = [];
102

103
    public function __construct(string|ConstraintViolationListInterface $message = new ConstraintViolationList(), string|int|null $code = null, int|\Throwable|null $previous = null, \Throwable|string|null $errorTitle = null)
104
    {
UNCOV
105
        $this->errorTitle = $errorTitle;
86✔
106

UNCOV
107
        if ($message instanceof ConstraintViolationListInterface) {
86✔
UNCOV
108
            $this->constraintViolationList = $message;
86✔
UNCOV
109
            parent::__construct($this->__toString(), $code ?? 0, $previous);
86✔
110

UNCOV
111
            return;
86✔
112
        }
113

114
        trigger_deprecation('api_platform/core', '5.0', \sprintf('The "%s" exception will have a "%s" first argument in 5.x.', self::class, ConstraintViolationListInterface::class));
×
115
        parent::__construct($message ?: $this->__toString(), $code ?? 0, $previous);
×
116
    }
117

118
    public function getId(): string
119
    {
UNCOV
120
        $ids = [];
64✔
UNCOV
121
        foreach ($this->getConstraintViolationList() as $violation) {
64✔
UNCOV
122
            $ids[] = $violation->getCode();
64✔
123
        }
124

UNCOV
125
        $id = 1 < \count($ids) ? CompositeIdentifierParser::stringify(identifiers: $ids) : ($ids[0] ?? null);
64✔
126

UNCOV
127
        if (!$id) {
64✔
UNCOV
128
            return spl_object_hash($this);
2✔
129
        }
130

UNCOV
131
        return $id;
62✔
132
    }
133

134
    #[Groups(['jsonld'])]
135
    #[ApiProperty(writable: false, initializable: false)]
136
    public function getDescription(): string
137
    {
UNCOV
138
        return $this->detail;
64✔
139
    }
140

141
    #[Groups(['jsonld', 'json', 'jsonapi'])]
142
    #[ApiProperty(writable: false, initializable: false)]
143
    public function getType(): string
144
    {
UNCOV
145
        return '/validation_errors/'.$this->getId();
64✔
146
    }
147

148
    #[Groups(['jsonld', 'json', 'jsonapi'])]
149
    #[ApiProperty(writable: false, initializable: false)]
150
    public function getTitle(): ?string
151
    {
UNCOV
152
        return $this->errorTitle ?? 'An error occurred';
84✔
153
    }
154

155
    #[Groups(['jsonld', 'json', 'jsonapi'])]
156
    #[ApiProperty(writable: false, initializable: false)]
157
    private string $detail;
158

159
    public function getDetail(): ?string
160
    {
UNCOV
161
        return $this->detail;
64✔
162
    }
163

164
    public function setDetail(string $detail): void
165
    {
UNCOV
166
        $this->detail = $detail;
64✔
167
    }
168

169
    #[Groups(['jsonld', 'json', 'jsonapi'])]
170
    public function getStatus(): ?int
171
    {
UNCOV
172
        return $this->status;
84✔
173
    }
174

175
    public function setStatus(int $status): void
176
    {
UNCOV
177
        $this->status = $status;
64✔
178
    }
179

180
    #[Groups(['jsonld', 'json', 'jsonapi'])]
181
    #[ApiProperty(writable: false, initializable: false)]
182
    public function getInstance(): ?string
183
    {
UNCOV
184
        return null;
64✔
185
    }
186

187
    #[SerializedName('violations')]
188
    #[Groups(['json', 'jsonld'])]
189
    #[ApiProperty(
UNCOV
190
        jsonldContext: ['@type' => 'ConstraintViolationList'],
UNCOV
191
        schema: [
UNCOV
192
            'type' => 'array',
UNCOV
193
            'items' => [
UNCOV
194
                'type' => 'object',
UNCOV
195
                'properties' => [
UNCOV
196
                    'propertyPath' => ['type' => 'string', 'description' => 'The property path of the violation'],
UNCOV
197
                    'message' => ['type' => 'string', 'description' => 'The message associated with the violation'],
UNCOV
198
                ],
UNCOV
199
            ],
UNCOV
200
        ]
UNCOV
201
    )]
202
    public function getConstraintViolationList(): ConstraintViolationListInterface
203
    {
UNCOV
204
        return $this->constraintViolationList;
86✔
205
    }
206

207
    public function __toString(): string
208
    {
UNCOV
209
        $message = '';
86✔
UNCOV
210
        foreach ($this->getConstraintViolationList() as $violation) {
86✔
UNCOV
211
            if ('' !== $message) {
66✔
UNCOV
212
                $message .= "\n";
14✔
213
            }
UNCOV
214
            if ($propertyPath = $violation->getPropertyPath()) {
66✔
UNCOV
215
                $message .= "$propertyPath: ";
66✔
216
            }
217

UNCOV
218
            $message .= $violation->getMessage();
66✔
219
        }
220

UNCOV
221
        return $message;
86✔
222
    }
223

224
    public function getStatusCode(): int
225
    {
UNCOV
226
        return $this->status;
64✔
227
    }
228

229
    public function getHeaders(): array
230
    {
UNCOV
231
        return [];
64✔
232
    }
233
}
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