GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( b12335...eab520 )
by Hong
03:17
created

FactoryTrait   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 260
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 15
Bugs 0 Features 1
Metric Value
wmc 34
c 15
b 0
f 1
lcom 1
cbo 1
dl 0
loc 260
rs 9.2

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefinition() 0 20 4
A constructObject() 0 20 2
A matchArguments() 0 16 4
A isTypeMatched() 0 13 3
B isRequiredClass() 0 20 5
A getObjectByClass() 0 11 3
A getCallableParameters() 0 19 3
A isInvocable() 0 4 2
A mergeMethods() 0 14 4
A executeCommonBatch() 0 18 4
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Di
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Di\Traits;
16
17
use Phossa2\Di\Container;
18
use Phossa2\Di\Exception\LogicException;
19
use Phossa2\Di\Message\Message;
20
21
/**
22
 * FactoryTrait
23
 *
24
 * Create service instance here
25
 *
26
 * @package Phossa2\Di
27
 * @author  Hong Zhang <[email protected]>
28
 * @version 2.0.0
29
 * @since   2.0.0 added
30
 */
31
trait FactoryTrait
32
{
33
    /**
34
     * @var    Container
35
     * @access protected
36
     */
37
    protected $master;
38
39
    /**
40
     * Get service definition (and fix it)
41
     *
42
     * @param  string $rawId
43
     * @param  array $args
44
     * @return array
45
     * @access protected
46
     */
47
    protected function getDefinition(
48
        /*# string */ $rawId,
49
        array $args
50
    )/*# : array */ {
51
        // get the definition
52
        $def = $this->master->getResolver()->getService($rawId);
53
54
        // fix class
55
        if (!is_array($def) || !isset($def['class'])) {
56
            $def = ['class' => $def];
57
        }
58
59
        // resolve arguments
60
        if (!empty($args)) {
61
            $this->master->resolve($args);
62
            $def['args'] = $args;
63
        }
64
65
        return (array) $def;
66
    }
67
68
    /**
69
     * Instantiate service object from classname
70
     *
71
     * @param  string $class
72
     * @param  array $args
73
     * @return object
74
     * @throws LogicException if something goes wrong
75
     * @access protected
76
     */
77
    protected function constructObject(/*# string */ $class, array $args)
78
    {
79
        $reflector = new \ReflectionClass($class);
80
        $constructor = $reflector->getConstructor();
81
82
        // not constructor defined
83
        if (is_null($constructor)) {
84
            $obj = $reflector->newInstanceWithoutConstructor();
85
86
        // normal class with constructor
87
        } else {
88
            $args = $this->matchArguments(
1 ignored issue
show
Coding Style introduced by
Consider using a different name than the parameter $args. This often makes code more readable.
Loading history...
89
                $constructor->getParameters(),
90
                $args
91
            );
92
            $obj = $reflector->newInstanceArgs($args);
93
        }
94
95
        return $obj;
96
    }
97
98
    /**
99
     * Match provided arguments with a method/function's reflection parameters
100
     *
101
     * @param  \ReflectionParameter[] $reflectionParameters
102
     * @param  array $providedArguments
103
     * @return array the resolved arguments
104
     * @throws LogicException
105
     * @access protected
106
     */
107
    protected function matchArguments(
108
        array $reflectionParameters,
109
        array $providedArguments
110
    )/*# : array */ {
111
        // result
112
        $resolvedArguments = [];
113
        foreach ($reflectionParameters as $i => $param) {
114
            $class = $param->getClass();
115
            if ($this->isTypeMatched($param, $providedArguments, $class)) {
116
                $resolvedArguments[$i] = array_shift($providedArguments);
117
            } elseif ($this->isRequiredClass($param, $providedArguments)) {
118
                $resolvedArguments[$i] = $this->getObjectByClass($class->getName());
119
            }
120
        }
121
        return array_merge($resolvedArguments, $providedArguments);
122
    }
123
124
    /**
125
     * Is $parameter same type as the $argument ?
126
     *
127
     * @param  \ReflectionParameter $parameter
128
     * @param  array $arguments
129
     * @param  null|string $class
130
     * @return bool
131
     * @access protected
132
     */
133
    protected function isTypeMatched(
134
        \ReflectionParameter $parameter,
0 ignored issues
show
Unused Code introduced by
The parameter $parameter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
135
        array $arguments,
136
        $class
137
    )/*# : bool */ {
138
        if (empty($arguments)) {
139
            return false;
140
        } elseif (null !== $class) {
141
            return is_a($arguments[0], $class->getName());
0 ignored issues
show
Bug introduced by
The method getName cannot be called on $class (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
142
        } else {
143
            return true;
144
        }
145
    }
146
147
    /**
148
     * Is $param required and is a class/interface
149
     *
150
     * @param  \ReflectionParameter $param
151
     * @param  array $arguments
152
     * @return bool
153
     * @throws LogicException if mismatched arguments
154
     * @access protected
155
     */
156
    protected function isRequiredClass(
157
        \ReflectionParameter $param,
158
        array $arguments
159
    )/*# : bool */ {
160
        $optional = $param->isOptional();
161
        if ($param->getClass()) {
162
            return !$optional || !empty($arguments);
163
        } elseif ($optional && empty($arguments)) {
164
            return false;
165
        } else {
166
            throw new LogicException(
167
                Message::get(
168
                    Message::DI_PARAMETER_MISMATCH,
169
                    $param->getName(),
170
                    $param->getDeclaringFunction()
171
                ),
172
                Message::DI_PARAMETER_MISMATCH
173
            );
174
        }
175
    }
176
177
    /**
178
     * Get an object base on provided classname or interface name
179
     *
180
     * @param  string $classname class or interface name
181
     * @return object
182
     * @throws \Exception if something goes wrong
183
     * @access protected
184
     */
185
    protected function getObjectByClass(/*# string */ $classname)
186
    {
187
        // mapping exists
188
        if ($this->master->getResolver()->hasMapping($classname)) {
189
            $classname = $this->master->getResolver()->getMapping($classname);
1 ignored issue
show
Coding Style introduced by
Consider using a different name than the parameter $classname. This often makes code more readable.
Loading history...
190
            if (is_object($classname)) {
191
                return $classname;
192
            }
193
        }
194
        return $this->master->getResolver()->get($classname);
195
    }
196
197
    /**
198
     * Get callable parameters
199
     *
200
     * @param  callable $callable
201
     * @return \ReflectionParameter[]
202
     * @throws LogicException if something goes wrong
203
     * @access protected
204
     */
205
    protected function getCallableParameters(callable $callable)/*# : array */
206
    {
207
        // array type
208
        if (is_array($callable)) {
209
            $reflector = new \ReflectionClass($callable[0]);
210
            $method = $reflector->getMethod($callable[1]);
211
212
        // object with __invoke() defined
213
        } elseif ($this->isInvocable($callable)) {
214
            $reflector = new \ReflectionClass($callable);
215
            $method = $reflector->getMethod('__invoke');
216
217
        // simple function
218
        } else {
219
            $method = new \ReflectionFunction($callable);
220
        }
221
222
        return $method->getParameters();
223
    }
224
225
    /**
226
     * Is $var an object with '__invoke()' defined ?
227
     *
228
     * @param  mixed $var
229
     * @return bool
230
     * @access protected
231
     */
232
    protected function isInvocable($var)/*# : bool */
233
    {
234
        return is_object($var) && method_exists($var, '__invoke');
235
    }
236
237
    /**
238
     * Merge different sections of a node
239
     *
240
     * convert
241
     *   `['section1' => [[1], [2]], 'section2' => [[3], [4]]]`
242
     *
243
     * to
244
     *   `[[1], [2], [3], [4]]`
245
     *
246
     * @param  array $nodeData
247
     * @return array
248
     * @access protected
249
     */
250
    protected function mergeMethods(array $nodeData)/*# : array */
251
    {
252
        // no merge
253
        if (empty($nodeData) || isset($nodeData[0])) {
254
            return $nodeData;
255
        }
256
257
        // in sections
258
        $result = [];
259
        foreach ($nodeData as $data) {
260
            $result = array_merge($result, $data);
261
        }
262
        return $result;
263
    }
264
265
    /**
266
     * Execute common methods defined in 'di.common' for all objects
267
     *
268
     * @param  object $object
269
     * @return $this
270
     * @access protected
271
     */
272
    protected function executeCommonBatch($object)
273
    {
274
        $methods = [];
275
276
        // get from 'di.common'
277
        if ($this->master->getResolver()->hasInSection('', 'common')) {
278
            $methods = $this->mergeMethods(
279
                $this->master->getResolver()->getInSection('', 'common')
280
            );
281
        }
282
283
        foreach ($methods as $method) {
284
            if (call_user_func($method[0], $object, $this->master)) {
285
                call_user_func($method[1], $object, $this->master);
286
            }
287
        }
288
        return $this;
289
    }
290
}
291