Passed
Push — master ( 0d9fd2...086231 )
by Oleg
03:35
created

Injector   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 213
Duplicated Lines 17.37 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 37
loc 213
wmc 37
lcom 1
cbo 0
rs 8.6

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 3
A addRequirement() 0 8 2
A check() 0 4 1
A get() 0 12 3
C loadInjection() 0 45 14
B buildParams() 0 15 5
B buildCalls() 22 22 6
A makeObject() 15 15 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php /** MicroInjector */
2
3
namespace Micro\Base;
4
5
6
/**
7
 * Class Injector
8
 *
9
 * @author Oleg Lunegov <[email protected]>
10
 * @link https://github.com/linpax/microphp-framework
11
 * @copyright Copyright &copy; 2013 Oleg Lunegov
12
 * @license /LICENSE
13
 * @package Micro
14
 * @subpackage Base
15
 * @version 1.0
16
 * @since 1.0
17
 */
18
class Injector implements IInjector
19
{
20
    /** @var array $CONFIG Configuration */
21
    private static $CONFIG = [];
22
    /** @var array $INJECTS Configured injects */
23
    private static $INJECTS = [];
24
25
26
    /**
27
     * Injector constructor.
28
     *
29
     * @access public
30
     * @param string $configPath
31
     * @result void
32
     */
33
    public function __construct($configPath = '')
34
    {
35
        if ($configPath !== '' && file_exists($configPath)) {
36
            /** @noinspection PhpIncludeInspection */
37
            self::$CONFIG = array_merge_recursive(self::$CONFIG, require $configPath);
38
        }
39
    }
40
41
    /**
42
     * Add requirement to injector
43
     *
44
     * @access public
45
     * @param string $name
46
     * @param mixed $component
47
     * @return void
48
     */
49
    public function addRequirement($name, $component)
50
    {
51
        if (is_object($component)) {
52
            self::$INJECTS[$name] = $component;
53
        } else {
54
            self::$CONFIG[$name] = $component;
55
        }
56
    }
57
58
    /**
59
     * Check injector or config
60
     *
61
     * @access public
62
     * @param string $name
63
     * @return bool
64
     */
65
    public function check($name)
66
    {
67
        return (bool)$this->get($name);
68
    }
69
70
    /**
71
     * Build object with injector
72
     *
73
     * class LogInject extends Injector {
74
     *  public function build() {
75
     *   return $this->get('logger');
76
     *  }
77
     * }
78
     * $log = (new LogInject())->build();
79
     *
80
     * @access protected
81
     * @param string $name
82
     * @return bool
83
     */
84
    public function get($name)
85
    {
86
        if (!empty(self::$CONFIG[$name])) {
87
            return self::$CONFIG[$name];
88
        }
89
90
        if (!empty(self::$CONFIG['components'][$name])) {
91
            return $this->loadInjection($name);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->loadInjection($name); of type false|object adds the type object to the return on line 91 which is incompatible with the return type declared by the interface Micro\Base\IInjector::get of type boolean.
Loading history...
92
        }
93
94
        return false;
95
    }
96
97
    /**
98
     * Load injection
99
     *
100
     * @access public
101
     *
102
     * @param string $name Name injection
103
     *
104
     * @return bool
105
     */
106
    private function loadInjection($name)
107
    {
108
        $options = self::$CONFIG['components'][$name];
109
110
        if (empty($options['class']) || !class_exists($options['class'])) {
111
            return false;
112
        }
113
114
        $className = $options['class'];
115
116
        $options['arguments'] = !empty($options['arguments']) ? $this->buildParams($options['arguments']) : null;
117
        $options['property'] = !empty($options['property']) ? $this->buildParams($options['property']) : null;
118
        $options['calls'] = !empty($options['calls']) ? $this->buildCalls($options['calls']) : null;
119
120
        /** Depends via construction */
121
        self::$INJECTS[$name] = $this->makeObject($className, $options['arguments']);
122
        if (!self::$INJECTS[$name]) {
123
            return false;
124
        }
125
126
        /** Depends via property */
127
        if (!empty($options['property'])) { // load properties
128
            foreach ($options['property'] as $property => $value) {
129
                if (property_exists(self::$INJECTS[$name], $property)) {
130
                    self::$INJECTS[$name]->$property = $value;
131
                }
132
            }
133
        }
134
135
        /** Depends via calls */
136
        if (!empty($options['calls'])) { // run methods
137
            foreach ($options['calls'] as $method => $arguments) {
138
                if (method_exists(self::$INJECTS[$name], $method)) {
139
                    $reflectionMethod = new \ReflectionMethod($className, $method);
140
                    if ($reflectionMethod->getNumberOfParameters() === 0) {
141
                        self::$INJECTS[$name]->$method();
142
                    } else {
143
                        call_user_func_array([self::$INJECTS[$name], $method], $arguments);
144
                    }
145
                }
146
            }
147
        }
148
149
        return self::$INJECTS[$name];
150
    }
151
152
    /**
153
     * Build params from array
154
     *
155
     * @access private
156
     * @param array $params
157
     * @return array
158
     */
159
    private function buildParams(array $params)
160
    {
161
        /** @noinspection AlterInForeachInspection */
162
        foreach ($params AS $key => &$val) { // IoC Constructor
163
            if (is_string($params[$key]) && (0 === strpos($val, '@'))) {
164
                if ($val === '@this') {
165
                    $val = $this;
166
                } else {
167
                    $val = $this->get(substr($val, 1));
168
                }
169
            }
170
        }
171
172
        return $params;
173
    }
174
175
    /**
176
     * Build calls arguments
177
     *
178
     * @access private
179
     * @param array $params
180
     * @return array
181
     */
182 View Code Duplication
    private function buildCalls(array $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183
    {
184
        $callers = [];
185
186
        if (!is_array($params[0])) {
187
            $params = [
188
                $params
189
            ];
190
        }
191
192
        foreach ($params as $arguments) {
193
            if (is_string($arguments[0])) {
194
                if (!empty($arguments[1]) && is_array($arguments[1])) {
195
                    $callers[$arguments[0]] = $this->buildParams($arguments[1]);
196
                } else {
197
                    $callers[$arguments[0]] = null;
198
                }
199
            }
200
        }
201
202
        return $callers;
203
    }
204
205
    /**
206
     * Make object with arguments
207
     *
208
     * @access private
209
     *
210
     * @param string $className
211
     * @param array $arguments
212
     *
213
     * @return mixed
214
     */
215 View Code Duplication
    private function makeObject($className, array $arguments = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        try {
218
            $reflection = new \ReflectionClass($className);
219
            $reflectionMethod = new \ReflectionMethod($className, '__construct');
220
221
            if ($reflectionMethod->getNumberOfParameters() === 0) {
222
                return new $className;
223
            } else {
224
                return $reflection->newInstanceArgs($arguments);
225
            }
226
        } catch (Exception $e) {
227
            return false;
228
        }
229
    }
230
}