Completed
Branch FET/asset-manager (018c4e)
by
unknown
87:46 queued 74:14
created

ClassInterfaceCache::getInterfaces()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 1
dl 0
loc 15
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\services\loaders;
4
5
use EventEspresso\core\domain\values\FullyQualifiedName;
6
7
defined('EVENT_ESPRESSO_VERSION') || exit;
8
9
10
11
/**
12
 * Class ClassInterfaceCache
13
 * Tracks and caches the interfaces and their aliases implemented by classes
14
 * so that we are not continuously and/or repeatedly looking up that information
15
 *
16
 * @package EventEspresso\core\services\loaders
17
 * @author  Brent Christensen
18
 * @since   $VID:$
19
 */
20
class ClassInterfaceCache
21
{
22
23
    /**
24
     * array of interfaces indexed by FQCNs where values are arrays of interface FQNs
25
     *
26
     * @var string[][] $interfaces
27
     */
28
    private $interfaces = array();
29
30
    /**
31
     * @type string[][] $aliases
32
     */
33
    protected $aliases = array();
34
35
36
    /**
37
     * @param string $fqn
38
     * @return string
39
     */
40
    public function getFqn($fqn)
41
    {
42
        return $fqn instanceof FullyQualifiedName ? $fqn->string() : $fqn;
43
    }
44
45
46
    /**
47
     * @param string $fqn
48
     * @return array
49
     */
50
    public function getInterfaces($fqn)
51
    {
52
        $fqn = $this->getFqn($fqn);
53
        // have we already seen this FQCN ?
54
        if (! array_key_exists($fqn, $this->interfaces)) {
55
            $this->interfaces[ $fqn ] = array();
56
            if (class_exists($fqn)) {
57
                $this->interfaces[ $fqn ] = class_implements($fqn, false);
58
                $this->interfaces[ $fqn ] = $this->interfaces[ $fqn ] !== false
59
                    ? $this->interfaces[ $fqn ]
60
                    : array();
61
            }
62
        }
63
        return $this->interfaces[ $fqn ];
64
    }
65
66
67
    /**
68
     * @param string $fqn
69
     * @param string $interface
70
     * @return bool
71
     */
72
    public function hasInterface($fqn, $interface)
73
    {
74
        $fqn        = $this->getFqn($fqn);
75
        $interfaces = $this->getInterfaces($fqn);
76
        return in_array($interface, $interfaces, true);
77
    }
78
79
80
    /**
81
     * adds an alias for a classname
82
     *
83
     * @param string $fqn       the class name that should be used (concrete class to replace interface)
84
     * @param string $alias     the class name that would be type hinted for (abstract parent or interface)
85
     * @param string $for_class the class that has the dependency (is type hinting for the interface)
86
     */
87
    public function addAlias($fqn, $alias, $for_class = '')
88
    {
89
        $fqn   = $this->getFqn($fqn);
90
        $alias = $this->getFqn($alias);
91
        // are we adding an alias for a specific class?
92
        if ($for_class !== '') {
93
            // make sure it's set up as an array
94
            if (! isset($this->aliases[ $for_class ])) {
95
                $this->aliases[ $for_class ] = array();
96
            }
97
            $this->aliases[ $for_class ][ $alias ] = $fqn;
98
            return;
99
        }
100
        $this->aliases[ $alias ] = $fqn;
101
    }
102
103
104
    /**
105
     * returns TRUE if the provided FQN is an alias
106
     *
107
     * @param string $fqn
108
     * @param string $for_class
109
     * @return bool
110
     */
111
    public function isAlias($fqn = '', $for_class = '')
112
    {
113
        $fqn = $this->getFqn($fqn);
114
        if ($this->isAliasForClass($fqn, $for_class)) {
115
            return true;
116
        }
117
        if ($for_class === '' && $this->isDirectAlias($fqn)) {
118
            return true;
119
        }
120
        return false;
121
    }
122
123
124
    /**
125
     * returns TRUE if the provided FQN is an alias
126
     *
127
     * @param string $fqn
128
     * @return bool
129
     */
130
    protected function isDirectAlias($fqn = '')
131
    {
132
        return isset($this->aliases[ (string) $fqn ]) && ! is_array($this->aliases[ (string) $fqn ]);
133
    }
134
135
136
    /**
137
     * returns TRUE if the provided FQN is an alias for the specified class
138
     *
139
     * @param string $fqn
140
     * @param string $for_class
141
     * @return bool
142
     */
143
    protected function isAliasForClass($fqn = '', $for_class = '')
144
    {
145
        return (
146
            $for_class !== ''
147
            && isset($this->aliases[ (string) $for_class ][ (string) $fqn ])
148
        );
149
    }
150
151
152
    /**
153
     * returns FQN for provided alias if one exists, otherwise returns the original FQN
154
     * functions recursively, so that multiple aliases can be used to drill down to a FQN
155
     *  for example:
156
     *      if the following two entries were added to the aliases array:
157
     *          array(
158
     *              'interface_alias'           => 'some\namespace\interface'
159
     *              'some\namespace\interface'  => 'some\namespace\classname'
160
     *          )
161
     *      then one could use Loader::getNew( 'interface_alias' )
162
     *      to load an instance of 'some\namespace\classname'
163
     *
164
     * @param string $alias
165
     * @param string $for_class
166
     * @return string
167
     */
168
    public function getFqnForAlias($alias = '', $for_class = '')
169
    {
170
        $alias = $this->getFqn($alias);
171
        if ($this->isAliasForClass($alias, $for_class)) {
172
            return $this->getFqnForAlias($this->aliases[ (string) $for_class ][ (string) $alias ], $for_class);
173
        }
174
        if ($this->isDirectAlias($alias)) {
175
            return $this->getFqnForAlias($this->aliases[ (string) $alias ], '');
176
        }
177
        return $alias;
178
    }
179
}
180