Completed
Push — master ( 650578...a5f802 )
by Vitaly
05:15
created

Container::service()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 1
nc 1
nop 3
crap 2
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\ClassNotFoundException;
9
use samsonframework\di\exception\ContainerException;
10
use samsonframework\di\exception\NotFoundException;
11
12
//TODO: caching
13
//TODO: Interface & abstract class resolving
14
//TODO: Other parameter types(not hintable) resolving
15
//TODO: Lazy creation by default
16
17
/**
18
 * Class Container
19
 * @package samsonframework\di
20
 */
21
class Container implements ContainerInterface
22
{
23
    /** @var array[string] Collection of loaded services */
24
    protected $services = array();
25
26
    /** @var array[string] Collection of alias => class name for alias resolving*/
27
    protected $aliases = array();
28
29
    /** @var array[string] Collection of class name dependencies trees */
30
    protected $dependencies = array();
31
32
    /**
33
     * Get reflection paramater class name type hint if present without
34
     * autoloading and throwing exceptions.
35
     *
36
     * @param \ReflectionParameter $param Parameter for parsing
37
     *
38
     * @return string|null Class name typehint or null
39
     */
40 1
    protected function getClassName(\ReflectionParameter $param)
41
    {
42 1
        preg_match('/\[\s\<\w+?>\s(?<class>[\w\\\\]+)/', (string)$param, $matches);
43 1
        return array_key_exists('class', $matches) && $matches['class'] !== 'array'
44 1
            ? '\\' . ltrim($matches[1], '\\')
45 1
            : null;
46
    }
47
48
    /**
49
     * Recursively build class constructor dependencies tree.
50
     * TODO: Analyze recurrent dependencies and throw an exception
51
     *
52
     * @param string $className    Current class name for analyzing
53
     * @param array  $dependencies Reference to tree for filling up
54
     *
55
     * @return array [string] Multidimensional array as dependency tree
56
     * @throws ClassNotFoundException
57
     */
58 1
    protected function buildDependenciesTree($className, array &$dependencies)
59
    {
60
        // We need this class to exists to use reflections, it will try to autoload it also
61 1
        if (class_exists($className)) {
62 1
            $class = new \ReflectionClass($className);
63
            // We can build dependency tree only from constructor dependencies
64 1
            $constructor = $class->getConstructor();
65 1
            if (null !== $constructor) {
66
                // Iterate all dependencies
67 1
                foreach ($constructor->getParameters() as $parameter) {
68
                    // Ignore optional parameters
69 1
                    if (!$parameter->isOptional()) {
70
                        // Read dependency class name
71 1
                        $dependencyClass = $this->getClassName($parameter);
72
73
                        // If we have found dependency class
74 1
                        if ($dependencyClass !== null) {
75
                            // Point dependency class name
76 1
                            $dependencies[$className][$parameter->getName()] = $dependencyClass;
77
                            // Go deeper in recursion and pass new branch there
78 1
                            $this->buildDependenciesTree($dependencyClass, $dependencies);
79 1
                        } else { // Set null parameter value
80 1
                            $dependencies[$className][$parameter->getName()] = null;
81
                        }
82
83 1
                    } else { // Stop iterating as first optional parameter is met
84 1
                        break;
85
                    }
86 1
                }
87 1
            }
88 1
        } else { // Something went wrong and class is not auto loaded and missing
89
            throw new ClassNotFoundException($className);
90
        }
91
92 1
        return $dependencies;
93
    }
94
95
    /**
96
     * Finds an entry of the container by its identifier and returns it.
97
     *
98
     * @param string $alias Identifier of the entry to look for.
99
     *
100
     * @throws NotFoundException  No entry was found for this identifier.
101
     * @throws ContainerException Error while retrieving the entry.
102
     *
103
     * @return mixed Entry.
104
     */
105
    public function get($alias)
106
    {
107
        // Set pointer to module
108
        $module = &$this->services[$alias];
109
110
        if (null === $module) {
111
            throw new NotFoundException($alias);
112
        } else {
113
            if (!is_object($module)) {
114
                throw new ContainerException($alias);
115
            } else {
116
                return $module;
117
            }
118
        }
119
    }
120
121
    /**
122
     * Returns true if the container can return an entry for the given identifier.
123
     * Returns false otherwise.
124
     *
125
     * @param string $alias Identifier of the entry to look for.
126
     *
127
     * @return boolean
128
     */
129
    public function has($alias)
130
    {
131
        return array_key_exists($alias, $this->services)
132
        || array_key_exists($alias, $this->aliases);
133
    }
134
135
    /**
136
     * Set dependency alias with callback function.
137
     *
138
     * @param callable $callable Callable to return dependency
139
     * @param string   $alias    Dependency name
140
     *
141
     * @return self Chaining
142
     */
143
    public function callback($callable, $alias = null)
144
    {
145
        // TODO: Implement callback() method.
146
    }
147
148
    /**
149
     * Set service dependency. Upon first creation of this class instance
150
     * it would be used everywhere where this dependency is needed.
151
     *
152
     * @param string $className  Fully qualified class name
153
     * @param string $alias      Dependency name
154
     * @param array  $parameters Collection of parameters needed for dependency creation
155
     *
156
     * @return self Chaining
157
     */
158
    public function service($className, $alias = null, array $parameters = array())
159
    {
160
        // TODO: Implement service() method.
161
    }
162
163
    /**
164
     * Set service dependency by passing object instance.
165
     *
166
     * @param mixed  $instance   Instance that needs to be return by this dependency
167
     * @param string $alias      Dependency name
168
     * @param array  $parameters Collection of parameters needed for dependency creation
169
     *
170
     * @return self Chaining
171
     */
172
    public function instance(&$instance, $alias = null, array $parameters = array())
173
    {
174
175
        // TODO: Implement instance() method.
176
    }
177
178
    /**
179
     * Set dependency.
180
     *
181
     * @param string $className  Fully qualified class name
182
     * @param string $alias      Dependency name
183
     * @param array  $parameters Collection of parameters needed for dependency creation
184
     *
185
     * @return ContainerInterface Chaining
186
     */
187 1
    public function set($className, $alias = null, array $parameters = array())
188
    {
189
        // Add this class dependencies to dependency tree
190 1
        $this->dependencies = array_merge(
191 1
            $this->dependencies,
192 1
            $this->buildDependenciesTree($className, $this->dependencies)
193 1
        );
194
195
        // Merge other class constructor parameters
196 1
        $this->dependencies[$className] = array_merge($this->dependencies[$className], $parameters);
197
198
        // Store alias for this class name
199 1
        $this->aliases[$alias] = $className;
200
201 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...
202 1
    }
203
}
204