Passed
Push — master ( 4db0d5...0f86a9 )
by Korotkov
02:48 queued 01:23
created

Rudra::setConfig()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 1
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 3
rs 10
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\Traits\{InstantiationsTrait};
13
use Rudra\Container\Interfaces\{RequestInterface, RudraInterface, ContainerInterface, ResponseInterface};
14
15
class Rudra implements RudraInterface, ContainerInterface
16
{
17
    use InstantiationsTrait;
18
19
    public static ?RudraInterface $rudra = null;
20
    private array $data = [];
21
22
    public function setConfig(array $config): void
23
    {
24
        ($this->has("config")) ?: $this->set(["config", new Container($config)]);
25
    }
26
27
    public 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
    }
32
33
    public function binding(): ContainerInterface
34
    {
35
        if ($this->has("binding")) return $this->get("binding");
36
        throw new \InvalidArgumentException("Service 'binding' not preinstalled");
37
    }
38
39
    public function services(): ContainerInterface
40
    {
41
        if ($this->has("services")) return $this->get("services");
42
        throw new \InvalidArgumentException("Service 'services' not preinstalled");
43
    }
44
    
45
    public function config(): ContainerInterface
46
    {
47
        if ($this->has("config")) return $this->get("config");
48
        throw new \InvalidArgumentException("Service 'config' not preinstalled");
49
    }
50
51
    public function request(): RequestInterface
52
    {
53
        return $this->containerize(Request::class);
54
    }
55
56
    public function response(): ResponseInterface
57
    {
58
        return $this->containerize(Response::class);
59
    }
60
61
    public function cookie(): Cookie
62
    {
63
        return $this->containerize(Cookie::class);
64
    }
65
66
    public function session(): Session
67
    {
68
        return $this->containerize(Session::class);
69
    }
70
71
    /*
72
     | Creates an object without adding to the container
73
     */
74
    public function new($object, $params = null)
75
    {
76
        $reflection = new \ReflectionClass($object);
77
        $constructor = $reflection->getConstructor();
78
79
        if ($constructor && $constructor->getNumberOfParameters()) {
80
            $paramsIoC = $this->getParamsIoC($constructor, $params);
81
82
            return $reflection->newInstanceArgs($paramsIoC);
83
        }
84
85
        return new $object();
86
    }
87
88
    public static function run(): RudraInterface
89
    {
90
        if (!static::$rudra instanceof static) {
91
            static::$rudra = new static();
92
        }
93
94
        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...
95
    }
96
97
    public function get(string $key = null)
98
    {
99
        if (isset($key) && !$this->has($key)) {
100
            if (!$this->services()->has($key)) {
101
                throw new \InvalidArgumentException("Service is not installed");
102
            }
103
104
            $this->set([$key, $this->services()->get($key)]);
105
        }
106
107
        return empty($key) ? $this->data : $this->data[$key];
108
    }
109
110
    public function set(array $data): void
111
    {
112
        list($key, $object) = $data;
113
114
        if (is_array($object)) {
115
            if (array_key_exists(1, $object) && !is_object($object[0])) {
116
                $this->iOc($key, $object[0], $object[1]);
117
                return;
118
            }
119
120
            $this->setObject($object[0], $key);
121
            return;
122
        }
123
124
        $this->setObject($object, $key);
125
    }
126
127
    public function has(string $key): bool
128
    {
129
        return array_key_exists($key, $this->data);
130
    }
131
132
    private function setObject($object, $key): void
133
    {
134
        (is_object($object)) ? $this->mergeData($key, $object) : $this->iOc($key, $object);
135
    }
136
137
    private function mergeData(string $key, $object)
138
    {
139
        $this->data = array_merge([$key => $object], $this->data);
140
    }
141
142
    private function iOc(string $key, $object, $params = null): void
143
    {
144
        $reflection = new \ReflectionClass($object);
145
        $constructor = $reflection->getConstructor();
146
147
        if ($constructor && $constructor->getNumberOfParameters()) {
148
            $paramsIoC = $this->getParamsIoC($constructor, $params);
149
            $this->mergeData($key, $reflection->newInstanceArgs($paramsIoC));
150
            return;
151
        }
152
153
        $this->mergeData($key, new $object());
154
    }
155
156
    private function getParamsIoC(\ReflectionMethod $constructor, $params): array
157
    {
158
        $i = 0;
159
        $paramsIoC = [];
160
        $params = (is_array($params) && array_key_exists(0, $params)) ? $params : [$params];
161
162
        foreach ($constructor->getParameters() as $value) {
163
            /*
164
             | If in the constructor expects the implementation of interface,
165
             | so that the container automatically created the necessary object and substituted as an argument,
166
             | we need to bind the interface with the implementation.
167
             */
168
            if (isset($value->getClass()->name) && $this->binding()->has($value->getClass()->name)) {
169
                $className = $this->binding()->get($value->getClass()->name);
170
                $paramsIoC[] = (is_object($className)) ? $className : new $className;
171
                continue;
172
            }
173
174
            /*
175
             | If the class constructor contains arguments with default values,
176
             | then if no arguments are passed,
177
             | values will be added by default by container
178
             */
179
            if ($value->isDefaultValueAvailable() && !isset($params[$i])) {
180
                $paramsIoC[] = $value->getDefaultValue();
181
                continue;
182
            }
183
184
            $paramsIoC[] = $params[$i++];
185
        }
186
187
        return $paramsIoC;
188
    }
189
}
190