Completed
Push — master ( 8bb41b...abc078 )
by Vitaly
02:49
created

Container::delegate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php declare(strict_types=1);
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 26.01.16 at 15:11
5
 */
6
namespace samsonframework\di;
7
use samsonframework\di\exception\ClassNotFoundException;
8
use samsonframework\di\exception\ContainerException;
9
10
/**
11
 * Dependency container.
12
 *
13
 * @author Vitaly Iegorov <[email protected]>
14
 */
15
class Container implements ContainerInterface
16
{
17
    /** @var array[string] Collection of loaded services */
18
    protected $services = [];
19
20
    /** @var array[string] Collection of alias => class name for alias resolving */
21
    protected $aliases = [];
22
23
    /** @var array[string] Collection of class name dependencies trees */
24
    protected $dependencies = [];
25
26
    /** @var ContainerInterface[] Collection of delegated containers */
27
    protected $delegates = [];
28
29
    /** @var callable Dependency resolving function callable */
30
    protected $logicCallable;
31
32
33
    /**
34
     * Wrapper for calling dependency resolving function.
35
     *
36
     * @param string $dependency Dependency name
37
     *
38
     * @return mixed Created instance or null
39
     * @throws ContainerException
40
     */
41 1
    protected function logic($dependency)
42
    {
43 1
        if (!is_callable($this->logicCallable)) {
44 1
            throw new ContainerException('Logic function is not callable');
45
        }
46
47
        return call_user_func($this->logicCallable, $dependency);
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     *
53
     * @throws \samsonframework\di\exception\ContainerException
54
     */
55 1
    public function get($dependency)
56
    {
57
        // Get pointer from logic
58 1
        $module = $this->logic($dependency);
59
60
        // Try delegate lookup
61
        if (null === $module) {
62
            foreach ($this->delegates as $delegate) {
63
                try {
64
                    $module = $delegate->get($dependency);
65
                } catch (ContainerException $e) {
66
                    // Catch all delegated exceptions
67
                } catch (ClassNotFoundException $e) {
68
                    // Catch all delegated exceptions
69
                }
70
            }
71
        }
72
73
        if (null === $module) {
74
            throw new ClassNotFoundException($dependency);
75
        } else {
76
            return $module;
77
        }
78
    }
79
80
    /**
81
     * Implementing delegate lookup feature.
82
     * If current container cannot resolve entity dependency
83
     * resolving process is passed to delegated container.
84
     *
85
     * @param ContainerInterface $container Container for delegate lookup
86
     */
87
    public function delegate(ContainerInterface $container)
88
    {
89
        $this->delegates[] = $container;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95
    public function has($dependency) : bool
96
    {
97
        $found = array_key_exists($dependency, $this->dependencies)
98
            || in_array($dependency, $this->aliases, true);
99
100
        if (!$found) {
101
            foreach ($this->delegates as $delegate) {
102
                if ($delegate->has($dependency)) {
103
                    return true;
104
                }
105
            }
106
        }
107
108
        return $found;
109
    }
110
111
    /**
112
     * Set service dependency. Upon first creation of this class instance
113
     * it would be used everywhere where this dependency is needed.
114
     *
115
     * @param string $className  Fully qualified class name
116
     * @param array  $parameters Collection of parameters needed for dependency creation
117
     * @param string $alias      Dependency name
118
     *
119
     * @return ContainerInterface Chaining
120
     */
121 3
    public function service($className, array $parameters = [], string $alias = null) : ContainerInterface
122
    {
123 3
        $this->services[$className] = $className;
124
125 3
        return $this->set($className, $parameters, $alias);
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 3
    public function set($className, array $dependencies = [], string $alias = null) : ContainerInterface
132
    {
133
        // Create dependencies collection for class name
134 3
        if (!array_key_exists($className, $this->dependencies)) {
135 3
            $this->dependencies[$className] = [];
136
        }
137
        
138
        // Merge other class constructor parameters
139 3
        $this->dependencies[$className] = array_merge($this->dependencies[$className], $dependencies);
140
141
        // Store alias for this class name
142 3
        $this->aliases[$className] = $alias;
143
144 3
        return $this;
145
    }
146
}
147