Passed
Pull Request — master (#65)
by Korotkov
01:27
created

Application::services()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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