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

api-platform / core / 14726067612

29 Apr 2025 07:47AM UTC coverage: 23.443% (+15.2%) from 8.252%
14726067612

push

github

web-flow
feat(symfony): Autoconfigure classes using `#[ApiResource]` attribute (#6943)

0 of 12 new or added lines in 4 files covered. (0.0%)

3578 existing lines in 159 files now uncovered.

11517 of 49127 relevant lines covered (23.44%)

54.29 hits per line

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

0.0
/src/Elasticsearch/Util/FieldDatatypeTrait.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\Elasticsearch\Util;
15

16
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
17
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
18
use ApiPlatform\Metadata\ResourceClassResolverInterface;
19
use ApiPlatform\Metadata\Util\TypeHelper;
20
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
21
use Symfony\Component\PropertyInfo\Type as LegacyType;
22
use Symfony\Component\TypeInfo\Type;
23
use Symfony\Component\TypeInfo\Type\ObjectType;
24

25
/**
26
 * Field datatypes helpers.
27
 *
28
 * @internal
29
 *
30
 * @experimental
31
 *
32
 * @author Baptiste Meyer <baptiste.meyer@gmail.com>
33
 */
34
trait FieldDatatypeTrait
35
{
36
    private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory;
37

38
    private readonly ResourceClassResolverInterface $resourceClassResolver;
39

40
    /**
41
     * Is the decomposed given property of the given resource class potentially mapped as a nested field in Elasticsearch?
42
     */
43
    private function isNestedField(string $resourceClass, string $property): bool
44
    {
UNCOV
45
        return null !== $this->getNestedFieldPath($resourceClass, $property);
×
46
    }
47

48
    /**
49
     * Get the nested path to the decomposed given property (e.g.: foo.bar.baz => foo.bar).
50
     *
51
     * Elasticsearch can save arrays of Objects as nested documents.
52
     * In the case of foo.bar.baz
53
     *   foo.bar will be returned if foo.bar is an array of objects.
54
     *   If neither foo nor bar is an array, it is not a nested property and will return null.
55
     */
56
    private function getNestedFieldPath(string $resourceClass, string $property): ?string
57
    {
UNCOV
58
        $properties = explode('.', $property);
×
UNCOV
59
        $currentProperty = array_shift($properties);
×
60

61
        if (!$properties) {
×
UNCOV
62
            return null;
×
63
        }
64

65
        try {
UNCOV
66
            $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $currentProperty);
×
UNCOV
67
        } catch (PropertyNotFoundException) {
×
68
            return null;
×
69
        }
70

UNCOV
71
        if (!method_exists(PropertyInfoExtractor::class, 'getType')) {
×
UNCOV
72
            $types = $propertyMetadata->getBuiltinTypes() ?? [];
×
73

74
            foreach ($types as $type) {
×
75
                if (
76
                    LegacyType::BUILTIN_TYPE_OBJECT === $type->getBuiltinType()
×
UNCOV
77
                    && null !== ($nextResourceClass = $type->getClassName())
×
78
                    && $this->resourceClassResolver->isResourceClass($nextResourceClass)
×
79
                ) {
80
                    $nestedPath = $this->getNestedFieldPath($nextResourceClass, implode('.', $properties));
×
81

82
                    return null === $nestedPath ? $nestedPath : "$currentProperty.$nestedPath";
×
83
                }
84

85
                if (
UNCOV
86
                    null !== ($type = $type->getCollectionValueTypes()[0] ?? null)
×
UNCOV
87
                    && LegacyType::BUILTIN_TYPE_OBJECT === $type->getBuiltinType()
×
88
                    && null !== ($className = $type->getClassName())
×
89
                    && $this->resourceClassResolver->isResourceClass($className)
×
90
                ) {
91
                    $nestedPath = $this->getNestedFieldPath($className, implode('.', $properties));
×
92

93
                    return null === $nestedPath ? $currentProperty : "$currentProperty.$nestedPath";
×
94
                }
95
            }
96

UNCOV
97
            return null;
×
98
        }
99

UNCOV
100
        $type = $propertyMetadata->getNativeType();
×
101

102
        if (null === $type) {
×
UNCOV
103
            return null;
×
104
        }
105

106
        /** @var class-string|null $className */
UNCOV
107
        $className = null;
×
108

109
        $typeIsResourceClass = function (Type $type) use (&$className): bool {
×
UNCOV
110
            return $type instanceof ObjectType && $this->resourceClassResolver->isResourceClass($className = $type->getClassName());
×
111
        };
×
112

113
        if ($type->isSatisfiedBy($typeIsResourceClass)) {
×
114
            $nestedPath = $this->getNestedFieldPath($className, implode('.', $properties));
×
115

116
            return null === $nestedPath ? $nestedPath : "$currentProperty.$nestedPath";
×
117
        }
118

UNCOV
119
        if (TypeHelper::getCollectionValueType($type)?->isSatisfiedBy($typeIsResourceClass)) {
×
120
            $nestedPath = $this->getNestedFieldPath($className, implode('.', $properties));
×
121

UNCOV
122
            return null === $nestedPath ? $currentProperty : "$currentProperty.$nestedPath";
×
123
        }
124

UNCOV
125
        return null;
×
126
    }
127
}
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