Issues (209)

src/Foundation/Cache/ModelCache.php (4 issues)

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: arthur
5
 * Date: 11.10.18
6
 * Time: 14:11.
7
 */
8
9
namespace Foundation\Cache;
10
11
use Cache;
12
use Foundation\Exceptions\Exception;
13
use Illuminate\Support\Facades\Redis;
14
15
class ModelCache
16
{
17
    protected $model;
18
19
    protected $cacheTime;
20
21
    /* Unique secondary indexes */
22
    protected $secondaryIndexes;
23
24
    /**
25
     * ModelCache constructor.
26
     */
27 1
    public function __construct(string $model, array $indexes = [], $cacheTime = null)
28
    {
29 1
        $this->model = $model;
30 1
        $this->secondaryIndexes = $indexes;
31 1
        $this->cacheTime = $cacheTime;
32 1
    }
33
34
    /**
35
     * @param $id
36
     * @param string $modelClass
37
     *
38
     * @return \Eloquent
39
     */
40
    public function find($id, $eagerLoad = true)
41
    {
42
        $model = Cache::get(self::getCacheName($id));
0 ignored issues
show
Bug Best Practice introduced by
The method Foundation\Cache\ModelCache::getCacheName() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

42
        $model = Cache::get(self::/** @scrutinizer ignore-call */ getCacheName($id));
Loading history...
43
44
        if ($eagerLoad) {
45
            return $this->eagerLoadRelations($model);
46
        }
47
48
        return $model;
49
    }
50
51
    public function findBy(string $index, $key, $eagerLoad = true)
52
    {
53
        if (! in_array($index, $this->secondaryIndexes)) {
54
            throw new Exception('provided index does not exist as secondary index on the cache model');
55
        }
56
        $modelId = $this->findSecondaryIndex($index, $key);
57
58
        if ($modelId === null) {
59
            $model = ($this->model)::where($index, $key)->first();
60
            if ($model !== null) {
61
                $this->store($model);
62
            }
63
64
            return $model;
65
        }
66
67
        return $this->find($modelId, $eagerLoad);
68
    }
69
70
    protected function eagerLoadRelations($model)
71
    {
72
        if ($model !== null) {
73
            return $model::eagerLoadRelations([$model])[0];
74
        }
75
    }
76
77
    protected function findSecondaryIndex(string $index, $key)
78
    {
79
        return Cache::get($this->getCacheName($key, $index));
80
    }
81
82
    /**
83
     * @param string
84
     */
85 1
    public function getCacheName($id, string $index = 'id')
86
    {
87 1
        return config('model.cache_prefix').':'.strtolower(get_short_class_name($this->model)).':'.$index.':'.$id;
88
    }
89
90
    /**
91
     * @return \Illuminate\Config\Repository|mixed
92
     */
93 1
    public function getCacheTime()
94
    {
95 1
        return $this->cacheTime ?? config('model.cache_time');
96
    }
97
98
    /**
99
     * @param \Eloquent $model
100
     */
101 1
    public function store($model)
102
    {
103 1
        Cache::put($this->getCacheName($model->getKey()), $model->newFromBuilder($model->getAttributes()), $this->getCacheTime());
0 ignored issues
show
It seems like $this->getCacheTime() can also be of type Illuminate\Config\Repository; however, parameter $ttl of Illuminate\Support\Facades\Cache::put() does only seem to accept DateInterval|DateTimeInterface|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        Cache::put($this->getCacheName($model->getKey()), $model->newFromBuilder($model->getAttributes()), /** @scrutinizer ignore-type */ $this->getCacheTime());
Loading history...
104 1
        $this->storeSecondaryIndexReferences($model);
105 1
    }
106
107
    /**
108
     * @param string    $index
109
     * @param \Eloquent $model
110
     */
111 1
    protected function storeSecondaryIndexReferences($model)
112
    {
113 1
        foreach ($this->secondaryIndexes as $index) {
114 1
            $indexValue = $model->$index;
115 1
            if ($indexValue !== null) {
116 1
                Cache::put($this->getCacheName($indexValue, $index), $model->getKey(), $this->getCacheTime());
0 ignored issues
show
It seems like $this->getCacheTime() can also be of type Illuminate\Config\Repository; however, parameter $ttl of Illuminate\Support\Facades\Cache::put() does only seem to accept DateInterval|DateTimeInterface|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

116
                Cache::put($this->getCacheName($indexValue, $index), $model->getKey(), /** @scrutinizer ignore-type */ $this->getCacheTime());
Loading history...
117
            }
118
        }
119 1
    }
120
121
    /**
122
     * @param $id
123
     * @param string $modelClass
124
     *
125
     * @return bool
126
     */
127
    public function remove($id)
128
    {
129
        return Cache::forget($this->getCacheName($id));
130
    }
131
132
    public static function clearAll()
133
    {
134
        $pattern = config('model.cache_prefix');
135
        self::deleteWithPrefix($pattern);
136
    }
137
138
    /**
139
     * @param $prefix
140
     *
141
     * @throws Exception
142
     */
143
    private static function deleteWithPrefix($prefix)
144
    {
145
        $redis = self::getCacheConnection();
146
        $keyPattern = Cache::getPrefix().$prefix.'*';
0 ignored issues
show
The call to Illuminate\Cache\CacheManager::getPrefix() has too few arguments starting with config. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

146
        $keyPattern = Cache::/** @scrutinizer ignore-call */ getPrefix().$prefix.'*';

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
147
        $keys = $redis->keys($keyPattern);
148
        $redis->delete($keys);
149
    }
150
151
    /**
152
     * @throws Exception
153
     *
154
     * @return \Illuminate\Redis\Connections\Connection
155
     */
156
    private static function getCacheConnection()
157
    {
158
        if (config('cache.default') === 'redis') {
159
            return Redis::connection('cache');
160
        }
161
162
        throw new Exception('This action is only possible with redis as cache driver');
163
    }
164
165
    /**
166
     * @param $modelClass
167
     *
168
     * @throws Exception
169
     */
170
    public function clearModelCache()
171
    {
172
        $pattern = config('model.cache_prefix').':'.strtolower(get_short_class_name($this->model));
173
        self::deleteWithPrefix($pattern);
174
    }
175
176
    public function enabled(): bool
177
    {
178
        return (bool) config('model.caching');
179
    }
180
}
181