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 ( 502620...0fb245 )
by Dangerous
02:18
created

DiMaria::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2
Metric Value
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
crap 2
1
<?php
2
namespace DD;
3
4
use DD\DiMaria\Exception\ContainerException;
5
use DD\DiMaria\Exception\NotFoundException;
6
use Interop\Container\ContainerInterface;
7
8
/**
9
 * DiMaria Dependency injector
10
 */
11
class DiMaria implements ContainerInterface
12
{
13
    protected $aliases = [];
14
    protected $cache = [];
15
    protected $injections = [];
16
    protected $params = [];
17
    protected $preferences = [];
18
    protected $shared = [];
19
    protected $sharedInstance = [];
20
21
    /**
22 3
     * Alias a class/interface/alias to a string
23
     * @param string $alias   the name of the alias
24 3
     * @param string $class   the name of the class
25 3
     * @param array  $params  a key/value array of parameter names and values
26 3
     * @return self
27 3
     */
28 3
    public function setAlias(string $alias, string $class, array $params = []): self
29
    {
30 3
        $this->aliases[$alias] = [
31 1
            'class' => $class,
32
            'params' => $params
33 3
        ];
34 1
        return $this;
35
    }
36 3
37 1
    /**
38
     * Set rule to call a method after constructing a class
39 3
     * @param string $class the name of the class
40 1
     * @param string $method    the name of the method
41 1
     * @param array  $params    a key/value array of parameter names and values
42
     * @return self
43
     */
44 3
    public function setInjection(string $class, string $method, array $params = []): self
45 1
    {
46 1
        $this->injections[$class][$method][] =  $params;
47
        return $this;
48
    }
49 3
50
    /**
51
     * Set parameters of a class
52
     * @param string $class the name of the class
53
     * @param array  $params    a key/value array of parameter names and values
54
     * @return self
55
     */
56
    public function setParams(string $class, array $params): self
57
    {
58 4
        $this->params[$class] = $params + ($this->params[$class] ?? []);
59
        return $this;
60 4
    }
61 4
62
    /**
63
     * Set a preferred implementation of a class/interface
64
     * @param string $alias  the name of the alias
65
     * @param string $class  the name of the class/interface
66
     * @return self
67
     */
68
    public function setPreference(string $alias, string $class): self
69
    {
70
        $this->preferences[$alias] = $class;
71 23
        return $this;
72
    }
73 23
74 23
    /**
75 23
     * Mark a class/alias as shared
76
     * @param string $class the name of class/alias
77 23
     * @return self
78
     */
79
    public function setShared(string $class): self
80
    {
81
        $this->shared[$class] = true;
82
        return $this;
83
    }
84
85
    /**
86
     * Set a value. Retrievable with the get method
87 19
     * @param string $key
88
     * @param mixed $value
89 19
     * @return self
90 19
     */
91
    public function set(string $key, $value): self
92
    {
93
        $this->sharedInstance[$key] = $value;
94
        return $this;
95
    }
96
97
    /**
98
     * Returns true if DiMaria can return an entry for the given string. Returns false otherwise.
99 21
     * @param string $id  identifier of the entry to look for
0 ignored issues
show
Bug introduced by
There is no parameter named $id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
100
     * @return boolean
101 21
     */
102 21
    public function has($class): bool
103
    {
104
        return isset($this->sharedInstance[$class]) ?:
105
            class_exists($class) ?:
106
            isset($this->aliases[$class]) ?:
107
            isset($this->preferences[$class]);
108
    }
109
110 4
    /**
111
     * Get an instance of a class
112 4
     * @param  string $class       the name of class/alias to create
113 4
     * @param  array $params       a key/value array of parameter names and values
114
     * @throws NotFoundException   when no entry was found
115
     * @throws ContainerException  if class could not be constructed
116
     * @return mixed               an instance of the class requested
117
     */
118
    public function get($class, array $params = [])
119
    {
120
        if (isset($this->sharedInstance[$class])) {
121
            return $this->sharedInstance[$class];
122 58
        }
123
        $class = $this->getClassName($class);
124 58
125 3
        $object = $this->getObject($class, $params);
126
        $this->sharedInstance[$class] = $object;
127 58
        return $object;
128 4
    }
129
130 58
    /**
131 58
     * Get a new instance of a class
132 22
     * @param  string $class       the name of class/alias to create
133 22
     * @param  array $params       a key/value array of parameter names and values
134
     * @throws NotFoundException   if no entry was found
135 58
     * @throws ContainerException  if class could not be constructed
136 58
     * @return mixed               an instance of the class requested
137 56
     */
138 4
    public function create(string $class, array $params = [])
139
    {
140 56
        if (isset($this->shared[$class])) {
141
            return $this->get($class, $params);
142
        }
143 58
        return $this->getObject($this->getClassName($class), $params);
144
    }
145 58
146 58
    protected function getClassName(string $class): string
147 18
    {
148 18
        if (! $this->has($class)) {
149 18
            throw new NotFoundException('Class or alias ' . $class . ' does not exist');
150 18
        }
151
        while ($preference = $this->preferences[$class] ?? false) {
152 18
            $class = $preference;
153 18
        }
154 18
        return $class;
155 18
    }
156
157
    protected function getObject(string $class, array $params)
158
    {
159 58
        $originalClass = $class;
160 58
        while ($alias = $this->aliases[$class] ?? false) {
161
            $params = $params + $alias['params'];
162
            $class = $alias['class'];
163 58
        }
164
        try {
165 58
            $callback = $this->cache[$originalClass] ?? $this->cache[$originalClass] = $this->getCallback($class, $originalClass);
166 58
            return $callback($params);
167
        } catch (\Exception $e) {
168 29
            throw new ContainerException($e->getMessage(), $e->getCode(), $e);
169 29
        } catch (\Error $e) {
170
            throw new ContainerException($e->getMessage(), $e->getCode(), $e);
171 40
        }
172 40
    }
173 40
174 40
    protected function getCallback(string $class, string $originalClass): callable
175 40
    {
176
        $callback = $this->generateCallback($class);
177
        if (isset($this->injections[$originalClass])) {
178 56
            foreach ($this->injections[$originalClass] as $method => $instance) {
179
                $methodInfo = $this->getMethodInfo(new \ReflectionMethod($class, $method));
180 56
                foreach ($instance as $methodParameters) {
181 56
                    $methodParams = $this->getParameters($methodInfo, $methodParameters);
182 53
                    $callback = function ($params) use ($callback, $method, $methodParams) {
183 53
                        $object = $callback($params);
184 53
                        $object->$method(...$methodParams);
185 53
                        return $object;
186 53
                    };
187 53
                };
188 53
            }
189 53
        }
190
        return $callback;
191
    }
192 56
193
    protected function generateCallback(string $class): callable
194
    {
195 56
        $constructor = (new \ReflectionClass($class))->getConstructor();
196
        if (! $constructor || ! $constructor->getNumberOfParameters()) {
197 56
            return function () use ($class) {
198 56
                return new $class;
199 53
            };
200 39
        }
201 29
        $constructorInfo = $this->getMethodInfo($constructor);
202 26
        $predefinedParams = $this->params[$class] ?? [];
203 4
204
        return function ($params) use ($class, $constructorInfo, $predefinedParams) {
205 22
            return new $class(...$this->getParameters($constructorInfo, $params + $predefinedParams));
206 15
        };
207 13
    }
208
209 51
    protected function getMethodInfo(\ReflectionMethod $method): array
210
    {
211
        $paramInfo = [];
212 54
        foreach ($method->getParameters() as $param) {
213
            $paramType = $param->hasType() ? $param->getType() : null;
214
            $paramType = $paramType ? $paramType->isBuiltin() ? null : $paramType->__toString() : null;
215 39
            $paramInfo[$param->name] = [
216
                'name' => $param->name,
217 39
                'optional' => $param->isOptional(),
218 15
                'default' => $param->isOptional() ? ($param->isVariadic() ? null : $param->getDefaultValue()) : null,
219 7
                'variadic' => $param->isVariadic(),
220 7
                'type' => $paramType,
221 7
            ];
222
        }
223 7
        return $paramInfo;
224
    }
225 8
226
    public function getParameters(array $methodInfo, array $params): array
227 33
    {
228
        $parameters = [];
229
        foreach ($methodInfo as $param) {
230
            if (isset($params[$param['name']])) {
231
                array_push($parameters, ...$this->determineParameter($params[$param['name']], $param['variadic']));
232
            } elseif ($param['optional']) {
233
                if ($param['variadic']) {
234
                    break;
235
                }
236
                $parameters[] = $param['default'];
237
            } elseif ($param['type']) {
238
                $parameters[] = $this->create($param['type']);
239
            } else {
240
                throw new ContainerException('Required parameter $' . $param['name'] . ' is missing');
241
            }
242
        }
243
        return $parameters;
244
    }
245
246
    protected function determineParameter($param, bool $isVariadic): array
247
    {
248
        if (is_array($param)) {
249
            if ($isVariadic) {
250
                $params = [];
251
                foreach ($param as $val) {
252
                    $params[] = isset($val['instanceOf']) ? $this->create($val['instanceOf'], $val['params'] ?? []) : $val;
253
                }
254
                return $params;
255
            }
256
            return isset($param['instanceOf']) ? [$this->create($param['instanceOf'], $param['params'] ?? [])] : [$param];
257
        }
258
        return [$param];
259
    }
260
}
261