Passed
Pull Request — master (#54)
by Arman
04:33 queued 01:55
created

Di::userDependencies()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 11
rs 10
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.6.0
13
 */
14
15
namespace Quantum\Di;
16
17
use Quantum\Libraries\Storage\FileSystem;
18
use Quantum\Exceptions\DiException;
19
use ReflectionFunction;
20
use ReflectionClass;
21
use ReflectionMethod;
22
23
/**
24
 * Di Class
25
 *
26
 * @package Quantum
27
 * @category Di
28
 */
29
class Di
30
{
31
32
    /**
33
     * @var array
34
     */
35
    private static $dependencies = [];
36
37
    /**
38
     * @var array
39
     */
40
    private static $container = [];
41
42
    /**
43
     * Loads dependency definitions
44
     */
45
    public static function loadDefinitions()
46
    {
47
        self::$dependencies = self::coreDependencies();
48
49
        $userDependencies = self::userDependencies();
50
51
        foreach ($userDependencies as $dependency) {
52
            self::add($dependency);
53
        }
54
    }
55
56
    /**
57
     * Creates and injects dependencies.
58
     * @param callable $entry
59
     * @param array $additional
60
     * @return array
61
     * @throws \Quantum\Exceptions\DiException
62
     * @throws \ReflectionException
63
     */
64
    public static function autowire(callable $entry, array $additional = []): array
65
    {
66
        if (is_closure($entry)) {
67
            $reflection = new ReflectionFunction($entry);
68
        } else {
69
            $reflection = new ReflectionMethod(...$entry);
0 ignored issues
show
Bug introduced by
$entry is expanded, but the parameter $objectOrMethod of ReflectionMethod::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

69
            $reflection = new ReflectionMethod(/** @scrutinizer ignore-type */ ...$entry);
Loading history...
70
        }
71
72
        $params = [];
73
74
        foreach ($reflection->getParameters() as $param) {
75
            $type = $param->getType();
76
77
            if(!self::instantiable($type)) {
78
                if($type && $type->getName() == 'array') {
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
                if($type && $type->/** @scrutinizer ignore-call */ getName() == 'array') {
Loading history...
79
                    array_push($params, $additional);
80
                } else {
81
                    array_push($params, current($additional));
82
                    next($additional);
83
                }
84
                continue;
85
            }
86
87
            array_push($params, self::get($type->getName()));
88
        }
89
90
        return $params;
91
    }
92
93
    /**
94
     * Adds new dependency
95
     * @param string $dependency
96
     */
97
    public static function add(string $dependency)
98
    {
99
        if (!in_array($dependency, self::$dependencies) && class_exists($dependency)) {
100
            array_push(self::$dependencies, $dependency);
101
        }
102
    }
103
104
    /**
105
     * Gets the dependency from the container
106
     * @param string $dependency
107
     * @return mixed
108
     * @throws \Quantum\Exceptions\DiException
109
     * @throws \ReflectionException
110
     */
111
    public static function get(string $dependency)
112
    {
113
        if (!in_array($dependency, self::$dependencies)) {
114
            throw DiException::dependencyNotDefined($dependency);
115
        }
116
117
        if (!isset(self::$container[$dependency])) {
118
            self::instantiate($dependency);
119
        }
120
121
        return self::$container[$dependency];
122
    }
123
124
    /**
125
     * Instantiates the dependency
126
     * @param string $dependency
127
     * @throws \Quantum\Exceptions\DiException|\ReflectionException
128
     */
129
    protected static function instantiate(string $dependency)
130
    {
131
        $class = new ReflectionClass($dependency);
132
133
        $constructor = $class->getConstructor();
134
135
        $params = [];
136
137
        if ($constructor) {
138
            foreach ($constructor->getParameters() as $param) {
139
                $type = $param->getType()->getName();
140
141
                if (!$type || !self::instantiable($type)) {
142
                    continue;
143
                }
144
145
                $params[] = self::get($type);
146
            }
147
        }
148
149
        self::$container[$dependency] = new $dependency(...$params);
150
    }
151
152
    /**
153
     * Checks if the class is instantiable
154
     * @param mixed $type
155
     * @return bool
156
     */
157
    protected static function instantiable($type): bool
158
    {
159
        return $type != 'Closure' && !is_callable($type) && class_exists($type);
160
    }
161
162
    /**
163
     * Loads user defined dependencies
164
     * @return array
165
     */
166
    private static function userDependencies(): array
167
    {
168
        $fs = new FileSystem();
169
170
        $dependencies = base_dir() . DS . 'config' . DS . 'dependencies.php';
171
172
        if (!$fs->exists($dependencies)) {
173
            return [];
174
        }
175
176
        return require_once $dependencies;
177
    }
178
179
    /**
180
     * Gets the core dependencies
181
     * @return array
182
     */
183
    private static function coreDependencies(): array
184
    {
185
        return [
186
            \Quantum\Http\Request::class,
187
            \Quantum\Http\Response::class,
188
            \Quantum\Loader\Loader::class,
189
            \Quantum\Factory\ViewFactory::class,
190
            \Quantum\Factory\ModelFactory::class,
191
            \Quantum\Factory\ServiceFactory::class,
192
            \Quantum\Libraries\Mailer\Mailer::class,
193
            \Quantum\Libraries\Storage\FileSystem::class,
194
        ];
195
    }
196
197
}
198