OrmEntityLocator::buildEntityPostfixByInterfaceName()   B
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 43
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 43
rs 8.8571
cc 3
eloc 24
nc 3
nop 1
1
<?php
2
/**
3
 * @link    https://github.com/nnx-framework/doctrine
4
 * @author  Malofeykin Andrey  <[email protected]>
5
 */
6
namespace Nnx\Doctrine\EntityManager;
7
8
use Nnx\Doctrine\ObjectManager\ObjectManagerAutoDetectorInterface;
9
use Nnx\Doctrine\Options\ModuleOptions;
10
use Nnx\Doctrine\Options\ModuleOptionsInterface;
11
use Nnx\Doctrine\Utils\DoctrineOrmModuleConfigInterface;
12
use ReflectionClass;
13
14
15
/**
16
 * Class OrmAbstractFactory
17
 *
18
 * @package Nnx\Doctrine\EntityManager
19
 */
20
class OrmEntityLocator implements OrmEntityLocatorInterface
21
{
22
    /**
23
     * @var array
24
     */
25
    protected $entityClassNameCache = [];
26
27
    /**
28
     * @var ObjectManagerAutoDetectorInterface
29
     */
30
    protected $objectManagerAutoDetector;
31
32
    /**
33
     * Настройки модуля
34
     *
35
     * @var ModuleOptions
36
     */
37
    protected $moduleOptions;
38
39
    /**
40
     * Утилита для работы с конфигами модуля DoctrineORMModule
41
     *
42
     * @var DoctrineOrmModuleConfigInterface
43
     */
44
    protected $doctrineOrmModuleConfig;
45
46
    /**
47
     * Ключем является имя интерфейса сущности, а значением постфикс сущности
48
     *
49
     * @var array
50
     */
51
    protected $interfaceNameToEntityPostfix = [];
52
53
    /**
54
     * OrmEntityLocator constructor.
55
     *
56
     * @param ObjectManagerAutoDetectorInterface $objectManagerAutoDetector
57
     * @param ModuleOptionsInterface             $moduleOptions
58
     * @param DoctrineOrmModuleConfigInterface   $doctrineOrmModuleConfig
59
     */
60
    public function __construct(
61
        ObjectManagerAutoDetectorInterface $objectManagerAutoDetector,
62
        ModuleOptionsInterface $moduleOptions,
63
        DoctrineOrmModuleConfigInterface $doctrineOrmModuleConfig
64
    ) {
65
        $this->setObjectManagerAutoDetector($objectManagerAutoDetector);
66
        $this->setModuleOptions($moduleOptions);
67
        $this->setDoctrineOrmModuleConfig($doctrineOrmModuleConfig);
68
    }
69
70
71
    /**
72
     * @inheritdoc
73
     *
74
     * @param string $id
75
     *
76
     * @return string
77
     *
78
     * @throws Exception\ErrorBuildEntityPostfixException
79
     * @throws Exception\ErrorBuildEntityClassNameException
80
     */
81
    public function get($id)
82
    {
83
        if (!$this->has($id)) {
84
            $errMsg = sprintf('Failed to get the name of the class nature of the interface %s', $id);
85
            throw new Exception\ErrorBuildEntityClassNameException($errMsg);
86
        }
87
88
        return $this->entityClassNameCache[$id];
89
    }
90
91
    /**
92
     * @inheritdoc
93
     *
94
     * @param string $id
95
     *
96
     * @return boolean
97
     *
98
     * @throws Exception\ErrorBuildEntityPostfixException
99
     */
100
    public function has($id)
101
    {
102
        if (array_key_exists($id, $this->entityClassNameCache)) {
103
            return false !== $this->entityClassNameCache[$id];
104
        }
105
106
        $objectManagerAutoDetector = $this->getObjectManagerAutoDetector();
107
        if (!$objectManagerAutoDetector->hasObjectManagerNameByClassName($id)) {
108
            $this->entityClassNameCache[$id] = false;
109
            return false;
110
        }
111
        $objectManagerName = $objectManagerAutoDetector->getObjectManagerNameByClassName($id);
112
113
        $doctrineOrmModuleConfig = $this->getDoctrineOrmModuleConfig();
114
        if (!$doctrineOrmModuleConfig->hasNamespacesByObjectManager($objectManagerName)) {
115
            $this->entityClassNameCache[$id] = false;
116
            return false;
117
        }
118
119
        $namespacesIndex = $doctrineOrmModuleConfig->getNamespacesIndexByObjectManagerName($objectManagerName);
120
121
        if (false === $this->hasEntityPostfixByInterfaceName($id)) {
122
            $this->entityClassNameCache[$id] = false;
123
            return false;
124
        }
125
        $entityPostfix = $this->getEntityPostfixByInterfaceName($id);
126
127
        $entityClassName = $this->resolveEntityClassName($entityPostfix, $namespacesIndex, $id);
128
129
        $this->entityClassNameCache[$id] = $entityClassName;
130
131
        return false !== $this->entityClassNameCache[$id];
132
    }
133
134
    /**
135
     * Поиск имени класса сущности
136
     *
137
     * @param string $entityPostfix
138
     * @param array  $namespacesIndex
139
     * @param string $entityInterface
140
     *
141
     * @return bool|string
142
     */
143
    public function resolveEntityClassName($entityPostfix, array $namespacesIndex = [], $entityInterface)
144
    {
145
        $entityClassName = false;
146
        foreach ($namespacesIndex as $rootNamespace) {
147
            $currentEntityClassName = $rootNamespace . $entityPostfix;
148
            if (class_exists($currentEntityClassName)) {
149
                $r = new ReflectionClass($currentEntityClassName);
150
                if ($r->implementsInterface($entityInterface)) {
151
                    $entityClassName = $currentEntityClassName;
152
                    break;
153
                }
154
            }
155
        }
156
157
        return $entityClassName;
158
    }
159
160
    /**
161
     * Проверяет можно ли получить постфикс имени сущности, на основе имени интерфейса
162
     *
163
     * @param $entityInterfaceName
164
     *
165
     * @return bool
166
     */
167
    public function hasEntityPostfixByInterfaceName($entityInterfaceName)
168
    {
169
        if (!array_key_exists($entityInterfaceName, $this->interfaceNameToEntityPostfix)) {
170
            $has = false !== $this->buildEntityPostfixByInterfaceName($entityInterfaceName);
171
        } else {
172
            $has = false !== $this->interfaceNameToEntityPostfix[$entityInterfaceName];
173
        }
174
175
        return $has;
176
    }
177
178
    /**
179
     *  По имени интерфейса получает постфикс имени сущности, либо возвращает false - если не удалось это сделать
180
     *
181
     * @param $entityInterfaceName
182
     *
183
     * @return string|bool
184
     */
185
    public function buildEntityPostfixByInterfaceName($entityInterfaceName)
186
    {
187
        $moduleOptions = $this->getModuleOptions();
188
189
        $delimiter = $moduleOptions->getEntitySeparator();
190
191
        $stackEntityInterfaceName = explode($delimiter, $entityInterfaceName);
192
193
        if (2 !== count($stackEntityInterfaceName)) {
194
            $this->interfaceNameToEntityPostfix[$entityInterfaceName] = false;
195
            return false;
196
        }
197
198
        $postfixEntityInterfaceName = array_pop($stackEntityInterfaceName);
199
200
        $stackPostfixEntityInterfaceName = explode('\\', $postfixEntityInterfaceName);
201
202
        $interfaceName = array_pop($stackPostfixEntityInterfaceName);
203
204
        $entityBodyNamePattern = $moduleOptions->getEntityBodyNamePattern();
205
206
        $entityBodyNameOutput = [];
207
        preg_match($entityBodyNamePattern, $interfaceName, $entityBodyNameOutput);
208
209
        if (2 !== count($entityBodyNameOutput)) {
210
            $this->interfaceNameToEntityPostfix[$entityInterfaceName] = false;
211
            return false;
212
        }
213
        $entityBodyName =  array_pop($entityBodyNameOutput);
214
215
        $prefix = $moduleOptions->getEntityNamePrefix();
216
        $postfix = $moduleOptions->getEntityNamePostfix();
217
218
        $entityName = $prefix . $entityBodyName . $postfix;
219
220
        $stackPostfixEntityInterfaceName[] = $entityName;
221
222
        $entityPostfix = implode('\\', $stackPostfixEntityInterfaceName);
223
224
        $this->interfaceNameToEntityPostfix[$entityInterfaceName] = $entityPostfix;
225
226
        return $this->interfaceNameToEntityPostfix[$entityInterfaceName];
227
    }
228
229
230
    /**
231
     * Получение постфикса имени сущности, на основе имени интерфейса
232
     *
233
     * @param $entityInterfaceName
234
     *
235
     * @return string
236
     *
237
     * @throws Exception\ErrorBuildEntityPostfixException
238
     */
239
    public function getEntityPostfixByInterfaceName($entityInterfaceName)
240
    {
241
        if (false === $this->hasEntityPostfixByInterfaceName($entityInterfaceName)) {
242
            $errMsg = sprintf('Error build entity postfix for %s', $entityInterfaceName);
243
            throw new Exception\ErrorBuildEntityPostfixException($errMsg);
244
        }
245
246
        return $this->interfaceNameToEntityPostfix[$entityInterfaceName];
247
    }
248
249
    /**
250
     * @return ObjectManagerAutoDetectorInterface
251
     */
252
    public function getObjectManagerAutoDetector()
253
    {
254
        return $this->objectManagerAutoDetector;
255
    }
256
257
    /**
258
     * @param ObjectManagerAutoDetectorInterface $objectManagerAutoDetector
259
     *
260
     * @return $this
261
     */
262
    public function setObjectManagerAutoDetector($objectManagerAutoDetector)
263
    {
264
        $this->objectManagerAutoDetector = $objectManagerAutoDetector;
265
266
        return $this;
267
    }
268
269
    /**
270
     * Возвращает настройки модуля
271
     *
272
     * @return ModuleOptionsInterface
273
     */
274
    public function getModuleOptions()
275
    {
276
        return $this->moduleOptions;
277
    }
278
279
    /**
280
     * Устанавливает настройки модуля
281
     *
282
     * @param ModuleOptionsInterface $moduleOptions
283
     *
284
     * @return $this
285
     */
286
    public function setModuleOptions(ModuleOptionsInterface $moduleOptions)
287
    {
288
        $this->moduleOptions = $moduleOptions;
0 ignored issues
show
Documentation Bug introduced by
$moduleOptions is of type object<Nnx\Doctrine\Opti...ModuleOptionsInterface>, but the property $moduleOptions was declared to be of type object<Nnx\Doctrine\Options\ModuleOptions>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
289
290
        return $this;
291
    }
292
293
    /**
294
     * Возвращает утилиту для работы с конфигами модуля DoctrineORMModule
295
     *
296
     * @return DoctrineOrmModuleConfigInterface
297
     */
298
    public function getDoctrineOrmModuleConfig()
299
    {
300
        return $this->doctrineOrmModuleConfig;
301
    }
302
303
    /**
304
     * Устанавливает утилиту для работы с конфигами модуля DoctrineORMModule
305
     *
306
     * @param DoctrineOrmModuleConfigInterface $doctrineOrmModuleConfig
307
     *
308
     * @return $this
309
     */
310
    public function setDoctrineOrmModuleConfig($doctrineOrmModuleConfig)
311
    {
312
        $this->doctrineOrmModuleConfig = $doctrineOrmModuleConfig;
313
314
        return $this;
315
    }
316
}
317