Passed
Pull Request — master (#188)
by Damien
02:37
created

TransactionManager::diff()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 38
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 25
c 0
b 0
f 0
nc 7
nop 3
dl 0
loc 38
rs 8.0555
1
<?php
2
3
namespace DH\DoctrineAuditBundle\Manager;
4
5
use DateTime;
6
use DateTimeZone;
7
use DH\DoctrineAuditBundle\Configuration;
8
use DH\DoctrineAuditBundle\Event\LifecycleEvent;
9
use DH\DoctrineAuditBundle\Helper\DoctrineHelper;
10
use DH\DoctrineAuditBundle\Model\Transaction;
11
use DH\DoctrineAuditBundle\User\UserInterface;
12
use Doctrine\DBAL\Types\Type;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Doctrine\ORM\Mapping\ClassMetadata;
15
use Doctrine\ORM\UnitOfWork;
16
use Exception;
17
18
class TransactionManager
19
{
20
    /**
21
     * @var Configuration
22
     */
23
    private $configuration;
24
25
    /**
26
     * @var EntityManagerInterface
27
     */
28
    private $em;
29
30
    public function __construct(Configuration $configuration)
31
    {
32
        $this->configuration = $configuration;
33
        $this->em = $this->configuration->getEntityManager();
34
    }
35
36
    /**
37
     * @return Configuration
38
     */
39
    public function getConfiguration(): Configuration
40
    {
41
        return $this->configuration;
42
    }
43
44
    /**
45
     * @param Transaction $transaction
46
     *
47
     * @throws \Doctrine\DBAL\DBALException
48
     * @throws \Doctrine\ORM\Mapping\MappingException
49
     */
50
    public function process(Transaction $transaction): void
51
    {
52
        $this->processInsertions($transaction);
53
        $this->processUpdates($transaction);
54
        $this->processAssociations($transaction);
55
        $this->processDissociations($transaction);
56
        $this->processDeletions($transaction);
57
    }
58
59
    /**
60
     * @param EntityManagerInterface $em
61
     *
62
     * @return EntityManagerInterface
63
     */
64
    public function selectStorageSpace(EntityManagerInterface $em): EntityManagerInterface
65
    {
66
        return $this->configuration->getEntityManager() ?? $em;
67
    }
68
69
    public function populate(Transaction $transaction): void
70
    {
71
        $uow = $this->em->getUnitOfWork();
72
73
        $this->populateWithScheduledInsertions($transaction, $uow);
74
        $this->populateWithScheduledUpdates($transaction, $uow);
75
        $this->populateWithScheduledDeletions($transaction, $uow, $this->em);
76
        $this->populateWithScheduledCollectionUpdates($transaction, $uow, $this->em);
77
        $this->populateWithScheduledCollectionDeletions($transaction, $uow, $this->em);
78
    }
79
80
    /**
81
     * @param array $payload
82
     */
83
    private function notify(array $payload): void
84
    {
85
        $dispatcher = $this->configuration->getEventDispatcher();
86
87
        if ($this->configuration->isPre43Dispatcher()) {
88
            // Symfony 3.x
89
            $dispatcher->dispatch(LifecycleEvent::class, new LifecycleEvent($payload));
0 ignored issues
show
Bug introduced by
DH\DoctrineAuditBundle\Event\LifecycleEvent::class of type string is incompatible with the type object expected by parameter $event of Symfony\Contracts\EventD...erInterface::dispatch(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
            $dispatcher->dispatch(/** @scrutinizer ignore-type */ LifecycleEvent::class, new LifecycleEvent($payload));
Loading history...
90
        } else {
91
            // Symfony 4.x
92
            $dispatcher->dispatch(new LifecycleEvent($payload));
93
        }
94
    }
95
96
    /**
97
     * Adds an insert entry to the audit table.
98
     *
99
     * @param EntityManagerInterface $em
100
     * @param object                 $entity
101
     * @param array                  $ch
102
     * @param string                 $transactionHash
103
     *
104
     * @throws \Doctrine\DBAL\DBALException
105
     * @throws \Doctrine\ORM\Mapping\MappingException
106
     */
107
    private function insert(EntityManagerInterface $em, $entity, array $ch, string $transactionHash): void
108
    {
109
        /** @var ClassMetadata $meta */
110
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
111
        $this->audit([
112
            'action' => 'insert',
113
            'blame' => $this->blame(),
114
            'diff' => $this->diff($em, $entity, $ch),
115
            'table' => $meta->getTableName(),
116
            'schema' => $meta->getSchemaName(),
117
            'id' => $this->id($em, $entity),
118
            'transaction_hash' => $transactionHash,
119
            'discriminator' => $this->getDiscriminator($entity, $meta->inheritanceType),
120
            'entity' => $meta->getName(),
121
        ]);
122
    }
123
124
    /**
125
     * Adds an update entry to the audit table.
126
     *
127
     * @param EntityManagerInterface $em
128
     * @param object                 $entity
129
     * @param array                  $ch
130
     * @param string                 $transactionHash
131
     *
132
     * @throws \Doctrine\DBAL\DBALException
133
     * @throws \Doctrine\ORM\Mapping\MappingException
134
     */
135
    private function update(EntityManagerInterface $em, $entity, array $ch, string $transactionHash): void
136
    {
137
        $diff = $this->diff($em, $entity, $ch);
138
        if (0 === \count($diff)) {
139
            return; // if there is no entity diff, do not log it
140
        }
141
        /** @var ClassMetadata $meta */
142
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
143
        $this->audit([
144
            'action' => 'update',
145
            'blame' => $this->blame(),
146
            'diff' => $diff,
147
            'table' => $meta->getTableName(),
148
            'schema' => $meta->getSchemaName(),
149
            'id' => $this->id($em, $entity),
150
            'transaction_hash' => $transactionHash,
151
            'discriminator' => $this->getDiscriminator($entity, $meta->inheritanceType),
152
            'entity' => $meta->getName(),
153
        ]);
154
    }
155
156
    /**
157
     * Adds a remove entry to the audit table.
158
     *
159
     * @param EntityManagerInterface $em
160
     * @param object                 $entity
161
     * @param mixed                  $id
162
     * @param string                 $transactionHash
163
     *
164
     * @throws \Doctrine\DBAL\DBALException
165
     * @throws \Doctrine\ORM\Mapping\MappingException
166
     */
167
    private function remove(EntityManagerInterface $em, $entity, $id, string $transactionHash): void
168
    {
169
        /** @var ClassMetadata $meta */
170
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
171
        $this->audit([
172
            'action' => 'remove',
173
            'blame' => $this->blame(),
174
            'diff' => $this->summarize($em, $entity, $id),
175
            'table' => $meta->getTableName(),
176
            'schema' => $meta->getSchemaName(),
177
            'id' => $id,
178
            'transaction_hash' => $transactionHash,
179
            'discriminator' => $this->getDiscriminator($entity, $meta->inheritanceType),
180
            'entity' => $meta->getName(),
181
        ]);
182
    }
183
184
    /**
185
     * Adds an association entry to the audit table.
186
     *
187
     * @param EntityManagerInterface $em
188
     * @param object                 $source
189
     * @param object                 $target
190
     * @param array                  $mapping
191
     * @param string                 $transactionHash
192
     *
193
     * @throws \Doctrine\DBAL\DBALException
194
     * @throws \Doctrine\ORM\Mapping\MappingException
195
     */
196
    private function associate(EntityManagerInterface $em, $source, $target, array $mapping, string $transactionHash): void
197
    {
198
        $this->associateOrDissociate('associate', $em, $source, $target, $mapping, $transactionHash);
199
    }
200
201
    /**
202
     * Adds a dissociation entry to the audit table.
203
     *
204
     * @param EntityManagerInterface $em
205
     * @param object                 $source
206
     * @param object                 $target
207
     * @param array                  $mapping
208
     * @param string                 $transactionHash
209
     *
210
     * @throws \Doctrine\DBAL\DBALException
211
     * @throws \Doctrine\ORM\Mapping\MappingException
212
     */
213
    private function dissociate(EntityManagerInterface $em, $source, $target, array $mapping, string $transactionHash): void
214
    {
215
        $this->associateOrDissociate('dissociate', $em, $source, $target, $mapping, $transactionHash);
216
    }
217
218
    /**
219
     * Returns the primary key value of an entity.
220
     *
221
     * @param EntityManagerInterface $em
222
     * @param object                 $entity
223
     *
224
     * @throws \Doctrine\DBAL\DBALException
225
     * @throws \Doctrine\ORM\Mapping\MappingException
226
     *
227
     * @return mixed
228
     */
229
    private function id(EntityManagerInterface $em, $entity)
230
    {
231
        /** @var ClassMetadata $meta */
232
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
233
        $pk = $meta->getSingleIdentifierFieldName();
234
235
        if (isset($meta->fieldMappings[$pk])) {
236
            $type = Type::getType($meta->fieldMappings[$pk]['type']);
237
238
            return $this->value($em, $type, $meta->getReflectionProperty($pk)->getValue($entity));
239
        }
240
241
        /**
242
         * Primary key is not part of fieldMapping.
243
         *
244
         * @see https://github.com/DamienHarper/DoctrineAuditBundle/issues/40
245
         * @see https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#identity-through-foreign-entities
246
         * We try to get it from associationMapping (will throw a MappingException if not available)
247
         */
248
        $targetEntity = $meta->getReflectionProperty($pk)->getValue($entity);
249
250
        $mapping = $meta->getAssociationMapping($pk);
251
252
        /** @var ClassMetadata $meta */
253
        $meta = $em->getClassMetadata($mapping['targetEntity']);
254
        $pk = $meta->getSingleIdentifierFieldName();
255
        $type = Type::getType($meta->fieldMappings[$pk]['type']);
256
257
        return $this->value($em, $type, $meta->getReflectionProperty($pk)->getValue($targetEntity));
258
    }
259
260
    /**
261
     * Computes a usable diff.
262
     *
263
     * @param EntityManagerInterface $em
264
     * @param object                 $entity
265
     * @param array                  $ch
266
     *
267
     * @throws \Doctrine\DBAL\DBALException
268
     * @throws \Doctrine\ORM\Mapping\MappingException
269
     *
270
     * @return array
271
     */
272
    private function diff(EntityManagerInterface $em, $entity, array $ch): array
273
    {
274
        /** @var ClassMetadata $meta */
275
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
276
        $diff = [];
277
278
        foreach ($ch as $fieldName => list($old, $new)) {
279
            $o = null;
280
            $n = null;
281
282
            if (
283
                $meta->hasField($fieldName) &&
284
                !isset($meta->embeddedClasses[$fieldName]) &&
285
                $this->configuration->isAuditedField($entity, $fieldName)
286
            ) {
287
                $mapping = $meta->fieldMappings[$fieldName];
288
                $type = Type::getType($mapping['type']);
289
                $o = $this->value($em, $type, $old);
290
                $n = $this->value($em, $type, $new);
291
            } elseif (
292
                $meta->hasAssociation($fieldName) &&
293
                $meta->isSingleValuedAssociation($fieldName) &&
294
                $this->configuration->isAuditedField($entity, $fieldName)
295
            ) {
296
                $o = $this->summarize($em, $old);
297
                $n = $this->summarize($em, $new);
298
            }
299
300
            if ($o !== $n) {
301
                $diff[$fieldName] = [
302
                    'old' => $o,
303
                    'new' => $n,
304
                ];
305
            }
306
        }
307
        ksort($diff);
308
309
        return $diff;
310
    }
311
312
    /**
313
     * Returns an array describing an entity.
314
     *
315
     * @param EntityManagerInterface $em
316
     * @param object                 $entity
317
     * @param mixed                  $id
318
     *
319
     * @throws \Doctrine\DBAL\DBALException
320
     * @throws \Doctrine\ORM\Mapping\MappingException
321
     *
322
     * @return array
323
     */
324
    private function summarize(EntityManagerInterface $em, $entity = null, $id = null): ?array
325
    {
326
        if (null === $entity) {
327
            return null;
328
        }
329
330
        $em->getUnitOfWork()->initializeObject($entity); // ensure that proxies are initialized
331
        /** @var ClassMetadata $meta */
332
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($entity));
333
        $pkName = $meta->getSingleIdentifierFieldName();
334
        $pkValue = $id ?? $this->id($em, $entity);
335
        // An added guard for proxies that fail to initialize.
336
        if (null === $pkValue) {
337
            return null;
338
        }
339
340
        if (method_exists($entity, '__toString')) {
341
            $label = (string) $entity;
342
        } else {
343
            $label = DoctrineHelper::getRealClassName($entity).'#'.$pkValue;
344
        }
345
346
        return [
347
            'label' => $label,
348
            'class' => $meta->name,
349
            'table' => $meta->getTableName(),
350
            $pkName => $pkValue,
351
        ];
352
    }
353
354
    /**
355
     * Blames an audit operation.
356
     *
357
     * @return array
358
     */
359
    private function blame(): array
360
    {
361
        $user_id = null;
362
        $username = null;
363
        $client_ip = null;
364
        $user_fqdn = null;
365
        $user_firewall = null;
366
367
        $request = $this->configuration->getRequestStack()->getCurrentRequest();
368
        if (null !== $request) {
369
            $client_ip = $request->getClientIp();
370
            $user_firewall = null === $this->configuration->getFirewallMap()->getFirewallConfig($request) ? null : $this->configuration->getFirewallMap()->getFirewallConfig($request)->getName();
371
        }
372
373
        $user = null === $this->configuration->getUserProvider() ? null : $this->configuration->getUserProvider()->getUser();
374
        if ($user instanceof UserInterface) {
375
            $user_id = $user->getId();
376
            $username = $user->getUsername();
377
            $user_fqdn = DoctrineHelper::getRealClassName($user);
378
        }
379
380
        return [
381
            'user_id' => $user_id,
382
            'username' => $username,
383
            'client_ip' => $client_ip,
384
            'user_fqdn' => $user_fqdn,
385
            'user_firewall' => $user_firewall,
386
        ];
387
    }
388
389
    /**
390
     * @param Transaction $transaction
391
     *
392
     * @throws \Doctrine\DBAL\DBALException
393
     * @throws \Doctrine\ORM\Mapping\MappingException
394
     */
395
    private function processInsertions(Transaction $transaction): void
396
    {
397
        $uow = $this->em->getUnitOfWork();
398
        foreach ($transaction->getInserted() as [$entity, $ch]) {
399
            // the changeset might be updated from UOW extra updates
400
            $ch = array_merge($ch, $uow->getEntityChangeSet($entity));
401
            $this->insert($this->em, $entity, $ch, $transaction->getTransactionHash());
402
        }
403
    }
404
405
    /**
406
     * @param Transaction $transaction
407
     *
408
     * @throws \Doctrine\DBAL\DBALException
409
     * @throws \Doctrine\ORM\Mapping\MappingException
410
     */
411
    private function processUpdates(Transaction $transaction): void
412
    {
413
        $uow = $this->em->getUnitOfWork();
414
        foreach ($transaction->getUpdated() as [$entity, $ch]) {
415
            // the changeset might be updated from UOW extra updates
416
            $ch = array_merge($ch, $uow->getEntityChangeSet($entity));
417
            $this->update($this->em, $entity, $ch, $transaction->getTransactionHash());
418
        }
419
    }
420
421
    /**
422
     * @param Transaction $transaction
423
     *
424
     * @throws \Doctrine\DBAL\DBALException
425
     * @throws \Doctrine\ORM\Mapping\MappingException
426
     */
427
    private function processAssociations(Transaction $transaction): void
428
    {
429
        foreach ($transaction->getAssociated() as [$source, $target, $mapping]) {
430
            $this->associate($this->em, $source, $target, $mapping, $transaction->getTransactionHash());
431
        }
432
    }
433
434
    /**
435
     * @param Transaction $transaction
436
     *
437
     * @throws \Doctrine\DBAL\DBALException
438
     * @throws \Doctrine\ORM\Mapping\MappingException
439
     */
440
    private function processDissociations(Transaction $transaction): void
441
    {
442
        foreach ($transaction->getDissociated() as [$source, $target, $id, $mapping]) {
443
            $this->dissociate($this->em, $source, $target, $mapping, $transaction->getTransactionHash());
444
        }
445
    }
446
447
    /**
448
     * @param Transaction $transaction
449
     *
450
     * @throws \Doctrine\DBAL\DBALException
451
     * @throws \Doctrine\ORM\Mapping\MappingException
452
     */
453
    private function processDeletions(Transaction $transaction): void
454
    {
455
        foreach ($transaction->getRemoved() as [$entity, $id]) {
456
            $this->remove($this->em, $entity, $id, $transaction->getTransactionHash());
457
        }
458
    }
459
460
    /**
461
     * @param UnitOfWork $uow
462
     */
463
    private function populateWithScheduledInsertions(Transaction $transaction, UnitOfWork $uow): void
464
    {
465
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
466
            if ($this->configuration->isAudited($entity)) {
467
                $transaction->trackAuditEvent(Transaction::INSERT, [
468
                    $entity,
469
                    $uow->getEntityChangeSet($entity),
470
                ]);
471
            }
472
        }
473
    }
474
475
    /**
476
     * @param UnitOfWork $uow
477
     */
478
    private function populateWithScheduledUpdates(Transaction $transaction, UnitOfWork $uow): void
479
    {
480
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
481
            if ($this->configuration->isAudited($entity)) {
482
                $transaction->trackAuditEvent(Transaction::UPDATE, [
483
                    $entity,
484
                    $uow->getEntityChangeSet($entity),
485
                ]);
486
            }
487
        }
488
    }
