getObjectManagerAutoDetector()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * @link    https://github.com/nnx-framework/doctrine
4
 * @author  Malofeykin Andrey  <[email protected]>
5
 */
6
namespace Nnx\Doctrine\Hydrator;
7
8
use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
9
use Doctrine\Common\Persistence\ObjectManager;
10
use ReflectionClass;
11
use Nnx\Doctrine\ObjectManager\ObjectManagerAutoDetectorInterface;
12
use Nnx\Doctrine\ObjectManager\DoctrineObjectManagerInterface;
13
14
15
/**
16
 * Class DoctrineObjectHydratorLocator
17
 *
18
 * @package Nnx\Doctrine\Hydrator
19
 */
20
class DoctrineObjectHydratorLocator implements DoctrineObjectHydratorLocatorInterface
21
{
22
    /**
23
     * Кеши - ключем является имя класса гидратора,  значением объект прототип, либо false
24
     *
25
     * @var array
26
     */
27
    protected $prototype = [];
28
29
    /**
30
     * Кеш ключем которого является имя класса гидратора, а значением true/false. Т.е. является ли класс корректным потомком
31
     * \DoctrineModule\Stdlib\Hydrator\DoctrineObject
32
     *
33
     * @var array
34
     */
35
    protected $validDoctrineObjectHydratorClass = [];
36
37
    /**
38
     * Сервис позволяющий получить ObjectManager по имени класса
39
     *
40
     * @var ObjectManagerAutoDetectorInterface
41
     */
42
    protected $objectManagerAutoDetector;
43
44
    /**
45
     * Плагин менеджер для получения ObjectManager'ов доктрины
46
     *
47
     * @var DoctrineObjectManagerInterface
48
     */
49
    protected $doctrineObjectManager;
50
51
    /**
52
     * Ключем является имя класса,  а значением объект рефлексии для него
53
     *
54
     * @var array
55
     */
56
    protected $reflectionClassCache = [];
57
58
    /**
59
     * DoctrineObjectHydratorLocator constructor.
60
     *
61
     * @param ObjectManagerAutoDetectorInterface $objectManagerAutoDetector
62
     * @param DoctrineObjectManagerInterface     $doctrineObjectManager
63
     */
64
    public function __construct(ObjectManagerAutoDetectorInterface $objectManagerAutoDetector, DoctrineObjectManagerInterface $doctrineObjectManager)
65
    {
66
        $this->setObjectManagerAutoDetector($objectManagerAutoDetector);
67
        $this->setDoctrineObjectManager($doctrineObjectManager);
68
    }
69
70
    /**
71
     * @param string $id
72
     *
73
     * @return DoctrineObject
74
     *
75
     * @throws Exception\NotFoundDoctrineObjectHydratorException
76
     */
77
    public function get($id)
78
    {
79
        if (false === $this->has($id)) {
80
            $errMsg = sprintf('Invalid create %s', $id);
81
            throw new Exception\NotFoundDoctrineObjectHydratorException($errMsg);
82
        }
83
84
        return clone $this->prototype[$id];
85
    }
86
87
    /**
88
     * @inheritdoc
89
     *
90
     * @param string $id
91
     *
92
     * @return bool
93
     */
94
    public function has($id)
95
    {
96
        if (array_key_exists($id, $this->prototype)) {
97
            return false !== $this->prototype[$id];
98
        }
99
100
        $this->prototype[$id] = $this->buildDoctrineObjectHydratorPrototype($id);
101
102
        return false !== $this->prototype[$id];
103
    }
104
105
    /**
106
     * Созддает объект прототип по имени гидратора
107
     *
108
     * @param $hydratorName
109
     *
110
     * @return DoctrineObject|false
111
     */
112
    protected function buildDoctrineObjectHydratorPrototype($hydratorName)
113
    {
114
        if (!class_exists($hydratorName)) {
115
            $this->prototype[$hydratorName] = false;
116
            return false;
117
        }
118
119
        if (!$this->isValidDoctrineObjectHydratorClass($hydratorName)) {
120
            $this->prototype[$hydratorName] = false;
121
            return false;
122
        }
123
124
        $objectManagerAutoDetector = $this->getObjectManagerAutoDetector();
125
        if (false === $objectManagerAutoDetector->hasObjectManagerNameByClassName($hydratorName)) {
126
            $this->prototype[$hydratorName] = false;
127
            return false;
128
        }
129
130
        $objectManagerName = $objectManagerAutoDetector->getObjectManagerNameByClassName($hydratorName);
131
132
        $doctrineObjectManager = $this->getDoctrineObjectManager();
133
134
        if (false === $doctrineObjectManager->has($objectManagerName)) {
135
            $this->prototype[$hydratorName] = false;
136
            return false;
137
        }
138
139
        /** @var ObjectManager $objectManager */
140
        $objectManager = $doctrineObjectManager->get($objectManagerName);
141
142
        $r = array_key_exists($hydratorName, $this->reflectionClassCache) ? $this->reflectionClassCache[$hydratorName] : new ReflectionClass($hydratorName);
143
144
        $this->prototype[$hydratorName] = $r->newInstance($objectManager);
145
146
147
        return $this->prototype[$hydratorName];
148
    }
149
150
    /**
151
     * Проверка является ли класс корректным потомком \DoctrineModule\Stdlib\Hydrator\DoctrineObject
152
     *
153
     * @param $hydratorClass
154
     *
155
     * @return bool
156
     */
157
    public function isValidDoctrineObjectHydratorClass($hydratorClass)
158
    {
159
        if (array_key_exists($hydratorClass, $this->validDoctrineObjectHydratorClass)) {
160
            return $this->validDoctrineObjectHydratorClass[$hydratorClass];
161
        }
162
163
        $r = array_key_exists($hydratorClass, $this->reflectionClassCache) ? $this->reflectionClassCache[$hydratorClass] : new ReflectionClass($hydratorClass);
164
165
        if (!$r->isInstantiable()) {
166
            $this->validDoctrineObjectHydratorClass[$hydratorClass] = false;
167
            return false;
168
        }
169
170
        if (!$r->isSubclassOf(DoctrineObject::class)) {
171
            $this->validDoctrineObjectHydratorClass[$hydratorClass] = false;
172
            return false;
173
        }
174
175
        $rConstructorParams = $r->getConstructor()->getParameters();
176
177
        $isConstructorParamValid = true;
178
        foreach ($rConstructorParams as $rParam) {
179
            if (0 === $rParam->getPosition()) {
180
                $rArgClass = $rParam->getClass();
181
                if (null !== $rArgClass && ObjectManager::class !== $rArgClass->getName()) {
182
                    $isConstructorParamValid = false;
183
                    break;
184
                }
185
                continue;
186
            }
187
188
            if (!$rParam->isOptional()) {
189
                $isConstructorParamValid = false;
190
                break;
191
            }
192
        }
193
194
195
        $this->validDoctrineObjectHydratorClass[$hydratorClass] = $isConstructorParamValid;
196
197
        return true;
198
    }
199
200
    /**
201
     * Возвращает сервис позволяющий получить ObjectManager по имени класса
202
     *
203
     * @return ObjectManagerAutoDetectorInterface
204
     */
205
    public function getObjectManagerAutoDetector()
206
    {
207
        return $this->objectManagerAutoDetector;
208
    }
209
210
    /**
211
     * Устанавливает сервис позволяющий получить ObjectManager по имени класса
212
     *
213
     * @param ObjectManagerAutoDetectorInterface $objectManagerAutoDetector
214
     *
215
     * @return $this
216
     */
217
    public function setObjectManagerAutoDetector(ObjectManagerAutoDetectorInterface $objectManagerAutoDetector)
218
    {
219
        $this->objectManagerAutoDetector = $objectManagerAutoDetector;
220
221
        return $this;
222
    }
223
224
    /**
225
     * Возвращает плагин менеджер для получения ObjectManager'ов доктрины
226
     *
227
     * @return DoctrineObjectManagerInterface
228
     */
229
    public function getDoctrineObjectManager()
230
    {
231
        return $this->doctrineObjectManager;
232
    }
233
234
    /**
235
     * Устанавливает плагин менеджер для получения ObjectManager'ов доктрины
236
     *
237
     * @param DoctrineObjectManagerInterface $doctrineObjectManager
238
     *
239
     * @return $this
240
     */
241
    public function setDoctrineObjectManager($doctrineObjectManager)
242
    {
243
        $this->doctrineObjectManager = $doctrineObjectManager;
244
245
        return $this;
246
    }
247
}
248