Passed
Push — master ( c8570b...99b6ec )
by Korotkov
01:50 queued 17s
created

Rudra::_new()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 3
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author    : Jagepard <[email protected]">
7
 * @license   https://mit-license.org/ MIT
8
 */
9
10
namespace Rudra\Container;
11
12
use Rudra\Container\Abstracts\{AbstractRudra,
13
    RudraInterface,
14
    ContainerInterface,
15
    AbstractRequest,
16
    AbstractResponse};
17
use Rudra\Container\Traits\{InstantiationsTrait, PublicApplicationTrait};
18
19
class Rudra extends AbstractRudra implements RudraInterface, ContainerInterface
20
{
21
    use InstantiationsTrait;
22
    use PublicApplicationTrait;
0 ignored issues
show
Bug introduced by
The trait Rudra\Container\Traits\PublicApplicationTrait requires the property $_new which is not provided by Rudra\Container\Rudra.
Loading history...
23
24
    public static ?AbstractRudra $rudra = null;
25
    private array $data = [];
26
27
    protected function _setServices(array $services): void
28
    {
29
        ($this->_has("binding")) ?: $this->_set(["binding", new Container($services["contracts"])]);
30
        ($this->_has("services")) ?: $this->_set(["services", new Container($services["services"])]);
31
        ($this->_has("config")) ?: $this->_set(["config", new Container($services["config"])]);
32
    }
33
34
    protected function _binding(): ContainerInterface
35
    {
36
        if ($this->_has("binding")) return $this->_get("binding");
37
        throw new \InvalidArgumentException("Service not preinstalled");
38
    }
39
40
    protected function _services(): ContainerInterface
41
    {
42
        if ($this->_has("services")) return $this->_get("services");
43
        throw new \InvalidArgumentException("Service not preinstalled");
44
    }
45
    
46
    protected function _config(): ContainerInterface
47
    {
48
        if ($this->_has("config")) return $this->_get("config");
49
        throw new \InvalidArgumentException("Service not preinstalled");
50
    }
51
52
    protected function _request(): AbstractRequest
53
    {
54
        return $this->containerize(Request::class);
55
    }
56
57
    protected function _response(): AbstractResponse
58
    {
59
        return $this->containerize(Response::class);
60
    }
61
62
    protected function _cookie(): Cookie
63
    {
64
        return $this->containerize(Cookie::class);
65
    }
66
67
    protected function _session(): Session
68
    {
69
        return $this->containerize(Session::class);
70
    }
71
72
    /*
73
     | Creates an object without adding to the container
74
     */
75
    protected function _new($object, $params = null)
76
    {
77
        $reflection = new \ReflectionClass($object);
78
        $constructor = $reflection->getConstructor();
79
80
        if ($constructor && $constructor->getNumberOfParameters()) {
81
            $paramsIoC = $this->getParamsIoC($constructor, $params);
82
83
            return $reflection->newInstanceArgs($paramsIoC);
84
        }
85
86
        return new $object();
87
    }
88
89
    public static function run(): AbstractRudra
90
    {
91
        if (!static::$rudra instanceof static) {
92
            static::$rudra = new static();
93
        }
94
95
        return static::$rudra;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::rudra could return the type null which is incompatible with the type-hinted return Rudra\Container\Abstracts\AbstractRudra. Consider adding an additional type-check to rule them out.
Loading history...
96
    }
97
98
    protected function _get(string $key = null)
99
    {
100
        if (isset($key) && !$this->_has($key)) {
101
            if (!$this->_services()->has($key)) {
102
                throw new \InvalidArgumentException("Service is not installed");
103
            }
104
105
            $this->_set([$key, $this->_services()->get($key)]);
106
        }
107
108
        return empty($key) ? $this->data : $this->data[$key];
109
    }
110
111
    protected function _set(array $data): void
112
    {
113
        list($key, $object) = $data;
114
115
        if (is_array($object)) {
116
            if (array_key_exists(1, $object) && !is_object($object[0])) {
117
                $this->iOc($key, $object[0], $object[1]);
118
                return;
119
            }
120
121
            $this->setObject($object[0], $key);
122
            return;
123
        }
124
125
        $this->setObject($object, $key);
126
    }
127
128
    protected function _has(string $key): bool
129
    {
130
        return array_key_exists($key, $this->data);
131
    }
132
133
    private function setObject($object, $key): void
134
    {
135
        (is_object($object)) ? $this->mergeData($key, $object) : $this->iOc($key, $object);
136
    }
137
138
    private function mergeData(string $key, $object)
139
    {
140
        $this->data = array_merge([$key => $object], $this->data);
141
    }
142
143
    private function iOc(string $key, $object, $params = null): void
144
    {
145
        $reflection = new \ReflectionClass($object);
146
        $constructor = $reflection->getConstructor();
147
148
        if ($constructor && $constructor->getNumberOfParameters()) {
149
            $paramsIoC = $this->getParamsIoC($constructor, $params);
150
            $this->mergeData($key, $reflection->newInstanceArgs($paramsIoC));
151
            return;
152
        }
153
154
        $this->mergeData($key, new $object());
155
    }
156
157
    private function getParamsIoC(\ReflectionMethod $constructor, $params): array
158
    {
159
        $i = 0;
160
        $paramsIoC = [];
161
        $params = (is_array($params) && array_key_exists(0, $params)) ? $params : [$params];
162
163
        foreach ($constructor->getParameters() as $value) {
164
            /*
165
             | If in the constructor expects the implementation of interface,
166
             | so that the container automatically created the necessary object and substituted as an argument,
167
             | we need to bind the interface with the implementation.
168
             */
169
            if (isset($value->getClass()->name) && $this->_binding()->has($value->getClass()->name)) {
170
                $className = $this->_binding()->get($value->getClass()->name);
171
                $paramsIoC[] = (is_object($className)) ? $className : new $className;
172
                continue;
173
            }
174
175
            /*
176
             | If the class constructor contains arguments with default values,
177
             | then if no arguments are passed,
178
             | values will be added by default by container
179
             */
180
            if ($value->isDefaultValueAvailable() && !isset($params[$i])) {
181
                $paramsIoC[] = $value->getDefaultValue();
182
                continue;
183
            }
184
185
            $paramsIoC[] = $params[$i++];
186
        }
187
188
        return $paramsIoC;
189
    }
190
}
191