Completed
Branch BUG/reg-status-change-recursio... (2db0c9)
by
unknown
20:03 queued 10:32
created

DependencyResolver   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 155
rs 10
c 0
b 0
f 0
wmc 14
lcom 1
cbo 4

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A mirror() 0 4 1
A classCache() 0 4 1
A dependencyMap() 0 4 1
A addAlias() 0 4 1
A resolveAlias() 0 6 2
A dependencyRecursionExists() 0 9 3
A resolveDependenciesForClass() 0 15 3
A addNamespaceRoot() 0 4 1
1
<?php
2
3
namespace EventEspresso\core\services\dependencies;
4
5
use EE_Dependency_Map;
6
use EventEspresso\core\exceptions\InvalidAliasException;
7
use EventEspresso\core\exceptions\InvalidDataTypeException;
8
use EventEspresso\core\services\container\Mirror;
9
use EventEspresso\core\services\loaders\ClassInterfaceCache;
10
use ReflectionException;
11
12
/**
13
 * Class DependencyResolver
14
 * Multiple classes that share the same common dependencies can have their dependencies
15
 * automatically resolved using a DependencyResolver, and do not need to be registered by calling
16
 * EE_Dependency_Map::registerDependencies() or manually adding an entry in the dependency map.
17
 * Classes with more complex or unique dependencies should register them normally.
18
 *
19
 * @package EventEspresso\core\services\container
20
 * @author  Brent Christensen
21
 * @since   $VID:$
22
 */
23
abstract class DependencyResolver implements DependencyResolverInterface
24
{
25
26
    /**
27
     * @var Mirror $mirror
28
     */
29
    private $mirror;
30
31
    /**
32
     * @var ClassInterfaceCache $class_cache
33
     */
34
    private $class_cache;
35
36
    /**
37
     * @var EE_Dependency_Map $dependency_map
38
     */
39
    private $dependency_map;
40
41
    /**
42
     * @var ClassAlias[] $aliases
43
     */
44
    protected $aliases = array();
45
46
    /**
47
     * @var array $namespace_roots
48
     */
49
    protected $namespace_roots = array();
50
51
52
    /**
53
     * RouteMatchSpecificationDependencyResolver constructor.
54
     *
55
     * @param Mirror              $mirror
56
     * @param ClassInterfaceCache $class_cache
57
     * @param EE_Dependency_Map   $dependency_map
58
     */
59
    public function __construct(
60
        Mirror $mirror,
61
        ClassInterfaceCache $class_cache,
62
        EE_Dependency_Map $dependency_map
63
    ) {
64
        $this->mirror = $mirror;
65
        $this->class_cache = $class_cache;
66
        $this->dependency_map = $dependency_map;
67
        $this->initialize();
68
    }
69
70
    /**
71
     * @return Mirror
72
     */
73
    public function mirror()
74
    {
75
        return $this->mirror;
76
    }
77
78
    /**
79
     * @return ClassInterfaceCache
80
     */
81
    public function classCache()
82
    {
83
        return $this->class_cache;
84
    }
85
86
    /**
87
     * @return EE_Dependency_Map
88
     */
89
    public function dependencyMap()
90
    {
91
        return $this->dependency_map;
92
    }
93
94
    /**
95
     * @param ClassAlias $alias
96
     * @throws InvalidAliasException
97
     */
98
    public function addAlias(ClassAlias $alias)
99
    {
100
        $this->aliases[ $alias->alias() ] = $alias;
101
    }
102
103
    /**
104
     * @param string $param_fqcn Fully Qualified Class Name for dependency parameter
105
     * @return string
106
     */
107
    public function resolveAlias($param_fqcn)
108
    {
109
        return isset($this->aliases[ $param_fqcn ])
110
            ? $this->aliases[ $param_fqcn ]->fqcn()
111
            : $this->classCache()->getFqnForAlias($param_fqcn);
112
    }
113
114
    /**
115
     * Primarily used to indicate the namespace root for composite objects
116
     * so that dependencies requiring the same DependencyResolver can be acquired
117
     * for example:
118
     * Vendor\path\to\class\A, Vendor\path\to\class\B, and Vendor\path\to\class\C
119
     * may all implement Vendor\path\to\Interface,
120
     * but Vendor\path\to\class\C could be a composite object
121
     * that requires Vendor\path\to\class\A and Vendor\path\to\class\B,
122
     * and needs both of those dependencies resolved, which would therefore require
123
     * the use of the same DependencyResolver.
124
     *
125
     * By specifying a namespace root of "Vendor\path\to\",
126
     * then all classes that are descendants of that namespace
127
     * will use DependencyResolver to acquire the classes they need
128
     *
129
     * @param string $namespace_root Partial namespace used for detecting other classes
130
     *                               that should employ this same DependencyResolver
131
     */
132
    public function addNamespaceRoot($namespace_root)
133
    {
134
        $this->namespace_roots[] = $namespace_root;
135
    }
136
137
    /**
138
     * Returns true if the parameter FQCN belongs to one of
139
     * the namespaces that utilizes this DependencyResolver
140
     *
141
     * @param string $param_fqcn Fully Qualified Class Name for dependency parameter
142
     * @return boolean
143
     * @since $VID:$
144
     */
145
    public function dependencyRecursionExists($param_fqcn)
146
    {
147
        foreach ($this->namespace_roots as $namespace_root) {
148
            if (strpos($param_fqcn, $namespace_root) !== false) {
149
                return true;
150
            }
151
        }
152
        return false;
153
    }
154
155
156
    /**
157
     * @param string $fqcn Fully Qualified Class Name
158
     * @throws InvalidDataTypeException
159
     * @throws ReflectionException
160
     * @since $VID:$
161
     */
162
    public function resolveDependenciesForClass($fqcn)
163
    {
164
        $dependencies = array();
165
        $params = $this->mirror()->getParameters($fqcn);
166
        foreach ($params as $index => $param) {
167
            // is this a dependency for a specific class ?
168
            $param_class = $this->mirror()->getParameterClassName($param, $fqcn, $index);
169
            if ($this->dependencyRecursionExists($param_class)) {
170
                $this->resolveDependenciesForClass($param_class);
171
            }
172
            $param_class = $this->resolveAlias($param_class);
173
            $dependencies[ $param_class ] = EE_Dependency_Map::load_from_cache;
174
        }
175
        $this->dependencyMap()->registerDependencies($fqcn, $dependencies);
176
    }
177
}
178