489
490
    /**
491
     * @param UnitOfWork             $uow
492
     * @param EntityManagerInterface $em
493
     *
494
     * @throws \Doctrine\DBAL\DBALException
495
     * @throws \Doctrine\ORM\Mapping\MappingException
496
     */
497
    private function populateWithScheduledDeletions(Transaction $transaction, UnitOfWork $uow, EntityManagerInterface $em): void
498
    {
499
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
500
            if ($this->configuration->isAudited($entity)) {
501
                $uow->initializeObject($entity);
502
                $transaction->trackAuditEvent(Transaction::REMOVE, [
503
                    $entity,
504
                    $this->id($em, $entity),
505
                ]);
506
            }
507
        }
508
    }
509
510
    /**
511
     * @param UnitOfWork             $uow
512
     * @param EntityManagerInterface $em
513
     *
514
     * @throws \Doctrine\DBAL\DBALException
515
     * @throws \Doctrine\ORM\Mapping\MappingException
516
     */
517
    private function populateWithScheduledCollectionUpdates(Transaction $transaction, UnitOfWork $uow, EntityManagerInterface $em): void
518
    {
519
        foreach ($uow->getScheduledCollectionUpdates() as $collection) {
520
            if ($this->configuration->isAudited($collection->getOwner())) {
521
                $mapping = $collection->getMapping();
522
                foreach ($collection->getInsertDiff() as $entity) {
523
                    if ($this->configuration->isAudited($entity)) {
524
                        $transaction->trackAuditEvent(Transaction::ASSOCIATE, [
525
                            $collection->getOwner(),
526
                            $entity,
527
                            $mapping,
528
                        ]);
529
                    }
530
                }
531
                foreach ($collection->getDeleteDiff() as $entity) {
532
                    if ($this->configuration->isAudited($entity)) {
533
                        $transaction->trackAuditEvent(Transaction::DISSOCIATE, [
534
                            $collection->getOwner(),
535
                            $entity,
536
                            $this->id($em, $entity),
537
                            $mapping,
538
                        ]);
539
                    }
540
                }
541
            }
542
        }
543
    }
