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

api-platform / core / 15133993414

20 May 2025 09:30AM UTC coverage: 26.313% (-1.2%) from 27.493%
15133993414

Pull #7161

github

web-flow
Merge e2c03d45f into 5459ba375
Pull Request #7161: fix(metadata): infer parameter string type from schema

0 of 2 new or added lines in 1 file covered. (0.0%)

11019 existing lines in 363 files now uncovered.

12898 of 49018 relevant lines covered (26.31%)

34.33 hits per line

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

92.62
/src/Metadata/ApiProperty.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\Metadata;
15

16
use Symfony\Component\PropertyInfo\Type;
17
use Symfony\Component\Serializer\Attribute\Context;
18
use Symfony\Component\Serializer\Attribute\Groups;
19
use Symfony\Component\Serializer\Attribute\Ignore;
20
use Symfony\Component\Serializer\Attribute\MaxDepth;
21
use Symfony\Component\Serializer\Attribute\SerializedName;
22
use Symfony\Component\Serializer\Attribute\SerializedPath;
23

24
/**
25
 * ApiProperty annotation.
26
 *
27
 * @author Kévin Dunglas <dunglas@gmail.com>
28
 */
29
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_PARAMETER | \Attribute::TARGET_CLASS_CONSTANT | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
30
final class ApiProperty
31
{
32
    private ?array $types;
33
    private ?array $serialize;
34

35
    /**
36
     * @param bool|null                                                                                                                                   $readableLink            https://api-platform.com/docs/core/serialization/#force-iri-with-relations-of-the-same-type-parentchilds-relations
37
     * @param bool|null                                                                                                                                   $writableLink            https://api-platform.com/docs/core/serialization/#force-iri-with-relations-of-the-same-type-parentchilds-relations
38
     * @param bool|null                                                                                                                                   $required                https://api-platform.com/docs/admin/validation/#client-side-validation
39
     * @param bool|null                                                                                                                                   $identifier              https://api-platform.com/docs/core/identifiers/
40
     * @param mixed                                                                                                                                       $example                 https://api-platform.com/docs/core/openapi/#using-the-openapi-and-swagger-contexts
41
     * @param string|null                                                                                                                                 $deprecationReason       https://api-platform.com/docs/core/deprecations/#deprecating-resource-classes-operations-and-properties
42
     * @param bool|null                                                                                                                                   $fetchEager              https://api-platform.com/docs/core/performance/#eager-loading
43
     * @param array|null                                                                                                                                  $jsonldContext           https://api-platform.com/docs/core/extending-jsonld-context/#extending-json-ld-and-hydra-contexts
44
     * @param array|null                                                                                                                                  $openapiContext          https://api-platform.com/docs/core/openapi/#using-the-openapi-and-swagger-contexts
45
     * @param bool|null                                                                                                                                   $push                    https://api-platform.com/docs/core/push-relations/
46
     * @param string|\Stringable|null                                                                                                                     $security                https://api-platform.com/docs/core/security
47
     * @param string|\Stringable|null                                                                                                                     $securityPostDenormalize https://api-platform.com/docs/core/security/#executing-access-control-rules-after-denormalization
48
     * @param string[]                                                                                                                                    $types                   the RDF types of this property
49
     * @param string[]                                                                                                                                    $iris
50
     * @param Type[]                                                                                                                                      $builtinTypes
51
     * @param string|null                                                                                                                                 $uriTemplate             (experimental) whether to return the subRessource collection IRI instead of an iterable of IRI
52
     * @param string|null                                                                                                                                 $property                The property name
53
     * @param Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth|array<array-key, Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth> $serialize               Serializer attributes
54
     */
55
    public function __construct(
56
        private ?string $description = null,
57
        private ?bool $readable = null,
58
        private ?bool $writable = null,
59
        private ?bool $readableLink = null,
60
        private ?bool $writableLink = null,
61
        private ?bool $required = null,
62
        private ?bool $identifier = null,
63
        private mixed $default = null,
64
        private mixed $example = null,
65
        /**
66
         * The `deprecationReason` option deprecates the current operation with a deprecation message.
67
         *
68
         * <div data-code-selector>
69
         *
70
         * ```php
71
         * <?php
72
         * // api/src/Entity/Review.php
73
         * use ApiPlatform\Metadata\ApiProperty;
74
         * use ApiPlatform\Metadata\ApiResource;
75
         *
76
         * #[ApiResource]
77
         * class Review
78
         * {
79
         *     #[ApiProperty(deprecationReason: "Use the rating property instead")]
80
         *     public string $letter;
81
         * }
82
         * ```
83
         *
84
         * ```yaml
85
         * # api/config/api_platform/properties.yaml
86
         * properties:
87
         *     App\Entity\Review:
88
         *         letter:
89
         *             deprecationReason: 'Create a Book instead'
90
         * ```
91
         *
92
         * ```xml
93
         * <?xml version="1.0" encoding="UTF-8" ?>
94
         * <!-- api/config/api_platform/properties.xml -->
95
         *
96
         * <properties
97
         *         xmlns="https://api-platform.com/schema/metadata/properties-3.0"
98
         *         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
99
         *         xsi:schemaLocation="https://api-platform.com/schema/metadata/properties-3.0
100
         *         https://api-platform.com/schema/metadata/properties-3.0.xsd">
101
         *     <property resource="App\Entity\Review" name="letter" deprecationReason="Create a Book instead" />
102
         * </properties>
103
         * ```
104
         *
105
         * </div>
106
         *
107
         * - With JSON-lD / Hydra, [an `owl:deprecated` annotation property](https://www.w3.org/TR/owl2-syntax/#Annotation_Properties) will be added to the appropriate data structure
108
         * - With Swagger / OpenAPI, [a `deprecated` property](https://swagger.io/docs/specification/2-0/paths-and-operations/) will be added
109
         * - With GraphQL, the [`isDeprecated` and `deprecationReason` properties](https://facebook.github.io/graphql/June2018/#sec-Deprecation) will be added to the schema
110
         */
111
        private ?string $deprecationReason = null,
112
        private ?bool $fetchable = null,
113
        private ?bool $fetchEager = null,
114
        private ?array $jsonldContext = null,
115
        private ?array $openapiContext = null,
116
        private ?array $jsonSchemaContext = null,
117
        private ?bool $push = null,
118
        /**
119
         * The `security` option defines the access to the current property, on normalization process, based on Symfony Security.
120
         * It receives an `object` variable related to the current object, and a `property` variable related to the current property.
121
         *
122
         * <div data-code-selector>
123
         *
124
         * ```php
125
         * <?php
126
         * // api/src/Entity/Review.php
127
         * use ApiPlatform\Metadata\ApiProperty;
128
         * use ApiPlatform\Metadata\ApiResource;
129
         *
130
         * #[ApiResource]
131
         * class Review
132
         * {
133
         *     #[ApiProperty(security: 'is_granted("ROLE_ADMIN")')]
134
         *     public string $letter;
135
         * }
136
         * ```
137
         *
138
         * ```yaml
139
         * # api/config/api_platform/properties.yaml
140
         * properties:
141
         *     App\Entity\Review:
142
         *         letter:
143
         *             security: 'is_granted("ROLE_ADMIN")'
144
         * ```
145
         *
146
         * ```xml
147
         * <?xml version="1.0" encoding="UTF-8" ?>
148
         * <!-- api/config/api_platform/properties.xml -->
149
         *
150
         * <properties
151
         *         xmlns="https://api-platform.com/schema/metadata/properties-3.0"
152
         *         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
153
         *         xsi:schemaLocation="https://api-platform.com/schema/metadata/properties-3.0
154
         *         https://api-platform.com/schema/metadata/properties-3.0.xsd">
155
         *     <property resource="App\Entity\Review" name="letter" security="is_granted('ROLE_ADMIN')" />
156
         * </properties>
157
         * ```
158
         *
159
         * </div>
160
         */
161
        private string|\Stringable|null $security = null,
162
        /**
163
         * The `securityPostDenormalize` option defines access to the current property after the denormalization process, based on Symfony Security.
164
         * It receives an `object` variable related to the current object, and a `property` variable related to the current property.
165
         *
166
         * <div data-code-selector>
167
         *
168
         * ```php
169
         * <?php
170
         * // api/src/Entity/Review.php
171
         * use ApiPlatform\Metadata\ApiProperty;
172
         * use ApiPlatform\Metadata\ApiResource;
173
         *
174
         * #[ApiResource]
175
         * class Review
176
         * {
177
         *     #[ApiProperty(securityPostDenormalize: 'is_granted("ROLE_ADMIN")')]
178
         *     public string $letter;
179
         * }
180
         * ```
181
         *
182
         * ```yaml
183
         * # api/config/api_platform/properties.yaml
184
         * properties:
185
         *     App\Entity\Review:
186
         *         letter:
187
         *             securityPostDenormalize: 'is_granted("ROLE_ADMIN")'
188
         * ```
189
         *
190
         * ```xml
191
         * <?xml version="1.0" encoding="UTF-8" ?>
192
         * <!-- api/config/api_platform/properties.xml -->
193
         *
194
         * <properties
195
         *         xmlns="https://api-platform.com/schema/metadata/properties-3.0"
196
         *         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
197
         *         xsi:schemaLocation="https://api-platform.com/schema/metadata/properties-3.0
198
         *         https://api-platform.com/schema/metadata/properties-3.0.xsd">
199
         *     <property resource="App\Entity\Review" name="letter" securityPostDenormalize="is_granted('ROLE_ADMIN')" />
200
         * </properties>
201
         * ```
202
         *
203
         * </div>
204
         */
205
        private string|\Stringable|null $securityPostDenormalize = null,
206
        array|string|null $types = null,
207
        /*
208
         * The related php types.
209
         */
210
        private ?array $builtinTypes = null,
211
        private ?array $schema = null,
212
        private ?bool $initializable = null,
213
        private $iris = null,
214
        private ?bool $genId = null,
215
        private ?string $uriTemplate = null,
216
        private ?string $property = null,
217
        private ?string $policy = null,
218
        array|Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth|null $serialize = null,
219
        /**
220
         * Whether to document this property as a hydra:supportedProperty.
221
         */
222
        private ?bool $hydra = null,
223
        private array $extraProperties = [],
224
    ) {
UNCOV
225
        $this->types = \is_string($types) ? (array) $types : $types;
295✔
UNCOV
226
        $this->serialize = \is_array($serialize) ? $serialize : [$serialize];
295✔
227
    }
228

229
    public function getProperty(): ?string
230
    {
UNCOV
231
        return $this->property;
70✔
232
    }
233

234
    public function withProperty(string $property): static
235
    {
UNCOV
236
        $self = clone $this;
5✔
UNCOV
237
        $self->property = $property;
5✔
238

UNCOV
239
        return $self;
5✔
240
    }
241

242
    public function getDescription(): ?string
243
    {
UNCOV
244
        return $this->description;
350✔
245
    }
246

247
    public function withDescription(string $description): static
248
    {
UNCOV
249
        $self = clone $this;
108✔
UNCOV
250
        $self->description = $description;
108✔
251

UNCOV
252
        return $self;
108✔
253
    }
254

255
    public function isReadable(): ?bool
256
    {
UNCOV
257
        return $this->readable;
891✔
258
    }
259

260
    public function withReadable(bool $readable): static
261
    {
UNCOV
262
        $self = clone $this;
263✔
UNCOV
263
        $self->readable = $readable;
263✔
264

UNCOV
265
        return $self;
263✔
266
    }
267

268
    public function isWritable(): ?bool
269
    {
UNCOV
270
        return $this->writable;
432✔
271
    }
272

273
    public function withWritable(bool $writable): static
274
    {
UNCOV
275
        $self = clone $this;
260✔
UNCOV
276
        $self->writable = $writable;
260✔
277

UNCOV
278
        return $self;
260✔
279
    }
280

281
    public function isReadableLink(): ?bool
282
    {
UNCOV
283
        return $this->readableLink;
343✔
284
    }
285

286
    public function withReadableLink(bool $readableLink): static
287
    {
UNCOV
288
        $self = clone $this;
101✔
UNCOV
289
        $self->readableLink = $readableLink;
101✔
290

UNCOV
291
        return $self;
101✔
292
    }
293

294
    public function isWritableLink(): ?bool
295
    {
UNCOV
296
        return $this->writableLink;
150✔
297
    }
298

299
    public function withWritableLink(bool $writableLink): static
300
    {
UNCOV
301
        $self = clone $this;
100✔
UNCOV
302
        $self->writableLink = $writableLink;
100✔
303

UNCOV
304
        return $self;
100✔
305
    }
306

307
    public function isRequired(): ?bool
308
    {
UNCOV
309
        return $this->required;
397✔
310
    }
311

312
    public function withRequired(bool $required): static
313
    {
UNCOV
314
        $self = clone $this;
287✔
UNCOV
315
        $self->required = $required;
287✔
316

UNCOV
317
        return $self;
287✔
318
    }
319

320
    public function isIdentifier(): ?bool
321
    {
UNCOV
322
        return $this->identifier;
271✔
323
    }
324

325
    public function withIdentifier(bool $identifier): static
326
    {
UNCOV
327
        $self = clone $this;
210✔
UNCOV
328
        $self->identifier = $identifier;
210✔
329

UNCOV
330
        return $self;
210✔
331
    }
332

333
    public function getDefault()
334
    {
UNCOV
335
        return $this->default;
241✔
336
    }
337

338
    public function withDefault($default): static
339
    {
UNCOV
340
        $self = clone $this;
93✔
UNCOV
341
        $self->default = $default;
93✔
342

UNCOV
343
        return $self;
93✔
344
    }
345

346
    public function getExample(): mixed
347
    {
UNCOV
348
        return $this->example;
240✔
349
    }
350

351
    public function withExample(mixed $example): static
352
    {
UNCOV
353
        $self = clone $this;
4✔
UNCOV
354
        $self->example = $example;
4✔
355

UNCOV
356
        return $self;
4✔
357
    }
358

359
    public function getDeprecationReason(): ?string
360
    {
UNCOV
361
        return $this->deprecationReason;
350✔
362
    }
363

364
    public function withDeprecationReason($deprecationReason): static
365
    {
UNCOV
366
        $self = clone $this;
9✔
UNCOV
367
        $self->deprecationReason = $deprecationReason;
9✔
368

UNCOV
369
        return $self;
9✔
370
    }
371

372
    public function isFetchable(): ?bool
373
    {
UNCOV
374
        return $this->fetchable;
70✔
375
    }
376

377
    public function withFetchable($fetchable): static
378
    {
379
        $self = clone $this;
×
380
        $self->fetchable = $fetchable;
×
381

382
        return $self;
×
383
    }
384

385
    public function getFetchEager(): ?bool
386
    {
UNCOV
387
        return $this->fetchEager;
75✔
388
    }
389

390
    public function withFetchEager($fetchEager): static
391
    {
392
        $self = clone $this;
×
393
        $self->fetchEager = $fetchEager;
×
394

395
        return $self;
×
396
    }
397

398
    public function getJsonldContext(): ?array
399
    {
UNCOV
400
        return $this->jsonldContext;
118✔
401
    }
402

403
    public function withJsonldContext($jsonldContext): static
404
    {
UNCOV
405
        $self = clone $this;
14✔
UNCOV
406
        $self->jsonldContext = $jsonldContext;
14✔
407

UNCOV
408
        return $self;
14✔
409
    }
410

411
    public function getOpenapiContext(): ?array
412
    {
UNCOV
413
        return $this->openapiContext;
242✔
414
    }
415

416
    public function withOpenapiContext($openapiContext): static
417
    {
UNCOV
418
        $self = clone $this;
5✔
UNCOV
419
        $self->openapiContext = $openapiContext;
5✔
420

UNCOV
421
        return $self;
5✔
422
    }
423

424
    public function getJsonSchemaContext(): ?array
425
    {
UNCOV
426
        return $this->jsonSchemaContext;
98✔
427
    }
428

429
    public function withJsonSchemaContext($jsonSchemaContext): static
430
    {
UNCOV
431
        $self = clone $this;
8✔
UNCOV
432
        $self->jsonSchemaContext = $jsonSchemaContext;
8✔
433

UNCOV
434
        return $self;
8✔
435
    }
436

437
    public function getPush(): ?bool
438
    {
UNCOV
439
        return $this->push;
135✔
440
    }
441

442
    public function withPush($push): static
443
    {
UNCOV
444
        $self = clone $this;
4✔
UNCOV
445
        $self->push = $push;
4✔
446

UNCOV
447
        return $self;
4✔
448
    }
449

450
    public function getSecurity(): ?string
451
    {
UNCOV
452
        return $this->security instanceof \Stringable ? (string) $this->security : $this->security;
846✔
453
    }
454

455
    public function withSecurity($security): static
456
    {
UNCOV
457
        $self = clone $this;
8✔
UNCOV
458
        $self->security = $security;
8✔
459

UNCOV
460
        return $self;
8✔
461
    }
462

463
    public function getSecurityPostDenormalize(): ?string
464
    {
UNCOV
465
        return $this->securityPostDenormalize instanceof \Stringable ? (string) $this->securityPostDenormalize : $this->securityPostDenormalize;
233✔
466
    }
467

468
    public function withSecurityPostDenormalize($securityPostDenormalize): static
469
    {
UNCOV
470
        $self = clone $this;
8✔
UNCOV
471
        $self->securityPostDenormalize = $securityPostDenormalize;
8✔
472

UNCOV
473
        return $self;
8✔
474
    }
475

476
    public function getTypes(): ?array
477
    {
UNCOV
478
        return $this->types;
287✔
479
    }
480

481
    /**
482
     * @param string[]|string $types
483
     */
484
    public function withTypes(array|string $types = []): static
485
    {
UNCOV
486
        $self = clone $this;
35✔
UNCOV
487
        $self->types = (array) $types;
35✔
488

UNCOV
489
        return $self;
35✔
490
    }
491

492
    /**
493
     * @return Type[]
494
     */
495
    public function getBuiltinTypes(): ?array
496
    {
UNCOV
497
        return $this->builtinTypes;
974✔
498
    }
499

500
    /**
501
     * @param Type[] $builtinTypes
502
     */
503
    public function withBuiltinTypes(array $builtinTypes = []): static
504
    {
UNCOV
505
        $self = clone $this;
269✔
UNCOV
506
        $self->builtinTypes = $builtinTypes;
269✔
507

UNCOV
508
        return $self;
269✔
509
    }
510

511
    public function getSchema(): ?array
512
    {
UNCOV
513
        return $this->schema;
329✔
514
    }
515

516
    public function withSchema(array $schema = []): static
517
    {
UNCOV
518
        $self = clone $this;
278✔
UNCOV
519
        $self->schema = $schema;
278✔
520

UNCOV
521
        return $self;
278✔
522
    }
523

524
    public function withInitializable(?bool $initializable): static
525
    {
UNCOV
526
        $self = clone $this;
240✔
UNCOV
527
        $self->initializable = $initializable;
240✔
528

UNCOV
529
        return $self;
240✔
530
    }
531

532
    public function isInitializable(): ?bool
533
    {
UNCOV
534
        return $this->initializable;
375✔
535
    }
536

537
    public function getExtraProperties(): ?array
538
    {
UNCOV
539
        return $this->extraProperties;
359✔
540
    }
541

542
    public function withExtraProperties(array $extraProperties = []): static
543
    {
UNCOV
544
        $self = clone $this;
75✔
UNCOV
545
        $self->extraProperties = $extraProperties;
75✔
546

UNCOV
547
        return $self;
75✔
548
    }
549

550
    /**
551
     * Gets IRI of this property.
552
     */
553
    public function getIris()
554
    {
UNCOV
555
        return $this->iris;
118✔
556
    }
557

558
    /**
559
     * Returns a new instance with the given IRI.
560
     *
561
     * @param string|string[] $iris
562
     */
563
    public function withIris(string|array $iris): static
564
    {
UNCOV
565
        $metadata = clone $this;
13✔
UNCOV
566
        $metadata->iris = (array) $iris;
13✔
567

UNCOV
568
        return $metadata;
13✔
569
    }
570

571
    /**
572
     * Whether to generate a skolem iri on anonymous resources.
573
     */
574
    public function getGenId()
575
    {
UNCOV
576
        return $this->genId;
414✔
577
    }
578

579
    public function withGenId(bool $genId): static
580
    {
UNCOV
581
        $metadata = clone $this;
6✔
UNCOV
582
        $metadata->genId = $genId;
6✔
583

UNCOV
584
        return $metadata;
6✔
585
    }
586

587
    /**
588
     * Whether to return the subRessource collection IRI instead of an iterable of IRI.
589
     *
590
     * @experimental
591
     */
592
    public function getUriTemplate(): ?string
593
    {
UNCOV
594
        return $this->uriTemplate;
450✔
595
    }
596

597
    public function withUriTemplate(?string $uriTemplate): static
598
    {
599
        $metadata = clone $this;
5✔
600
        $metadata->uriTemplate = $uriTemplate;
5✔
601

602
        return $metadata;
5✔
603
    }
604

605
    public function getPolicy(): ?string
606
    {
UNCOV
607
        return $this->policy;
811✔
608
    }
609

610
    public function withPolicy(?string $policy): static
611
    {
612
        $self = clone $this;
×
613
        $self->policy = $policy;
×
614

615
        return $self;
×
616
    }
617

618
    public function getSerialize(): ?array
619
    {
UNCOV
620
        return $this->serialize;
70✔
621
    }
622

623
    /**
624
     * @param Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth|array<array-key, Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth> $serialize
625
     */
626
    public function withSerialize(array|Context|Groups|Ignore|SerializedName|SerializedPath|MaxDepth $serialize): static
627
    {
UNCOV
628
        $self = clone $this;
70✔
UNCOV
629
        $self->serialize = (array) $serialize;
70✔
630

UNCOV
631
        return $self;
70✔
632
    }
633

634
    public function getHydra(): ?bool
635
    {
UNCOV
636
        return $this->hydra;
73✔
637
    }
638

639
    public function withHydra(bool $hydra): static
640
    {
UNCOV
641
        $self = clone $this;
5✔
UNCOV
642
        $self->hydra = $hydra;
5✔
643

UNCOV
644
        return $self;
5✔
645
    }
646
}
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