ILIAS  trunk Revision v12.0_alpha-413-g215742c0453
NewsCache.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
27
36{
37 protected readonly bool $enabled;
39 protected readonly int $cache_ttl;
40 protected readonly \ilCache $il_cache;
41
42 public function __construct(
43 ) {
44 $settings = new \ilSetting('news');
45
46 $this->cache_ttl = (int) $settings->get('acc_cache_mins');
47 $this->enabled = $this->cache_ttl !== 0;
48
49 $this->il_cache = new \ilCache('ServicesNews', 'NewsMultiLevel', true);
50 $this->il_cache->setExpiresAfter($this->cache_ttl * 60);
51 }
52
61 public function getAggregatedContexts(array $contexts): array
62 {
63 if (!$this->enabled || empty($contexts)) {
64 return ['hit' => [], 'missing' => $contexts];
65 }
66
67 $context_ids = array_map(fn($context) => $context->getRefId(), $contexts);
68 sort($context_ids, SORT_NUMERIC);
69
70 if ($entry = $this->il_cache->getEntry($this->generateL1Key($context_ids))) {
71 $contexts = array_map(fn($raw) => NewsContext::denormalize($raw), unserialize($entry));
72 return ['hit' => $contexts, 'missing' => []];
73 }
74
75 return ['hit' => [], 'missing' => $contexts];
76 }
77
78 protected function generateL1Key(string|array $contexts): string
79 {
80 return 'agg:' . md5(is_array($contexts) ? implode(',', $contexts) : $contexts);
81 }
82
87 public function storeAggregatedContexts(array $contexts, array $aggregated): void
88 {
89 if (!$this->enabled || empty($contexts)) {
90 return;
91 }
92
93 $context_ids = array_map(fn($context) => $context->getRefId(), $contexts);
94 sort($context_ids, SORT_NUMERIC);
95 $key = implode(',', $context_ids);
96
97 $payload = array_map(fn($context) => $context->normalize(), $aggregated);
98 $this->il_cache->storeEntry($this->generateL1Key($key), serialize($payload));
99 }
100
104 public function invalidateAggregatedContexts(array $contexts): void
105 {
106 if (!$this->enabled || empty($contexts)) {
107 return;
108 }
109
110 $context_ids = array_map(fn($context) => $context->getRefId(), $contexts);
111 sort($context_ids, SORT_NUMERIC);
112 $key = implode(',', $context_ids);
113
114 // Delete cache entry
115 $this->il_cache->deleteEntry($this->generateL1Key($key));
116 }
117
118
125 public function getUserContextAccess(int $user_id, NewsCriteria $criteria): ?array
126 {
127 if (!$this->enabled) {
128 return null;
129 }
130
131 $entry = $this->il_cache->getEntry("access:{$user_id}");
132 if (!$entry) {
133 return null;
134 }
135
136 // Check if the stored payload matches the criteria
137 $payload = unserialize($entry);
138 if ($payload['only_public'] !== $criteria->isOnlyPublic()) {
139 $this->invalidateUserContextAccess($user_id);
140 return null;
141 }
142
143 return array_map(fn($ref_id) => new NewsContext($ref_id), $payload['contexts']);
144 }
145
149 public function storeUserContextAccess(int $user_id, NewsCriteria $criteria, array $contexts): void
150 {
151 if (!$this->enabled) {
152 return;
153 }
154
155 $contexts = array_map(fn($context) => $context->getRefId(), $contexts);
156 $payload = ['contexts' => $contexts, 'only_public' => $criteria->isOnlyPublic()];
157 $this->il_cache->storeEntry("access:{$user_id}", serialize($payload));
158 }
159
160 public function invalidateUserContextAccess(int $user_id): void
161 {
162 if ($this->enabled) {
163 $this->il_cache->deleteEntry("access:{$user_id}");
164 }
165 }
166
167
172 public function getNewsForUser(int $user_id, NewsCriteria $criteria): ?LazyNewsCollection
173 {
174 if (!$this->enabled) {
175 return null;
176 }
177
178 $entry = $this->il_cache->getEntry($this->generateL3Key($user_id, $criteria));
179 if (!$entry) {
180 return null;
181 }
182
183 $payload = unserialize($entry);
184 return (new LazyNewsCollection(array_keys($payload)))
185 ->setUserReadStatus($user_id, $payload);
186 }
187
188 public function storeNewsForUser(int $user_id, NewsCriteria $criteria, NewsCollection $news): void
189 {
190 if (!$this->enabled) {
191 return;
192 }
193
194 $this->il_cache->storeEntry(
195 $this->generateL3Key($user_id, $criteria),
196 serialize($news->getUserReadStatus($user_id))
197 );
198 }
199
200 public function invalidateNewsForUser(int $user_id, NewsCriteria $criteria): void
201 {
202 $this->il_cache->deleteEntry($this->generateL3Key($user_id, $criteria));
203 }
204
205 protected function generateL3Key(int $user_id, NewsCriteria $criteria): string
206 {
207 $payload = [
208 'start_date' => $criteria->getStartDate(),
209 'min_priority' => $criteria->getMinPriority(),
210 'max_priority' => $criteria->getMaxPriority(),
211 'no_auto_generated' => $criteria->isNoAutoGenerated(),
212 ];
213
214 // The Period of entries only needs to be considered if cache entries are stored for longer periods
215 $period_minutes = ($criteria->getPeriod() ?? 0) * 1440;
216 if ($period_minutes <= $this->cache_ttl) {
217 $payload['period'] = $criteria->getPeriod();
218 }
219
220 return "user:{$user_id}:" . md5(serialize($payload));
221 }
222
223
224 public function flush(): void
225 {
226 $this->il_cache->deleteAllEntries();
227 }
228}
This class is a special implementation of a NewsCollection that is designed to load the complete News...
Optimized News Collection with memory-efficient data structures to support large news feeds.
News Context DTO represents a context where news items can be associated with.
Definition: NewsContext.php:29
static denormalize(array $raw)
Create new object from reduced array representation.
News Criteria DTO for querying news items supports caching, JSON serialization, and validation.
Multi-Level News Cache Implementation:
Definition: NewsCache.php:36
invalidateNewsForUser(int $user_id, NewsCriteria $criteria)
Definition: NewsCache.php:200
storeUserContextAccess(int $user_id, NewsCriteria $criteria, array $contexts)
Definition: NewsCache.php:149
storeNewsForUser(int $user_id, NewsCriteria $criteria, NewsCollection $news)
Definition: NewsCache.php:188
getUserContextAccess(int $user_id, NewsCriteria $criteria)
Level-2 Cache stores a collection of the base news contexts for a specific user.
Definition: NewsCache.php:125
generateL1Key(string|array $contexts)
Definition: NewsCache.php:78
invalidateUserContextAccess(int $user_id)
Definition: NewsCache.php:160
storeAggregatedContexts(array $contexts, array $aggregated)
Definition: NewsCache.php:87
getNewsForUser(int $user_id, NewsCriteria $criteria)
Level-3 Cache stores a collection of the news items for a specific user.
Definition: NewsCache.php:172
getAggregatedContexts(array $contexts)
Level-1 Cache stores a collection of the aggregated contexts for the provided base context.
Definition: NewsCache.php:61
generateL3Key(int $user_id, NewsCriteria $criteria)
Definition: NewsCache.php:205
invalidateAggregatedContexts(array $contexts)
Definition: NewsCache.php:104
$ref_id
Definition: ltiauth.php:66
if(count($parts) !=3) $payload
Definition: ltitoken.php:67
$context
Definition: webdav.php:31