Completed
Push — master ( 10575c...1b914b )
by Korotkov
04:08 queued 02:36
created

Application::getParamsIoC()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 12
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 21
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author    : Jagepard <[email protected]">
7
 * @copyright Copyright (c) 2019, Jagepard
8
 * @license   https://mit-license.org/ MIT
9
 */
10
11
namespace Rudra\Container;
12
13
use Rudra\Container\Interfaces\{ReflectionInterface,
14
    ApplicationInterface,
15
    ContainerInterface,
16
    CookieInterface,
17
    SessionInterface,
18
    ResponseInterface,
19
    ConfigInterface
0 ignored issues
show
Bug introduced by
The type Rudra\Container\Interfaces\ConfigInterface 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...
20
};
21
22
class Application implements ApplicationInterface, ReflectionInterface
23
{
24
    /**
25
     * @var ApplicationInterface
26
     */
27
    private static $app;
28
    /**
29
     * @var array
30
     */
31
    private $objects = [];
32
    /**
33
     * @var array
34
     */
35
    private $bind = [];
36
    /**
37
     * @var ContainerInterface
38
     */
39
    private $request;
40
    /**
41
     * @var CookieInterface
42
     */
43
    private $cookie;
44
    /**
45
     * @var SessionInterface
46
     */
47
    private $session;
48
    /**
49
     * @var ResponseInterface
50
     */
51
    private $response;
52
    /**
53
     * @var ConfigInterface
54
     */
55
    private $config;
56
57
    public function __construct()
58
    {
59
        $this->request = new Request();
0 ignored issues
show
Documentation Bug introduced by
It seems like new Rudra\Container\Request() of type Rudra\Container\Request is incompatible with the declared type Rudra\Container\Interfaces\ContainerInterface of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
60
        $this->cookie = new Cookie();
61
        $this->session = new Session();
62
        $this->response = new Response();
63
        $this->config = new Config();
0 ignored issues
show
Documentation Bug introduced by
It seems like new Rudra\Container\Config() of type Rudra\Container\Config is incompatible with the declared type Rudra\Container\Interfaces\ConfigInterface of property $config.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
64
    }
65
66
    /**
67
     * @return ApplicationInterface
68
     */
69
    public static function app(): ApplicationInterface
70
    {
71
        if (!static::$app instanceof static) {
0 ignored issues
show
Bug introduced by
Since $app is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $app to at least protected.
Loading history...
72
            static::$app = new static();
73
        }
74
75
        return static::$app;
76
    }
77
78
    /**
79
     * @param  string  $key
80
     * @param        $object
81
     */
82
    private function rawSet(string $key, $object)
83
    {
84
        $this->objects[$key] = $object;
85
    }
86
87
    /**
88
     * @param  string  $key
89
     * @param        $object
90
     * @param  null  $params
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $params is correct as it would always require null to be passed?
Loading history...
91
     * @throws \ReflectionException
92
     */
93
    private function iOc(string $key, $object, $params = null): void
94
    {
95
        $reflection = new \ReflectionClass($object);
96
        $constructor = $reflection->getConstructor();
97
98
        if ($constructor && $constructor->getNumberOfParameters()) {
99
            $paramsIoC = $this->getParamsIoC($constructor, $params);
100
            $this->objects[$key] = $reflection->newInstanceArgs($paramsIoC);
101
102
            return;
103
        }
104
105
        $this->objects[$key] = new $object();
106
    }
107
108
    /**
109
     * @param      $object
110
     * @param  null  $params
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $params is correct as it would always require null to be passed?
Loading history...
111
     * @return object
112
     * @throws \ReflectionException
113
     */
114
    public function new($object, $params = null)
115
    {
116
        $reflection = new \ReflectionClass($object);
117
        $constructor = $reflection->getConstructor();
118
119
        if ($constructor && $constructor->getNumberOfParameters()) {
120
            $paramsIoC = $this->getParamsIoC($constructor, $params);
121
122
            return $reflection->newInstanceArgs($paramsIoC);
123
        }
124
125
        return new $object();
126
    }
127
128
    /**
129
     * @param  \ReflectionMethod  $constructor
130
     * @param                  $params
131
     * @return array
132
     * @throws \ReflectionException
133
     */
134
    private function getParamsIoC(\ReflectionMethod $constructor, $params): array
135
    {
136
        $i = 0;
137
        $paramsIoC = [];
138
139
        foreach ($constructor->getParameters() as $value) {
140
            if (isset($value->getClass()->name) && $this->hasBinding($value->getClass()->name)) {
141
                $className = $this->getBinding($value->getClass()->name);
142
                $paramsIoC[] = (is_object($className)) ? $className : new $className;
143
                continue;
144
            }
145
146
            if ($value->isDefaultValueAvailable() && !isset($params[$i])) {
147
                $paramsIoC[] = $value->getDefaultValue();
148
                continue;
149
            }
150
151
            $paramsIoC[] = $params[$i++];
152
        }
153
154
        return $paramsIoC;
155
    }
156
157
158
    /**
159
     * @param  string|null  $key
160
     * @return array|mixed
161
     */
162
    public function get(string $key = null)
163
    {
164
        return (empty($key)) ? $this->objects : $this->objects[$key];
165
    }
166
167
    /**
168
     * @param  string  $key
169
     * @param        $object
170
     * @param  null  $params
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $params is correct as it would always require null to be passed?
Loading history...
171
     * @throws \ReflectionException
172
     */
173
    public function set(string $key, $object, $params = null)
174
    {
175
        ('raw' === $params) ? $this->rawSet($key, $object) : $this->iOc($key, $object, $params);
0 ignored issues
show
introduced by
The condition 'raw' === $params is always false.
Loading history...
176
    }
177
178
    /**
179
     * @param  string  $key
180
     * @return bool
181
     */
182
    public function has(string $key): bool
183
    {
184
        return isset($this->objects[$key]);
185
    }
186
187
    /**
188
     * @param  string  $key
189
     * @param  string  $param
190
     * @return mixed
191
     */
192
    public function getParam(string $key, string $param)
193
    {
194
        if ($this->has($key) && isset($this->get($key)->$param)) {
195
            return $this->get($key)->$param;
196
        }
197
    }
198
199
    /**
200
     * @param  string  $key
201
     * @param  string  $param
202
     * @param        $value
203
     */
204
    public function setParam(string $key, string $param, $value): void
205
    {
206
        if (isset($this->objects[$key])) {
207
            $this->get($key)->$param = $value;
208
        }
209
    }
210
211
    /**
212
     * @param  string  $key
213
     * @param  string  $param
214
     * @return bool
215
     */
216
    public function hasParam(string $key, string $param)
217
    {
218
        if ($this->has($key)) {
219
            return isset($this->get($key)->$param);
220
        }
221
    }
222
223
    /**
224
     * @param  array  $services
225
     * @throws \ReflectionException
226
     */
227
    public function setServices(array $services): void
228
    {
229
        foreach ($services['contracts'] as $interface => $contract) {
230
            $this->setBinding($interface, $contract);
231
        }
232
233
        foreach ($services['services'] as $name => $service) {
234
            $this->set($name, ...$service);
0 ignored issues
show
Bug introduced by
$service is expanded, but the parameter $object of Rudra\Container\Application::set() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

234
            $this->set($name, /** @scrutinizer ignore-type */ ...$service);
Loading history...
235
        }
236
    }
237
238
    /**
239
     * @param  string  $key
240
     * @return mixed|string
241
     */
242
    public function getBinding(string $key)
243
    {
244
        return $this->bind[$key] ?? $key;
245
    }
246
247
    /**
248
     * @param  string  $key
249
     * @return bool
250
     */
251
    public function hasBinding(string $key): bool
252
    {
253
        return array_key_exists($key, $this->bind);
254
    }
255
256
    /**
257
     * @param  string  $key
258
     * @param        $value
259
     */
260
    public function setBinding(string $key, $value): void
261
    {
262
        $this->bind[$key] = $value;
263
    }
264
265
    /**
266
     * @return Request
267
     */
268
    public function request(): Request
269
    {
270
        return $this->request;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->request returns the type Rudra\Container\Interfaces\ContainerInterface which is incompatible with the type-hinted return Rudra\Container\Request.
Loading history...
271
    }
272
273
    /**
274
     * @return CookieInterface
275
     */
276
    public function cookie(): CookieInterface
277
    {
278
        return $this->cookie;
279
    }
280
281
    /**
282
     * @return SessionInterface
283
     */
284
    public function session(): SessionInterface
285
    {
286
        return $this->session;
287
    }
288
289
    /**
290
     * @return ResponseInterface
291
     */
292
    public function response(): ResponseInterface
293
    {
294
        return $this->response;
295
    }
296
297
    /**
298
     * @return ContainerInterface
299
     */
300
    public function config(): ContainerInterface
301
    {
302
        return $this->config;
303
    }
304
}
305