Register::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
nc 4
nop 1
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 3
rs 10
c 2
b 0
f 0
1
<?php
2
3
namespace BlueRegister;
4
5
use BlueRegister\Events\Event;
6
use BlueEvent\Event\Base\EventDispatcher;
7
use SimpleLog\Log as SimpleLog;
8
9
class Register
10
{
11
    /**
12
     * @var array
13
     */
14
    protected $config = [
15
        'log' => false,
16
        'events' => false,
17
        'log_object' => SimpleLog::class,
18
        'event_object' => EventDispatcher::class,
19
        'event_config' => [],
20
    ];
21
22
    /**
23
     * store information of all called by register objects
24
     *
25
     * @var array
26
     */
27
    protected $registeredObjects = [];
28
29
    /**
30
     * store list of objects called as singletons
31
     *
32
     * @var array
33
     */
34
    protected $singletons = [];
35
36
    /**
37
     * store list of overrides
38
     *
39
     * @var array
40
     */
41
    protected $overrides = [];
42
43
    /**
44
     * store information about number of created objects
45
     *
46
     * @var array
47
     */
48
    protected $classCounter = [];
49
50
    /**
51
     * @var bool
52
     */
53
    protected $allowOverride = false;
54
55
    /**
56
     * @var null|\BlueRegister\Events\Event
57
     */
58
    protected $event;
59
60
    /**
61
     * @var null|\BlueRegister\Log
62
     */
63
    protected $log;
64
65
    /**
66
     * Register constructor. Allow to set config on create
67
     *
68
     * @param array $config
69
     * @throws \LogicException
70
     * @throws \InvalidArgumentException
71
     */
72 20
    public function __construct(array $config = [])
73
    {
74 20
        $this->config = array_merge($this->config, $config);
75
76 20
        if ($this->config['log'] === true) {
77 7
            $this->log = new Log($this->config['log_object']);
78 4
        }
79
80 17
        if ($this->config['events'] === true) {
81 8
            $this->event = new Event($this->config, $this->log);
82 5
        }
83 14
    }
84
85
    /**
86
     * create new instance of given class
87
     *
88
     * @param string $namespace
89
     * @param array $args
90
     * @return mixed
91
     * @throws \InvalidArgumentException
92
     * @throws RegisterException
93
     */
94 12
    public function factory($namespace, array $args = [])
95
    {
96 12
        $namespace = $this->checkOverrider($namespace);
97
98 11
        $this->classExists($namespace)
99 10
            ->callEvent('register_before_create', [$namespace, $args]);
100
101
        try {
102 10
            $object = new $namespace(...$args);
103 10
        } catch (\Exception $exception) {
104 1
            throw new RegisterException($exception);
105
        }
106
107 9
        $this->callEvent('register_after_create', [$object]);
108
109 9
        $this->setClassCounter($namespace);
110 9
        $this->registeredObjects[$namespace] = get_class($object);
111
112 9
        $this->makeLog([
113 9
            'Object created: ' . $namespace . '. With args:',
114
            $args
115 9
        ]);
116
117 9
        return $object;
118
    }
119
120
    /**
121
     * create singleton instance of given class
122
     *
123
     * @param string $namespace
124
     * @param array $args
125
     * @param null|string $name
126
     * @return mixed
127
     * @throws \InvalidArgumentException
128
     * @throws RegisterException
129
     */
130 4
    public function singletonFactory($namespace, array $args = [], $name = null)
131
    {
132 4
        if (is_null($name)) {
133 4
            $name = $namespace;
134 4
        }
135
136 4
        if (!isset($this->singletons[$name])) {
137 4
            $this->singletons[$name] = $this->factory($namespace, $args);
138 4
        }
139
140 4
        $this->callEvent(
141 4
            'register_before_return_singleton',
142 4
            [$this->singletons[$name], $args, $name]
143 4
        );
144
145 4
        return $this->singletons[$name];
146
    }
147
148
    /**
149
     * check that given class should be replaced by some other
150
     *
151
     * @param string $namespace
152
     * @return string
153
     * @throws \InvalidArgumentException
154
     */
155 12
    protected function checkOverrider($namespace)
156
    {
157 12
        if ($this->allowOverride && isset($this->overrides[$namespace])) {
158 4
            $oldNamespace = $namespace;
159
160 4
            $namespace = $this->overrides[$namespace]['overrider'];
161 4
            $this->classExists($namespace);
162
163 3
            if ($this->overrides[$oldNamespace]['only_once']) {
164 1
                $this->unsetOverrider($oldNamespace);
165 1
            }
166 3
        }
167
168 11
        return $namespace;
169
    }
170
171
    /**
172
     * get all configuration or only specified key
173
     *
174
     * @param null|string $key
175
     * @return array|mixed
176
     */
177 1
    public function getConfig($key = null)
178
    {
179 1
        if (is_null($key)) {
180 1
            return $this->config;
181
        }
182
183 1
        return $this->config[$key];
184
    }
185
186
    /**
187
     * set config parameter
188
     *
189
     * @param string $key
190
     * @param mixed $val
191
     * @return $this
192
     */
193 1
    public function setConfig($key, $val)
194
    {
195 1
        $this->config[$key] = $val;
196 1
        return $this;
197
    }
198
199
    /**
200
     * check that class exists and throw exception if not
201
     *
202
     * @param string $namespace
203
     * @return $this
204
     * @throws \InvalidArgumentException
205
     */
206 12
    protected function classExists($namespace)
207
    {
208 12
        if (!class_exists($namespace)) {
209 4
            $this->callEvent('register_class_dont_exists', [$namespace]);
210
211 3
            throw new \InvalidArgumentException('Class don\'t exists: ' . $namespace);
212
        }
213
214 10
        return $this;
215
    }
216
217
    /**
218
     * @param string $name
219
     * @param array $data
220
     * @return $this
221
     */
222 12
    protected function callEvent($name, array $data)
223
    {
224 12
        if (!is_null($this->event)) {
225 2
            $this->event->callEvent($name, $data);
226 1
        }
227
228 11
        return $this;
229
    }
230
231
    /**
232
     * @param string|array $message
233
     * @return $this
234
     */
235 10
    protected function makeLog($message)
236
    {
237 10
        if (!is_null($this->log)) {
238 2
            $this->log->makeLog($message);
239 2
        }
240
241 10
        return $this;
242
    }
243
244
    /**
245
     * destroy called object
246
     *
247
     * @param string $name
248
     * @return $this
249
     */
250 3
    public function destroySingleton($name = null)
251
    {
252 3
        if (is_null($name)) {
253 2
            $this->singletons = [];
254 2
        }
255
256 3
        if (isset($this->singletons[$name])) {
257 1
            unset($this->singletons[$name]);
258 1
        }
259
260 3
        $this->makeLog('Destroy singleton: ' . (is_null($name) ? 'all' : $name));
261
262 3
        return $this;
263
    }
264
265
    /**
266
     * get called object
267
     *
268
     * @param string $name
269
     * @return mixed
270
     * @throws \InvalidArgumentException
271
     * @throws RegisterException
272
     */
273 2
    public function getSingleton($name)
274
    {
275 2
        return $this->singletonFactory($name);
276
    }
277
278
    /**
279
     * return all registered objects by their references
280
     *
281
     * @return array
282
     */
283 4
    public function getRegisteredObjects()
284
    {
285 4
        return $this->registeredObjects;
286
    }
287
288
    /**
289
     * return list of created by Loader::getClass objects and number of executions
290
     *
291
     * @return array
292
     */
293 4
    public function getClassCounter()
294
    {
295 4
        return $this->classCounter;
296
    }
297
298
    /**
299
     * increment by 1 class execution
300
     *
301
     * @param string $class
302
     * @return Register
303
     */
304 9
    protected function setClassCounter($class)
305
    {
306 9
        if (!isset($this->classCounter[$class])) {
307 9
            $this->classCounter[$class] = 0;
308 9
        }
309
310 9
        ++$this->classCounter[$class];
311 9
        return $this;
312
    }
313
314
    /**
315
     * set class that be called instead of given in factory or singleton (override is disabled by default)
316
     *
317
     * @param string $namespace
318
     * @param string $overrider
319
     * @param bool $onlyOnce
320
     * @return $this
321
     */
322 4
    public function setOverrider($namespace, $overrider, $onlyOnce = false)
323
    {
324 4
        $this->overrides[$namespace] = [
325 4
            'overrider' => $overrider,
326 4
            'only_once' => (bool)$onlyOnce,
327
        ];
328
329 4
        $this->makeLog(
330
            'Override set for: '
331
            . $namespace
332 4
            . ', to: '
333 4
            . $overrider
334 4
            . '. Once: '
335 4
            . ($onlyOnce ? 'true' : 'false')
336 4
        );
337
338 4
        return $this;
339
    }
340
341
    /**
342
     * disable given or all overriders
343
     *
344
     * @param null|string $namespace
345
     * @return $this
346
     */
347 3
    public function unsetOverrider($namespace = null)
348
    {
349 3
        if (is_null($namespace)) {
350 1
            $this->overrides = [];
351 1
        } else {
352 2
            unset($this->overrides[$namespace]);
353
        }
354
355 3
        $this->makeLog('Override unset for: ' . $namespace);
356
357 3
        return $this;
358
    }
359
360
    /**
361
     * enable overriding
362
     *
363
     * @return $this
364
     */
365 4
    public function enableOverride()
366
    {
367 4
        $this->allowOverride = true;
368 4
        return $this;
369
    }
370
371
    /**
372
     * disable overriding
373
     *
374
     * @return $this
375
     */
376 1
    public function disableOverride()
377
    {
378 1
        $this->allowOverride = false;
379 1
        return $this;
380
    }
381
382
    /**
383
     * return information that overriding is enabled
384
     *
385
     * @return bool
386
     */
387 1
    public function isOverrideEnable()
388
    {
389 1
        return $this->allowOverride;
390
    }
391
}
392