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