EntityResolver   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 92
dl 0
loc 195
ccs 90
cts 90
cp 1
rs 10
c 0
b 0
f 0
wmc 28

10 Methods

Rating   Name   Duplication   Size   Complexity  
A isCacheBuilded() 0 3 1
A buildCache() 0 29 4
B resolve() 0 50 9
A buildWhere() 0 11 4
A fetchFromRepository() 0 5 1
A fetchFromCache() 0 24 2
A __construct() 0 6 1
A getFakeOriginalData() 0 11 2
A isCacheable() 0 3 1
A clear() 0 15 3
1
<?php
2
3
namespace Darkilliant\ImportBundle\Resolver;
4
5
use Darkilliant\ImportBundle\Registry\EntityResolverWhereBuilderRegistry;
6
use Doctrine\Common\Persistence\ManagerRegistry;
7
use Doctrine\ORM\EntityManager;
8
9
class EntityResolver
10
{
11
    const STRATEGY_WHERE = 'where';
12
    /** @var array */
13
    private $config;
14
15
    /** @var ManagerRegistry */
16
    private $registry;
17
18
    private $cache = [];
19
20
    /** @var EntityResolverWhereBuilderRegistry */
21
    private $whereBuilderRegistry;
22
23
    /**
24
     * @var array
25
     */
26
    private $cacheable;
27
28 6
    public function __construct(ManagerRegistry $registry, EntityResolverWhereBuilderRegistry $whereBuilderRegistry, array $config, array $cacheable)
29
    {
30 6
        $this->registry = $registry;
31 6
        $this->config = $config;
32 6
        $this->cacheable = $cacheable;
33 6
        $this->whereBuilderRegistry = $whereBuilderRegistry;
34 6
    }
35
36 5
    public function resolve($class, array $data, array $config = null)
37
    {
38 5
        if (null === $config) {
39 3
            $config = $this->config[$class] ?? [];
40
        }
41
42
        // Legacy format (remove for 1.1)
43 5
        if (isset($config[0])) {
44
            $config = [
45 3
                'strategy' => self::STRATEGY_WHERE,
46
                'options' => [
47
                    'service' => null,
48 3
                    'fields' => $config,
49
                ],
50
            ];
51
        }
52
53 5
        if (empty($config)) {
54 1
            return null;
55
        }
56
57 5
        if (self::STRATEGY_WHERE === $config['strategy']) {
58
            // Use custom where
59 4
            if ($config['options']['service']) {
60 1
                $where = $this->whereBuilderRegistry->resolveService(
61 1
                    $config['options']['service']
62 1
                )->buildWhere($class, $config['options'], $data);
63
            } else {
64 3
                $where = $this->buildWhere($config['options']['fields'], $data);
65
            }
66
67 4
            if (empty($where)) {
68 1
                return null;
69
            }
70
71 3
            if (!$this->isCacheable($class)) {
72 2
                return $this->fetchFromRepository($class, $where);
73
            }
74
75 1
            if (!$this->isCacheBuilded($class)) {
76 1
                $this->cache[$class] = $this->buildCache($class, $where);
77
            }
78
79 1
            return $this->fetchFromCache($class, $where);
80
        }
81
82 1
        throw new \Exception(sprintf(
83 1
            'unknow strategy %s, resolve entity %s',
84 1
            $config['strategy'],
85 1
            $class
86
        ));
87
    }
88
89 2
    public function clear($class = null)
90
    {
91 2
        if (null === $class) {
92 1
            $this->cache = [];
93
94 1
            return;
95
        }
96
97 2
        if (isset($this->cache[$class])) {
98 1
            $this->cache[$class] = [];
99
100 1
            return;
101
        }
102
103 1
        return;
104
    }
105
106 1
    private function fetchFromCache(string $class, array $where)
107
    {
108 1
        $searchCompostiteKey = implode('_', array_values($where));
109
110 1
        $entityId = $this->cache[$class][$searchCompostiteKey] ?? null;
111
112
        /** @var EntityManager $objectManager */
113 1
        $objectManager = $this->registry->getManagerForClass($class);
114
115 1
        if (null !== $entityId) {
116
            $entity = $objectManager
117 1
                ->getUnitOfWork()
118 1
                ->createEntity($class, ['id' => $entityId]);
119
            $objectManager
120 1
                ->getUnitOfWork()
121 1
                ->setOriginalEntityData(
122 1
                    $entity,
123 1
                    $this->getFakeOriginalData($objectManager, $entity)
124
                );
125
126 1
            return $entity;
127
        }
128
129 1
        return null;
130
    }
131
132 3
    private function buildWhere(array $config, array $data): array
133
    {
134 3
        $where = [];
135 3
        foreach ($config as $key => $fieldName) {
136 3
            $dataFieldName = (is_integer($key)) ? $fieldName : $key;
137 3
            if (!empty($data[$dataFieldName])) {
138 3
                $where[$fieldName] = $data[$dataFieldName];
139
            }
140
        }
141
142 3
        return $where;
143
    }
144
145 3
    private function isCacheable($class)
146
    {
147 3
        return $this->cacheable[$class] ?? false;
148
    }
149
150 1
    private function isCacheBuilded($class)
151
    {
152 1
        return isset($this->cache[$class]);
153
    }
154
155 1
    private function buildCache($class, $where): array
156
    {
157
        /** @var EntityManager $objectManager */
158 1
        $objectManager = $this->registry->getManagerForClass($class);
159
160 1
        $selectFields = [];
161 1
        foreach ($where as $fieldName => $fieldValue) {
162 1
            $selectFields[] = sprintf('o.%s', $fieldName);
163
        }
164
165 1
        $qb = $objectManager->createQueryBuilder()
166 1
            ->select('o.id, '.implode(', ', $selectFields))
167 1
            ->from($class, 'o')
168 1
            ->indexBy('o', 'o.id');
169
170 1
        $result = $qb->getQuery()->getArrayResult();
171
172 1
        $cache = [];
173 1
        foreach ($result as $resultItem) {
174 1
            $compositeValues = $resultItem;
175 1
            if (!isset($where['id'])) {
176 1
                unset($compositeValues['id']);
177
            }
178 1
            $compositeKey = implode('_', array_values($compositeValues));
179
180 1
            $cache[$compositeKey] = $resultItem['id'];
181
        }
182
183 1
        return $cache;
184
    }
185
186 2
    private function fetchFromRepository($class, $where)
187
    {
188 2
        $objectManager = $this->registry->getManagerForClass($class);
189
190 2
        return $objectManager->getRepository($class)->findOneBy($where);
191
    }
192
193 1
    private function getFakeOriginalData(EntityManager $em, $entity)
194
    {
195 1
        $class = $em->getClassMetadata(get_class($entity));
196
197 1
        $field = [];
198
199 1
        foreach ($class->reflFields as $name => $refProp) {
200 1
            $field[$name] = null;
201
        }
202
203 1
        return $field;
204
    }
205
}
206