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

api-platform / core / 13175753759

06 Feb 2025 09:30AM UTC coverage: 0.0% (-7.7%) from 7.663%
13175753759

Pull #6947

github

web-flow
Merge 432a515ad into de2d298e3
Pull Request #6947: fix(metadata): remove temporary fix for ArrayCollection

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

11655 existing lines in 385 files now uncovered.

0 of 47351 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/Serializer/Mapping/Loader/PropertyMetadataLoader.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\Serializer\Mapping\Loader;
15

16
use ApiPlatform\Metadata\ApiProperty;
17
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
18
use Illuminate\Database\Eloquent\Model;
19
use Symfony\Component\Serializer\Attribute\Context;
20
use Symfony\Component\Serializer\Attribute\DiscriminatorMap;
21
use Symfony\Component\Serializer\Attribute\Groups;
22
use Symfony\Component\Serializer\Attribute\Ignore;
23
use Symfony\Component\Serializer\Attribute\MaxDepth;
24
use Symfony\Component\Serializer\Attribute\SerializedName;
25
use Symfony\Component\Serializer\Attribute\SerializedPath;
26
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
27
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
28
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
29
use Symfony\Component\Serializer\Mapping\ClassMetadataInterface;
30
use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
31

32
/**
33
 * Loader for PHP attributes using ApiProperty.
34
 */
35
final class PropertyMetadataLoader implements LoaderInterface
36
{
37
    public function __construct(private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory)
38
    {
UNCOV
39
    }
×
40

41
    public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
42
    {
43
        $attributesMetadata = $classMetadata->getAttributesMetadata();
×
44
        // It's very weird to grab Eloquent's properties in that case as they're never serialized
45
        // the Serializer makes a call on the abstract class, let's save some unneeded work with a condition
46
        if (Model::class === $classMetadata->getName()) {
×
47
            return false;
×
48
        }
49

50
        $refl = $classMetadata->getReflectionClass();
×
51
        $attributes = [];
×
52
        $classGroups = [];
×
53
        $classContextAnnotation = null;
×
54

55
        foreach ($refl->getAttributes(ApiProperty::class) as $clAttr) {
×
56
            $this->addAttributeMetadata($clAttr->newInstance(), $attributes);
×
57
        }
58

59
        $attributesMetadata = $classMetadata->getAttributesMetadata();
×
60

61
        foreach ($refl->getAttributes() as $a) {
×
62
            $attribute = $a->newInstance();
×
63
            if ($attribute instanceof DiscriminatorMap) {
×
64
                $classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping(
×
65
                    $attribute->getTypeProperty(),
×
66
                    $attribute->getMapping()
×
67
                ));
×
68
                continue;
×
69
            }
70

71
            if ($attribute instanceof Groups) {
×
72
                $classGroups = $attribute->getGroups();
×
73

74
                continue;
×
75
            }
76

77
            if ($attribute instanceof Context) {
×
78
                $classContextAnnotation = $attribute;
×
79
            }
80
        }
81

82
        foreach ($refl->getProperties() as $reflProperty) {
×
83
            foreach ($reflProperty->getAttributes(ApiProperty::class) as $propAttr) {
×
84
                $this->addAttributeMetadata($propAttr->newInstance()->withProperty($reflProperty->name), $attributes);
×
85
            }
86
        }
87

88
        foreach ($refl->getMethods() as $reflMethod) {
×
89
            foreach ($reflMethod->getAttributes(ApiProperty::class) as $methodAttr) {
×
90
                $this->addAttributeMetadata($methodAttr->newInstance()->withProperty($reflMethod->getName()), $attributes);
×
91
            }
92
        }
93

94
        foreach ($this->propertyNameCollectionFactory->create($classMetadata->getName()) as $propertyName) {
×
95
            if (!isset($attributesMetadata[$propertyName])) {
×
96
                $attributesMetadata[$propertyName] = new AttributeMetadata($propertyName);
×
97
                $classMetadata->addAttributeMetadata($attributesMetadata[$propertyName]);
×
98
            }
99

100
            foreach ($classGroups as $group) {
×
101
                $attributesMetadata[$propertyName]->addGroup($group);
×
102
            }
103

104
            if ($classContextAnnotation) {
×
105
                $this->setAttributeContextsForGroups($classContextAnnotation, $attributesMetadata[$propertyName]);
×
106
            }
107

108
            if (!isset($attributes[$propertyName])) {
×
109
                continue;
×
110
            }
111

112
            $attributeMetadata = $attributesMetadata[$propertyName];
×
113

114
            // This code is adapted from Symfony\Component\Serializer\Mapping\Loader\AttributeLoader
115
            foreach ($attributes[$propertyName] as $attr) {
×
116
                if ($attr instanceof Groups) {
×
117
                    foreach ($attr->getGroups() as $group) {
×
118
                        $attributeMetadata->addGroup($group);
×
119
                    }
120
                    continue;
×
121
                }
122

UNCOV
123
                match (true) {
×
124
                    $attr instanceof MaxDepth => $attributeMetadata->setMaxDepth($attr->getMaxDepth()),
×
125
                    $attr instanceof SerializedName => $attributeMetadata->setSerializedName($attr->getSerializedName()),
×
126
                    $attr instanceof SerializedPath => $attributeMetadata->setSerializedPath($attr->getSerializedPath()),
×
127
                    $attr instanceof Ignore => $attributeMetadata->setIgnore(true),
×
128
                    $attr instanceof Context => $this->setAttributeContextsForGroups($attr, $attributeMetadata),
×
129
                    default => null,
×
UNCOV
130
                };
×
131
            }
132
        }
133

134
        return true;
×
135
    }
136

137
    /**
138
     * @param ApiProperty[] $attributes
139
     */
140
    private function addAttributeMetadata(ApiProperty $attribute, array &$attributes): void
141
    {
142
        if (($prop = $attribute->getProperty()) && ($value = $attribute->getSerialize())) {
×
143
            $attributes[$prop] = $value;
×
144
        }
145
    }
146

147
    private function setAttributeContextsForGroups(Context $annotation, AttributeMetadataInterface $attributeMetadata): void
148
    {
149
        $context = $annotation->getContext();
×
150
        $groups = $annotation->getGroups();
×
151
        $normalizationContext = $annotation->getNormalizationContext();
×
152
        $denormalizationContext = $annotation->getDenormalizationContext();
×
153
        if ($normalizationContext || $context) {
×
154
            $attributeMetadata->setNormalizationContextForGroups($normalizationContext ?: $context, $groups);
×
155
        }
156

157
        if ($denormalizationContext || $context) {
×
158
            $attributeMetadata->setDenormalizationContextForGroups($denormalizationContext ?: $context, $groups);
×
159
        }
160
    }
161
}
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