Completed
Branch FET/11450/reserved-instance-in... (cfa977)
by
unknown
69:04 queued 55:58
created

CachingLoader::getCacheIdentifierForArgument()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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