Completed
Branch EDTR/master (6bd139)
by
unknown
35:03 queued 26:41
created

DependencyResolver::initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
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   4.9.71.p
22
 */
23
class DependencyResolver implements DependencyResolverInterface
24
{
25
26
    /**
27
     * @var Mirror $mirror
28
     */
29
    private $mirror;
30
31
    /**
32
     * @var ClassInterfaceCache $class_cache
33
     */
34
    protected $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
    /**
72
     * Used to configure and/or setup any aliases or namespace roots required by the DependencyResolver
73
     *
74
     * @throws InvalidAliasException
75
     * @since 4.9.71.p
76
     */
77
    public function initialize()
78
    {
79
        // nothing to do here for default resolver
80
    }
81
82
83
    /**
84
     * @return Mirror
85
     */
86
    public function mirror()
87
    {
88
        return $this->mirror;
89
    }
90
91
    /**
92
     * @return ClassInterfaceCache
93
     */
94
    public function classCache()
95
    {
96
        return $this->class_cache;
97
    }
98
99
    /**
100
     * @return EE_Dependency_Map
101
     */
102
    public function dependencyMap()
103
    {
104
        return $this->dependency_map;
105
    }
106
107
    /**
108
     * @param string $fqcn      the class name that should be used (concrete class to replace interface)
109
     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
110
     * @param string $for_class the class that has the dependency (is type hinting for the interface)
111
     * @throws InvalidAliasException
112
     */
113
    public function addAlias($fqcn, $alias, $for_class = '')
114
    {
115
        $this->class_cache->addAlias($fqcn, $alias, $for_class);
116
    }
117
118
    /**
119
     * @param string $param_fqcn Fully Qualified Class Name for dependency parameter
120
     * @return string
121
     */
122
    public function resolveAlias($param_fqcn)
123
    {
124
        return $this->class_cache->getFqnForAlias($param_fqcn);
125
    }
126
127
    /**
128
     * Primarily used to indicate the namespace root for composite objects
129
     * so that dependencies requiring the same DependencyResolver can be acquired
130
     * for example:
131
     * Vendor\path\to\class\A, Vendor\path\to\class\B, and Vendor\path\to\class\C
132
     * may all implement Vendor\path\to\Interface,
133
     * but Vendor\path\to\class\C could be a composite object
134
     * that requires Vendor\path\to\class\A and Vendor\path\to\class\B,
135
     * and needs both of those dependencies resolved, which would therefore require
136
     * the use of the same DependencyResolver.
137
     *
138
     * By specifying a namespace root of "Vendor\path\to\",
139
     * then all classes that are descendants of that namespace
140
     * will use DependencyResolver to acquire the classes they need
141
     *
142
     * @param string $namespace_root Partial namespace used for detecting other classes
143
     *                               that should employ this same DependencyResolver
144
     */
145
    public function addNamespaceRoot($namespace_root)
146
    {
147
        $this->namespace_roots[] = $namespace_root;
148
    }
149
150
    /**
151
     * Returns true if the parameter FQCN belongs to one of
152
     * the namespaces that utilizes this DependencyResolver
153
     *
154
     * @param string $param_fqcn Fully Qualified Class Name for dependency parameter
155
     * @return boolean
156
     * @since 4.9.71.p
157
     */
158
    public function dependencyRecursionExists($param_fqcn)
159
    {
160
        foreach ($this->namespace_roots as $namespace_root) {
161
            if (strpos($param_fqcn, $namespace_root) !== false) {
162
                return true;
163
            }
164
        }
165
        return false;
166
    }
167
168
169
    /**
170
     * @param string $fqcn Fully Qualified Class Name
171
     * @throws InvalidDataTypeException
172
     * @throws ReflectionException
173
     * @since 4.9.71.p
174
     */
175
    public function resolveDependenciesForClass($fqcn)
176
    {
177
        $dependencies = array();
178
        $params = $this->mirror()->getParameters($fqcn);
179
        foreach ($params as $index => $param) {
180
            // is this a dependency for a specific class ?
181
            $param_class = $this->mirror()->getParameterClassName($param, $fqcn, $index);
182
            if ($this->dependencyRecursionExists($param_class)) {
183
                $this->resolveDependenciesForClass($param_class);
184
            }
185
            $param_class = $this->resolveAlias($param_class);
186
            $dependencies[ $param_class ] = EE_Dependency_Map::load_from_cache;
187
        }
188
        $this->dependencyMap()->registerDependencies($fqcn, $dependencies);
189
    }
190
}
191