19declare(strict_types=1);
29class NewsCollection implements \Countable, \IteratorAggregate, \JsonSerializable
67 $this->news_items[
$id] = $item;
71 $this->context_map[$context_key][] =
$id;
86 $context_key = $context_obj_id .
'_' . $context_obj_type;
88 if (!isset($this->context_map[$context_key])) {
93 fn(
$id) => $this->news_items[
$id],
94 $this->context_map[$context_key]
100 if (!isset($this->type_map[$obj_type])) {
105 fn(
$id) => $this->news_items[
$id],
106 $this->type_map[$obj_type]
115 $this->user_read_status[
$user_id] = array_filter($read_news_ids);
121 return isset($this->user_read_status[
$user_id][$news_id]);
130 foreach (array_keys($this->news_items) as $news_id) {
131 $result[$news_id] = $this->
isReadByUser($user_id, $news_id);
142 foreach (array_filter($this->news_items) as $item) {
143 if ($item->getContextObjType() ===
'file') {
144 if (isset($this->grouped_items_map[$item->getContextObjId()])) {
145 $this->grouped_items_map[$item->getContextObjId()][
'aggregation'][] = $item->getId();
147 $this->grouped_items_map[$item->getContextObjId()] = [
148 'first' => $item->getId(),
161 foreach (array_filter($this->news_items) as $item) {
163 if ($group_posting_sequence && $last_forum !== $item->getContextObjType() && $last_forum !== 0) {
164 $this->grouped_items_map[$last_forum] =
null;
167 if ($item->getContextObjType() ===
'frm') {
168 if (isset($this->grouped_items_map[$item->getContextObjId()])) {
169 $this->grouped_items_map[$item->getContextObjId()][
'aggregation'][] = $item->getId();
171 $this->grouped_items_map[$item->getContextObjId()] = [
172 'first' => $item->getId(),
175 $last_forum = $item->getContextObjId();
196 if ($aggregation[
'first'] !== $item->
getId()) {
201 $item = $item->
withContent(
'')->withContentLong(
'');
206 'aggregation' => [$item, ...array_map(fn(
$id) => $this->news_items[
$id], $aggregation[
'aggregation'])],
225 bool $aggregate_files =
false,
226 bool $aggregate_forums =
false,
227 bool $group_posting_sequence =
false
230 $file_aggregation_map = [];
231 $forum_aggregation_map = [];
234 foreach ($this->news_items as $item) {
236 'id' => $item->getId(),
237 'priority' => $item->getPriority(),
238 'title' => $item->getTitle(),
239 'content' => $item->getContent(),
240 'context_obj_id' => $item->getContextObjId(),
241 'context_obj_type' => $item->getContextObjType(),
242 'context_sub_obj_id' => $item->getContextSubObjId(),
243 'context_sub_obj_type' => $item->getContextSubObjType(),
244 'content_type' => $item->getContentType(),
245 'creation_date' => $item->getCreationDate()->format(
'Y-m-d H:i:s'),
246 'user_id' => $item->getUserId(),
247 'visibility' => $item->getVisibility(),
248 'content_long' => $item->getContentLong(),
249 'content_is_lang_var' => $item->isContentIsLangVar(),
250 'mob_id' => $item->getMobId(),
251 'playtime' => $item->getPlaytime(),
252 'start_date' =>
null,
254 'content_text_is_lang_var' => $item->isContentTextIsLangVar(),
255 'mob_cnt_download' => $item->getMobCntDownload(),
256 'mob_cnt_play' => $item->getMobCntPlay(),
257 'content_html' => $item->isContentHtml(),
258 'update_user_id' => $item->getUpdateUserId(),
259 'user_read' => (
int) $this->
isReadByUser($item->getUserId(), $item->getId()),
260 'ref_id' => $item->getContextRefId()
263 if ($aggregate_files && $item->getContextObjType() ===
'file') {
264 if (isset($file_aggregation_map[$item->getContextObjId()])) {
266 $idx = $file_aggregation_map[$item->getContextObjId()];
267 $items[$idx][
'aggregation'][$item->getId()] = $entry;
272 $entry[
'aggregation'] = [];
273 $entry[
'agg_ref_id'] = $item->getContextRefId();
274 $file_aggregation_map[$item->getContextObjId()] = $item->getId();
278 if ($aggregate_forums) {
280 if ($group_posting_sequence && $last_forum !== 0 && $last_forum !== $item->getContextObjType()) {
281 $forum_aggregation_map[$last_forum] =
null;
284 if ($item->getContextObjType() ===
'frm') {
285 $entry[
'no_context_title'] =
true;
287 if (isset($forum_aggregation_map[$item->getContextObjId()])) {
289 $idx = $forum_aggregation_map[$item->getContextObjId()];
290 $items[$idx][
'aggregation'][$item->getId()] = $entry;
295 $entry[
'agg_ref_id'] = $item->getContextRefId();
296 $entry[
'content'] =
'';
297 $entry[
'content_long'] =
'';
299 $forum_aggregation_map[$item->getContextObjId()] = $item->getId();
300 $last_forum = $item->getContextObjType();
305 $items[$item->getId()] = $entry;
316 return array_values($this->news_items);
321 return new ArrayIterator($this->news_items);
326 return count($this->news_items);
331 return empty($this->news_items);
336 return reset($this->news_items) ?:
null;
341 return end($this->news_items) ?:
null;
346 return isset($this->news_items[$news_id]);
351 return $this->news_items[$news_id] ??
null;
356 $pages = array_keys($this->news_items);
357 return (
int) array_search($news_id, $pages);
362 $index = max(0, $offset);
363 return array_values($this->news_items)[$index] ??
null;
366 public function pluck(
string $key,
bool $wrap =
false): array
368 $arr = array_column($this->toArray(), $key);
369 return $wrap ? array_map(fn($item) => [$item], $arr) : $arr;
377 return array_map(fn($item) => $item->toArray(), $this->news_items);
386 $merged =
new static();
387 $merged->addNewsItems($this->news_items);
391 foreach ($other->user_read_status as
$user_id => $read_ids) {
392 $merged->user_read_status[
$user_id] = isset($this->user_read_status[
$user_id])
393 ? array_merge($this->user_read_status[
$user_id], $read_ids)
403 public function limit(?
int $limit): static
405 if ($limit ===
null || $limit >= count($this->news_items)) {
409 $limited =
new static();
410 $items = array_slice($this->news_items, 0, $limit,
true);
411 $limited->addNewsItems($items);
421 public function exclude(array $news_ids): static
423 if (empty($news_ids)) {
427 $filtered =
new static();
428 $filtered->addNewsItems(array_filter(
430 fn($item) => !in_array($item->getId(), $news_ids)
435 public function load(array $news_ids = []): static
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Optimized News Collection with memory-efficient data structures to support large news feeds.
getNewsForContext(int $context_obj_id, string $context_obj_type)
limit(?int $limit)
Limit the number of news items and returns it as a new collection.
addNewsItems(array $news_items)
Add multiple news items efficiently.
pluck(string $key, bool $wrap=false)
isReadByUser(int $user_id, int $news_id)
addNewsItem(NewsItem $item)
Add a single news item with indexing.
setUserReadStatus(int $user_id, array $read_news_ids)
getGroupingFor(NewsItem $item)
Returns the grouping for a given news item.
getNewsByType(string $obj_type)
__construct(array $news_items=[])
getAggregatedNews(bool $aggregate_files=false, bool $aggregate_forums=false, bool $group_posting_sequence=false)
Get news items in a format compatible with the legacy rendering implementation.
merge(NewsCollection $other)
Merge with another collection and returns it as a new collection.
getUserReadStatus(int $user_id)
exclude(array $news_ids)
Returns a new collection with only the news items that are not in the provided list.
groupForums(bool $group_posting_sequence)
News Item DTO for transfer of news items.
withContent(string $content)