Completed
Pull Request — master (#27)
by jean
12:06
created

EntityResolver::buildCache()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 2
dl 0
loc 29
rs 9.456
c 0
b 0
f 0
1
<?php
2
3
namespace Darkilliant\ImportBundle\Resolver;
4
5
use Doctrine\Common\Persistence\ManagerRegistry;
6
use Doctrine\ORM\EntityManager;
7
8
class EntityResolver
9
{
10
    /** @var array */
11
    private $config;
12
13
    /** @var ManagerRegistry */
14
    private $registry;
15
16
    private $cache = [];
17
18
    /**
19
     * @var array
20
     */
21
    private $cacheable;
22
23
    public function __construct(ManagerRegistry $registry, array $config, array $cacheable)
24
    {
25
        $this->registry = $registry;
26
        $this->config = $config;
27
        $this->cacheable = $cacheable;
28
    }
29
30
    public function resolve($class, array $data, array $config = null)
31
    {
32
        if (null === $config) {
33
            $config = $this->config[$class] ?? [];
34
        }
35
36
        $where = $this->buildWhere($config, $data);
37
        if (empty($where)) {
38
            return null;
39
        }
40
41
        if (!$this->isCacheable($class)) {
42
            return $this->fetchFromRepository($class, $where);
43
        }
44
45
        if (!$this->isCacheBuilded($class)) {
46
            $this->cache[$class] = $this->buildCache($class, $where);
47
        }
48
49
        return $this->fetchFromCache($class, $where);
50
    }
51
52
    public function clear($class = null)
53
    {
54
        if (null === $class) {
55
            $this->cache = [];
56
57
            return;
58
        }
59
60
        if (isset($this->cache[$class])) {
61
            $this->cache[$class] = [];
62
63
            return;
64
        }
65
66
        return;
67
    }
68
69
    private function fetchFromCache(string $class, array $where)
70
    {
71
        $searchCompostiteKey = implode('_', array_values($where));
72
73
        $entityId = $this->cache[$class][$searchCompostiteKey] ?? null;
74
75
        /** @var EntityManager $objectManager */
76
        $objectManager = $this->registry->getManagerForClass($class);
77
78
        if (null !== $entityId) {
79
            $entity = $objectManager
80
                ->getUnitOfWork()
81
                ->createEntity($class, ['id' => $entityId]);
82
            $objectManager
83
                ->getUnitOfWork()
84
                ->setOriginalEntityData(
85
                    $entity,
86
                    $this->getFakeOriginalData($objectManager, $entity)
87
                );
88
89
            return $entity;
90
        }
91
92
        return null;
93
    }
94
95
    private function buildWhere(array $config, array $data): array
96
    {
97
        $where = [];
98
        foreach ($config as $key => $fieldName) {
99
            $dataFieldName = (is_integer($key)) ? $fieldName : $key;
100
            if (!empty($data[$dataFieldName])) {
101
                $where[$fieldName] = $data[$dataFieldName];
102
            }
103
        }
104
105
        return $where;
106
    }
107
108
    private function isCacheable($class)
109
    {
110
        return $this->cacheable[$class] ?? false;
111
    }
112
113
    private function isCacheBuilded($class)
114
    {
115
        return isset($this->cache[$class]);
116
    }
117
118
    private function buildCache($class, $where): array
119
    {
120
        /** @var EntityManager $objectManager */
121
        $objectManager = $this->registry->getManagerForClass($class);
122
123
        $selectFields = [];
124
        foreach ($where as $fieldName => $fieldValue) {
125
            $selectFields[] = sprintf('o.%s', $fieldName);
126
        }
127
128
        $qb = $objectManager->createQueryBuilder()
129
            ->select('o.id, '.implode(', ', $selectFields))
130
            ->from($class, 'o')
131
            ->indexBy('o', 'o.id');
132
133
        $result = $qb->getQuery()->getArrayResult();
134
135
        $cache = [];
136
        foreach ($result as $resultItem) {
137
            $compositeValues = $resultItem;
138
            if (!isset($where['id'])) {
139
                unset($compositeValues['id']);
140
            }
141
            $compositeKey = implode('_', array_values($compositeValues));
142
143
            $cache[$compositeKey] = $resultItem['id'];
144
        }
145
146
        return $cache;
147
    }
148
149
    private function fetchFromRepository($class, $where)
150
    {
151
        $objectManager = $this->registry->getManagerForClass($class);
152
153
        return $objectManager->getRepository($class)->findOneBy($where);
154
    }
155
156
    private function getFakeOriginalData(EntityManager $em, $entity)
157
    {
158
        $class = $em->getClassMetadata(get_class($entity));
159
160
        $field = [];
161
162
        foreach ($class->reflFields as $name => $refProp) {
163
            $field[$name] = null;
164
        }
165
166
        return $field;
167
    }
168
}
169