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

api-platform / core / 15255731762

26 May 2025 01:55PM UTC coverage: 0.0% (-26.5%) from 26.526%
15255731762

Pull #7176

github

web-flow
Merge 66f6cf4d2 into 79edced67
Pull Request #7176: Merge 4.1

0 of 387 new or added lines in 28 files covered. (0.0%)

11394 existing lines in 372 files now uncovered.

0 of 51334 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/src/Laravel/Eloquent/Metadata/Factory/Property/EloquentPropertyMetadataFactory.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\Laravel\Eloquent\Metadata\Factory\Property;
15

16
use ApiPlatform\Laravel\Eloquent\Metadata\ModelMetadata;
17
use ApiPlatform\Metadata\ApiProperty;
18
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
19
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
20
use Illuminate\Database\Eloquent\Model;
21
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
22
use Illuminate\Database\Eloquent\Relations\HasMany;
23
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
24
use Illuminate\Database\Eloquent\Relations\MorphMany;
25
use Illuminate\Database\Eloquent\Relations\MorphToMany;
26
use Illuminate\Support\Collection;
27
use Symfony\Component\TypeInfo\Type;
28
use Symfony\Component\TypeInfo\TypeIdentifier;
29

30
/**
31
 * Uses Eloquent metadata to populate the identifier property.
32
 *
33
 * @author Kévin Dunglas <dunglas@gmail.com>
34
 */
35
final class EloquentPropertyMetadataFactory implements PropertyMetadataFactoryInterface
36
{
37
    public function __construct(
38
        private readonly ModelMetadata $modelMetadata,
39
        private readonly ?PropertyMetadataFactoryInterface $decorated = null,
40
    ) {
41
    }
×
42

43
    /**
44
     * {@inheritdoc}
45
     *
46
     * @param class-string $resourceClass
47
     */
48
    public function create(string $resourceClass, string $property, array $options = []): ApiProperty
49
    {
50
        if (!is_a($resourceClass, Model::class, true)) {
×
51
            return $this->decorated?->create($resourceClass, $property, $options) ?? new ApiProperty();
×
52
        }
53

54
        try {
55
            $refl = new \ReflectionClass($resourceClass);
×
56
            $model = $refl->newInstanceWithoutConstructor();
×
57
        } catch (\ReflectionException) {
×
58
            return $this->decorated?->create($resourceClass, $property, $options) ?? new ApiProperty();
×
59
        }
60

61
        try {
62
            $propertyMetadata = $this->decorated?->create($resourceClass, $property, $options) ?? new ApiProperty();
×
63
        } catch (PropertyNotFoundException) {
×
64
            $propertyMetadata = new ApiProperty();
×
65
        }
66

67
        if ($model->getKeyName() === $property) {
×
68
            $propertyMetadata = $propertyMetadata->withIdentifier(true)->withWritable($propertyMetadata->isWritable() ?? false);
×
69
        }
70

71
        foreach ($this->modelMetadata->getAttributes($model) as $p) {
×
72
            if ($p['name'] !== $property) {
×
73
                continue;
×
74
            }
75

76
            // see https://laravel.com/docs/11.x/eloquent-mutators#attribute-casting
77
            $builtinType = $p['cast'] ?? $p['type'];
×
78
            $type = match ($builtinType) {
×
79
                'integer' => Type::int(),
×
80
                'double', 'real' => Type::float(),
×
81
                'boolean', 'bool' => Type::bool(),
×
82
                'datetime', 'date', 'timestamp' => Type::object(\DateTime::class),
×
83
                'immutable_datetime', 'immutable_date' => Type::object(\DateTimeImmutable::class),
×
84
                'collection', 'encrypted:collection' => Type::collection(Type::object(Collection::class)),
×
85
                'encrypted:array' => Type::builtin(TypeIdentifier::ARRAY),
×
86
                'encrypted:object' => Type::object(),
×
87
                default => \in_array($builtinType, TypeIdentifier::values(), true) ? Type::builtin($builtinType) : Type::string(),
×
88
            };
×
89

90
            if ($p['nullable']) {
×
91
                $type = Type::nullable($type);
×
92
            }
93

NEW
94
            $propertyMetadata = $propertyMetadata
×
NEW
95
                ->withNativeType([$type]);
×
96

97
            // If these are set let the SerializerPropertyMetadataFactory do the work
NEW
98
            if (!isset($options['denormalization_groups'])) {
×
NEW
99
                $propertyMetadata = $propertyMetadata
×
NEW
100
                    ->withWritable($propertyMetadata->isWritable() ?? true === $p['fillable']);
×
101
            }
102

NEW
103
            if (!isset($options['normalization_groups'])) {
×
NEW
104
                $propertyMetadata = $propertyMetadata
×
NEW
105
                    ->withReadable($propertyMetadata->isReadable() ?? false === $p['hidden']);
×
106
            }
107

NEW
108
            return $propertyMetadata;
×
109
        }
110

111
        foreach ($this->modelMetadata->getRelations($model) as $relation) {
×
112
            if ($relation['name'] !== $property) {
×
113
                continue;
×
114
            }
115

116
            $collection = match ($relation['type']) {
×
117
                HasMany::class,
×
118
                HasManyThrough::class,
×
119
                BelongsToMany::class,
×
120
                MorphMany::class,
×
121
                MorphToMany::class => true,
×
122
                default => false,
×
123
            };
×
124

125
            $type = Type::object($relation['related']);
×
126
            if ($collection) {
×
127
                $type = Type::iterable($type);
×
128
            }
129

130
            return $propertyMetadata
×
131
                ->withNativeType($type)
×
132
                ->withExtraProperties(['eloquent_relation' => $relation] + $propertyMetadata->getExtraProperties());
×
133
        }
134

135
        return $propertyMetadata;
×
136
    }
137
}
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