ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilObjectBadgeTableGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 namespace ILIAS\Badge;
22 
27 use ilLanguage;
34 use Generator;
37 use ilBadge;
38 use ilBadgeHandler;
39 use ILIAS\Data\URI;
41 use ilObject;
42 use ilLink;
46 use ilAccessHandler;
48 
50 {
51  private const RECORD_RAW = '__raw__';
52 
53  private readonly Factory $factory;
54  private readonly Renderer $renderer;
55  private readonly \ILIAS\Refinery\Factory $refinery;
57  private readonly Services $http;
58  private readonly ilLanguage $lng;
59  private readonly ilGlobalTemplateInterface $tpl;
61  private readonly ilAccessHandler $access;
62  private readonly \ILIAS\ResourceStorage\Services $irss;
76  private ?array $cached_records = null;
78  private array $has_access_by_parent_cache = [];
80  private array $first_ref_id_for_parent_cache = [];
81 
82  public function __construct(
83  ilObjBadgeAdministrationGUI $parentObj,
84  protected bool $has_write = false
85  ) {
86  global $DIC;
87 
88  $this->lng = $DIC->language();
89  $this->tpl = $DIC->ui()->mainTemplate();
90  $this->factory = $DIC->ui()->factory();
91  $this->renderer = $DIC->ui()->renderer();
92  $this->refinery = $DIC->refinery();
93  $this->request = $DIC->http()->request();
94  $this->http = $DIC->http();
95  $this->access = $DIC->access();
96  $this->parent_obj = $parentObj;
97  $this->irss = $DIC->resourceStorage();
98  $this->badge_image_service = new ilBadgeImage(
99  $this->irss,
100  $DIC->upload(),
101  $DIC->ui()->mainTemplate()
102  );
103  }
104 
105  public function getRows(
106  DataRowBuilder $row_builder,
107  array $visible_column_ids,
108  Range $range,
109  Order $order,
110  ?array $filter_data,
111  ?array $additional_parameters
112  ): Generator {
113  $records = $this->getRecords();
114 
115  if ($order) {
116  [$order_field, $order_direction] = $order->join(
117  [],
118  fn($ret, $key, $value) => [$key, $value]
119  );
120 
121  usort($records, static function (array $left, array $right) use ($order_field): int {
122  if (\in_array($order_field, ['container', 'title', 'type'], true)) {
123  if (\in_array($order_field, ['container', 'title'], true)) {
124  $order_field .= '_sortable';
125  }
126 
127  return \ilStr::strCmp(
128  $left[$order_field],
129  $right[$order_field]
130  );
131  }
132 
133  if ($order_field === 'active') {
134  return $right[$order_field] <=> $left[$order_field];
135  }
136 
137  return $left[$order_field] <=> $right[$order_field];
138  });
139 
140  if ($order_direction === Order::DESC) {
141  $records = array_reverse($records);
142  }
143  }
144 
145  if ($range) {
146  $records = \array_slice($records, $range->getStart(), $range->getLength());
147  }
148 
149  $identifications = [];
150  foreach ($records as $record) {
151  if (isset($record[self::RECORD_RAW]['image_rid']) && $record[self::RECORD_RAW]['image_rid'] !== '') {
152  $identifications[] = $record[self::RECORD_RAW]['image_rid'];
153  }
154  }
155 
156  $this->irss->preload($identifications);
157 
158  $modal_container = new ModalBuilder();
159  $container_deleted_title_part = '<span class="il_ItemAlertProperty">' . $this->lng->txt('deleted') . '</span>';
160  foreach ($records as $record) {
161  yield $row_builder->buildDataRow(
162  (string) $record['id'],
163  $this->enrichRecord($modal_container, $container_deleted_title_part, $record)
164  );
165  }
166  }
167 
168  public function getTotalRowCount(
169  ?array $filter_data,
170  ?array $additional_parameters
171  ): ?int {
172  return \count($this->getRecords());
173  }
174 
210  private function enrichRecord(
211  ModalBuilder $modal_builder,
212  string $container_deleted_title_part,
213  array $record
214  ): array {
215  $badge_item = $record[self::RECORD_RAW];
216 
217  $badge = new ilBadge(0);
218  $badge->setId($badge_item['id']);
219  $badge->setImageRid($badge_item['image_rid']);
220  $badge->setImage($badge_item['image']);
221 
222  $images = [
223  'rendered' => null,
224  'large' => null,
225  ];
226  $image_src = $this->badge_image_service->getImageFromResourceId($badge);
227  if ($image_src !== '') {
228  $images['rendered'] = $this->renderer->render(
229  $this->factory->image()->responsive(
230  $image_src,
231  $badge_item['title']
232  )
233  );
234 
235  $image_src_large = $this->badge_image_service->getImageFromResourceId(
236  $badge,
238  );
239  if ($image_src_large !== '') {
240  $images['large'] = $this->factory->image()->responsive(
241  $image_src_large,
242  $badge_item['title']
243  );
244  }
245  }
246 
247  $container_title_parts = [
248  'icon' => $this->renderer->render(
249  $this->factory->symbol()->icon()->custom(
250  ilObject::_getIcon($badge_item['parent_id'], 'big', $badge_item['parent_type'] ?? ''),
251  $this->lng->txt('obj_' . ($badge_item['parent_type'] ?? ''))
252  )
253  ),
254  'title' => $badge_item['parent_title'] ?? '',
255  ];
256 
257  $sortable_container_title_parts = [
258  'title' => $badge_item['parent_title'] ?? ''
259  ];
260  if ($badge_item['deleted']) {
261  $container_title_parts['suffix'] = $container_deleted_title_part;
262  $sortable_container_title_parts['suffix'] = $container_deleted_title_part;
263  } else {
264  if (isset($this->has_access_by_parent_cache[$badge_item['parent_id']])) {
265  $has_access = $this->has_access_by_parent_cache[$badge_item['parent_id']] ?? false;
266  $ref_id = $this->first_ref_id_for_parent_cache[$badge_item['parent_id']] ?? null;
267  } else {
268  $ref_ids = ilObject::_getAllReferences($badge_item['parent_id']);
269  $ref_id = array_shift($ref_ids);
270  $this->first_ref_id_for_parent_cache[$badge_item['parent_id']] = $ref_id;
271  $has_access = $ref_id && $this->access->checkAccess('read', '', $ref_id);
272  $this->has_access_by_parent_cache[$badge_item['parent_id']] = $has_access;
273  }
274 
275  if ($has_access) {
276  $container_title_parts['title'] = $this->renderer->render(
277  new Standard(
278  $container_title_parts['title'],
279  (string) new URI(
280  ilLink::_getLink(
281  $ref_id,
282  $badge_item['parent_type'] ?? ''
283  )
284  )
285  )
286  );
287  } else {
288  $container_title_parts['suffix'] = $container_deleted_title_part;
289  $sortable_container_title_parts['suffix'] = $container_deleted_title_part;
290  }
291  }
292 
293  $modal = $modal_builder->constructModal(
294  $images['large'],
295  $badge_item['title'],
296  [
297  'active' => $badge_item['active'] ? $this->lng->txt('yes') : $this->lng->txt('no'),
298  'type' => $record['type'],
299  'container' => implode(' ', \array_slice($container_title_parts, 1, null, true)),
300  ]
301  );
302 
303  return [
304  'id' => $badge_item['id'],
305  'active' => (bool) $badge_item['active'],
306  'type' => $record['type'],
307  'image' => $images['rendered'] ? ($modal_builder->renderShyButton(
308  $images['rendered'],
309  $modal
310  ) . ' ') : '',
311  'title' => implode('', [
312  $modal_builder->renderShyButton($badge_item['title'], $modal),
313  $modal_builder->renderModal($modal)
314  ]),
315  'title_sortable' => $badge_item['title'],
316  'container' => implode(' ', $container_title_parts),
317  'container_sortable' => implode(' ', $sortable_container_title_parts),
318  ];
319  }
320 
346  private function getRecords(): array
347  {
348  if ($this->cached_records !== null) {
349  return $this->cached_records;
350  }
351 
352  // A filter is not implemented, yet
353  $filter = [
354  'type' => '',
355  'title' => '',
356  'object' => ''
357  ];
358 
359  $types = ilBadgeHandler::getInstance()->getAvailableTypes(false);
360  $raw_records = ilBadge::getObjectInstances($filter);
361 
362  $sortable_rows = array_map(function (array $badge_item) use ($types) {
363  return [
364  'id' => $badge_item['id'],
365  'active' => (bool) $badge_item['active'],
366  'type' => ilBadge::getExtendedTypeCaption($types[$badge_item['type_id']]),
367  'title_sortable' => $badge_item['title'],
368  'container_sortable' => ($badge_item['parent_title'] ?? '') .
369  ($badge_item['deleted'] ? ' ' . $this->lng->txt('deleted') : ''),
370  self::RECORD_RAW => $badge_item
371  ];
372  }, $raw_records);
373 
374  $this->cached_records = $sortable_rows;
375 
376  return $this->cached_records;
377  }
378 
382  public function getColumns(): array
383  {
384  return [
385  'image' => $this->factory->table()->column()->text($this->lng->txt('image'))->withIsSortable(false),
386  'title' => $this->factory->table()->column()->text($this->lng->txt('title')),
387  'type' => $this->factory->table()->column()->text($this->lng->txt('type')),
388  'container' => $this->factory->table()->column()->text($this->lng->txt('object')),
389  'active' => $this->factory->table()->column()->boolean(
390  $this->lng->txt('active'),
391  $this->lng->txt('yes'),
392  $this->lng->txt('no')
393  )->withOrderingLabels(
394  $this->lng->txt('badge_sort_active_badges_first'),
395  $this->lng->txt('badge_sort_active_badges_last')
396  )
397  ];
398  }
399 
403  private function getActions(
404  URLBuilder $url_builder,
405  URLBuilderToken $action_parameter_token,
406  URLBuilderToken $row_id_token
407  ): array {
408  return $this->has_write ? [
409  'obj_badge_activate' => $this->factory->table()->action()->multi(
410  $this->lng->txt('activate'),
411  $url_builder->withParameter($action_parameter_token, 'obj_badge_activate'),
412  $row_id_token
413  ),
414  'obj_badge_deactivate' =>
415  $this->factory->table()->action()->multi(
416  $this->lng->txt('deactivate'),
417  $url_builder->withParameter($action_parameter_token, 'obj_badge_deactivate'),
418  $row_id_token
419  ),
420  'obj_badge_delete' =>
421  $this->factory->table()->action()->multi(
422  $this->lng->txt('delete'),
423  $url_builder->withParameter($action_parameter_token, 'obj_badge_delete'),
424  $row_id_token
425  ),
426  'obj_badge_show_users' =>
427  $this->factory->table()->action()->single(
428  $this->lng->txt('user'),
429  $url_builder->withParameter($action_parameter_token, 'obj_badge_show_users'),
430  $row_id_token
431  )
432  ] : [];
433  }
434 
435  public function renderTable(string $url): void
436  {
437  $df = new \ILIAS\Data\Factory();
438 
439  $table_uri = $df->uri($url);
440  $url_builder = new URLBuilder($table_uri);
441  $query_params_namespace = ['tid'];
442 
443  [$url_builder, $action_parameter_token, $row_id_token] = $url_builder->acquireParameters(
444  $query_params_namespace,
445  'table_action',
446  'id',
447  );
448 
449  $table = $this->factory
450  ->table()
451  ->data($this, $this->lng->txt('badge_object_badges'), $this->getColumns())
452  ->withId(self::class)
453  ->withOrder(new Order('title', Order::ASC))
454  ->withActions($this->getActions($url_builder, $action_parameter_token, $row_id_token))
455  ->withRequest($this->request);
456 
457  $out = [$table];
458 
459  $query = $this->http->wrapper()->query();
460  if ($query->has($action_parameter_token->getName())) {
461  $action = $query->retrieve($action_parameter_token->getName(), $this->refinery->kindlyTo()->string());
462  $ids = $query->retrieve($row_id_token->getName(), $this->refinery->custom()->transformation(fn($v) => $v));
463 
464  if ($action === 'obj_badge_delete') {
465  $items = [];
466  if (\is_array($ids) && \count($ids) > 0) {
467  if ($ids === ['ALL_OBJECTS']) {
468  $filter = [
469  'type' => '',
470  'title' => '',
471  'object' => ''
472  ];
473  $ids = [];
474  foreach (ilBadge::getObjectInstances($filter) as $badge_item) {
475  $ids[] = $badge_item['id'];
476  }
477  }
478 
479  foreach ($ids as $id) {
480  $badge = new ilBadge((int) $id);
481  $items[] = $this->factory->modal()->interruptiveItem()->keyValue(
482  (string) $id,
483  (string) $badge->getId(),
484  $badge->getTitle()
485  );
486  }
487 
488  $this->http->saveResponse(
489  $this->http
490  ->response()
491  ->withBody(
492  Streams::ofString($this->renderer->renderAsync([
493  $this->factory->modal()->interruptive(
494  $this->lng->txt('badge_deletion'),
495  $this->lng->txt('badge_deletion_confirmation'),
496  '#'
497  )->withAffectedItems($items)
498  ]))
499  )
500  );
501  $this->http->sendResponse();
502  $this->http->close();
503  }
504  }
505  }
506 
507  $this->tpl->setContent($this->renderer->render($out));
508  }
509 }
constructModal(?Image $badge_image, string $badge_title, array $badge_properties=[])
getRows(DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, ?array $filter_data, ?array $additional_parameters)
join($init, callable $fn)
Definition: Order.php:75
static _getIcon(int $obj_id=0, string $size="big", string $type="", bool $offline=false)
Get icon for repository item.
__construct(ilObjBadgeAdministrationGUI $parentObj, protected bool $has_write=false)
factory()
static _getAllReferences(int $id)
get all reference ids for object ID
renderModal(Modal $modal)
renderer()
$url
Definition: shib_logout.php:68
getActions(URLBuilder $url_builder, URLBuilderToken $action_parameter_token, URLBuilderToken $row_id_token)
readonly ServerRequestInterface RequestInterface $request
enrichRecord(ModalBuilder $modal_builder, string $container_deleted_title_part, array $record)
Both the subject and the direction need to be specified when expressing an order. ...
Definition: Order.php:28
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
getTotalRowCount(?array $filter_data, ?array $additional_parameters)
Mainly for the purpose of pagination-support, it is important to know about the total number of recor...
$ref_id
Definition: ltiauth.php:65
static http()
Fetches the global http state from ILIAS.
readonly ilObjBadgeAdministrationGUI $parent_obj
static getExtendedTypeCaption(ilBadgeType $a_type)
$out
Definition: buildRTE.php:24
global $DIC
Definition: shib_login.php:26
Builds data types.
Definition: Factory.php:35
readonly ILIAS ResourceStorage Services $irss
readonly ilGlobalTemplateInterface $tpl
readonly ILIAS Refinery Factory $refinery
static ofString(string $string)
Creates a new stream with an initial value.
Definition: Streams.php:41
withParameter(URLBuilderToken $token, string|array $value)
Change an acquired parameter&#39;s value if the supplied token is valid.
Definition: URLBuilder.php:166
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static getObjectInstances(?array $filter=null)
renderShyButton(string $label, Modal $modal)
URLBuilder.
Definition: URLBuilder.php:40
const DESC
Definition: Order.php:31
A simple class to express a naive range of whole positive numbers.
Definition: Range.php:28