Test Failed
Push — master ( c05d89...eb1dac )
by Gerrit
04:38
created

EntityHydrator   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 161
Duplicated Lines 11.18 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 79.45%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 8
dl 18
loc 161
ccs 58
cts 73
cp 0.7945
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B hydrateEntity() 9 76 8
B assertHydrationOnEntity() 9 61 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 string $className */
52 3
        $className = get_class($entity);
53
54 3
        if (class_exists(ClassUtils::class)) {
55 3
            $className = ClassUtils::getRealClass($className);
56
        }
57
58 3
        $classReflection = new ReflectionClass($className);
59
60
        /** @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...
61 3
        $mapping = $this->mappingDriver->loadRDMMetadataForClass($className);
62
63
        /** @var array<string> $dataFromAdditionalColumns */
64 3
        $dataFromAdditionalColumns = array();
65
66 3
        if ($mapping instanceof EntityMappingInterface) {
67
            /** @var string $processDescription */
68 3
            $processDescription = sprintf("of entity '%s'", $className);
69
70
            try {
71 3
                if (!empty($mapping->collectDBALColumns())) {
72 1
                    $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
73 1
                        $entity,
74 1
                        $entityManager
75
                    );
76
                }
77
78 3
                if ($mapping instanceof EntityMappingInterface) {
79 3
                    $context = new HydrationContext($entity, $entityManager);
80
81 3
                    foreach ($mapping->getFieldMappings() as $fieldName => $fieldMapping) {
82
                        /** @var MappingInterface $fieldMapping */
83
84 3
                        $processDescription = sprintf(
85 3
                            "of field '%s' of entity '%s'",
86 3
                            $fieldName,
87 3
                            $className
88
                        );
89
90
                        /** @var mixed $value */
91 3
                        $value = $fieldMapping->resolveValue(
92 3
                            $context,
93 3
                            $dataFromAdditionalColumns
94
                        );
95
96
                        /** @var ReflectionClass $concreteClassReflection */
97 3
                        $concreteClassReflection = $classReflection;
98
99 3 View Code Duplication
                        while (!$concreteClassReflection->hasProperty($fieldName)) {
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...
100
                            $concreteClassReflection = $concreteClassReflection->getParentClass();
101
102
                            Assert::object($concreteClassReflection, sprintf(
103
                                "Property '%s' does not exist on object of class '%s'!",
104
                                $fieldName,
105
                                $className
106
                            ));
107
                        }
108
109
                        /** @var ReflectionProperty $propertyReflection */
110 3
                        $propertyReflection = $concreteClassReflection->getProperty($fieldName);
111
112 3
                        $propertyReflection->setAccessible(true);
113 3
                        $propertyReflection->setValue($entity, $value);
114
                    }
115
                }
116
117
            } catch (Throwable $exception) {
118
                throw new MappingException(sprintf(
119
                    "Exception during hydration %s!",
120
                    $processDescription
121
                ), 0, $exception);
122
            }
123
        }
124 3
    }
125
126 3
    public function assertHydrationOnEntity($entity, EntityManagerInterface $entityManager): void
127
    {
128
        /** @var string $className */
129 3
        $className = get_class($entity);
130
131 3
        if (class_exists(ClassUtils::class)) {
132 3
            $className = ClassUtils::getRealClass($className);
133
        }
134
135 3
        $classReflection = new ReflectionClass($className);
136
137
        /** @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...
138 3
        $mapping = $this->mappingDriver->loadRDMMetadataForClass($className);
139
140
        /** @var array<string> $dataFromAdditionalColumns */
141 3
        $dataFromAdditionalColumns = array();
142
143 3
        if ($mapping instanceof EntityMappingInterface) {
144 3
            if (!empty($mapping->collectDBALColumns())) {
145 1
                $dataFromAdditionalColumns = $this->dbalDataLoader->loadDBALDataForEntity(
146 1
                    $entity,
147 1
                    $entityManager
148
                );
149
            }
150
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 View Code Duplication
                    while (!$concreteClassReflection->hasProperty($fieldName)) {
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...
161
                        $concreteClassReflection = $concreteClassReflection->getParentClass();
162
163
                        Assert::notNull($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 $actualValue */
176 3
                    $actualValue = $propertyReflection->getValue($entity);
177
178 3
                    $fieldMapping->assertValue(
179 3
                        $context,
180 3
                        $dataFromAdditionalColumns,
181 3
                        $actualValue
182
                    );
183
                }
184
            }
185
        }
186 2
    }
187
188
}
189