AppContainer::resolveWithSetParams()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace HotRodCli;
4
5
use HotRodCli\Checkers\BaseStatus;
6
use HotRodCli\Checkers\Container\HasArguments;
7
use HotRodCli\Checkers\Container\HasConstructor;
8
use HotRodCli\Checkers\Container\IsAlreadyExists;
9
use HotRodCli\Checkers\Container\IsInstantiable;
10
11
class AppContainer
12
{
13
    /**
14
     * All registered.
15
     * ----------------------------------------
16
     * @var array
17
     */
18
    protected $registry = [];
19
20
    protected $checkers = [
21
        IsAlreadyExists::class => 'isAlreadyExists',
22
        IsInstantiable::class => 'canNotInstantiate',
23
        HasConstructor::class => 'hasConstructor',
24
        HasArguments::class => 'hasArguments'
25
    ];
26
27
    public function resolve(string $class, $args = null)
28
    {
29
        $status = $this->runCheckers($class, $args);
30
31
        if (!$status->getStatus()) {
32
            return $this->{$this->checkers[$status->getFailedWith()]}($class, $args);
33
        }
34
35
        $reflector = new \ReflectionClass($class);
36
        $constructor = $reflector->getConstructor();
37
        $parameters = $constructor->getParameters();
38
        $dependencies = $this->getDependencies($parameters);
39
        $result = $reflector->newInstanceArgs($dependencies);
40
        $this->bind($class, $result);
41
42
        return $result;
43
    }
44
45
    protected function runCheckers($class, $args)
46
    {
47
        $exists = new IsAlreadyExists($this->registry, $class);
48
        $isInstantiable = new IsInstantiable($class);
49
        $hasConstructor = new HasConstructor($class);
50
        $hasArguments = new HasArguments($args);
51
52
        $exists->succeedWIth($isInstantiable);
53
        $isInstantiable->succeedWIth($hasConstructor);
54
        $hasConstructor->succeedWIth($hasArguments);
55
56
        return $exists->check(new BaseStatus());
57
    }
58
59
    protected function hasArguments($class, $args)
60
    {
61
        return $this->resolveWithSetParams($class, $args);
62
    }
63
64
    protected function hasConstructor($class)
65
    {
66
        return $this->resolveWithoutConstructor($class);
67
    }
68
69
    protected function isAlreadyExists($class)
70
    {
71
        return $this->registry[$class];
72
    }
73
74
    protected function canNotInstantiate($class)
75
    {
76
        throw new \Exception("[$class] is not instantiable");
77
    }
78
79
    protected function resolveWithoutConstructor(string $class)
80
    {
81
        $result = new $class;
82
        $this->bind($class, $result);
83
84
        return $result;
85
    }
86
87
    protected function resolveWithSetParams(string $class, $args)
88
    {
89
        $reflector = new \ReflectionClass($class);
90
        $result = $reflector->newInstance($args);
91
        $this->bind($class, $result);
92
93
        return $result;
94
    }
95
96
    /**
97
     * @param $parameters
98
     * @return array
99
     */
100
    public function getDependencies($parameters)
101
    {
102
        $dependencies = [];
103
104
        /** @var \ReflectionParameter $parameter */
105
        foreach ($parameters as $parameter) {
106
            $dependency = $parameter->getClass();
107
108
            if (is_null($dependency)) {
109
                $dependencies[] = $this->resolveNonClass($parameter);
110
            } else {
111
                $dependencies[] = $this->resolve($dependency->name);
112
            }
113
        }
114
115
        return $dependencies;
116
    }
117
118
    /**
119
     * @param $key
120
     * @param $value
121
     * @throws \Exception
122
     */
123
    public function bind($key, $value)
124
    {
125
        if (! array_key_exists($key, $this->registry)) {
126
            $this->registry[$key] = $value;
127
        } else {
128
            throw new \Exception("{$key} is already bound in the container.");
129
        }
130
    }
131
132
    /**
133
     * @param $key
134
     * @return mixed
135
     * @throws \Exception
136
     */
137
    public function get($key)
138
    {
139
        if (! array_key_exists($key, $this->registry)) {
140
            throw new \Exception("No {$key} is bound in the container.");
141
        }
142
143
        return $this->registry[$key];
144
    }
145
146
    /**
147
     * @param \ReflectionParameter $parameter
148
     * @return mixed
149
     * @throws \Exception
150
     */
151
    public function resolveNonClass(\ReflectionParameter $parameter)
152
    {
153
        if ($parameter->isDefaultValueAvailable()) {
154
            return $parameter->getDefaultValue();
155
        }
156
157
        throw new \Exception("Cannot resolve the unknown");
158
    }
159
}
160