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

DiMaria::setShared()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
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
     * Alias a class/interface/alias to a string
23
     * @param string $alias   the name of the alias
24
     * @param string $class   the name of the class
25
     * @param array  $params  a key/value array of parameter names and values
26
     * @return self
27
     */
28 23
    public function setAlias(string $alias, string $class, array $params = []): self
29
    {
30 23
        $this->aliases[$alias] = [
31 23
            'class' => $class,
32 23
            'params' => $params
33
        ];
34 23
        return $this;
35
    }
36
37
    /**
38
     * Set rule to call a method after constructing a class
39
     * @param string $class the name of the class
40
     * @param string $method    the name of the method
41
     * @param array  $params    a key/value array of parameter names and values
42
     * @return self
43
     */
44 18
    public function setInjection(string $class, string $method, array $params = []): self
45
    {
46 18
        $this->injections[$class][$method][] = $params;
47 18
        return $this;
48
    }
49
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 20
    public function setParams(string $class, array $params): self
57
    {
58 20
        $this->params[$class] = $params + ($this->params[$class] ?? []);
59 20
        return $this;
60
    }
61
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 3
    public function setPreference(string $alias, string $class): self
69
    {
70 3
        $this->preferences[$alias] = $class;
71 3
        return $this;
72
    }
73
74
    /**
75
     * Mark a class/alias as shared
76
     * @param string $class the name of class/alias
77
     * @return self
78
     */
79 4
    public function setShared(string $class): self
80
    {
81 4
        $this->shared[$class] = true;
82 4
        return $this;
83
    }
84
85
    /**
86
     * Set a value. Retrievable with the get method
87
     * @param string $key
88
     * @param mixed $value
89
     * @return self
90
     */
91 4
    public function set(string $key, $value): self
92
    {
93 4
        $this->sharedInstance[$key] = $value;
94 4
        return $this;
95
    }
96
97
    /**
98
     * Returns true if DiMaria can return an entry for the given string. Returns false otherwise.
99
     * @param string $class  identifier of the entry to look for
100
     * @return boolean
101
     */
102 64
    public function has($class): bool
103
    {
104 64
        return isset($this->sharedInstance[$class]) ?: class_exists($class) ?: isset($this->aliases[$class]) ?: isset($this->preferences[$class]);
105
    }
106
107
    /**
108
     * Get an instance of a class
109
     * @param  string $class       the name of class/alias to create
110
     * @param  array $params       a key/value array of parameter names and values
111
     * @throws NotFoundException   when no entry was found
112
     * @throws ContainerException  if class could not be constructed
113
     * @return mixed               an instance of the class requested
114
     */
115 62
    public function get($class, array $params = [])
116
    {
117 62
        if (isset($this->sharedInstance[$class])) {
118 5
            return $this->sharedInstance[$class];
119
        }
120 59
        $class = $this->getClassName($class);
121
122 57
        $object = $this->getObject($class, $params);
123 53
        $this->sharedInstance[$class] = $object;
124 53
        return $object;
125
    }
126
127
    /**
128
     * Get a new instance of a class
129
     * @param  string $class       the name of class/alias to create
130
     * @param  array $params       a key/value array of parameter names and values
131
     * @throws NotFoundException   if no entry was found
132
     * @throws ContainerException  if class could not be constructed
133
     * @return mixed               an instance of the class requested
134
     */
135 27
    public function create(string $class, array $params = [])
136
    {
137 27
        if (isset($this->shared[$class])) {
138 4
            return $this->get($class, $params);
139
        }
140 23
        return $this->getObject($this->getClassName($class), $params);
141
    }
142
143 61
    protected function getClassName(string $class): string
144
    {
145 61
        if (!$this->has($class)) {
146 2
            throw new NotFoundException('Class or alias ' . $class . ' does not exist');
147
        }
148 59
        while ($preference = $this->preferences[$class] ?? false) {
149 3
            $class = $preference;
150
        }
151 59
        return $class;
152
    }
153
154 59
    protected function getObject(string $class, array $params)
