Passed
Push — master ( 9a6f23...bacd56 )
by Korotkov
07:19 queued 13s
created

Rudra::get()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 10
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 19
rs 8.8333
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\Interfaces\RudraInterface;
13
use Rudra\Container\Interfaces\RequestInterface;
14
use Rudra\Container\Interfaces\ResponseInterface;
15
use Rudra\Container\Interfaces\ContainerInterface;
16
use Rudra\Container\Traits\InstantiationsTrait;
17
18
class Rudra implements RudraInterface, ContainerInterface
19
{
20
    use InstantiationsTrait;
21
22
    public static ?RudraInterface $rudra = null;
23
    private array $data = [];
24
25
    public function binding(array $contracts = []): ContainerInterface
26
    {
27
        return $this->instantiate("binding", Container::class, $contracts);
28
    }
29
30
    public function services(array $services = []): ContainerInterface
31
    {
32
        return $this->instantiate("services", Container::class, $services);
33
    }
34
    
35
    public function config(array $config = []): ContainerInterface
36
    {
37
        return $this->instantiate("config", Container::class, $config);
38
    }
39
40
    public function data(array $data = []): ContainerInterface
41
    {
42
        return $this->instantiate("data", Container::class, $data);
43
    }
44
    
45
    public function request(): RequestInterface
46
    {
47
        return $this->containerize(Request::class);
48
    }
49
50
    public function response(): ResponseInterface
51
    {
52
        return $this->containerize(Response::class);
53
    }
54
55
    public function cookie(): Cookie
56
    {
57
        return $this->containerize(Cookie::class);
58
    }
59
60
    public function session(): Session
61
    {
62
        return $this->containerize(Session::class);
63
    }
64
65
    /*
66
     | Creates an object without adding to the container
67
     */
68
    public function new($object, $params = null)
69
    {
70
        $reflection = new \ReflectionClass($object);
71
        $constructor = $reflection->getConstructor();
72
73
        if ($constructor && $constructor->getNumberOfParameters()) {
74
            $paramsIoC = $this->getParamsIoC($constructor, $params);
75
76
            return $reflection->newInstanceArgs($paramsIoC);
77
        }
78
79
        return new $object();
80
    }
81
82
    public static function run(): RudraInterface
83
    {
84
        if (!static::$rudra instanceof static) {
85
            static::$rudra = new static();
86
        }
87
88
        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\Interfaces\RudraInterface. Consider adding an additional type-check to rule them out.
Loading history...
89
    }
90
91
    public function get(string $key = null)
92
    {
93
        if (isset($key) && !$this->has($key)) {
94
            if (!$this->services()->has($key)) {
95
                if (class_exists($key)) {
96
                    $this->services()->set([$key => $key]);
97
                } else {
98
                    throw new \InvalidArgumentException("Service '$key' is not installed");
99
                }
100
            }
101
102
            $this->set([$key, $this->services()->get($key)]);
103
        }
104
105
        if (empty($key)) {
106
            return $this->data;
107
        }
108
109
        return ($this->data[$key] instanceof \Closure) ? $this->data[$key]() : $this->data[$key];
110
    }
111
112
    public function set(array $data): void
113
    {
114
        list($key, $object) = $data;
115
116
        if (is_array($object)) {
117
            if (array_key_exists(1, $object) && !is_object($object[0])) {
118
                $this->iOc($key, $object[0], $object[1]);
119
                return;
120
            }
121
122
            $this->setObject($object[0], $key);
123
            return;
124
        }
125
126
        $this->setObject($object, $key);
127
    }
128
129
    public function has(string $key): bool
130
    {
131
        return array_key_exists($key, $this->data);
132
    }
133
134
    private function setObject($object, $key): void
135
    {
136
        (is_object($object)) ? $this->mergeData($key, $object) : $this->iOc($key, $object);
137
    }
138
139
    private function mergeData(string $key, $object)
140
    {
141
        $this->data = array_merge([$key => $object], $this->data);
142
    }
143
144
    private function iOc(string $key, $object, $params = null): void
145
    {
146
        $reflection = new \ReflectionClass($object);
147
        $constructor = $reflection->getConstructor();
148
149
        if ($constructor && $constructor->getNumberOfParameters()) {
150
            $paramsIoC = $this->getParamsIoC($constructor, $params);
151
            $this->mergeData($key, $reflection->newInstanceArgs($paramsIoC));
152
            return;
153
        }
154
155
        $this->mergeData($key, new $object());
156
    }
157
158
    private function getParamsIoC(\ReflectionMethod $constructor, $params): array
159
    {
160
        $i = 0;
161
        $paramsIoC = [];
162
        $params = (is_array($params) && array_key_exists(0, $params)) ? $params : [$params];
163
164
        foreach ($constructor->getParameters() as $value) {
165
            /*
166
             | If in the constructor expects the implementation of interface,
167
             | so that the container automatically created the necessary object and substituted as an argument,
168
             | we need to bind the interface with the implementation.
169
             */
170
            if (version_compare(PHP_VERSION, '8.0.0') >= 0) {
171
                if (null !== $value->getType()->getName() && $this->binding()->has($value->getType()->getName())) {
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

171
                if (null !== $value->getType()->/** @scrutinizer ignore-call */ getName() && $this->binding()->has($value->getType()->getName())) {
Loading history...
172
                    $className = $this->binding()->get($value->getType()->getName());
173
                    $paramsIoC[] = (is_object($className)) ? $className : new $className;
174
                    continue;
175
                }
176
            } else {
177
                if (isset($value->getClass()->name) && $this->binding()->has($value->getClass()->name)) {
178
                    $className = $this->binding()->get($value->getClass()->name);
179
                    $paramsIoC[] = (is_object($className)) ? $className : new $className;
180
                    continue;
181
                }
182
            }
183
184
            /*
185
             | If the class constructor contains arguments with default values,
186
             | then if no arguments are passed,
187
             | values will be added by default by container
188
             */
189
            if ($value->isDefaultValueAvailable() && !isset($params[$i])) {
190
                $paramsIoC[] = $value->getDefaultValue();
191
                continue;
192
            }
193
194
            $paramsIoC[] = $params[$i++];
195
        }
196
197
        return $paramsIoC;
198
    }
199
}
200