Completed
Push — master ( b6f60c...515c2c )
by Vitaly
08:02 queued 03:16
created

Container::buildDependenciesTree()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 35
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 35
ccs 21
cts 21
cp 1
rs 8.439
cc 6
eloc 16
nc 4
nop 2
crap 6
1
<?php
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 22.01.16 at 23:53
5
 */
6
namespace samsonframework\di;
7
8
use samsonframework\di\exception\ContainerException;
9
use samsonframework\di\exception\NotFoundException;
10
11
//TODO: caching
12
//TODO: Interface & abstract class resolving
13
//TODO: Other parameter types(not hintable) resolving
14
//TODO: Lazy creation by default
15
16
/**
17
 * Class Container
18
 * @package samsonframework\di
19
 */
20
class Container implements ContainerInterface
21
{
22
    /** @var array[string] Collection of loaded services */
23
    protected $services = array();
24
25
    /** @var array[string] Collection of alias => class name for alias resolving*/
26
    protected $aliases = array();
27
28
    /** @var array[string] Collection of class name dependencies trees */
29
    protected $dependencies = array();
30
31
    /**
32
     * Get reflection paramater class name type hint if present without
33
     * autoloading and throwing exceptions.
34
     *
35
     * @param \ReflectionParameter $param Parameter for parsing
36
     *
37
     * @return string|null Class name typehint or null
38
     */
39 1
    protected function getClassName(\ReflectionParameter $param) {
40 1
        preg_match('/\[\s\<\w+?>\s([\w\\\\]+)/s', $param->__toString(), $matches);
41 1
        return isset($matches[1]) ? '\\' . ltrim($matches[1], '\\') : null;
42
    }
43
44
    /**
45
     * Recursively build class constructor dependencies tree.
46
     *
47
     * @param string $className Current class name for analyzing
48
     * @param array  $dependencies Reference to tree for filling up
49
     *
50
     * @return array[string] Multidimensional array as dependency tree
0 ignored issues
show
Documentation introduced by
The doc-type array[string] could not be parsed: Expected "]" at position 2, but found "string". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
51
     */
52 1
    protected function buildDependenciesTree($className, array &$dependencies = array())
53
    {
54
        // We need this class to exists to use reflections
55 1
        if (class_exists($className)) {
56 1
            $class = new \ReflectionClass($className);
57
            // We can build dependency tree only from constructor dependencies
58 1
            $constructor = $class->getConstructor();
59 1
            if (null !== $constructor) {
60
                // Iterate all dependencies
61 1
                foreach ($constructor->getParameters() as $parameter) {
62
                    // Ignore optional parameters
63 1
                    if (!$parameter->isOptional()) {
64
                        // Read dependency class name
65 1
                        $dependencyClass = $this->getClassName($parameter);
66
67
                        // If we have found dependency class
68 1
                        if ($dependencyClass !== null) {
69
                            // Store new inner dependency branch
70 1
                            $dependencies[$className][$parameter->getName()] = array($dependencyClass => array());
71
                            // Go deeper in recursion and pass new branch there
72 1
                            $this->buildDependenciesTree(
73 1
                                $dependencyClass,
74 1
                                $dependencies[$className][$parameter->getName()]
75 1
                            );
76 1
                        }
77
78 1
                    } else { // Stop iterating as first optional parameter is met
79 1
                        break;
80
                    }
81 1
                }
82 1
            }
83 1
        }
84
85 1
        return $dependencies;
86
    }
87
88
    /**
89
     * Finds an entry of the container by its identifier and returns it.
90
     *
91
     * @param string $id Identifier of the entry to look for.
92
     *
93
     * @throws NotFoundException  No entry was found for this identifier.
94
     * @throws ContainerException Error while retrieving the entry.
95
     *
96
     * @return mixed Entry.
97
     */
98
    public function get($id)
99
    {
100
        // Set pointer to module
101
        $module = &$this->services[$id];
102
103
        if (null === $module) {
104
            throw new NotFoundException($id);
105
        } else {
106
            if (!is_object($module)) {
107
                throw new ContainerException($id);
108
            } else {
109
                return $module;
110
            }
111
        }
112
    }
113
114
    /**
115
     * Returns true if the container can return an entry for the given identifier.
116
     * Returns false otherwise.
117
     *
118
     * @param string $id Identifier of the entry to look for.
119
     *
120
     * @return boolean
121
     */
122
    public function has($id)
123
    {
124
        return isset($this->services[$id]) || isset($this->aliases[$id]);
125
    }
126
127
    /**
128
     * Set dependency alias with callback function.
129
     *
130
     * @param callable $callable Callable to return dependency
131
     * @param string   $alias    Dependency name
132
     *
133
     * @return self Chaining
134
     */
135
    public function callback($callable, $alias = null)
136
    {
137
        // TODO: Implement callback() method.
138
    }
139
140
    /**
141
     * Set service dependency. Upon first creation of this class instance
142
     * it would be used everywhere where this dependency is needed.
143
     *
144
     * @param string $className  Fully qualified class name
145
     * @param string $alias      Dependency name
146
     * @param array  $parameters Collection of parameters needed for dependency creation
147
     *
148
     * @return self Chaining
149
     */
150
    public function service($className, $alias = null, array $parameters = array())
151
    {
152
        // TODO: Implement service() method.
153
    }
154
155
    /**
156
     * Set service dependency by passing object instance.
157
     *
158
     * @param mixed  $instance   Instance that needs to be return by this dependency
159
     * @param string $alias      Dependency name
160
     * @param array  $parameters Collection of parameters needed for dependency creation
161
     *
162
     * @return self Chaining
163
     */
164
    public function instance(&$instance, $alias = null, array $parameters = array())
165
    {
166
167
        // TODO: Implement instance() method.
168
    }
169
170
    /**
171
     * Set dependency.
172
     *
173
     * @param string $className  Fully qualified class name
174
     * @param string $alias      Dependency name
175
     * @param array  $parameters Collection of parameters needed for dependency creation
176
     *
177
     * @return ContainerInterface Chaining
178
     */
179 1
    public function set($className, $alias = null, array $parameters = array())
180
    {
181
        // Add this class dependencies to dependency tree
182 1
        $this->dependencies = array_merge(
183 1
            $this->dependencies,
184 1
            $this->buildDependenciesTree($className, $this->dependencies)
185 1
        );
186
187
        // Merge other class constructor parameters
188 1
        $this->dependencies[$className] = array_merge($this->dependencies[$className], $parameters);
189
190 1
        var_dump($this->dependencies);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($this->dependencies); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
191 1
    }
192
}
193