ViewModel::cacheKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 10
1
<?php
2
3
namespace Sfneal\ViewModels;
4
5
use Illuminate\Support\Facades\Cache;
6
use Illuminate\Support\Facades\View;
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\Container\NotFoundExceptionInterface;
9
use RuntimeException;
10
use Sfneal\Caching\Traits\IsCacheable;
11
use Sfneal\Helpers\Redis\RedisCache;
12
use Sfneal\Helpers\Strings\StringHelpers;
13
use Sfneal\ViewModels\Traits\CachingPreferences;
14
use Spatie\ViewModels\ViewModel as SpatieViewModel;
15
16
abstract class ViewModel extends SpatieViewModel
17
{
18
    // todo: make more properties private and add getters/setters
19
    use CachingPreferences;
20
    use IsCacheable;
21
22
    /**
23
     * @var int|null Time to live
24
     */
25
    public ?int $ttl = null;
26
27
    /**
28
     * @var string|null Use manually declare redis_key (warning: can cause issues with caching)
29
     */
30
    public ?string $redis_key = null;
31
32
    /**
33
     * View Directory Prefix.
34
     */
35
    public string $prefix = '';
36
37
    /**
38
     * @var string|null View name
39
     */
40
    public $view = null;
41
42
    /**
43
     * Render the View.
44
     *
45
     * @return string
46
     */
47
    private function __render(): string
48
    {
49
        return View::make($this->view, $this->toArray())->render();
50
    }
51
52
    /**
53
     * Retrieve the authenticated user's ID from the session.
54
     *
55
     *  - avoid executing database query
56
     *  // todo: make this optional, we dont always want to tag cached pages by user
57
     *
58
     * @return int
59
     *
60
     * @throws ContainerExceptionInterface
61
     * @throws NotFoundExceptionInterface
62
     */
63
    private function userId(): int
64
    {
65
        try {
66
            // Find the 'login_web' session key that holds the authenticated user_id value
67
            // If there's no key containing 'login_web' the user is not logged in
68
            $session_key = collect(request()->session()->all())->keys()->filter(function ($key) {
0 ignored issues
show
Bug introduced by
request()->session()->all() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

68
            $session_key = collect(/** @scrutinizer ignore-type */ request()->session()->all())->keys()->filter(function ($key) {
Loading history...
69
                return is_string($key) && (new StringHelpers($key))->inString('login_web');
70
            })->first();
71
        } catch (RuntimeException $runtimeException) {
72
            // request and/or session is not set (called from a job)
73
            $session_key = 0;
74
        }
75
76
        // Get the $session_key if it's not null
77
        return ! empty($session_key) ? session()->get($session_key) : 0;
78
    }
79
80
    /**
81
     * Retrieve a unique redis key for caching the view.
82
     *
83
     * // todo: add property?
84
     *
85
     * @return string
86
     *
87
     * @throws ContainerExceptionInterface
88
     * @throws NotFoundExceptionInterface
89
     */
90
    public function cacheKey(): string
91
    {
92
        return 'views'.
93
            ':'.$this->view.
94
            ':'.$this->userId().
95
            ':'.($this->redis_key ?? request()->fullUrl());
96
    }
97
98
    /**
99
     * Set an override Redis Key.
100
     *
101
     * // todo: refactor this
102
     *
103
     * @param  string  $redis_key
104
     * @return $this
105
     */
106
    public function setRedisKey(string $redis_key): self
107
    {
108
        $this->redis_key = $redis_key;
109
110
        return $this;
111
    }
112
113
    /**
114
     * Retrieve/render the ViewModel from/to the application cache.
115
     *
116
     * @param  string|null  $view
117
     * @param  int|null  $ttl
118
     * @return string
119
     *
120
     * @throws ContainerExceptionInterface
121
     * @throws NotFoundExceptionInterface
122
     */
123
    public function render(string $view = null, int $ttl = null): string
124
    {
125
        // Don't cache if caching has been disabled
126
        if ($this->cachingDisabled) {
127
            return $this->renderNoCache($view);
128
        }
129
130
        // Set $view if it is not null
131
        if ($view) {
132
            $this->view = $view;
133
        }
134
135
        // Cache the View if it doesn't exist
136
        return Cache::remember($this->cacheKey(), $this->getTTL($ttl), function () {
137
            return $this->__render();
138
        });
139
    }
140
141
    /**
142
     * Render the ViewModel without storing or retrieving from the Cache.
143
     *
144
     * @param  string|null  $view
145
     * @return string
146
     */
147
    public function renderNoCache(string $view = null): string
148
    {
149
        // Set $view if it is not null
150
        if ($view) {
151
            $this->view = $view;
152
        }
153
154
        return $this->__render();
155
    }
156
157
    /**
158
     * Invalidate the View Cache for this ViewModel.
159
     *
160
     * @param  bool  $children
161
     * @return $this
162
     *
163
     * @throws ContainerExceptionInterface
164
     * @throws NotFoundExceptionInterface
165
     */
166
    public function invalidateCache(bool $children = true): self
167
    {
168
        RedisCache::delete($children ? 'views:'.$this->view : $this->cacheKey(), $children);
169
170
        return $this;
171
    }
172
173
    /**
174
     * Return a concatenated route or view name by using the PREFIX const.
175
     *
176
     * @param  string  $string
177
     * @return $this
178
     */
179
    public function viewWithPrefix(string $string): self
180
    {
181
        $this->view = $this->prefix.$string;
182
183
        return $this;
184
    }
185
186
    /**
187
     * Extend a view name.
188
     *
189
     * @param  string  $string
190
     * @return $this
191
     */
192
    public function viewExtend(string $string): self
193
    {
194
        $this->view .= $string;
195
196
        return $this;
197
    }
198
199
    /**
200
     * Retrieve the time to live for the cached values
201
     *  - 1. passed $ttl parameter
202
     *  - 2. initialized $this->ttl property
203
     *  - 3. application default cache ttl.
204
     *
205
     * @param  int|null  $ttl
206
     * @return int
207
     */
208
    public function getTTL(int $ttl = null): int
209
    {
210
        return intval($ttl ?? $this->ttl ?? config('redis-helpers.ttl'));
211
    }
212
213
    /**
214
     * Set the $ttl property during runtime.
215
     *
216
     * @param  int  $ttl
217
     * @return $this
218
     */
219
    public function setTTL(int $ttl): self
220
    {
221
        $this->ttl = $ttl;
222
223
        return $this;
224
    }
225
226
    // todo: fix issues with getTTL & setTTL methods
227
}
228