544
545
    /**
546
     * @param UnitOfWork             $uow
547
     * @param EntityManagerInterface $em
548
     *
549
     * @throws \Doctrine\DBAL\DBALException
550
     * @throws \Doctrine\ORM\Mapping\MappingException
551
     */
552
    private function populateWithScheduledCollectionDeletions(Transaction $transaction, UnitOfWork $uow, EntityManagerInterface $em): void
553
    {
554
        foreach ($uow->getScheduledCollectionDeletions() as $collection) {
555
            if ($this->configuration->isAudited($collection->getOwner())) {
556
                $mapping = $collection->getMapping();
557
                foreach ($collection->toArray() as $entity) {
558
                    if ($this->configuration->isAudited($entity)) {
559
                        $transaction->trackAuditEvent(Transaction::DISSOCIATE, [
560
                            $collection->getOwner(),
561
                            $entity,
562
                            $this->id($em, $entity),
563
                            $mapping,
564
                        ]);
565
                    }
566
                }
567
            }
568
        }
569
    }
570
571
    /**
572
     * Adds an association entry to the audit table.
573
     *
574
     * @param string                 $type
575
     * @param EntityManagerInterface $em
576
     * @param object                 $source
577
     * @param object                 $target
578
     * @param array                  $mapping
579
     * @param string                 $transactionHash
580
     *
581
     * @throws \Doctrine\DBAL\DBALException
582
     * @throws \Doctrine\ORM\Mapping\MappingException
583
     */
