LoadFlushListener::postLoad()   B
last analyzed

Complexity

Conditions 6
Paths 16

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 40
c 0
b 0
f 0
ccs 26
cts 26
cp 1
rs 8.439
cc 6
eloc 25
nc 16
nop 1
crap 6
1
<?php
2
3
/**
4
 * @author KonstantinKuklin <[email protected]>
5
 */
6
7
namespace KonstantinKuklin\DoctrineCompressedFields\EventListener;
8
9
use Doctrine\Common\EventSubscriber;
10
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
11
use Doctrine\DBAL\Types\Type;
12
use Doctrine\ORM\EntityManager;
13
use Doctrine\ORM\Event\PreFlushEventArgs;
14
use Doctrine\ORM\Events;
15
use KonstantinKuklin\DoctrineCompressedFields\Engine;
16
use KonstantinKuklin\DoctrineCompressedFields\MetadataLayer;
17
18
class LoadFlushListener implements EventSubscriber
19
{
20
    private $engine;
21
22
    /**
23
     * @var array
24
     */
25
    private $originalData;
26
27
    public function __construct()
28
    {
29
        $this->engine = new Engine();
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function getSubscribedEvents()
36
    {
37
        return [
38
            Events::preFlush,
39
            Events::postLoad,
40
        ];
41
    }
42
43
    /**
44
     * @param LifecycleEventArgs $args
45
     */
46 3
    public function postLoad(LifecycleEventArgs $args)
47
    {
48 3
        $entity = $args->getObject();
49
        /** @var EntityManager $em */
50 3
        $em = $args->getObjectManager();
51 3
        $entityClass = get_class($entity);
52 3
        $classMetadata = $em->getClassMetadata($entityClass);
53
54 3
        $pathHub = MetadataLayer::PATH_HUB;
55 3
        $pathMaskGrouped = MetadataLayer::PATH_MASK_BY_HUB;
56
57 3
        $maskListGrouped = !empty($classMetadata->$pathMaskGrouped) ? $classMetadata->$pathMaskGrouped : [];
58 3
        $hubList = !empty($classMetadata->$pathHub) ? $classMetadata->$pathHub : [];
59
60 3
        $hash = implode(' ', (array)$classMetadata->getIdentifier());
61 3
        $identifierValueList = implode(' ', $classMetadata->getIdentifierValues($entity));
62 3
        foreach ($hubList as $hubData) {
63
            /** @var \ReflectionProperty $property */
64 3
            $property = $hubData['reflection'];
65 3
            $hubValue = $property->getValue($entity);
66
67 3
            $valueList = $this->engine->getUnpackedValueList(
68 3
                $hubValue,
69 3
                $maskListGrouped[$property->getName()]
70
            );
71
72 3
            foreach ($valueList as $valueKey => $value) {
73
                /** @var \ReflectionProperty $reflection */
74 3
                $reflection = $maskListGrouped[$property->getName()][$valueKey]['reflection'];
75 3
                if ($maskListGrouped[$property->getName()][$valueKey]['annotation']->type === Type::BOOLEAN) {
76 3
                    $value = (bool)$value;
77
                }
78 3
                $reflection->setValue($entity, $value);
79 3
                $this->originalData[$entityClass][$hash][$property->getName()] = [
80 3
                    'id' => $identifierValueList,
81 3
                    'value' => $value,
82
                ];
83
            }
84
        }
85 3
    }
86
87
    /**
88
     * @param PreFlushEventArgs $args
89
     *
90
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
91
     */
92 5
    public function preFlush(PreFlushEventArgs $args)
93
    {
94 5
        $em = $args->getEntityManager();
95 5
        $unitOfWork = $em->getUnitOfWork();
96
97 5
        foreach ($unitOfWork->getScheduledEntityInsertions() as $entity) {
98 3
            $this->updateCompressedHubProperty($em, $entity);
99
        }
100
101 5
        if (empty($this->originalData)) {
102 3
            return;
103
        }
104
105 2
        foreach ($this->originalData as $classEntity => $hashList) {
106 2
            foreach ($hashList as $hash => $valueList) {
107 2
                $value = array_pop($valueList);
108 2
                $entity = $unitOfWork->tryGetByIdHash($value['id'], $classEntity);
109 2
                if (!$entity) {
110 1
                    continue;
111
                }
112
113 1
                $is_updated = $this->updateCompressedHubProperty($em, $entity);
114 1
                if ($is_updated && !$unitOfWork->isScheduledForUpdate($entity)) {
115 2
                    $unitOfWork->scheduleForUpdate($entity);
116
                }
117
            }
118
        }
119 2
    }
120
121
    /**
122
     * @param \Doctrine\ORM\EntityManager $em
123
     * @param                             $entity
124
     *
125
     * @return bool
126
     */
127 4
    private function updateCompressedHubProperty(EntityManager $em, $entity)
128
    {
129 4
        $entityClass = get_class($entity);
130 4
        $hash = spl_object_hash($entity);
131 4
        $classMetadata = $em->getClassMetadata($entityClass);
132
133 4
        $pathHub = MetadataLayer::PATH_HUB;
134 4
        $pathMaskGrouped = MetadataLayer::PATH_MASK_BY_HUB;
135
136 4
        $maskListGrouped = !empty($classMetadata->$pathMaskGrouped) ? $classMetadata->$pathMaskGrouped : [];
137 4
        $hubList = !empty($classMetadata->$pathHub) ? $classMetadata->$pathHub : [];
138
139 4
        $is_updated = false;
140 4
        foreach ($hubList as $hubData) {
141
            /** @var \ReflectionProperty $hubReflection */
142 4
            $hubReflection = $hubData['reflection'];
143
144 4
            $valueList = [];
145 4
            if (!isset($maskListGrouped[$hubReflection->getName()])) {
146
                continue;
147
            }
148
149 4
            foreach ($maskListGrouped[$hubReflection->getName()] as $maskData) {
150
                /** @var \ReflectionProperty $maskReflection */
151 4
                $maskReflection = $maskData['reflection'];
152 4
                $value = $maskReflection->getValue($entity);
153 4
                if (isset($this->originalData[$entityClass][$hash][$maskReflection->getName()])) {
154
                    if ($this->originalData[$entityClass][$hash][$maskReflection->getName()] == $value) {
155
                        // nothing was changed, we can skip it
156
                        continue;
157
                    }
158
                }
159 4
                if (!$value) {
160 2
                    $value = 0;
161
                }
162 4
                $valueList[$maskReflection->getName()] = $value;
163
            }
164
165 4
            if (empty($valueList)) {
166
                continue;
167
            }
168
169 4
            $oldHubValue = $hubReflection->getValue($entity);
170 4
            if (!$oldHubValue) {
171 3
                $oldHubValue = 0;
172
            }
173 4
            $newHubValue = $this->engine->getPackedValue(
174 4
                $oldHubValue,
175 4
                $maskListGrouped[$hubReflection->getName()],
176 4
                $valueList
177
            );
178 4
            if ($oldHubValue !== $newHubValue) {
179 4
                $hubReflection->setValue($entity, $newHubValue);
180 4
                $is_updated = true;
181
            }
182
        }
183
184 4
        return $is_updated;
185
    }
186
}
187