Passed
Push — master ( ea741a...a4432c )
by Korotkov
02:46 queued 01:24
created

Application::objects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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