584
    private function associateOrDissociate(string $type, EntityManagerInterface $em, $source, $target, array $mapping, string $transactionHash): void
585
    {
586
        /** @var ClassMetadata $meta */
587
        $meta = $em->getClassMetadata(DoctrineHelper::getRealClassName($source));
588
        $data = [
589
            'action' => $type,
590
            'blame' => $this->blame(),
591
            'diff' => [
592
                'source' => $this->summarize($em, $source),
593
                'target' => $this->summarize($em, $target),
594
            ],
595
            'table' => $meta->getTableName(),
596
            'schema' => $meta->getSchemaName(),
597
            'id' => $this->id($em, $source),
598
            'transaction_hash' => $transactionHash,
599
            'discriminator' => $this->getDiscriminator($source, $meta->inheritanceType),
600
            'entity' => $meta->getName(),
601
        ];
602
603
        if (isset($mapping['joinTable']['name'])) {
604
            $data['diff']['table'] = $mapping['joinTable']['name'];
605
        }
606
607
        $this->audit($data);
608
    }
609
610
    /**
611
     * Adds an entry to the audit table.
612
     *
613
     * @param array $data
614
     *
615
     * @throws Exception
616
     */
617
    private function audit(array $data): void
618
    {
619
        $schema = $data['schema'] ? $data['schema'].'.' : '';
620
        $auditTable = $schema.$this->configuration->getTablePrefix().$data['table'].$this->configuration->getTableSuffix();
621
        $dt = new DateTime('now', new DateTimeZone($this->getConfiguration()->getTimezone()));
622
623
        $payload = [
624
            'entity' => $data['entity'],
625
            'table' => $auditTable,
626
            'type' => $data['action'],
627
            'object_id' => (string) $data['id'],
628
            'discriminator' => $data['discriminator'],
629
            'transaction_hash' => (string) $data['transaction_hash'],
630
            'diffs' => json_encode($data['diff']),
631
            'blame_id' => $data['blame']['user_id'],
632
            'blame_user' => $data['blame']['username'],
633
            'blame_user_fqdn' => $data['blame']['user_fqdn'],
634
            'blame_user_firewall' => $data['blame']['user_firewall'],
635
            'ip' => $data['blame']['client_ip'],
636
            'created_at' => $dt->format('Y-m-d H:i:s'),
637
        ];
638
639
        // send an `AuditEvent` event
640
        $this->notify($payload);
641
    }
