ILIAS  trunk Revision v12.0_alpha-399-g579a087ced2
NewsRepository.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
30
36{
37 public function __construct(
38 protected readonly \ilDBInterface $db,
39 protected readonly Factory $factory
40 ) {
41 }
42
43 public function findById(int $news_id): ?NewsItem
44 {
45 $query = "SELECT * FROM il_news_item WHERE id = %s";
46 $result = $this->db->queryF($query, [\ilDBConstants::T_INTEGER], [$news_id]);
47
48 return $result->numRows()
49 ? $this->factory->newsItem($this->db->fetchAssoc($result))
50 : null;
51 }
52
57 public function findByIds(array $news_ids): array
58 {
59 if (empty($news_ids)) {
60 return [];
61 }
62
63 $result = $this->db->query($this->buildFindQuery($news_ids));
64 return array_map(fn($row) => $this->factory->newsItem($row), $this->db->fetchAll($result));
65 }
66
67
73 public function loadLazyItems(array $news_ids, array $group_context_types): array
74 {
75 if (empty($news_ids)) {
76 return [];
77 }
78
79 $result = $this->db->query($this->buildFindQuery($news_ids));
80 $news_items = [];
81 $additional_obj_ids = [];
82
83 foreach ($this->db->fetchAll($result) as $row) {
84 $news_item = $this->factory->newsItem($row);
85
86 if (in_array($news_item->getContextObjType(), $group_context_types)) {
87 $additional_obj_ids[] = $news_item->getContextObjId();
88 }
89
90 $news_items[] = $news_item;
91 }
92
93 if (empty($additional_obj_ids)) {
94 return $news_items;
95 }
96
97 // Fetch all additional items with same context_obj_id for grouping
98 $query = $this->buildFindQuery()
99 . " WHERE " . $this->db->in('context_obj_id', $additional_obj_ids, false, \ilDBConstants::T_INTEGER)
100 . " AND " . $this->db->in('id', $news_ids, true, \ilDBConstants::T_INTEGER);
101 $result = $this->db->query($query);
102
103 return array_merge(
104 $news_items,
105 array_map(fn($row) => $this->factory->newsItem($row), $this->db->fetchAll($result))
106 );
107 }
108
109 private function buildFindQuery(?array $news_ids = null): string
110 {
111 $query = "
112 SELECT il_news_item.*,
113 COALESCE(
114 (SELECT ref_id FROM object_reference WHERE object_reference.obj_id = il_news_item.context_obj_id LIMIT 1),
115 0
116 ) AS ref_id
117 FROM il_news_item ";
118
119 if ($news_ids !== null) {
120 $query .= "WHERE " . $this->db->in('id', $news_ids, false, \ilDBConstants::T_INTEGER);
121 }
122
123 return $query;
124 }
125
129 public function findByContextsBatch(array $contexts, NewsCriteria $criteria): NewsCollection
130 {
131 if (empty($contexts)) {
132 return new NewsCollection();
133 }
134
135 $obj_ids = array_map(fn($context) => $context->getObjId(), $contexts);
136 $result = $this->db->queryF(...$this->buildBatchQuery($obj_ids, $criteria));
137
138 $items = [];
139 $user_read = [];
140
141 while ($row = $this->db->fetchAssoc($result)) {
142 $items[] = $this->factory->newsItem($row);
143 $user_read[$row['id']] = isset($row['user_read']) && $row['user_read'] !== 0;
144 }
145
146 $collection = new NewsCollection($items);
147 if ($criteria->isIncludeReadStatus()) {
148 $collection->setUserReadStatus($criteria->getReadUserId(), $user_read);
149 }
150
151 return $collection;
152 }
153
157 public function findByContextsBatchLazy(array $contexts, NewsCriteria $criteria): LazyNewsCollection
158 {
159 if (empty($contexts)) {
160 return new LazyNewsCollection();
161 }
162
163 $obj_ids = array_map(fn($context) => $context->getObjId(), $contexts);
164 $result = $this->db->queryF(...$this->buildBatchQuery($obj_ids, $criteria, true));
165
166 $items = [];
167 $user_read = [];
168 while ($row = $this->db->fetchAssoc($result)) {
169 $items[] = $row['id'];
170 $user_read[$row['id']] = isset($row['user_read']) && $row['user_read'] !== 0;
171 }
172
173 $collection = new LazyNewsCollection($items, fn(...$args) => $this->loadLazyItems(...$args));
174 if ($criteria->isIncludeReadStatus()) {
175 $collection->setUserReadStatus($criteria->getReadUserId(), $user_read);
176 }
177
178 return $collection;
179 }
180
185 public function countByContextsBatch(array $contexts): array
186 {
187 $context_map = [];
188 foreach ($contexts as $context) {
189 $context_map[$context->getObjId()] = $context;
190 }
191
192 $in_clause = $this->db->in('context_obj_id', array_keys($context_map), false, ilDBConstants::T_INTEGER);
193 $query = "SELECT context_obj_id, count(context_obj_id) as count FROM il_news_item WHERE {$in_clause} GROUP BY context_obj_id";
194 $result = $this->db->query($query);
195
196 $count = [];
197 foreach ($this->db->fetchAll($result) as $row) {
198 $count[] = [
199 $context_map[$row['context_obj_id']],
200 $row['count']
201 ];
202 }
203
204 return $count;
205 }
206
207 private function buildBatchQuery(array $obj_ids, NewsCriteria $criteria, bool $only_id = false): array
208 {
209 $values = [];
210 $types = [];
211 $joins = '';
212
213 if ($only_id) {
214 $columns = ['il_news_item.id'];
215 } else {
216 $columns = [
217 'il_news_item.*',
218 'COALESCE((SELECT ref_id FROM object_reference WHERE object_reference.obj_id = il_news_item.context_obj_id LIMIT 1), 0) AS ref_id'
219 ];
220 }
221
222 if ($criteria->isIncludeReadStatus()) {
223 if ($criteria->getReadUserId() === null) {
224 throw new \InvalidArgumentException("Read user id is required for read status");
225 }
226
227 $columns[] = 'il_news_read.user_id AS user_read';
228 $joins .= 'LEFT JOIN il_news_read ON il_news_item.id = il_news_read.news_id AND il_news_read.user_id = %s ';
229
230 $values[] = $criteria->getReadUserId();
231 $types[] = ilDBConstants::T_INTEGER;
232 }
233
234 $query = "SELECT " . join(', ', $columns) . " FROM il_news_item {$joins} WHERE "
235 . $this->db->in('context_obj_id', $obj_ids, false, ilDBConstants::T_INTEGER);
236
237 if ($criteria->getPeriod() > 0) {
238 $query .= " AND creation_date >= %s";
239 $values[] = self::parseTimePeriod($criteria->getPeriod());
241 }
242
243 if ($criteria->getStartDate()) {
244 $query .= " AND creation_date >= %s";
245 $values[] = $criteria->getStartDate()->format('Y-m-d H:i:s');
247 }
248
249 if ($criteria->isNoAutoGenerated()) {
250 $query .= " AND priority = 1 AND content_type = 'text'";
251 }
252
253 if ($criteria->getMinPriority() !== null || $criteria->getMaxPriority() !== null) {
254 $operator = $criteria->getMinPriority() !== null ? '>=' : '<=';
255 $query .= " AND n.priority {$operator} %s";
256 $values[] = $criteria->getMinPriority();
257 $types[] = ilDBConstants::T_INTEGER;
258 }
259
260 if ($criteria->isOnlyPublic()) {
261 $query .= " AND visibility = '" . NEWS_PUBLIC . "'";
262 }
263
264 $query .= " ORDER BY creation_date DESC";
265
266 return [$query, $types, $values];
267 }
268
269 private static function parseTimePeriod(string|int $time_period): string
270 {
271 // time period is a number of days
272 if (is_numeric($time_period) && $time_period > 0) {
273 return date('Y-m-d H:i:s', time() - ($time_period * 24 * 60 * 60));
274 }
275
276 // time period is datetime (string)
277 if (preg_match("/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/", $time_period)) {
278 return $time_period;
279 }
280
281 return '';
282 }
283}
factory()
Factory for creating News DTOs from database results (arrays)
Definition: Factory.php:29
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
News Criteria DTO for querying news items supports caching, JSON serialization, and validation.
News Item DTO for transfer of news items.
Definition: NewsItem.php:29
News Repository provides basic CRUD operations and optimized database access for news operations with...
findByContextsBatchLazy(array $contexts, NewsCriteria $criteria)
__construct(protected readonly \ilDBInterface $db, protected readonly Factory $factory)
static parseTimePeriod(string|int $time_period)
loadLazyItems(array $news_ids, array $group_context_types)
buildBatchQuery(array $obj_ids, NewsCriteria $criteria, bool $only_id=false)
findByContextsBatch(array $contexts, NewsCriteria $criteria)
const NEWS_PUBLIC
Class ilDBConstants.
Interface ilDBInterface.
$context
Definition: webdav.php:31