Passed
Push — master ( 8f1e40...8f3027 )
by Korotkov
02:03 queued 13s
created

Rudra::setServices()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 4
nc 1
nop 1
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\{RequestInterface, RudraInterface, ContainerInterface, AbstractRequest, ResponseInterface};
0 ignored issues
show
Bug introduced by
The type Rudra\Container\Interfaces\AbstractRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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