Passed
Pull Request — master (#2144)
by Alan
04:07
created

PropertyHelper   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 20
eloc 44
dl 0
loc 118
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getNestedMetadata() 0 13 3
A splitPropertyParts() 0 28 5
A isPropertyEmbedded() 0 3 2
A isPropertyNested() 0 8 3
A __construct() 0 3 1
A getClassMetadata() 0 6 1
A isPropertyMapped() 0 11 4
A getDoctrineFieldType() 0 6 1
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
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\Core\Bridge\Doctrine\Common;
15
16
use Doctrine\Common\Persistence\ManagerRegistry;
17
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
18
19
/**
20
 * {@inheritdoc}
21
 *
22
 * @author Kévin Dunglas <[email protected]>
23
 * @author Théo FIDRY <[email protected]>
24
 * @author Alan Poulain <[email protected]>
25
 */
26
final class PropertyHelper implements PropertyHelperInterface
27
{
28
    private $managerRegistry;
29
30
    public function __construct(ManagerRegistry $managerRegistry)
31
    {
32
        $this->managerRegistry = $managerRegistry;
33
    }
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function isPropertyMapped(string $property, string $resourceClass, bool $allowAssociation = false): bool
39
    {
40
        if ($this->isPropertyNested($property, $resourceClass)) {
41
            $propertyParts = $this->splitPropertyParts($property, $resourceClass);
42
            $metadata = $this->getNestedMetadata($resourceClass, $propertyParts['associations']);
43
            $property = $propertyParts['field'];
44
        } else {
45
            $metadata = $this->getClassMetadata($resourceClass);
46
        }
47
48
        return $metadata->hasField($property) || ($allowAssociation && $metadata->hasAssociation($property));
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function isPropertyNested(string $property, ?string $resourceClass): bool
55
    {
56
        $pos = strpos($property, '.');
57
        if (false === $pos) {
58
            return false;
59
        }
60
61
        return null !== $resourceClass && $this->getClassMetadata($resourceClass)->hasAssociation(substr($property, 0, $pos));
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function isPropertyEmbedded(string $property, string $resourceClass): bool
68
    {
69
        return false !== strpos($property, '.') && $this->getClassMetadata($resourceClass)->hasField($property);
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function splitPropertyParts(string $property, ?string $resourceClass): array
76
    {
77
        $parts = explode('.', $property);
78
79
        if (null === $resourceClass) {
80
            return [
81
                'associations' => \array_slice($parts, 0, -1),
82
                'field' => end($parts),
83
            ];
84
        }
85
86
        $metadata = $this->getClassMetadata($resourceClass);
87
        $slice = 0;
88
89
        foreach ($parts as $part) {
90
            if ($metadata->hasAssociation($part)) {
91
                $metadata = $this->getClassMetadata($metadata->getAssociationTargetClass($part));
92
                ++$slice;
93
            }
94
        }
95
96
        if (\count($parts) === $slice) {
97
            --$slice;
98
        }
99
100
        return [
101
            'associations' => \array_slice($parts, 0, $slice),
102
            'field' => implode('.', \array_slice($parts, $slice)),
103
        ];
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function getDoctrineFieldType(string $property, string $resourceClass)
110
    {
111
        $propertyParts = $this->splitPropertyParts($property, $resourceClass);
112
        $metadata = $this->getNestedMetadata($resourceClass, $propertyParts['associations']);
113
114
        return $metadata->getTypeOfField($propertyParts['field']);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function getNestedMetadata(string $resourceClass, array $associations): ClassMetadata
121
    {
122
        $metadata = $this->getClassMetadata($resourceClass);
123
124
        foreach ($associations as $association) {
125
            if ($metadata->hasAssociation($association)) {
126
                $associationClass = $metadata->getAssociationTargetClass($association);
127
128
                $metadata = $this->getClassMetadata($associationClass);
129
            }
130
        }
131
132
        return $metadata;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function getClassMetadata(string $resourceClass): ClassMetadata
139
    {
140
        return $this
141
            ->managerRegistry
142
            ->getManagerForClass($resourceClass)
143
            ->getClassMetadata($resourceClass);
144
    }
145
}
146