Completed
Push — master ( d9f04e...3eb62a )
by Arman
21s queued 11s
created

Di::autowire()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 27
rs 9.4555
cc 5
nc 6
nop 2
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.2.0
13
 */
14
15
namespace Quantum\Di;
16
17
use Quantum\Exceptions\DiException;
18
use ReflectionFunction;
19
use ReflectionClass;
20
use ReflectionMethod;
21
22
/**
23
 * Di Class
24
 * 
25
 * @package Quantum
26
 * @category Di
27
 */
28
class Di
29
{
30
31
    /**
32
     * @var array
33
     */
34
    private static $dependencies = [];
35
36
    /**
37
     * @var array
38
     */
39
    private static $contianer = [];
40
41
    /**
42
     * Loads dependency definitions
43
     */
44
    public static function loadDefinitions()
45
    {
46
        self::$dependencies = self::coreDependencies();
47
    }
48
49
    /**
50
     * Create and inject dependencies.
51
     * @param string|callable $entry
52
     * @param array $additional
53
     * @return array
54
     */
55
    public static function autowire($entry, array $additional = [])
56
    {
57
        if (is_callable($entry)) {
58
            $reflaction = new ReflectionFunction($entry);
59
        } else {
60
            list($controller, $action) = explode(':', $entry);
0 ignored issues
show
Bug introduced by
It seems like $entry can also be of type callable; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

60
            list($controller, $action) = explode(':', /** @scrutinizer ignore-type */ $entry);
Loading history...
61
62
            $reflaction = new ReflectionMethod($controller, $action);
63
        }
64
65
        $params = [];
66
67
        foreach ($reflaction->getParameters() as $param) {
68
            $type = $param->getType();
69
70
            if (!$type || !self::instatiatable($type)) {
71
                array_push($params, current($additional));
72
                next($additional);
73
                continue;
74
            }
75
76
            $dependency = $param->getType();
77
78
            array_push($params, self::get($dependency));
79
        }
80
81
        return $params;
82
    }
83
84
    /**
85
     * Gets the dependency from the container
86
     * @param string $dependency
87
     * @return mixed
88
     * @throws DiException
89
     */
90
    public static function get(string $dependency)
91
    {
92
        if (!in_array($dependency, self::$dependencies)) {
93
            throw new DiException(_message(DiException::NOT_FOUND, $dependency));
94
        }
95
96
        if (!isset(self::$contianer[$dependency])) {
97
            self::instantiate($dependency);
98
        }
99
100
        return self::$contianer[$dependency];
101
    }
102
103
    /**
104
     * Instantiates the dependency
105
     * @param string $dependency
106
     */
107
    protected static function instantiate(string $dependency)
108
    {
109
        $class = new ReflectionClass($dependency);
110
111
        $constructor = $class->getConstructor();
112
113
        $params = [];
114
115
        if ($constructor) {
116
            foreach ($constructor->getParameters() as $param) {
117
                $type = (string) $param->getType();
118
119
                if (!$type || !self::instatiatable($type)) {
120
                    continue;
121
                }
122
123
                $params[] = self::get($type);
124
            }
125
        }
126
127
        self::$contianer[$dependency] = new $dependency(...$params);
128
    }
129
130
    /**
131
     * Checks if the class is instantiable
132
     * @param mixed $type
133
     * @return boolean
134
     */
135
    protected static function instatiatable($type)
136
    {
137
        return $type != 'Closure' && !is_callable($type) && class_exists($type);
138
    }
139
140
    /**
141
     * Gets the core dependencies 
142
     * @return array
143
     */
144
    private static function coreDependencies()
145
    {
146
        return [
147
            \Quantum\Http\Request::class,
148
            \Quantum\Http\Response::class,
149
            \Quantum\Loader\Loader::class,
150
            \Quantum\Factory\ViewFactory::class,
151
            \Quantum\Factory\ModelFactory::class,
152
            \Quantum\Factory\ServiceFactory::class,
153
            \Quantum\Libraries\Mailer\Mailer::class,
154
            \Quantum\Libraries\Storage\FileSystem::class,
155
        ];
156
    }
157
158
}
159