UniqueActiveListener   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
eloc 41
dl 0
loc 102
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A uniqueActive() 0 31 4
A prePersist() 0 3 1
A __construct() 0 7 2
A preUpdate() 0 3 1
A getSubscribedEvents() 0 6 1
A addFieldFilter() 0 10 4
A loadClassMetadata() 0 14 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * (c) Christian Gripp <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Core23\Doctrine\EventListener\ORM;
13
14
use Core23\Doctrine\Model\UniqueActiveInterface;
15
use Doctrine\Common\EventSubscriber;
16
use Doctrine\ORM\Event\LifecycleEventArgs;
17
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
18
use Doctrine\ORM\Events;
19
use Doctrine\ORM\Mapping\MappingException;
20
use Doctrine\ORM\QueryBuilder;
21
use Doctrine\ORM\UnitOfWork;
22
use Symfony\Component\PropertyAccess\PropertyAccess;
23
use Symfony\Component\PropertyAccess\PropertyAccessor;
24
25
final class UniqueActiveListener implements EventSubscriber
26
{
27
    /**
28
     * @var PropertyAccessor
29
     */
30
    private $propertyAccessor;
31
32
    /**
33
     * @param PropertyAccessor $propertyAccessor
34
     */
35
    public function __construct(PropertyAccessor $propertyAccessor = null)
36
    {
37
        if (null === $propertyAccessor) {
38
            $propertyAccessor = PropertyAccess::createPropertyAccessor();
39
        }
40
41
        $this->propertyAccessor = $propertyAccessor;
42
    }
43
44
    public function getSubscribedEvents()
45
    {
46
        return [
47
            Events::prePersist,
48
            Events::preUpdate,
49
            Events::loadClassMetadata,
50
        ];
51
    }
52
53
    public function prePersist(LifecycleEventArgs $args): void
54
    {
55
        $this->uniqueActive($args);
56
    }
57
58
    public function preUpdate(LifecycleEventArgs $args): void
59
    {
60
        $this->uniqueActive($args);
61
    }
62
63
    /**
64
     * @throws MappingException
65
     */
66
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void
67
    {
68
        $meta = $eventArgs->getClassMetadata();
69
70
        $reflClass = $meta->getReflectionClass();
71
72
        if (null === $reflClass || !$reflClass->implementsInterface(UniqueActiveInterface::class)) {
73
            return;
74
        }
75
76
        if (!$meta->hasField('active')) {
77
            $meta->mapField([
78
                'type'      => 'integer',
79
                'fieldName' => 'active',
80
            ]);
81
        }
82
    }
83
84
    private function uniqueActive(LifecycleEventArgs $args): void
85
    {
86
        $entity = $args->getEntity();
87
88
        if (!$entity instanceof UniqueActiveInterface) {
89
            return;
90
        }
91
92
        if (!$entity->isActive()) {
93
            return;
94
        }
95
96
        $em   = $args->getEntityManager();
97
        $uow  = $em->getUnitOfWork();
98
        $meta = $em->getClassMetadata(\get_class($entity));
99
100
        $qb = $em->createQueryBuilder()
101
            ->update($meta->getName(), 'e')
102
            ->set('e.active', 'false')
103
            ->andWhere('e.active = true')
104
        ;
105
106
        foreach ($meta->getIdentifier() as $key) {
107
            $qb->andWhere(sprintf('e.%s != :%s', $key, $key))
108
                ->setParameter($key, $this->propertyAccessor->getValue($entity, $key))
109
            ;
110
        }
111
112
        $this->addFieldFilter($qb, $entity, $uow);
113
114
        $qb->getQuery()->execute();
115
    }
116
117
    private function addFieldFilter(QueryBuilder $qb, UniqueActiveInterface $entity, UnitOfWork $uow): void
118
    {
119
        foreach ($entity->getUniqueActiveFields() as $field) {
120
            $value = $this->propertyAccessor->getValue($entity, $field);
121
122
            if (\is_object($value) && null === $uow->getSingleIdentifierValue($value)) {
123
                continue;
124
            }
125
126
            $qb->andWhere('e.'.$field.' = :'.$field)->setParameter($field, $value);
127
        }
128
    }
129
}
130