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

Application   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 1
Metric Value
eloc 58
c 5
b 0
f 1
dl 0
loc 164
rs 9.1199
wmc 41

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
B getParamsIoC() 0 32 9
A run() 0 7 2
A request() 0 3 1
A mergeData() 0 3 1
A response() 0 3 1
A set() 0 15 4
A get() 0 11 5
A session() 0 3 1
A binding() 0 3 1
A iOc() 0 12 3
A setObject() 0 3 2
A cookie() 0 3 1
A new() 0 12 3
A config() 0 3 1
A setServices() 0 5 4
A services() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Application often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Application, and based on these observations, apply Extract Interface, too.

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