Completed
Push — master ( a2778c...a7177c )
by
unknown
15s queued 12s
created

DoctrineInsertUpdateLoader::processObject()   C

Complexity

Conditions 17
Paths 99

Size

Total Lines 71
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 17.1051

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 17
eloc 45
c 1
b 0
f 0
nc 99
nop 1
dl 0
loc 71
ccs 39
cts 42
cp 0.9286
crap 17.1051
rs 5.2166

How to fix   Long Method    Complexity   

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
namespace Smart\EtlBundle\Loader;
4
5
use Doctrine\ORM\EntityManager;
6
use Smart\EtlBundle\Entity\ImportableInterface;
7
use Smart\EtlBundle\Exception\Loader\EntityTypeNotHandledException;
8
use Smart\EtlBundle\Exception\Loader\EntityAlreadyRegisteredException;
9
use Symfony\Component\PropertyAccess\PropertyAccess;
10
use Symfony\Component\PropertyAccess\PropertyAccessor;
11
12
/**
13
 * Nicolas Bastien <[email protected]>
14
 */
15
class DoctrineInsertUpdateLoader implements LoaderInterface
16
{
17
    /**
18
     * @var EntityManager
19
     */
20
    protected $entityManager;
21
22
    /**
23
     * @var array
24
     */
25
    protected $references;
26
27
    /**
28
     * @var PropertyAccessor
29
     */
30
    protected $accessor;
31
32
    /**
33
     * List of entities to extract
34
     * [
35
     *      'class' => []
36
     * ]
37
     * @var array
38
     */
39
    protected $entitiesToProcess = [];
40
41 1
    public function __construct($entityManager)
42
    {
43 1
        $this->entityManager = $entityManager;
44 1
        $this->accessor = PropertyAccess::createPropertyAccessor();
45 1
    }
46
47
    /**
48
     * @param string $entityClass
49
     * @param callback $identifierCallback
50
     * @param string $identifierProperty : if null this entity will be always insert
51
     * @param array $entityProperties properties to synchronize
52
     * @return $this
53
     */
54 1
    public function addEntityToProcess($entityClass, $identifierCallback, $identifierProperty, array $entityProperties = [])
55
    {
56 1
        if (isset($this->entitiesToProcess[$entityClass])) {
57
            throw new EntityAlreadyRegisteredException($entityClass);
58
        }
59
60 1
        $this->entitiesToProcess[$entityClass] = [
61 1
            'class' => $entityClass,
62 1
            'callback' => $identifierCallback,
63 1
            'identifier' => $identifierProperty,
64 1
            'properties' => $entityProperties
65
        ];
66
67 1
        return $this;
68
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73 1
    public function load(array $data)
74
    {
75 1
        $this->entityManager->beginTransaction();
76
        try {
77 1
            foreach ($data as $object) {
78 1
                $this->processObject($object);
79
            }
80 1
            $this->entityManager->flush();
81 1
            $this->entityManager->commit();
82
        } catch (\Exception $e) {
83
            var_dump('EXCEPTION LOADER : ' . $e->getMessage());
0 ignored issues
show
Security Debugging Code introduced by
var_dump('EXCEPTION LOAD...: ' . $e->getMessage()) looks like debug code. Are you sure you do not want to remove it?
Loading history...
84
            $this->entityManager->rollback();
85
        }
86 1
    }
87
88
    /**
89
     * @param  ImportableInterface $object
90
     * @return ImportableInterface
91
     * @throws \Exception
92
     * @throws \TypeError
93
     */
94 1
    protected function processObject($object)
95
    {
96 1
        if (!isset($this->entitiesToProcess[get_class($object)])) {
97
            throw new EntityTypeNotHandledException(get_class($object));
98
        }
99 1
        $identifier = $this->entitiesToProcess[get_class($object)]['callback']($object);
100
101
        //Replace relations by their reference
102 1
        foreach ($this->entitiesToProcess[get_class($object)]['properties'] as $property) {
103 1
            $propertyValue = $this->accessor->getValue($object, $property);
104 1
            if ($this->isEntityRelation($propertyValue)) {
105 1
                $relation = $propertyValue; //better understanding
106
107 1
                if (!isset($this->entitiesToProcess[get_class($relation)])) {
108
                    throw new EntityTypeNotHandledException(get_class($relation));
109
                }
110 1
                $relationIdentifier = $this->entitiesToProcess[get_class($relation)]['callback']($relation);
111 1
                if (!isset($this->references[$relationIdentifier])) {
112
                    //new relation should be processed before
113 1
                    $this->processObject($relation);
114
                }
115 1
                $this->accessor->setValue(
116 1
                    $object,
117
                    $property,
118 1
                    $this->references[$relationIdentifier]
119
                );
120 1
            } elseif ($propertyValue instanceof \Traversable) {
121 1
                foreach ($propertyValue as $k => $v) {
122 1
                    if ($this->isEntityRelation($v)) {
123 1
                        if (!isset($this->entitiesToProcess[get_class($v)])) {
124
                            throw new EntityTypeNotHandledException(get_class($v));
125
                        }
126 1
                        $relationIdentifier = $this->entitiesToProcess[get_class($v)]['callback']($v);
127 1
                        if (!isset($this->references[$relationIdentifier])) {
128
                            //new relation should be processed before
129 1
                            $this->processObject($v);
130
                        }
131 1
                        $propertyValue[$k] = $this->references[$relationIdentifier];
132
                    }
133
                }
134 1
                $this->accessor->setValue(
135 1
                    $object,
136
                    $property,
137
                    $propertyValue
138
                );
139
            }
140
        }
141
142 1
        $dbObject = null;
143 1
        if (!is_null($this->entitiesToProcess[get_class($object)]['identifier'])) {
144 1
            $dbObject = $this->entityManager->getRepository(get_class($object))->findOneBy([$this->entitiesToProcess[get_class($object)]['identifier'] => $identifier]);
145
        }
146 1
        if ($dbObject === null) {
147 1
            if (!$object->isImported()) {
148 1
                $object->setImportedAt(new \DateTime());
149
            }
150 1
            $this->entityManager->persist($object);
151 1
            if (!is_null($identifier)) {
152 1
                $this->references[$identifier] = $object;
153
            }
154
        } else {
155 1
            foreach ($this->entitiesToProcess[get_class($object)]['properties'] as $property) {
156 1
                $this->accessor->setValue($dbObject, $property, $this->accessor->getValue($object, $property));
157
            }
158 1
            if (!$dbObject->isImported()) {
159 1
                $dbObject->setImportedAt(new \DateTime());
160
            }
161 1
            $this->references[$identifier] = $dbObject;
162
        }
163
164 1
        return $object;
165
    }
166
167
    /**
168
     * Check if $propertyValue is an entity relation to process
169
     *
170
     * @param  mixed $propertyValue
171
     * @return bool
172
     */
173 1
    protected function isEntityRelation($propertyValue)
174
    {
175 1
        return (is_object($propertyValue) && !($propertyValue instanceof \DateTime) && !($propertyValue instanceof \Traversable));
176
    }
177
}
178