DoctrineWriter::reEnableLogging()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Ddeboer\DataImport\Writer;
4
5
use Ddeboer\DataImport\Writer;
6
use Doctrine\DBAL\Logging\SQLLogger;
7
use Doctrine\ORM\EntityManagerInterface;
8
use Doctrine\ORM\EntityRepository;
9
use Doctrine\ORM\Mapping\ClassMetadata;
10
11
/**
12
 * A bulk Doctrine writer
13
 *
14
 * See also the {@link http://www.doctrine-project.org/docs/orm/2.1/en/reference/batch-processing.html Doctrine documentation}
15
 * on batch processing.
16
 *
17
 * @author David de Boer <[email protected]>
18
 */
19
class DoctrineWriter implements Writer, FlushableWriter
20
{
21
    /**
22
     * @var EntityManagerInterface
23
     */
24
    protected $entityManager;
25
26
    /**
27
     * @var string
28
     */
29
    protected $entityName;
30
31
    /**
32
     * @var EntityRepository
33
     */
34
    protected $entityRepository;
35
36
    /**
37
     * @var ClassMetadata
38
     */
39
    protected $entityMetadata;
40
41
    /**
42
     * Original Doctrine logger
43
     *
44
     * @var SQLLogger
45
     */
46
    protected $originalLogger;
47
48
    /**
49
     * Whether to truncate the table first
50
     *
51
     * @var boolean
52
     */
53
    protected $truncate = true;
54
55
    /**
56
     * List of fields used to lookup an entity
57
     *
58
     * @var array
59
     */
60
    protected $lookupFields = array();
61
62
    /**
63
     * @param EntityManagerInterface $entityManager
64
     * @param string                 $entityName
65
     * @param string|array           $index Field or fields to find current entities by
66
     */
67 4
    public function __construct(EntityManagerInterface $entityManager, $entityName, $index = null)
68
    {
69 4
        $this->entityManager = $entityManager;
70 4
        $this->entityRepository = $entityManager->getRepository($entityName);
71 4
        $this->entityMetadata = $entityManager->getClassMetadata($entityName);
72
        //translate entityName in case a namespace alias is used
73 4
        $this->entityName = $this->entityMetadata->getName();
74 4
        if ($index) {
75
            if (is_array($index)) {
76
                $this->lookupFields = $index;
77
            } else {
78
                $this->lookupFields = [$index];
79
            }
80
        }
81 4
    }
82
83
    /**
84
     * @return boolean
85
     */
86
    public function getTruncate()
87
    {
88
        return $this->truncate;
89
    }
90
91
    /**
92
     * Set whether to truncate the table first
93
     *
94
     * @param boolean $truncate
95
     *
96
     * @return $this
97
     */
98
    public function setTruncate($truncate)
99
    {
100
        $this->truncate = $truncate;
101
102
        return $this;
103
    }
104
105
    /**
106
     * Disable truncation
107
     *
108
     * @return $this
109
     */
110
    public function disableTruncate()
111
    {
112
        $this->truncate = false;
113
114
        return $this;
115
    }
116
117
    /**
118
     * Disable Doctrine logging
119
     *
120
     * @return $this
121
     */
122
    public function prepare()
123
    {
124
        $this->disableLogging();
125
126
        if (true === $this->truncate) {
127
            $this->truncateTable();
128
        }
129
    }
130
131
    /**
132
     * Return a new instance of the entity
133
     *
134
     * @return object
135
     */
136 3
    protected function getNewInstance()
137
    {
138 3
        $className = $this->entityMetadata->getName();
139
140 3
        if (class_exists($className) === false) {
141
            throw new \Exception('Unable to create new instance of ' . $className);
142
        }
143
144 3
        return new $className;
145
    }
146
147
    /**
148
     * Call a setter of the entity
149
     *
150
     * @param object $entity
151
     * @param mixed  $value
152
     * @param string $setter
153
     */
154 3
    protected function setValue($entity, $value, $setter)
155
    {
156 3
        if (method_exists($entity, $setter)) {
157 3
            $entity->$setter($value);
158 3
        }
159 3
    }
160
161
    /**
162
     * Re-enable Doctrine logging
163
     *
164
     * @return $this
165
     */
166 1
    public function finish()
167
    {
168 1
        $this->flush();
169 1
        $this->reEnableLogging();
170 1
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 3
    public function writeItem(array $item)
176
    {
177 3
        $entity = $this->findOrCreateItem($item);
178
179 3
        $this->loadAssociationObjectsToEntity($item, $entity);
180 3
        $this->updateEntity($item, $entity);
181
182 3
        $this->entityManager->persist($entity);
183 3
    }
184
185
    /**
186
     * @param array  $item
187
     * @param object $entity
188
     */
189 3
    protected function updateEntity(array $item, $entity)
190
    {
191 3
        $fieldNames = array_merge($this->entityMetadata->getFieldNames(), $this->entityMetadata->getAssociationNames());
192 3
        foreach ($fieldNames as $fieldName) {
193 3
            $value = null;
194 3
            if (isset($item[$fieldName])) {
195 3
                $value = $item[$fieldName];
196 3
            } elseif (method_exists($item, 'get' . ucfirst($fieldName))) {
197
                $value = $item->{'get' . ucfirst($fieldName)};
198
            }
199
200 3
            if (null === $value) {
201
                continue;
202
            }
203
204 3
            if (!($value instanceof \DateTime)
205 3
                || $value != $this->entityMetadata->getFieldValue($entity, $fieldName)
206 3
            ) {
207 3
                $setter = 'set' . ucfirst($fieldName);
208 3
                $this->setValue($entity, $value, $setter);
209 3
            }
210 3
        }
211 3
    }
212
213
    /**
214
     * Add the associated objects in case the item have for persist its relation
215
     *
216
     * @param array  $item
217
     * @param object $entity
218
     */
219 3
    protected function loadAssociationObjectsToEntity(array $item, $entity)
220
    {
221 3
        foreach ($this->entityMetadata->getAssociationMappings() as $associationMapping) {
222
223 3
            $value = null;
224 3
            if (isset($item[$associationMapping['fieldName']]) && !is_object($item[$associationMapping['fieldName']])) {
225 1
                $value = $this->entityManager->getReference($associationMapping['targetEntity'], $item[$associationMapping['fieldName']]);
226 1
            }
227
228 3
            if (null === $value) {
229 3
                continue;
230
            }
231
232
            $setter = 'set' . ucfirst($associationMapping['fieldName']);
233
            $this->setValue($entity, $value, $setter);
234 3
        }
235 3
    }
236
237
    /**
238
     * Truncate the database table for this writer
239
     */
240
    protected function truncateTable()
241
    {
242
        $tableName = $this->entityMetadata->table['name'];
243
        $connection = $this->entityManager->getConnection();
244
        $query = $connection->getDatabasePlatform()->getTruncateTableSQL($tableName, true);
245
        $connection->executeQuery($query);
246
    }
247
248
    /**
249
     * Disable Doctrine logging
250
     */
251
    protected function disableLogging()
252
    {
253
        $config = $this->entityManager->getConnection()->getConfiguration();
254
        $this->originalLogger = $config->getSQLLogger();
255
        $config->setSQLLogger(null);
256
    }
257
258
    /**
259
     * Re-enable Doctrine logging
260
     */
261 1
    protected function reEnableLogging()
262
    {
263 1
        $config = $this->entityManager->getConnection()->getConfiguration();
264 1
        $config->setSQLLogger($this->originalLogger);
265 1
    }
266
267
    /**
268
     * Finds existing entity or create a new instance
269
     *
270
     * @param array $item
271
     */
272 3
    protected function findOrCreateItem(array $item)
273
    {
274 3
        $entity = null;
275
        // If the table was not truncated to begin with, find current entity
276
        // first
277 3
        if (false === $this->truncate) {
278
            if (!empty($this->lookupFields)) {
279
                $lookupConditions = array();
280
                foreach ($this->lookupFields as $fieldName) {
281
                    $lookupConditions[$fieldName] = $item[$fieldName];
282
                }
283
                $entity = $this->entityRepository->findOneBy(
284
                    $lookupConditions
285
                );
286
            } else {
287
                $entity = $this->entityRepository->find(current($item));
288
            }
289
        }
290
291 3
        if (!$entity) {
292 3
            return $this->getNewInstance();
293
        }
294
295
        return $entity;
296
    }
297
298
    /**
299
     * Flush and clear the entity manager
300
     */
301 1
    public function flush()
302
    {
303 1
        $this->entityManager->flush();
304 1
        $this->entityManager->clear($this->entityName);
305 1
    }
306
}
307