ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
MailFolderTableUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21namespace ILIAS\Mail\Folder;
22
23use ilLanguage;
24use ilMail;
28use ILIAS\Data\Factory as DataFactory;
32use ILIAS\Refinery\Factory as Refinery;
34use ILIAS\UI\Component\Table\Data as DataTable;
43use Psr\Http\Message\ServerRequestInterface;
44use DateTimeImmutable;
45use DateTimeZone;
46
48{
49 // table actions
50 public const string ACTION_SHOW = 'show';
51 public const string ACTION_EDIT = 'edit';
52 public const string ACTION_REPLY = 'reply';
53 public const string ACTION_FORWARD = 'forward';
54 public const string ACTION_DOWNLOAD_ATTACHMENT = 'download';
55 public const string ACTION_PRINT = 'print';
56 public const string ACTION_PROFILE = 'profile';
57 public const string ACTION_MOVE_TO = 'moveTo';
58 public const string ACTION_DELETE = 'delete';
59 public const string ACTION_MARK_READ = 'markRead';
60 public const string ACTION_MARK_UNREAD = 'marUnread';
61
63 private array $avatars = [];
64
68 public function __construct(
69 private readonly URLBuilder $url_builder,
70 private readonly URLBuilderToken $action_token,
71 private readonly URLBuilderToken $row_id_token,
72 private readonly URLBuilderToken $folder_token,
73 private readonly array $user_folders,
74 private readonly MailFolderData $current_folder,
75 private readonly MailFolderSearch $search,
76 private readonly ilMail $mail,
77 private readonly Factory $ui_factory,
78 private readonly Renderer $ui_renderer,
79 private readonly ilLanguage $lng,
80 private readonly ServerRequestInterface $http_request,
81 private readonly DataFactory $data_factory,
82 private readonly Refinery $refinery,
83 private readonly DateFormat $date_format,
84 private readonly string $time_format,
85 private readonly DateTimeZone $user_time_zone
86 ) {
87 }
88
89 public function getComponent(): DataTable
90 {
91 return $this->ui_factory
92 ->table()
93 ->data(
94 $this,
95 $this->getTableTitle(),
96 $this->getColumnDefinition(),
97 )
98 ->withId(self::class)
99 ->withOrder(new Order('date', Order::DESC))
100 ->withActions($this->getActions())
101 ->withRequest($this->http_request);
102 }
103
107 private function getColumnDefinition(): array
108 {
109 if ((int) $this->time_format === \ilCalendarSettings::TIME_FORMAT_12) {
110 $date_format = $this->data_factory->dateFormat()->withTime12($this->date_format);
111 } else {
112 $date_format = $this->data_factory->dateFormat()->withTime24($this->date_format);
113 }
114
115 $columns = [
116 'status' => $this->ui_factory
117 ->table()
118 ->column()
119 ->statusIcon($this->lng->txt('status'))
120 ->withIsSortable(true),
121
122 'avatar' => $this->ui_factory
123 ->table()
124 ->column()
125 ->status($this->lng->txt('personal_picture'))
126 ->withIsSortable(true),
127
128 'sender' => $this->ui_factory
129 ->table()
130 ->column()
131 ->text($this->lng->txt('sender'))
132 ->withIsSortable(true),
133
134 'recipients' => $this->ui_factory
135 ->table()
136 ->column()
137 ->text($this->lng->txt('recipient'))
138 ->withIsSortable(true),
139
140 'subject' => $this->ui_factory
141 ->table()
142 ->column()
143 ->link($this->lng->txt('subject'))
144 ->withIsSortable(true),
145
146 'attachments' => $this->ui_factory
147 ->table()
148 ->column()
149 ->status($this->lng->txt('attachments'))
150 ->withIsSortable(true),
151
152 'date' => $this->ui_factory
153 ->table()
154 ->column()
155 ->date(
156 $this->lng->txt('date'),
157 $date_format
158 )
159 ->withIsSortable(true),
160 ];
161
162 if ($this->current_folder->hasOutgoingMails()) {
163 unset($columns['status'], $columns['avatar'], $columns['sender']);
164 } else {
165 unset($columns['recipients']);
166 }
167
168 return $columns;
169 }
170
174 private function getActions(): array
175 {
176 $actions = [
177 self::ACTION_SHOW => $this->ui_factory->table()->action()->single(
178 $this->lng->txt('view'),
179 $this->url_builder->withParameter($this->action_token, self::ACTION_SHOW),
180 $this->row_id_token
181 ),
182 self::ACTION_EDIT => $this->ui_factory->table()->action()->single(
183 $this->lng->txt('edit'),
184 $this->url_builder->withParameter($this->action_token, self::ACTION_EDIT),
185 $this->row_id_token
186 ),
187 self::ACTION_REPLY => $this->ui_factory->table()->action()->single(
188 $this->lng->txt('reply'),
189 $this->url_builder->withParameter($this->action_token, self::ACTION_REPLY),
190 $this->row_id_token
191 ),
192 self::ACTION_FORWARD => $this->ui_factory->table()->action()->single(
193 $this->lng->txt('forward'),
194 $this->url_builder->withParameter($this->action_token, self::ACTION_FORWARD),
195 $this->row_id_token
196 ),
197 self::ACTION_DOWNLOAD_ATTACHMENT => $this->ui_factory->table()->action()->single(
198 $this->lng->txt('mail_download_attachment'),
199 $this->url_builder->withParameter($this->action_token, self::ACTION_DOWNLOAD_ATTACHMENT),
200 $this->row_id_token
201 ),
202 self::ACTION_PRINT => $this->ui_factory->table()->action()->single(
203 $this->lng->txt('print'),
204 $this->url_builder->withParameter($this->action_token, self::ACTION_PRINT),
205 $this->row_id_token
206 ),
207 self::ACTION_MARK_READ => $this->ui_factory->table()->action()->multi(
208 $this->lng->txt('mail_mark_read'),
209 $this->url_builder->withParameter($this->action_token, self::ACTION_MARK_READ),
210 $this->row_id_token
211 ),
212 self::ACTION_MARK_UNREAD => $this->ui_factory->table()->action()->multi(
213 $this->lng->txt('mail_mark_unread'),
214 $this->url_builder->withParameter($this->action_token, self::ACTION_MARK_UNREAD),
215 $this->row_id_token
216 ),
217 self::ACTION_DELETE => $this->ui_factory->table()->action()->standard(
218 $this->lng->txt('delete'),
219 $this->url_builder->withParameter($this->action_token, self::ACTION_DELETE),
220 $this->row_id_token
221 )->withAsync(), // for confirmation modal
222 ];
223
224 foreach ($this->user_folders as $target_folder) {
225 if ($target_folder->getFolderId() !== $this->current_folder->getFolderId()) {
226 $action_title = $this->lng->txt('mail_move_to') . ' ' . $target_folder->getTitle();
227 if ($target_folder->isTrash()) {
228 $action_title .= ' (' . $this->lng->txt('delete') . ')';
229 }
230
231 $actions[self::ACTION_MOVE_TO . $target_folder->getFolderId()] = $this->ui_factory
232 ->table()
233 ->action()
234 ->multi(
235 $action_title,
236 $this->url_builder
237 ->withParameter($this->action_token, self::ACTION_MOVE_TO)
238 ->withParameter($this->folder_token, (string) $target_folder->getFolderId()),
239 $this->row_id_token
240 );
241 }
242 }
243
244 if ($this->current_folder->isDrafts() || $this->current_folder->isOutbox()) {
245 unset($actions[self::ACTION_SHOW], $actions[self::ACTION_REPLY], $actions[self::ACTION_FORWARD]);
246 } else {
247 unset($actions[self::ACTION_EDIT]);
248 }
249
250 if ($this->current_folder->hasOutgoingMails()) {
251 unset($actions[self::ACTION_MARK_READ], $actions[self::ACTION_MARK_UNREAD]);
252 }
253
254 if (!$this->current_folder->isTrash()) {
255 unset($actions[self::ACTION_DELETE]);
256 }
257
258 return $actions;
259 }
260
261 public function getRows(
262 DataRowBuilder $row_builder,
263 array $visible_column_ids,
265 Order $order,
266 mixed $additional_viewcontrol_data,
267 mixed $filter_data, // not used, because data is filtered by MailDataSearch
268 mixed $additional_parameters // not used
269 ): \Generator {
270 // mapping of table columns to allowed order columns of the mailbox query
271 $order_columns = [
272 'status' => MailBoxOrderColumn::STATUS,
273 'subject' => MailBoxOrderColumn::SUBJECT,
274 'sender' => MailBoxOrderColumn::FROM,
275 'recipients' => MailBoxOrderColumn::RCP_TO,
276 'date' => MailBoxOrderColumn::SEND_TIME,
277 'attachments' => MailBoxOrderColumn::ATTACHMENTS
278 ];
279
280 [$order_column, $order_direction] = $order->join([], fn($ret, $key, $value) => [$key, $value]);
281
282 $records = $this->search->getPagedRecords(
283 $range->getLength(),
284 $range->getStart(),
285 $order_columns[$order_column] ?? null,
286 $order_direction
287 );
288
289 // preload user objects for display of avatar and sender
290 if ($this->current_folder->hasIncomingMails()) {
291 $user_ids = [];
292 foreach ($records as $record) {
293 if ($record->hasPersonalSender()) {
294 $user_ids[$record->getSenderId()] = $record->getSenderId();
295 }
296 }
298 }
299
300 foreach ($records as $record) {
301 if ($this->current_folder->hasIncomingMails()) {
302 $data = [
303 'status' => $this->getStatus($record),
304 'avatar' => $this->getAvatar($record),
305 'sender' => $this->getSender($record),
306 'subject' => $this->getSubject($record),
307 'attachments' => $this->getAttachments($record),
308 'date' => $this->getDate($record)
309 ];
310 } else {
311 $data = [
312 'recipients' => $this->getRecipients($record),
313 'subject' => $this->getSubject($record),
314 'attachments' => $this->getAttachments($record),
315 'date' => $this->getDate($record)
316 ];
317 }
318
319 yield $row_builder->buildDataRow(
320 (string) $record->getMailId(),
321 $data
322 )->withDisabledAction(self::ACTION_REPLY, !$record->hasPersonalSender())->withDisabledAction(
323 self::ACTION_DOWNLOAD_ATTACHMENT,
324 !$record->hasAttachments()
325 );
326 }
327 }
328
329 public function getTotalRowCount(
330 mixed $additional_viewcontrol_data,
331 mixed $filter_data,
332 mixed $additional_parameters
333 ): ?int {
334 return $this->search->getCount();
335 }
336
337 private function getTableTitle(): string
338 {
339 if ($this->current_folder->hasIncomingMails() && $this->search->getUnread() > 0) {
340 return \sprintf(
341 '%s: %s (%s %s)',
342 $this->current_folder->getTitle(),
343 $this->search->getCount() === 1
344 ? $this->lng->txt('mail_1')
345 : \sprintf($this->lng->txt('mail_s'), $this->search->getCount()),
346 $this->search->getUnread(),
347 $this->lng->txt('unread')
348 );
349 }
350
351 return \sprintf(
352 '%s: %s',
353 $this->current_folder->getTitle(),
354 $this->search->getCount() === 1
355 ? $this->lng->txt('mail_1')
356 : \sprintf($this->lng->txt('mail_s'), $this->search->getCount()),
357 );
358 }
359
360 private function getAvatar(MailRecordData $record): string
361 {
362 if (!\array_key_exists($record->getSenderId(), $this->avatars)) {
363 if ($record->getSenderId() === ANONYMOUS_USER_ID) {
364 $avatar = $this->ui_factory->symbol()->avatar()->picture(
365 \ilUtil::getImagePath('logo/ilias_logo_centered.png'),
366 $this->getSender($record)
367 );
368 } else {
370 $avatar = $user?->getAvatar();
371 }
372
373 $this->avatars[$record->getSenderId()] = $avatar
374 ? $this->ui_renderer->render($avatar)
375 : '';
376 }
377
378 return $this->avatars[$record->getSenderId()];
379 }
380
381 private function getStatus(MailRecordData $record): Icon
382 {
383 return $record->isRead()
384 ? $this->ui_factory->symbol()->icon()->standard('mailr', $this->lng->txt('mailr'))
385 : $this->ui_factory->symbol()->icon()->standard('mailu', $this->lng->txt('mailu'));
386 }
387
388 private function getSender(MailRecordData $record): string
389 {
390 if ($record->getSenderId() === ANONYMOUS_USER_ID) {
392 }
393
395 if ($user !== null) {
396 if ($user->hasPublicProfile()) {
397 return $this->ui_renderer->render(
398 $this->ui_factory->link()->standard(
399 $user->getPublicName(),
400 (string) $this->url_builder
401 ->withParameter($this->action_token, self::ACTION_PROFILE)
402 ->withParameter($this->row_id_token, (string) $record->getMailId())
403 ->buildURI()
404 )
405 );
406 }
407
408 return $user->getPublicName();
409 }
410
411 return trim(($record->getImportName() ?? '') . ' (' . $this->lng->txt('user_deleted') . ')');
412 }
413
414 private function getRecipients(MailRecordData $record): string
415 {
416 return $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform(
417 $this->mail->formatNamesForOutput((string) $record->getRcpTo())
418 );
419 }
420
421 private function getSubject(MailRecordData $record): Link
422 {
423 return $this->ui_factory->link()->standard(
424 $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform($record->getSubject()),
425 (string) $this->url_builder
426 ->withParameter(
427 $this->action_token,
428 $this->current_folder->isDrafts() || $this->current_folder->isOutbox() ? self::ACTION_EDIT : self::ACTION_SHOW
429 )
430 ->withParameter($this->row_id_token, (string) $record->getMailId())
431 ->buildURI()
432 );
433 }
434
435 private function getDate(MailRecordData $record): ?DateTimeImmutable
436 {
437 return empty($record->getSendTime()) ? null : $record->getSendTime()->setTimezone($this->user_time_zone);
438 }
439
440 private function getAttachments(MailRecordData $record): string
441 {
442 return $record->hasAttachments()
443 ? $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->attachment())
444 : '';
445 }
446}
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
A Date Format provides a format definition akin to PHP's date formatting options, but stores the sing...
Definition: DateFormat.php:27
Builds data types.
Definition: Factory.php:36
Both the subject and the direction need to be specified when expressing an order.
Definition: Order.php:29
join($init, callable $fn)
Definition: Order.php:75
const DESC
Definition: Order.php:31
A simple class to express a naive range of whole positive numbers.
Definition: Range.php:29
getTotalRowCount(mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
Mainly for the purpose of pagination-support, it is important to know about the total number of recor...
getAttachments(MailRecordData $record)
getRows(DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
This is called by the table to retrieve rows; map data-records to rows using the $row_builder e....
__construct(private readonly URLBuilder $url_builder, private readonly URLBuilderToken $action_token, private readonly URLBuilderToken $row_id_token, private readonly URLBuilderToken $folder_token, private readonly array $user_folders, private readonly MailFolderData $current_folder, private readonly MailFolderSearch $search, private readonly ilMail $mail, private readonly Factory $ui_factory, private readonly Renderer $ui_renderer, private readonly ilLanguage $lng, private readonly ServerRequestInterface $http_request, private readonly DataFactory $data_factory, private readonly Refinery $refinery, private readonly DateFormat $date_format, private readonly string $time_format, private readonly DateTimeZone $user_time_zone)
language handling
static getUserObjectById(int $usr_id)
static preloadUserObjects(array $usr_ids)
static _getIliasMailerName()
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
const ANONYMOUS_USER_ID
Definition: constants.php:27
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This describes how an icon could be modified during construction of UI.
Definition: Icon.php:29
A Column describes the form of presentation for a certain aspect of data, i.e.
Definition: Column.php:28
buildDataRow(string $id, array $record)
This describes a Data Table.
Definition: Data.php:33
This is how the factory for UI elements looks.
Definition: Factory.php:38
An entity that renders components to a string output.
Definition: Renderer.php:31
global $lng
Definition: privfeed.php:31