Completed
Branch FET/11450/caching-unit-tests (fd4ae9)
by
unknown
51:38 queued 38:35
created

CachingLoader::getIdentifierForArguments()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 22
Code Lines 17

Duplication

Lines 14
Ratio 63.64 %

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 6
nop 1
dl 14
loc 22
rs 8.6737
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\services\loaders;
4
5
use Closure;
6
use EventEspresso\core\exceptions\InvalidDataTypeException;
7
use EventEspresso\core\services\collections\CollectionInterface;
8
use InvalidArgumentException;
9
10
defined('EVENT_ESPRESSO_VERSION') || exit;
11
12
13
14
/**
15
 * Class CachingLoader
16
 * caches objects returned by the decorated loader
17
 *
18
 * @package       Event Espresso
19
 * @author        Brent Christensen
20
 * 
21
 */
22
class CachingLoader extends CachingLoaderDecorator
23
{
24
25
    /**
26
     * @var CollectionInterface $cache
27
     */
28
    protected $cache;
29
30
    /**
31
     * @var string $identifier
32
     */
33
    protected $identifier;
34
35
36
37
    /**
38
     * CachingLoader constructor.
39
     *
40
     * @param LoaderDecoratorInterface $loader
41
     * @param CollectionInterface      $cache
42
     * @param string                   $identifier
43
     * @throws InvalidDataTypeException
44
     */
45
    public function __construct(
46
        LoaderDecoratorInterface $loader,
47
        CollectionInterface $cache,
48
        $identifier = ''
49
    ) {
50
        parent::__construct($loader);
51
        $this->cache = $cache;
52
        $this->setIdentifier($identifier);
53
        if ($this->identifier !== '') {
54
            // to only clear this cache, and assuming an identifier has been set, simply do the following:
55
            // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__IDENTIFIER');
56
            // where "IDENTIFIER" = the string that was set during construction
57
            add_action(
58
                "AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__{$identifier}",
59
                array($this, 'reset')
60
            );
61
        }
62
        // to clear ALL caches, simply do the following:
63
        // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache');
64
        add_action(
65
            'AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache',
66
            array($this, 'reset')
67
        );
68
    }
69
70
71
72
    /**
73
     * @return string
74
     */
75
    public function identifier()
76
    {
77
        return $this->identifier;
78
    }
79
80
81
82
    /**
83
     * @param string $identifier
84
     * @throws InvalidDataTypeException
85
     */
86
    private function setIdentifier($identifier)
87
    {
88
        if (! is_string($identifier)) {
89
            throw new InvalidDataTypeException('$identifier', $identifier, 'string');
90
        }
91
        $this->identifier = $identifier;
92
    }
93
94
95
    /**
96
     * @param string $fqcn
97
     * @param mixed  $object
98
     * @return bool
99
     * @throws InvalidArgumentException
100
     */
101
    public function share($fqcn, $object)
102
    {
103
        if ($object instanceof $fqcn) {
104
            return $this->cache->add($object, md5($fqcn));
105
        }
106
        throw new InvalidArgumentException(
107
            sprintf(
108
                esc_html__(
109
                    'The supplied class name "%1$s" must match the class of the supplied object.',
110
                    'event_espresso'
111
                ),
112
                $fqcn
113
            )
114
        );
115
    }
116
117
118
    /**
119
     * @param string $fqcn
120
     * @param array  $arguments
121
     * @param bool   $shared
122
     * @return mixed
123
     */
124
    public function load($fqcn, $arguments = array(), $shared = true)
125
    {
126
        $fqcn = ltrim($fqcn, '\\');
127
        // caching can be turned off via the following code:
128
        // add_filter('FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', '__return_true');
129
        if(
130
            apply_filters(
131
                'FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache',
132
                false,
133
                $this
134
            )
135
        ){
136
            // even though $shared might be true, caching could be bypassed for whatever reason,
137
            // so we don't want the core loader to cache anything, therefore caching is turned off
138
            return $this->loader->load($fqcn, $arguments, false);
139
        }
140
        $identifier = $this->getClassIdentifier($fqcn, $arguments);
141
        if ($this->cache->has($identifier)) {
142
            return $this->cache->get($identifier);
143
        }
144
        $object = $this->loader->load($fqcn, $arguments, $shared);
145
        if ($object instanceof $fqcn) {
146
            $this->cache->add($object, $identifier);
147
        }
148
        return $object;
149
    }
150
151
152
153
    /**
154
     * empties cache and calls reset() on loader if method exists
155
     */
156
    public function reset()
157
    {
158
        $this->cache->trashAndDetachAll();
159
        $this->loader->reset();
160
    }
161
    /**
162
     * build a string representation of a class' name and arguments
163
     *
164
     * @param string $fqcn
165
     * @param array $arguments
166
     * @return string
167
     */
168
    private function getClassIdentifier($fqcn, $arguments = array())
169
    {
170
        $identifier = $this->getIdentifierForArguments($arguments);
171
        if(!empty($identifier)) {
172
            $fqcn .= '||' . md5($identifier);
173
        }
174
        return $fqcn;
175
    }
176
177
178
    /**
179
     * build a string representation of a class' arguments
180
     * (mostly because Closures can't be serialized)
181
     *
182
     * @param array $arguments
183
     * @return string
184
     */
185
    private function getIdentifierForArguments(array $arguments)
186
    {
187
        if(empty($arguments)){
188
            return '';
189
        }
190
        $identifier = '';
191 View Code Duplication
        foreach ($arguments as $argument) {
192
            switch (true) {
193
                case is_object($argument) :
194
                case $argument instanceof Closure :
0 ignored issues
show
Bug introduced by
The class Closure does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
195
                    $identifier .= spl_object_hash($argument);
196
                    break;
197
                case is_array($argument) :
198
                    $identifier .= $this->getIdentifierForArguments($argument);
199
                    break;
200
                default :
201
                    $identifier .= $argument;
202
                    break;
203
            }
204
        }
205
        return $identifier;
206
    }
207
208
209
}
210
// End of file CachingLoader.php
211
// Location: EventEspresso\core\services\loaders/CachingLoader.php
212