155
    {
156 59
        $originalClass = $class;
157 59
        while ($alias = $this->aliases[$class] ?? false) {
158 21
            $params = $params + $alias['params'];
159 21
            $class = $alias['class'];
160
        }
161
        try {
162 59
            $callback = $this->cache[$originalClass] ?? $this->cache[$originalClass] = $this->getCallback($class, $originalClass);
163 58
            return $callback($params);
164 5
        } catch (\Exception $e) {
165 4
            throw new ContainerException($e->getMessage(), $e->getCode(), $e);
166 1
        } catch (\Error $e) {
167 1
            throw new ContainerException($e->getMessage(), $e->getCode(), $e);
168
        }
169
    }
170
171 59
    protected function getCallback(string $class, string $originalClass): callable
172
    {
173 59
        $callback = $this->generateCallback($class);
174 58
        if (isset($this->injections[$originalClass])) {
175 17
            foreach ($this->injections[$originalClass] as $method => $instance) {
176 17
                $methodInfo = $this->getMethodInfo(new \ReflectionMethod($class, $method));
177 17
                foreach ($instance as $methodParameters) {
178 17
                    $methodParams = $this->getParameters($methodInfo, $methodParameters);
179
                    $callback = function($params) use ($callback, $method, $methodParams) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
180 17
                        $object = $callback($params);
181 17
                        $object->$method(...$methodParams);
182 17
                        return $object;
183 17
                    };
184
                };
185
            }
186
        }
187 58
        return $callback;
188
    }
189
190 59
    protected function generateCallback(string $class): callable
191
    {
192 59
        $constructor = (new \ReflectionClass($class))->getConstructor();
193 58
        if (!$constructor || !$constructor->getNumberOfParameters()) {
194
            return function () use ($class) {
195 27
                return new $class;
196 27
            };
197
        }
198 41
        $constructorInfo = $this->getMethodInfo($constructor);
199 41
        $predefinedParams = $this->params[$class] ?? [];
200
201 41
        return function($params) use ($class, $constructorInfo, $predefinedParams) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
202 41
            return new $class(...$this->getParameters($constructorInfo, $params + $predefinedParams));
203 41
        };
204
    }
205
206 56
    protected function getMethodInfo(\ReflectionMethod $method): array
207
    {
208 56
        $paramInfo = [];
209 56
        foreach ($method->getParameters() as $param) {
210 53
            $paramType = $param->hasType() ? $param->getType() : null;
211 53
            $paramType = $paramType ? $paramType->isBuiltin() ? null : $paramType->__toString() : null;
212 53
            $paramInfo[$param->name] = [
213 53
                'name' => $param->name,
214 53
                'optional' => $param->isOptional(),
215 53
                'default' => $param->isOptional() ? ($param->isVariadic() ? null : $param->getDefaultValue()) : null,
216 53
                'variadic' => $param->isVariadic(),
217 53
                'type' => $paramType,
218
            ];
219
        }
220 56
        return $paramInfo;
221
    }
222
223 56
    public function getParameters(array $methodInfo, array $params): array
224
    {
225 56
        $parameters = [];
226 56
        foreach ($methodInfo as $param) {
227 53
            if (isset($params[$param['name']])) {
228 39
                array_push($parameters, ...$this->determineParameter($params[$param['name']], $param['variadic']));
229 30
            } elseif ($param['optional']) {
230 26
                if ($param['variadic']) {
231 4
                    break;
232
                }
233 22
                $parameters[] = $param['default'];
234 15
            } elseif ($param['type']) {
235 12
                $parameters[] = $this->create($param['type']);
236
            } else {
237 51
                throw new ContainerException('Required parameter $' . $param['name'] . ' is missing');
238
            }
239
        }
240 53
        return $parameters;
241
    }
242
243 39
    protected function determineParameter($param, bool $isVariadic): array
244
    {
245 39
        if (is_array($param)) {
246 16
            if ($isVariadic) {
247 7
                $params = [];
248 7
                foreach ($param as $val) {
249 7
                    $params[] = isset($val['instanceOf']) ? $this->create($val['instanceOf'], $val['params'] ?? []) : $val;
250
                }
251 7
                return $params;
252
            }
253 9
            return isset($param['instanceOf']) ? [$this->create($param['instanceOf'], $param['params'] ?? [])] : [$param];
254
        }
255 33
        return [$param];
256
    }
257
}
258