Passed
Push — master ( 50749f...7b5f02 )
by Gerrit
12:36
created

EntityHydrator::hydrateEntity()   B

Complexity

Conditions 8
Paths 38

Size

Total Lines 77

Duplication

Lines 38
Ratio 49.35 %

Code Coverage

Tests 26
CRAP Score 8.6106

Importance

Changes 0
Metric Value
dl 38
loc 77
ccs 26
cts 33
cp 0.7879
rs 7.2573
c 0
b 0
f 0
cc 8
nc 38
nop 2
crap 8.6106

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 5
    }
48
49 3
    public function hydrateEntity($entity, EntityManagerInterface $entityManager): void
50
    {
51
        /** @var array<string> $dataFromAdditionalColumns */
52 3
        $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
53 3
            $entity,
54
            $entityManager
55
        );
56
57
        /** @var class-string $className */
0 ignored issues
show
Documentation introduced by
The doc-type class-string could not be parsed: Unknown type name "class-string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
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 */
0 ignored issues
show
Documentation introduced by
The doc-type ?EntityMappingInterface could not be parsed: Unknown type name "?EntityMappingInterface" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
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 View Code Duplication
                    if ($mapping instanceof EntityMappingInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 3
                                "of field '%s' of entity '%s'",
84
                                $fieldName,
85
                                $className
86
                            );
87
88
                            /** @var mixed $value */
89 3
                            $value = $fieldMapping->resolveValue(
90 3
                                $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!",
118
                        $processDescription
119
                    ), 0, $exception);
120
                }
121
            }
122
123 3
            $className = current(class_parents($className));
124 3
        } while (class_exists($className));
125 3
    }
126
127 3
    public function assertHydrationOnEntity($entity, EntityManagerInterface $entityManager): void
128
    {
129
        /** @var array<string> $dataFromAdditionalColumns */
130 3
        $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
131 3
            $entity,
132
            $entityManager
133
        );
134
135
        /** @var class-string $className */
0 ignored issues
show
Documentation introduced by
The doc-type class-string could not be parsed: Unknown type name "class-string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
136 3
        $className = get_class($entity);
137
138
        do {
139 3
            if (class_exists(ClassUtils::class)) {
140 3
                $className = ClassUtils::getRealClass($className);
141 3
                Assert::classExists($className);
142
            }
143
144 3
            $classReflection = new ReflectionClass($className);
145
146
            /** @var ?EntityMappingInterface $mapping */
0 ignored issues
show
Documentation introduced by
The doc-type ?EntityMappingInterface could not be parsed: Unknown type name "?EntityMappingInterface" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
147 3
            $mapping = $this->mappingDriver->loadRDMMetadataForClass($className);
148
149 3 View Code Duplication
            if ($mapping instanceof EntityMappingInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150 3
                if ($mapping instanceof EntityMappingInterface) {
151 3
                    $context = new HydrationContext($entity, $entityManager);
152
153 3
                    foreach ($mapping->getFieldMappings() as $fieldName => $fieldMapping) {
154
                        /** @var MappingInterface $fieldMapping */
155
156
                        /** @var ReflectionClass $concreteClassReflection */
157 3
                        $concreteClassReflection = $classReflection;
158
159 3
                        while (!$concreteClassReflection->hasProperty($fieldName)) {
160
                            $concreteClassReflection = $concreteClassReflection->getParentClass();
161
162
                            Assert::notFalse($concreteClassReflection, sprintf(
163
                                "Property '%s' does not exist on object of class '%s'!",
164
                                $fieldName,
165
                                $className
166
                            ));
167
                        }
168
169
                        /** @var ReflectionProperty $propertyReflection */
170 3
                        $propertyReflection = $concreteClassReflection->getProperty($fieldName);
171
172 3
                        $propertyReflection->setAccessible(true);
173
174
                        /** @var object $actualValue */
175 3
                        $actualValue = $propertyReflection->getValue($entity);
176
177 3
                        $fieldMapping->assertValue(
178 3
                            $context,
179
                            $dataFromAdditionalColumns,
180
                            $actualValue
181
                        );
182
                    }
183
                }
184
            }
185
186 2
            $className = current(class_parents($className));
187 2
        } while (class_exists($className));
188 2
    }
189
190
}
191