Passed
Push — master ( e6736a...411609 )
by Korotkov
02:31 queued 01:13
created

Rudra::setObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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