Passed
Push — master ( 5e6d7b...38474e )
by Nicolaas
04:20 queued 17s
created

PageControllerExtension::getRandomKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 9
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Sunnysideup\SimpleTemplateCaching\Extensions;
4
5
use PageController;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Core\Extension;
8
use SilverStripe\Security\Security;
9
use SilverStripe\Versioned\Versioned;
10
11
/**
12
 * Class \Sunnysideup\SimpleTemplateCaching\Extensions\PageControllerExtension.
13
 *
14
 * @property PageController|PageControllerExtension $owner
15
 */
16
class PageControllerExtension extends Extension
17
{
18
    private static bool $unique_cache_for_each_member = true;
19
20
    /**
21
     * make sure to set unique_cache_for_each_member to false
22
     * to use this.
23
     */
24
    private static bool $unique_cache_for_each_member_group_combo = false;
25
26
    /**
27
     * @var null|string
28
     */
29
    protected static $_cache_key_any_data_object_changes;
30
31
    /**
32
     * @var null|bool
33
     */
34
    private static $_can_cache_content;
35
36
    /**
37
     * @var string
38
     */
39
    private static string $_can_cache_content_string = '';
40
41
    /**
42
     * does the page have cache keys AKA can it be cached?
43
     */
44
    public function HasCacheKeys(): bool
45
    {
46
        $owner = $this->getOwner();
47
        if (null === self::$_can_cache_content) {
48
            $canCache = true;
49
            self::$_can_cache_content_string = '';
50
            if ($owner->hasMethod('canCachePage')) {
51
                // if it can cache the page, then it the cache string will remain empty.
52
                $canCache = $owner->canCachePage();
53
                self::$_can_cache_content_string .=  $canCache ? '' : $this->getRandomKey();
54
            }
55
56
            //action
57
            $action = $owner->request->param('Action');
58
            if ($action) {
59
                self::$_can_cache_content_string .= 'UA' . $action;
60
            }
61
62
            // id
63
            $id = $owner->request->param('ID');
64
            if ($id) {
65
                self::$_can_cache_content_string .= 'UI' . $id;
66
            }
67
68
            // otherid
69
            $otherId = $owner->request->param('OtherID');
70
            if ($otherId) {
71
                self::$_can_cache_content_string .= 'UI' . $otherId;
72
            }
73
74
            //request vars
75
            $requestVars = $owner->request->requestVars();
76
            if ($requestVars) {
77
                foreach ($owner->request->requestVars() as $key => $item) {
78
<<<<<<< HEAD
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_SL on line 78 at column 0
Loading history...
79
                    $canCache = false;
80
=======
81
>>>>>>> 5e6d7b8a22bfca77ec46593a5063fa14ef3c3e64
82
                    if (! $item) {
83
                        $item = '';
84
                    }
85
                    self::$_can_cache_content_string .= serialize($key . '_' . serialize($item));
86
                }
87
            }
88
89
            if (Versioned::get_reading_mode() !== 'Stage.Live') {
90
                self::$_can_cache_content_string .= 'V' . Versioned::get_reading_mode();
91
                $canCache = false;
92
            }
93
94
            //member
95
            $member = Security::getCurrentUser();
96
            if ($member && $member->exists()) {
97
                if (Config::inst()->get(self::class, 'unique_cache_for_each_member')) {
98
                    self::$_can_cache_content_string .= 'UM' . $member->ID;
99
                } elseif (Config::inst()->get(self::class, 'unique_cache_for_each_member_group_combo')) {
100
                    $groupIds = $member->Groups()->columnUnique();
101
                    sort($groupIds, SORT_NUMERIC);
102
                    self::$_can_cache_content_string .= 'UG' . implode(',', $groupIds);
103
                } else {
104
                    $canCache = false;
105
                }
106
            }
107
            // crucial
108
            self::$_can_cache_content = $canCache;
109
        }
110
111
        return self::$_can_cache_content;
112
    }
113
114
    public function HasCacheKeyHeader(): bool
115
    {
116
        return $this->HasCacheKeys();
117
    }
118
119
    public function HasCacheKeyMenu(): bool
120
    {
121
        return $this->HasCacheKeys();
122
    }
123
124
    public function HasCacheKeyContent(): bool
125
    {
126
        if ($this->getOwner()->NeverCachePublicly) {
127
            return false;
128
        }
129
        return $this->HasCacheKeys();
130
    }
131
132
    public function HasCacheKeyFooter(): bool
133
    {
134
        return $this->HasCacheKeys();
135
    }
136
137
    public function CacheKeyHeader(?bool $includePageId = false, ?bool $forceCaching = false): string
138
    {
139
        return $this->CacheKeyGenerator('H', $includePageId, $forceCaching);
140
    }
141
142
    public function CacheKeyMenu(?bool $includePageId = true, ?bool $forceCaching = false): string
143
    {
144
        return $this->CacheKeyGenerator('M', $includePageId, $forceCaching);
145
    }
146
147
    public function CacheKeyFooter(?bool $includePageId = false, ?bool $forceCaching = false): string
148
    {
149
        return $this->CacheKeyGenerator('F', $includePageId, $forceCaching);
150
    }
151
152
    public function CacheKeyContent(?bool $forceCaching = false): string
153
    {
154
        $owner = $this->getOwner();
155
        if ($owner->NeverCachePublicly) {
156
            return $this->getRandomKey();
157
        }
158
        $cacheKey = $this->CacheKeyGenerator('C');
159
        if ($owner->hasMethod('CacheKeyContentCustom')) {
160
            $cacheKey .= '_' . $owner->CacheKeyContentCustom();
161
        }
162
163
        return $cacheKey;
164
    }
165
166
    public function CacheKeyGenerator(string $letter, ?bool $includePageId = true, ?bool $forceCaching = false): string
167
    {
168
        $owner = $this->getOwner();
169
        if ($this->HasCacheKeys() || $forceCaching) {
170
            $string = $letter . '_' . $this->getCanCacheContentString() . '_' . $this->cacheKeyAnyDataObjectChanges();
171
172
            if ($includePageId) {
173
                $string .= '_ID_' . $owner->ID;
174
            }
175
        } else {
176
            $string = 'NOT_CACHED__ID_' . $this->getRandomKey();
177
        }
178
179
        return $string;
180
    }
181
182
    /**
183
     * if the cache string is NOT empty then we cannot cache
184
     * as there are specific caching values that indicate the page can not be cached.
185
     */
186
    protected function canCacheCheck(): bool
187
    {
188
        // back to source
189
        return $this->HasCacheKeys();
190
    }
191
192
    protected function getRandomKey()
193
    {
194
        $uniqueId = uniqid('', true);
195
196
        // Combine it with some random data
197
        $randomData = bin2hex(random_bytes(16));
198
199
        // Create a SHA-256 hash
200
        return hash('sha256', $uniqueId . $randomData);
201
    }
202
203
    protected function getCanCacheContentString(): string
204
    {
205
        return self::$_can_cache_content_string;
206
    }
207
208
    protected function cacheKeyAnyDataObjectChanges(): string
209
    {
210
        if (null === self::$_cache_key_any_data_object_changes) {
211
            self::$_cache_key_any_data_object_changes = SimpleTemplateCachingSiteConfigExtension::site_cache_key();
212
        }
213
214
        return self::$_cache_key_any_data_object_changes;
215
    }
216
}
217