From ede66dc4d92c4440743d3f945b59d25c152adffa Mon Sep 17 00:00:00 2001 From: mjansen Date: Tue, 17 Dec 2024 14:28:18 +0100 Subject: [PATCH] Badge: Fix handling of deleted objects See: https://mantis.ilias.de/view.php?id=43259 (cherry picked from commit a2e5c16ec44d8194f9115e21524e519ea331f772) --- .../ILIAS/Badge/classes/class.ilBadge.php | 67 ++++--- .../Badge/classes/class.ilBadgeImage.php | 4 +- .../class.ilObjBadgeAdministrationGUI.php | 4 +- .../classes/class.ilObjectBadgeTableGUI.php | 169 ++++++++++-------- 4 files changed, 138 insertions(+), 106 deletions(-) diff --git a/components/ILIAS/Badge/classes/class.ilBadge.php b/components/ILIAS/Badge/classes/class.ilBadge.php index 1d80d957009d..54c83c23e218 100755 --- a/components/ILIAS/Badge/classes/class.ilBadge.php +++ b/components/ILIAS/Badge/classes/class.ilBadge.php @@ -170,57 +170,68 @@ public function copy( } /** - * @param array|null $a_filter - * @return array[] + * @param array{type: string, title: string, object: string}|null $filter + * @return list */ public static function getObjectInstances( - array $a_filter = null + ?array $filter = null ): array { global $DIC; $ilDB = $DIC->database(); - $res = $raw = []; + $rows = []; - $where = ""; + $where = ''; - if ($a_filter["type"]) { - $where .= " AND bb.type_id = " . $ilDB->quote($a_filter["type"], "text"); + if ($filter['type']) { + $where .= ' AND bb.type_id = ' . $ilDB->quote($filter['type'], ilDBConstants::T_TEXT); } - if ($a_filter["title"]) { - $where .= " AND " . $ilDB->like("bb.title", "text", "%" . $a_filter["title"] . "%"); + if ($filter['title']) { + $where .= ' AND ' . $ilDB->like('bb.title', ilDBConstants::T_TEXT, '%' . $filter['title'] . '%'); } - if ($a_filter["object"]) { - $where .= " AND " . $ilDB->like("od.title", "text", "%" . $a_filter["object"] . "%"); + if ($filter['object']) { + $where .= ' AND ' . $ilDB->like('od.title', ilDBConstants::T_TEXT, '%' . $filter['object'] . '%'); } - $set = $ilDB->query("SELECT bb.*, od.title parent_title, od.type parent_type" . - " FROM badge_badge bb" . - " JOIN object_data od ON (bb.parent_id = od.obj_id)" . - " WHERE od.type <> " . $ilDB->quote("bdga", "text") . + $set = $ilDB->query('SELECT bb.*, od.title parent_title, od.type parent_type' . + ' FROM badge_badge bb' . + ' INNER JOIN object_data od ON bb.parent_id = od.obj_id' . + ' WHERE od.type != ' . $ilDB->quote('bdga', ilDBConstants::T_TEXT) . $where); while ($row = $ilDB->fetchAssoc($set)) { - $raw[] = $row; + $row['deleted'] = false; + $rows[] = $row; } - $set = $ilDB->query("SELECT bb.*, od.title parent_title, od.type parent_type" . - " FROM badge_badge bb" . - " JOIN object_data_del od ON (bb.parent_id = od.obj_id)" . - " WHERE od.type <> " . $ilDB->quote("bdga", "text") . + $set = $ilDB->query('SELECT bb.*, od.title parent_title, od.type parent_type' . + ' FROM badge_badge bb' . + ' INNER JOIN object_data_del od ON bb.parent_id = od.obj_id' . + ' WHERE od.type != ' . $ilDB->quote('bdga', ilDBConstants::T_TEXT) . $where); while ($row = $ilDB->fetchAssoc($set)) { - $row["deleted"] = true; - $raw[] = $row; - } - - foreach ($raw as $row) { - $res[] = $row; + $row['deleted'] = true; + $rows[] = $row; } - return $res; + return $rows; } - // // setter/getter // diff --git a/components/ILIAS/Badge/classes/class.ilBadgeImage.php b/components/ILIAS/Badge/classes/class.ilBadgeImage.php index ffa74ded56b9..c8d97e2b4be3 100644 --- a/components/ILIAS/Badge/classes/class.ilBadgeImage.php +++ b/components/ILIAS/Badge/classes/class.ilBadgeImage.php @@ -68,11 +68,11 @@ public function getImageFromResourceId( if ($identification !== null) { $flavour = $this->resource_storage->flavours()->get($identification, new \ilBadgePictureDefinition()); $urls = $this->resource_storage->consume()->flavourUrls($flavour)->getURLsAsArray(false); - if (count($urls) === self::IMAGE_URL_COUNT && isset($urls[$size])) { + if (\count($urls) === self::IMAGE_URL_COUNT && isset($urls[$size])) { $image_src = $urls[$size]; } } - } elseif (is_array($badge) && isset($badge['image'])) { + } elseif (\is_array($badge) && isset($badge['image'])) { $image_src = $badge['image']; } elseif ($badge instanceof ilBadge) { $image_src = $badge->getImage(); diff --git a/components/ILIAS/Badge/classes/class.ilObjBadgeAdministrationGUI.php b/components/ILIAS/Badge/classes/class.ilObjBadgeAdministrationGUI.php index 6cabedd0ba42..de259969ea1d 100755 --- a/components/ILIAS/Badge/classes/class.ilObjBadgeAdministrationGUI.php +++ b/components/ILIAS/Badge/classes/class.ilObjBadgeAdministrationGUI.php @@ -710,9 +710,7 @@ protected function toggleObjectBadges(bool $a_status): void $filter = ['type' => '' , 'title' => '', 'object' => '']; $badge_ids = []; foreach (ilBadge::getObjectInstances($filter) as $badge_item) { - if (isset($badge_item['id'])) { - $badge_ids[] = $badge_item['id']; - } + $badge_ids[] = $badge_item['id']; } foreach ($badge_ids as $badge_id) { $badge = new ilBadge($badge_id); diff --git a/components/ILIAS/Badge/classes/class.ilObjectBadgeTableGUI.php b/components/ILIAS/Badge/classes/class.ilObjectBadgeTableGUI.php index 133e732f2644..e9e21326fdcd 100755 --- a/components/ILIAS/Badge/classes/class.ilObjectBadgeTableGUI.php +++ b/components/ILIAS/Badge/classes/class.ilObjectBadgeTableGUI.php @@ -55,7 +55,6 @@ class ilObjectBadgeTableGUI private readonly ilLanguage $lng; private readonly ilGlobalTemplateInterface $tpl; private ilObjBadgeAdministrationGUI $parent_obj; - private ?bool $user_has_write_permission = null; private ilAccess $access; public function __construct(ilObjBadgeAdministrationGUI $parentObj) @@ -74,20 +73,6 @@ public function __construct(ilObjBadgeAdministrationGUI $parentObj) } - private function userHasWritePermission(int $parent_id): bool - { - if ($this->user_has_write_permission === null) { - $parent_ref_id = ilObject::_getAllReferences($parent_id); - if (\count($parent_ref_id) > 0) { - $parent_ref_id = array_pop($parent_ref_id); - } - $this->user_has_write_permission = $this->access->checkAccess('write', '', $parent_ref_id); - } - - return $this->user_has_write_permission; - } - - private function buildDataRetrievalObject( Factory $f, Renderer $r, @@ -100,7 +85,6 @@ private function buildDataRetrievalObject( private \ilCtrlInterface $ctrl; private ilLanguage $lng; private \ilAccessHandler $access; - private ?bool $user_has_write_permission = null; public function __construct( private Factory $ui_factory, @@ -148,93 +132,119 @@ public function getTotalRowCount( * id: int, * active: bool, * type: string, - * image_rid: string, + * image: string, + * image_sortable: string, * title: string, + * title_sortable: string, * container: string, - * container_icon: string, - * container_url: string, - * container_deleted: bool, - * container_id: int, - * container_type: string}> + * container_sortable: string + * }> */ private function getRecords(Range $range = null, Order $order = null): array { - $data = []; - $image_html = ''; - $badge_img_large = ''; - $container_icon = ''; + $container_deleted_title_part = '' . $this->lng->txt('deleted') . ''; $modal_container = new ModalBuilder(); + // A filter is not implemented, yet + $filter = [ + 'type' => '', + 'title' => '', + 'object' => '' + ]; + $types = ilBadgeHandler::getInstance()->getAvailableTypes(false); - $filter = ['type' => '', 'title' => '', 'object' => '']; + $rows = []; foreach (ilBadge::getObjectInstances($filter) as $badge_item) { $type_caption = ilBadge::getExtendedTypeCaption($types[$badge_item['type_id']]); - $badge_rid = $badge_item['image_rid']; - $image_src = $this->badge_image_service->getImageFromResourceId($badge_item, $badge_rid); - if ($badge_rid) { - $badge_template_image = $image_src; - if ($badge_template_image !== '') { - $badge_img = $this->factory->image()->responsive( - $badge_template_image, + + $images = [ + 'rendered' => '', + 'rendered_large' => '', + ]; + $image_src = $this->badge_image_service->getImageFromResourceId( + $badge_item, + $badge_item['image_rid'] + ); + if ($image_src !== '') { + $images['rendered'] = $this->renderer->render( + $this->factory->image()->responsive( + $image_src, $badge_item['title'] - ); - $image_html = $this->renderer->render($badge_img); - } + ) + ); + $image_html_large = $this->badge_image_service->getImageFromResourceId( $badge_item, - $badge_rid, + $badge_item['image_rid'], ilBadgeImage::IMAGE_SIZE_XL ); if ($image_html_large !== '') { - $badge_img_large = $this->ui_factory->image()->responsive( + $images['rendered_large'] = $this->ui_factory->image()->responsive( $image_html_large, $badge_item['title'] ); } } - $ref_ids = ilObject::_getAllReferences($badge_item['parent_id']); - $ref_id = array_shift($ref_ids); + $sortable_container_title_parts = [ + 'title' => $badge_item['parent_title'] ?? '' + ]; + $container_title_parts = [ + 'icon' => $this->ui_renderer->render($this->ui_factory->symbol()->icon()->custom( + ilObject::_getIcon($badge_item['parent_id'], 'big', $badge_item['parent_type'] ?? ''), + $this->lng->txt('obj_' . ($badge_item['parent_type'] ?? '')) + )), + 'title' => $sortable_container_title_parts['title'], + ]; - $container_url_link = ''; - if ($this->access->checkAccess('read', '', $ref_id)) { - $container_url = ilLink::_getLink($ref_id); - $container_url_link = $this->renderer->render( - new Standard($badge_item['parent_title'], (string) new URI($container_url)) - ); - $container_icon = '' . $this->lng->txt('obj_' . $badge_item['parent_type']) .
-                            ' '; + if ($badge_item['deleted']) { + $container_title_parts['suffix'] = $container_deleted_title_part; + $sortable_container_title_parts['suffix'] = $container_deleted_title_part; + } else { + $ref_ids = ilObject::_getAllReferences($badge_item['parent_id']); + $ref_id = array_shift($ref_ids); + if ($ref_id && $this->access->checkAccess('read', '', $ref_id)) { + $container_title_parts['title'] = $this->renderer->render( + new Standard( + $container_title_parts['title'], + (string) new URI(ilLink::_getLink($ref_id)) + ) + ); + } else { + $container_title_parts['suffix'] = $container_deleted_title_part; + $sortable_container_title_parts['suffix'] = $container_deleted_title_part; + } } $badge_information = [ - 'active' => ($badge_item['active'] ? $this->lng->txt('yes') : $this->lng->txt('no')), + 'active' => $badge_item['active'] ? $this->lng->txt('yes') : $this->lng->txt('no'), 'type' => $type_caption, - 'container' => $container_url_link ?: $badge_item['parent_title'], + 'container' => implode(' ', \array_slice($container_title_parts, 1, null, true)), ]; $modal = $modal_container->constructModal( - $badge_img_large ?: null, + $images['rendered_large'] ?: null, $badge_item['title'], $badge_information ); - $data[] = [ - 'id' => (int) $badge_item['id'], + $rows[] = [ + 'id' => $badge_item['id'], 'active' => (bool) $badge_item['active'], 'type' => $type_caption, - 'image_rid' => $modal_container->renderShyButton( - $image_html, + 'image' => $images['rendered'] ? ($modal_container->renderShyButton( + $images['rendered'], $modal - ) . ' ' . $modal_container->renderModal($modal), - 'title' => $modal_container->renderShyButton($badge_item['title'], $modal), - 'container' => $badge_item['parent_title'], - 'container_icon' => $container_icon, - 'container_url' => $container_icon . $container_url_link ?: '', - 'container_deleted' => ($badge_item['deleted'] ?? false), - 'container_id' => (int) $badge_item['parent_id'], - 'container_type' => $badge_item['parent_type'], + ) . ' ') : '', + // Just an boolean-like indicator for sorting + 'image_sortable' => $images['rendered'] ? 'A' : 'Z', + 'title' => implode('', [ + $modal_container->renderShyButton($badge_item['title'], $modal), + $modal_container->renderModal($modal) + ]), + 'title_sortable' => $badge_item['title'], + 'container' => implode(' ', $container_title_parts), + 'container_sortable' => implode(' ', $sortable_container_title_parts), ]; } @@ -243,21 +253,33 @@ private function getRecords(Range $range = null, Order $order = null): array [], fn($ret, $key, $value) => [$key, $value] ); - usort($data, static fn($a, $b) => $a[$order_field] <=> $b[$order_field]); + usort( + $rows, + static function (array $left, array $right) use ($order_field): int { + if (\in_array($order_field, ['image', 'container', 'title'], true)) { + return \ilStr::strCmp( + $left[$order_field . '_sortable'], + $right[$order_field . '_sortable'] + ); + } + + return $left[$order_field] <=> $right[$order_field]; + } + ); if ($order_field === 'active') { if ($order_direction === 'ASC') { - $data = array_reverse($data); + $rows = array_reverse($rows); } } elseif ($order_direction === 'DESC') { - $data = array_reverse($data); + $rows = array_reverse($rows); } } if ($range) { - $data = \array_slice($data, $range->getStart(), $range->getLength()); + $rows = \array_slice($rows, $range->getStart(), $range->getLength()); } - return $data; + return $rows; } }; } @@ -309,10 +331,10 @@ public function renderTable(): void $df = new \ILIAS\Data\Factory(); $columns = [ - 'image_rid' => $f->table()->column()->text($this->lng->txt('image')), + 'image' => $f->table()->column()->text($this->lng->txt('image')), 'title' => $f->table()->column()->text($this->lng->txt('title')), 'type' => $f->table()->column()->text($this->lng->txt('type')), - 'container_url' => $f->table()->column()->text($this->lng->txt('container')), + 'container' => $f->table()->column()->text($this->lng->txt('container')), 'active' => $f->table()->column()->boolean( $this->lng->txt('active'), $this->lng->txt('yes'), @@ -337,6 +359,7 @@ public function renderTable(): void $table = $f->table() ->data($this->lng->txt('badge_object_badges'), $columns, $data_retrieval) + ->withOrder(new Order('title', Order::ASC)) ->withActions($actions) ->withRequest($request);