Passed
Push — master ( 7106e3...456ee0 )
by Menno
02:12
created

ManagedCache::created()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Codefocus\ManagedCache;
4
5
use BadFunctionCallException;
6
use Codefocus\ManagedCache\Events\Event;
7
use Codefocus\ManagedCache\Traits\HandlesEloquentEvents;
8
use Exception;
9
use Illuminate\Cache\MemcachedStore;
10
use Illuminate\Cache\Repository as CacheRepository;
11
use Illuminate\Database\Eloquent\Model;
12
use Illuminate\Foundation\Application;
13
14
/**
15
 * ManagedCache.
16
 *
17
 * @method DefinitionChain setForgetConditions(array $conditions)
18
 */
19
class ManagedCache
20
{
21
    use HandlesEloquentEvents;
22
23
    //  Cache keys.
24
    const TAG_MAP_CACHE_KEY = 'ManagedCache_TagMap';
25
26
    /**
27
     * @var Application
28
     */
29
    protected $application;
30
31
    /**
32
     * @var CacheRepository
33
     */
34
    protected $store;
35
36
    private $isDebugModeEnabled = false;
37
38
    /**
39
     * Maps cache keys to their tags.
40
     *
41
     * @var array
42
     */
43
    protected $tagMap = [];
44
45
    /**
46
     * Constructor.
47
     *
48
     * @param Application $application
49
     */
50
    public function __construct(Application $application)
51
    {
52
        //  Inject Application.
53
        $this->application = $application;
54
        //  Get the configured cache store.
55
        $this->store = $this->application['cache.store'];
56
        if ( ! ($this->store->getStore() instanceof MemcachedStore)) {
57
            throw new Exception('Memcached not configured. Cache store is "' . class_basename($this->store) . '"');
58
        }
59
        //  Register the event listeners.
60
        $this->registerEventListener($this->application['events']);
61
    }
62
63
    public function enableDebugMode()
64
    {
65
        $this->isDebugModeEnabled = true;
66
67
        return $this;
68
    }
69
70
    public function isDebugModeEnabled()
71
    {
72
        return $this->isDebugModeEnabled;
73
    }
74
75
    public function getTagMap(): array
76
    {
77
        if (empty($this->tagMap)) {
78
            $this->tagMap = $this->store->get(self::TAG_MAP_CACHE_KEY, []);
79
            if ( ! is_array($this->tagMap)) {
80
                $this->tagMap = [];
81
            }
82
        }
83
84
        return $this->tagMap;
85
    }
86
87
    public function getTagsForKey(string $key): array
88
    {
89
        $tagMap = $this->getTagMap();
90
        if ( ! isset($tagMap[$key])) {
91
            return [];
92
        }
93
94
        return $tagMap[$key];
95
    }
96
97
    public function setTagsForKey(string $key, array $tags): void
98
    {
99
        $this->getTagMap();
100
        $this->tagMap[$key] = $tags;
101
        $this->store->forever(self::TAG_MAP_CACHE_KEY, $this->tagMap);
102
    }
103
104
    public function deleteTagsForKey(string $key)
105
    {
106
        $this->getTagMap();
107
        if (isset($this->tagMap[$key])) {
108
            unset($this->tagMap[$key]);
109
            $this->store->forever(self::TAG_MAP_CACHE_KEY, $this->tagMap);
110
        }
111
    }
112
113
    /**
114
     * Returns the Cache store instance.
115
     *
116
     * @return CacheRepository
117
     */
118
    public function getStore(): CacheRepository
119
    {
120
        return $this->store;
121
    }
122
123
    /**
124
     * Returns a Condition instance that tags a cache to get invalidated when
125
     * a related Model of the specified class is attached.
126
     *
127
     * @param mixed $model model instance or class name
128
     * @param int|null $modelId (default: null) the Model id, if $model is a class name
129
     * @param mixed|null $relatedModel (default: null) the related Model instance or class name
130
     * @param int|null $relatedModelId (default: null) the related Model id
131
     *
132
     * @return Condition
133
     */
134
    public function relationAttached($model, ?int $modelId = null, $relatedModel = null, ?int $relatedModelId = null): Condition
135
    {
136
        if ($this->isModel($model)) {
137
            $modelClassName = get_class($model);
138
            $modelId = $model->getKey();
139
        } else {
140
            $modelClassName = $model;
141
        }
142
        if ($this->isModel($relatedModel)) {
143
            $relatedModelClassName = get_class($relatedModel);
144
            $relatedModelId = $relatedModel->/* @scrutinizer ignore-call */getKey();
145
        } else {
146
            $relatedModelClassName = $relatedModel;
147
        }
148
149
        return new Condition(
150
            Event::EVENT_ELOQUENT_ATTACHED,
151
            $modelClassName,
152
            $modelId,
153
            $relatedModelClassName,
154
            $relatedModelId
155
        );
156
    }
157
158
    /**
159
     * Returns a Condition instance that tags a cache to get invalidated when
160
     * a related Model of the specified class is detached.
161
     *
162
     * @param mixed $model model instance or class name
163
     * @param int|null $modelId (default: null) the Model id, if $model is a class name
164
     * @param mixed|null $relatedModel (default: null) the related Model instance or class name
165
     * @param int|null $relatedModelId (default: null) the related Model id
166
     *
167
     * @return Condition
168
     */
169
    public function relationDetached($model, ?int $modelId = null, $relatedModel = null, ?int $relatedModelId = null): Condition
170
    {
171
        if ($this->isModel($model)) {
172
            $modelClassName = get_class($model);
173
            $modelId = $model->getKey();
174
        } else {
175
            $modelClassName = $model;
176
        }
177
        if ($this->isModel($relatedModel)) {
178
            $relatedModelClassName = get_class($relatedModel);
179
            $relatedModelId = $relatedModel->/* @scrutinizer ignore-call */getKey();
180
        } else {
181
            $relatedModelClassName = $relatedModel;
182
        }
183
184
        return new Condition(
185
            Event::EVENT_ELOQUENT_DETACHED,
186
            $modelClassName,
187
            $modelId,
188
            $relatedModelClassName,
189
            $relatedModelId
190
        );
191
    }
192
193
    /**
194
     * Returns a Condition instance that tags a cache to get invalidated when
195
     * a related Model of the specified class is updated.
196
     *
197
     * @param mixed $model model instance or class name
198
     * @param int|null $modelId (default: null) the Model id, if $model is a class name
199
     * @param mixed|null $relatedModel (default: null) the related Model instance or class name
200
     * @param int|null $relatedModelId (default: null) the related Model id
201
     *
202
     * @return Condition
203
     */
204
    public function relationUpdated($model, ?int $modelId = null, $relatedModel = null, ?int $relatedModelId = null): Condition
205
    {
206
        if ($this->isModel($model)) {
207
            $modelClassName = get_class($model);
208
            $modelId = $model->getKey();
209
        } else {
210
            $modelClassName = $model;
211
        }
212
        if ($this->isModel($relatedModel)) {
213
            $relatedModelClassName = get_class($relatedModel);
214
            $relatedModelId = $relatedModel->/* @scrutinizer ignore-call */getKey();
215
        } else {
216
            $relatedModelClassName = $relatedModel;
217
        }
218
219
        return new Condition(
220
            Event::EVENT_ELOQUENT_UPDATED,
221
            $modelClassName,
222
            $modelId,
223
            $relatedModelClassName,
224
            $relatedModelId
225
        );
226
    }
227
228
    /**
229
     * Route function calls to a new DefinitionChain.
230
     *
231
     * @param string $name
232
     * @param array $arguments
233
     *
234
     * @throws BadFunctionCallException
235
     */
236
    public function __call(string $name, array $arguments)
237
    {
238
        $definitionChain = new DefinitionChain($this);
239
        if ( ! method_exists($definitionChain, $name)) {
240
            throw new BadFunctionCallException('Function ' . $name . ' does not exist.');
241
        }
242
243
        return call_user_func_array([$definitionChain, $name], $arguments);
244
    }
245
}
246