Completed
Push — master ( b4ca26...e16bad )
by James Ekow Abaka
01:17
created

Container::getConstructorArguments()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.0208

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 11
cts 12
cp 0.9167
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 13
nc 9
nop 2
crap 6.0208
1
<?php
2
3
namespace ntentan\panie;
4
5
/**
6
 * Description of Container
7
 *
8
 * @author ekow
9
 */
10
class Container {
11
12
    private $bindings;
13
    private $singletons = [];
14
15 7
    public function __construct() {
16 7
        $this->bindings = new Bindings();
17 7
    }
18
19
    /**
20
     * 
21
     * @param string|\ReflectionClass $class
22
     * @return \ReflectionClass
23
     */
24 7
    public function getResolvedClassName($class) {
25 7
        $bound = null;
26 7
        if ($this->bindings->has($class)) {
27 5
            $bound = $this->bindings->get($class);
28 5
        } else if (is_string($class) && class_exists($class)) {
29 4
            $bound = ['binding' => $class];
30
        }     
31 7
        return $bound;
32
    }
33
34 5
    public function bind($type) {
35 5
        return $this->bindings->setActiveKey($type);
36
    }
37
    
38
    public function has($type) {
39
        return $this->bindings->has($type);
40
    }
41
    
42
    public function setup($bindings, $replace = true) {
43
        $this->bindings->merge($bindings, $replace);
44
    }
45
        
46
    public function unbind($type) {
47
        $this->bindings->remove($type);
48
    }
49
50 1
    public function singleton($type, $constructorArguments = []) {
51 1
        $resolvedClass = $this->getResolvedClassName($type)['binding'];
52 1
        return $this->getSingletonInstance($type, $resolvedClass, $constructorArguments);
53
    }
54
    
55 1
    private function getSingletonInstance($type, $class,  $constructorArguments) {
56 1
        if (!isset($this->singletons[$type])) {
57 1
            $this->singletons[$type] = $this->getInstance($class, $constructorArguments);
58
        }
59 1
        return $this->singletons[$type];        
60
    }
61
    
62 6
    public function resolve($type, $constructorArguments = []) {
63 6
        if($type === null) {
64
            throw new exceptions\ResolutionException("Cannot resolve an empty type");
65
        } 
66 6
        $resolvedClass = $this->getResolvedClassName($type);
67 6
        if ($resolvedClass['binding'] === null) {
68 1
            throw new exceptions\ResolutionException("Could not resolve dependency $type");
69
        }           
70 5
        if($resolvedClass['singleton'] ?? false) {
71
            return $this->getSingletonInstance($type, $resolvedClass['binding'], $constructorArguments);
72
        } else {
73 5
            return $this->getInstance($resolvedClass['binding'], $constructorArguments);
74
        }
75
    }
76
    
77 3
    private function getConstructorArguments($constructor, $constructorArguments)
78
    {
79 3
        $argumentValues = [];
80 3
        $parameters = $constructor->getParameters();
81 3
        foreach ($parameters as $parameter) {
82 3
            $class = $parameter->getClass();
83 3
            $className = $class ? $class->getName() : null;
84 3
            if (isset($constructorArguments[$parameter->getName()])) {
85 1
                $argumentValues[] = $constructorArguments[$parameter->getName()];
86 3
            } else if($className == self::class){
87
                $argumentValues[] = $this;
88
            } else {                    
89 3
                $argumentValues[] = $className ? $this->resolve($className) : null;
90
            }
91
        }
92 3
        return $argumentValues;
93
    }
94
95 6
    public function getInstance($className, $constructorArguments = []) {
96 6
        if (is_callable($className)) {
97
            return $className($this);
98
        }
99 6
        if(is_object($className)) {
100
            return $className;
101
        } 
102 6
        $reflection = new \ReflectionClass($className);
103 6
        if ($reflection->isAbstract()) {
104 1
            throw new exceptions\ResolutionException(
105 1
            "Abstract class {$reflection->getName()} cannot be instantiated. "
106 1
            . "Please provide a binding to an implementation."
107
            );
108
        }
109 5
        $constructor = $reflection->getConstructor();
110 5
        return $reflection->newInstanceArgs($constructor ? $this->getConstructorArguments($constructor, $constructorArguments) : []);
111
    }
112
113
}
114