Completed
Branch FET/11450/reserved-instance-in... (972752)
by
unknown
55:29 queued 42:15
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
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
     * @var ClassInterfaceCache $class_cache
37
     */
38
    private $class_cache;
39
40
41
    /**
42
     * CachingLoader constructor.
43
     *
44
     * @param LoaderDecoratorInterface $loader
45
     * @param CollectionInterface      $cache
46
     * @param ClassInterfaceCache      $class_cache
47
     * @param string                   $identifier
48
     * @throws InvalidDataTypeException
49
     */
50
    public function __construct(
51
        LoaderDecoratorInterface $loader,
52
        CollectionInterface $cache,
53
        ClassInterfaceCache $class_cache,
54
        $identifier = ''
55
    ) {
56
        parent::__construct($loader);
57
        $this->cache       = $cache;
58
        $this->class_cache = $class_cache;
59
        $this->setIdentifier($identifier);
60
        if ($this->identifier !== '') {
61
            // to only clear this cache, and assuming an identifier has been set, simply do the following:
62
            // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__IDENTIFIER');
63
            // where "IDENTIFIER" = the string that was set during construction
64
            add_action(
65
                "AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__{$identifier}",
66
                array($this, 'reset')
67
            );
68
        }
69
        // to clear ALL caches, simply do the following:
70
        // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache');
71
        add_action(
72
            'AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache',
73
            array($this, 'reset')
74
        );
75
    }
76
77
78
    /**
79
     * @return string
80
     */
81
    public function identifier()
82
    {
83
        return $this->identifier;
84
    }
85
86
87
    /**
88
     * @param string $identifier
89
     * @throws InvalidDataTypeException
90
     */
91
    private function setIdentifier($identifier)
92
    {
93
        if (! is_string($identifier)) {
94
            throw new InvalidDataTypeException('$identifier', $identifier, 'string');
95
        }
96
        $this->identifier = $identifier;
97
    }
98
99
100
    /**
101
     * @param FullyQualifiedName|string $fqcn
102
     * @param mixed                     $object
103
     * @return bool
104
     * @throws InvalidArgumentException
105
     */
106
    public function share($fqcn, $object)
107
    {
108
        if ($object instanceof $fqcn) {
109
            return $this->cache->add($object, md5($fqcn));
110
        }
111
        throw new InvalidArgumentException(
112
            sprintf(
113
                esc_html__(
114
                    'The supplied class name "%1$s" must match the class of the supplied object.',
115
                    'event_espresso'
116
                ),
117
                $fqcn
118
            )
119
        );
120
    }
121
122
123
    /**
124
     * @param FullyQualifiedName|string $fqcn
125
     * @param array                     $arguments
126
     * @param bool                      $shared
127
     * @param array                     $interfaces
128
     * @return mixed
129
     */
130
    public function load($fqcn, $arguments = array(), $shared = true, array $interfaces = array())
131
    {
132
        $fqcn = ltrim($fqcn, '\\');
133
        // caching can be turned off via the following code:
134
        // add_filter('FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', '__return_true');
135
        if (
136
            apply_filters(
137
                'FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache',
138
                false,
139
                $this
140
            )
141
        ) {
142
            // even though $shared might be true, caching could be bypassed for whatever reason,
143
            // so we don't want the core loader to cache anything, therefore caching is turned off
144
            return $this->loader->load($fqcn, $arguments, false);
145
        }
146
        $identifier = $this->getClassIdentifier($fqcn, $arguments);
147
        if ($this->cache->has($identifier)) {
148
            return $this->cache->get($identifier);
149
        }
150
        $object = $this->loader->load($fqcn, $arguments, $shared);
151
        if ($object instanceof $fqcn) {
152
            $this->cache->add($object, $identifier);
153
        }
154
        return $object;
155
    }
156
157
158
    /**
159
     * empties cache and calls reset() on loader if method exists
160
     */
161
    public function reset()
162
    {
163
        $this->cache->trashAndDetachAll();
164
        $this->loader->reset();
165
    }
166
167
168
    /**
169
     * build a string representation of a class' name and arguments
170
     *
171
     * @param string $fqcn
172
     * @param array  $arguments
173
     * @return string
174
     */
175
    private function getClassIdentifier($fqcn, array $arguments = array())
176
    {
177
        // only build identifier from arguments if class is not ReservedInstanceInterface
178
        $identifier = ! $this->class_cache->hasInterface($fqcn,
179
            'EventEspresso\core\interfaces\ReservedInstanceInterface')
180
            ? $this->getIdentifierForArguments($arguments)
181
            : '';
182
        if (! empty($identifier)) {
183
            $fqcn .= '____' . md5($identifier);
184
        }
185
        return $fqcn;
186
    }
187
188
189
    /**
190
     * build a string representation of a class' arguments
191
     * (mostly because Closures can't be serialized)
192
     *
193
     * @param array $arguments
194
     * @return string
195
     */
196
    protected function getIdentifierForArguments(array $arguments)
197
    {
198
        if (empty($arguments)) {
199
            return '';
200
        }
201
        $identifier = '';
202 View Code Duplication
        foreach ($arguments as $argument) {
203
            switch (true) {
204
                case is_object($argument) :
205
                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...
206
                    $identifier .= spl_object_hash($argument);
207
                    break;
208
                case is_array($argument) :
209
                    $identifier .= $this->getIdentifierForArguments($argument);
210
                    break;
211
                default :
212
                    $identifier .= $argument;
213
                    break;
214
            }
215
        }
216
        return $identifier;
217
    }
218
}
219
// End of file CachingLoader.php
220
// Location: EventEspresso\core\services\loaders/CachingLoader.php
221