EntityHydrator::assertHydrationOnEntity()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 65
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 8.0368

Importance

Changes 0
Metric Value
cc 8
eloc 32
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 65
ccs 22
cts 24
cp 0.9167
crap 8.0368
rs 8.1635

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 * @license GPL-3.0
8
 * @author Gerrit Addiks <[email protected]>
9
 */
10
11
namespace Addiks\RDMBundle\Hydration;
12
13
use ReflectionClass;
14
use ReflectionProperty;
15
use Doctrine\Common\Util\ClassUtils;
16
use Addiks\RDMBundle\Mapping\Drivers\MappingDriverInterface;
17
use Addiks\RDMBundle\Mapping\EntityMappingInterface;
18
use Addiks\RDMBundle\Mapping\MappingInterface;
19
use Addiks\RDMBundle\Hydration\EntityHydratorInterface;
20
use Addiks\RDMBundle\DataLoader\DataLoaderInterface;
21
use Doctrine\ORM\EntityManagerInterface;
22
use Addiks\RDMBundle\Hydration\HydrationContext;
23
use Webmozart\Assert\Assert;
24
use Exception;
25
use Throwable;
26
use Doctrine\ORM\Mapping\MappingException;
27
28
final class EntityHydrator implements EntityHydratorInterface
29
{
30
31
    /**
32
     * @var MappingDriverInterface
33
     */
34
    private $mappingDriver;
35
36
    /**
37
     * @var DataLoaderInterface
38
     */
39
    private $dbalDataLoader;
40
41 5
    public function __construct(
42
        MappingDriverInterface $mappingDriver,
43
        DataLoaderInterface $dbalDataLoader
44
    ) {
45 5
        $this->mappingDriver = $mappingDriver;
46 5
        $this->dbalDataLoader = $dbalDataLoader;
47
    }
48
49 3
    public function hydrateEntity($entity, EntityManagerInterface $entityManager): void
50
    {
51
        /** @var array<string> $dataFromAdditionalColumns */
52 3
        $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
53
            $entity,
54
            $entityManager
55
        );
56
57
        /** @var class-string $className */
58 3
        $className = get_class($entity);
59
60
        do {
61 3
            if (class_exists(ClassUtils::class)) {
62 3
                $className = ClassUtils::getRealClass($className);
63 3
                Assert::classExists($className);
64
            }
65
66 3
            $classReflection = new ReflectionClass($className);
67
68
            /** @var ?EntityMappingInterface $mapping */
69 3
            $mapping = $this->mappingDriver->loadRDMMetadataForClass($className);
70
71 3
            if ($mapping instanceof EntityMappingInterface) {
72
                /** @var string $processDescription */
73 3
                $processDescription = sprintf("of entity '%s'", $className);
74
75
                try {
76 3
                    if ($mapping instanceof EntityMappingInterface) {
77 3
                        $context = new HydrationContext($entity, $entityManager);
78
79 3
                        foreach ($mapping->getFieldMappings() as $fieldName => $fieldMapping) {
80
                            /** @var MappingInterface $fieldMapping */
81
82 3
                            $processDescription = sprintf(
83
                                "of field '%s' of entity '%s'",
84
                                $fieldName,
85
                                $className
86
                            );
87
88
                            /** @var mixed $value */
89 3
                            $value = $fieldMapping->resolveValue(
90
                                $context,
91
                                $dataFromAdditionalColumns
92
                            );
93
94
                            /** @var ReflectionClass $concreteClassReflection */
95 3
                            $concreteClassReflection = $classReflection;
96
97 3
                            while (!$concreteClassReflection->hasProperty($fieldName)) {
98
                                $concreteClassReflection = $concreteClassReflection->getParentClass();
99
100
                                Assert::object($concreteClassReflection, sprintf(
101
                                    "Property '%s' does not exist on object of class '%s'!",
102
                                    $fieldName,
103
                                    $className
104
                                ));
105
                            }
106
107
                            /** @var ReflectionProperty $propertyReflection */
108 3
                            $propertyReflection = $concreteClassReflection->getProperty($fieldName);
109
110 3
                            $propertyReflection->setAccessible(true);
111 3
                            $propertyReflection->setValue($entity, $value);
112
                        }
113
                    }
114
115
                } catch (Throwable $exception) {
116
                    throw new MappingException(sprintf(
117
                        "Exception during hydration %s: '%s'!",
118
                        $processDescription,
119
                        $exception->getMessage()
120
                    ), 0, $exception);
121
                }
122
            }
123
124 3
            $className = current(class_parents($className));
125 3
        } while (class_exists($className));
126
    }
127
128 3
    public function assertHydrationOnEntity($entity, EntityManagerInterface $entityManager): void
129
    {
130
        /** @var array<string> $dataFromAdditionalColumns */
131 3
        $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
132
            $entity,
133
            $entityManager
134
        );
135
136
        /** @var class-string $className */
137 3
        $className = get_class($entity);
138
139
        do {
140 3
            if (class_exists(ClassUtils::class)) {
141 3
                $className = ClassUtils::getRealClass($className);
142 3
                Assert::classExists($className);
143
            }
144
145 3
            $classReflection = new ReflectionClass($className);
146
147
            /** @var ?EntityMappingInterface $mapping */
148 3
            $mapping = $this->mappingDriver->loadRDMMetadataForClass($className);
149
150 3
            if ($mapping instanceof EntityMappingInterface) {
151 3
                if ($mapping instanceof EntityMappingInterface) {
152 3
                    $context = new HydrationContext($entity, $entityManager);
153
154 3
                    foreach ($mapping->getFieldMappings() as $fieldName => $fieldMapping) {
155
                        /** @var MappingInterface $fieldMapping */
156
157
                        /** @var ReflectionClass $concreteClassReflection */
158 3
                        $concreteClassReflection = $classReflection;
159
160 3
                        while (!$concreteClassReflection->hasProperty($fieldName)) {
161
                            $concreteClassReflection = $concreteClassReflection->getParentClass();
162
163
                            Assert::notFalse($concreteClassReflection, sprintf(
164
                                "Property '%s' does not exist on object of class '%s'!",
165
                                $fieldName,
166
                                $className
167
                            ));
168
                        }
169
170
                        /** @var ReflectionProperty $propertyReflection */
171 3
                        $propertyReflection = $concreteClassReflection->getProperty($fieldName);
172
173 3
                        $propertyReflection->setAccessible(true);
174
175
                        /** @var object|null $actualValue */
176 3
                        $actualValue = null;
177
178 3
                        if ($propertyReflection->isInitialized($entity)) {
179 3
                            $actualValue = $propertyReflection->getValue($entity);
180
                        }
181
182 3
                        $fieldMapping->assertValue(
183
                            $context,
184
                            $dataFromAdditionalColumns,
185
                            $actualValue
186
                        );
187
                    }
188
                }
189
            }
190
191 2
            $className = current(class_parents($className));
192 2
        } while (class_exists($className));
193
    }
194
195
}
196