642
643
    /**
644
     * @param object $entity
645
     * @param int    $inheritanceType
646
     *
647
     * @return null|string
648
     */
649
    private function getDiscriminator($entity, int $inheritanceType): ?string
650
    {
651
        return ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $inheritanceType ? DoctrineHelper::getRealClassName($entity) : null;
652
    }
653
654
    /**
655
     * Type converts the input value and returns it.
656
     *
657
     * @param EntityManagerInterface $em
658
     * @param Type                   $type
659
     * @param mixed                  $value
660
     *
661
     * @throws \Doctrine\DBAL\DBALException
662
     *
663
     * @return mixed
664
     */
665
    private function value(EntityManagerInterface $em, Type $type, $value)
666
    {
667
        if (null === $value) {
668
            return null;
669
        }
670
671
        $platform = $em->getConnection()->getDatabasePlatform();
672
673
        switch ($type->getName()) {
674
            case DoctrineHelper::getDoctrineType('BIGINT'):
675
                $convertedValue = (string) $value;
676
677
                break;
678
            case DoctrineHelper::getDoctrineType('INTEGER'):
679
            case DoctrineHelper::getDoctrineType('SMALLINT'):
680
                $convertedValue = (int) $value;
681
682
                break;
683
            case DoctrineHelper::getDoctrineType('DECIMAL'):
684
            case DoctrineHelper::getDoctrineType('FLOAT'):
685
            case DoctrineHelper::getDoctrineType('BOOLEAN'):
686
                $convertedValue = $type->convertToPHPValue($value, $platform);
687
688
                break;
689
            default:
690
                $convertedValue = $type->convertToDatabaseValue($value, $platform);
691
        }
692
693
        return $convertedValue;
694
    }
695
}
696