ILIAS  trunk Revision v13.0_alpha-52-g21c366bbdd4
BookableItemTable.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use Generator;
36use ILIAS\Refinery\Factory as Refinery;
41use ILIAS\UI\Factory as UIFactory;
42use ILIAS\UI\Renderer as UIRenderer;
44use ilLanguage;
46use ilObjUser;
47use ilUIService;
48use ilUtil;
52use DateTimeImmutable;
53
54abstract class BookableItemTable implements Table
55{
57
58 public const string ROW_ID_PARAMETER = 'bookable_item_row';
59
60 public const string ACTION_PARAMETER = 'action';
61
62 public const string ACTION_TYPE_PARAMETER = 'action_type';
63
67 private array $reservation_cache = [];
68
70
71 public function __construct(
72 protected readonly UIFactory $ui_factory,
73 protected readonly UIRenderer $ui_renderer,
74 protected readonly ilLanguage $lng,
75 protected readonly HttpService $http,
76 protected readonly ilUIService $ui_service,
77 protected readonly ilCtrlInterface $ctrl,
78 protected readonly ilGlobalTemplateInterface $tpl,
79 protected readonly Refinery $refinery,
80 protected readonly AccessManager $access,
81 protected readonly ilObjBookingPool $pool,
82 protected readonly BookingProcessManager $process_manager,
83 protected readonly Settings $settings,
84 protected readonly ilObjUser $user,
85 protected readonly int $ref_id,
86 protected readonly bool $active_management,
87 protected readonly int $booking_context_obj_id,
88 ) {
89 }
90
91 public function getTableId(): string
92 {
93 return static::ID;
94 }
95
99 public function getComponents(URLBuilder $url_builder): array
100 {
101 $components = [];
102
103 if ($this->pool->getScheduleType() === ilObjBookingPool::TYPE_NO_SCHEDULE) {
105 $this->user->getId(),
106 $this->pool->getId()
107 );
108
109 if ($this->pool->getOverallLimit() <= $booking_count) {
110 $components[] = $this->ui_factory->messageBox()->info($this->lng->txt('book_overall_limit_warning'));
111 }
112 }
113
114 $components[] = $filter = $this->getFilterComponent();
115 $filter_data = $this->ui_service->filter()->getData($filter);
116
117 $components[] = $this->ui_factory->table()->data(
118 $this,
119 $this->lng->txt('book_booking_objects'),
120 $this->getColumns()
121 )
122 ->withActions($this->getTableActions()->getEnabledActions(...$this->acquireParameters($url_builder)))
123 ->withRequest($this->http->getRequest())
124 ->withId($this->getTableId())
125 ->withFilter($filter_data)
126 ->withOrder(new Order($this instanceof BookableItemWithScheduleTable ? 'date_time' : 'title', Order::ASC));
127
128 return array_filter($components);
129 }
130
131 public function getTotalRowCount(
132 mixed $additional_viewcontrol_data,
133 mixed $filter_data,
134 mixed $additional_parameters
135 ): ?int {
136 return count($this->loadRecords($filter_data));
137 }
138
139 public function getRows(
140 DataRowBuilder $row_builder,
141 array $visible_column_ids,
143 Order $order,
144 mixed $additional_viewcontrol_data,
145 mixed $filter_data,
146 mixed $additional_parameters
147 ): Generator {
148 $records = $this->limitRecords($range, $this->sortRecords($order, $this->loadRecords($filter_data)));
149
150 foreach ($records as $record) {
151 yield $this->getTableActions()->onDataRow(
152 $row_builder->buildDataRow((string) $record['row_id'], $this->buildRowCells($record)),
153 $record
154 );
155 }
156 }
157
161 abstract protected function getColumns(): array;
162
166 abstract protected function getFilterInputs(): array;
167
171 abstract protected function loadRecords(mixed $filter_data): array;
172
176 abstract protected function buildRowCells(array $record): array;
177
182 protected function sortRecords(Order $order, array $records): array
183 {
184 $order_data = $order->get();
185 if ($order_data === []) {
186 return $records;
187 }
188
189 foreach ($order_data as $key => $direction) {
190 $order_direction = $direction === Order::DESC ? -1 : 1;
191 $callable = $this->getSortCallable($key, $order_direction);
192
193 if ($callable === null) {
194 continue;
195 }
196
197 usort($records, $callable);
198 }
199
200 return $records;
201 }
202
203 protected function getSortCallable(string $key, int $direction): ?callable
204 {
205 return match ($key) {
206 'availability' => static fn(array $a, array $b): int
207 => ((int) $a['available'] <=> (int) $b['available']) * $direction,
208 'title' => static fn(array $a, array $b): int
209 => strcasecmp((string) $a['title'], (string) $b['title']) * $direction,
210 'description' => static fn(array $a, array $b): int
211 => strcasecmp((string) $a['description'], (string) $b['description']) * $direction,
212 default => null,
213 };
214 }
215
220 protected function limitRecords(Range $range, array $records): array
221 {
222 return array_slice($records, $range->getStart(), $range->getLength());
223 }
224
225 protected function getFilterComponent(): FilterComponent
226 {
227 $filter_inputs = $this->getFilterInputs();
228
229 $filter_inputs = $this->presetFilterInputs($filter_inputs);
230
231 return $this->ui_service->filter()->standard(
232 "bookable_item_filter_{$this->pool->getId()}",
233 $this->ctrl->getLinkTargetByClass(ilBookingObjectGUI::class),
234 $filter_inputs,
235 array_fill(0, count($filter_inputs), true),
236 true,
237 true
238 );
239 }
240
241 private function presetFilterInputs(array $filter_inputs): array
242 {
243 if ($this->settings->getReservationPeriod() > 0) {
244 $filter_inputs['period'] = $filter_inputs['period']->withValue(
245 [
246 new DateTimeImmutable('today 00:00:00'),
247 new DateTimeImmutable("today +{$this->settings->getReservationPeriod()} days 23:59:59")
248 ]
249 );
250 }
251
252 return $filter_inputs;
253 }
254
258 protected function acquireParameters(URLBuilder $url_builder): array
259 {
260 return $url_builder->acquireParameters(
261 [$this->getTableId()],
262 self::ROW_ID_PARAMETER,
263 self::ACTION_PARAMETER,
264 self::ACTION_TYPE_PARAMETER
265 );
266 }
267
268 protected function getTableActions(): TableActions
269 {
270 return $this->table_actions ??= (new BookableItemTableActionsFactory(
271 $this->ctrl,
272 $this->lng,
273 $this->tpl,
274 $this->ui_factory,
275 $this->ui_renderer,
276 $this->refinery,
277 $this->http,
278 $this->access,
279 $this->pool,
280 $this->process_manager,
281 $this->user,
282 $this->ref_id,
283 $this->active_management,
284 $this->booking_context_obj_id,
285 array_column($this->loadRecords([]), null, 'row_id'),
286 ))->getTableActions();
287 }
288
292 protected function loadFilteredBookingObjects(
293 ?string $title_filter,
294 ?string $description_filter,
295 ?array $object_ids_filter
296 ): array {
297 $items = ilBookingObject::getList($this->pool->getId());
298 $title_filter = mb_strtolower($title_filter ?? '') ?: null;
299 $description_filter = mb_strtolower($description_filter ?? '') ?: null;
300 $object_ids_filter = $object_ids_filter ?: null;
301
302 $filtered = [];
303 foreach ($items as $item) {
304 $object_id = (int) $item['booking_object_id'];
305
306 if ($object_ids_filter !== null && !in_array($object_id, $object_ids_filter, true)) {
307 continue;
308 }
309
310 if ($title_filter !== null && !str_contains(mb_strtolower((string) $item['title']), $title_filter)) {
311 continue;
312 }
313
314 if ($description_filter !== null && !str_contains(mb_strtolower((string) ($item['description'] ?? '')), $description_filter)) {
315 continue;
316 }
317
318 $filtered[] = $item;
319 }
320
321 return $filtered;
322 }
323
327 protected function getReservationsForObject(int $booking_object_id): array
328 {
329 if (isset($this->reservation_cache[$booking_object_id])) {
330 return $this->reservation_cache[$booking_object_id];
331 }
332
333 $list = ilBookingReservation::getList([$booking_object_id], 1000, 0, []);
334 $this->reservation_cache[$booking_object_id] = array_values(array_map(
335 static fn(array $row): array => [
336 'user_id' => (int) $row['user_id'],
337 'status' => isset($row['status']) ? (int) $row['status'] : null,
338 'date_from' => (int) $row['date_from'],
339 'date_to' => (int) $row['date_to'],
340 ],
341 $list['data'] ?? []
342 ));
343
344 return $this->reservation_cache[$booking_object_id];
345 }
346
347 protected function buildAvailabilityCell(int $available, int $total): string
348 {
349 $icon = $this->ui_factory->symbol()->icon()->custom(
350 ilUtil::getImagePath($available > 0 ? 'standard/icon_ok.svg' : 'standard/icon_not_ok.svg'),
351 $this->lng->txt($available > 0 ? 'book_book' : 'book_no_objects')
352 );
353 return "{$this->ui_renderer->render($icon)} ({$available} / {$total})";
354 }
355}
$settings
Definition: index.php:44
$components
loadFilteredBookingObjects(?string $title_filter, ?string $description_filter, ?array $object_ids_filter)
__construct(protected readonly UIFactory $ui_factory, protected readonly UIRenderer $ui_renderer, protected readonly ilLanguage $lng, protected readonly HttpService $http, protected readonly ilUIService $ui_service, protected readonly ilCtrlInterface $ctrl, protected readonly ilGlobalTemplateInterface $tpl, protected readonly Refinery $refinery, protected readonly AccessManager $access, protected readonly ilObjBookingPool $pool, protected readonly BookingProcessManager $process_manager, protected readonly Settings $settings, protected readonly ilObjUser $user, protected readonly int $ref_id, protected readonly bool $active_management, protected readonly int $booking_context_obj_id,)
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....
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...
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
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
A simple class to express a naive range of whole positive numbers.
Definition: Range.php:29
acquireParameters(array $namespace, string ... $names)
Definition: URLBuilder.php:138
@ilCtrl_Calls ilBookingObjectGUI: ilPropertyFormGUI, ilBookingProcessWithScheduleGUI,...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isBookingPoolLimitReachedByUser(int $a_user_id, int $a_pool_id)
static getList(array $a_object_ids, int $a_limit=10, int $a_offset=0, array $filter=[])
List all reservations.
language handling
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
User class.
Filter service.
Util class various functions, usage as namespace.
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
return['3gp', '7z', 'ai', 'aif', 'aifc', 'aiff', 'au', 'arw', 'avi', 'backup', 'bak', 'bas', 'bpmn', 'bpmn2', 'bmp', 'bib', 'bibtex', 'bz', 'bz2', 'c', 'c++', 'cc', 'cct', 'cdf', 'cer', 'class', 'cls', 'conf', 'cpp', 'crt', 'crs', 'crw', 'cr2', 'css', 'cst', 'csv', 'cur', 'db', 'dcr', 'des', 'dng', 'doc', 'docx', 'dot', 'dotx', 'dtd', 'dvi', 'el', 'eps', 'epub', 'f', 'f77', 'f90', 'flv', 'for', 'g3', 'gif', 'gl', 'gan', 'ggb', 'gsd', 'gsm', 'gtar', 'gz', 'gzip', 'h', 'hpp', 'htm', 'html', 'htmls', 'ibooks', 'ico', 'ics', 'ini', 'ipynb', 'java', 'jbf', 'jpeg', 'jpg', 'js', 'jsf', 'jso', 'json', 'latex', 'lang', 'less', 'log', 'lsp', 'ltx', 'm1v', 'm2a', 'm2v', 'm3u', 'm4a', 'm4v', 'markdown', 'm', 'mat', 'md', 'mdl', 'mdown', 'mid', 'min', 'midi', 'mobi', 'mod', 'mov', 'movie', 'mp2', 'mp3', 'mp4', 'mpa', 'mpeg', 'mpg', 'mph', 'mpga', 'mpp', 'mpt', 'mpv', 'mpx', 'mv', 'mw', 'mv4', 'nb', 'nbp', 'nef', 'nif', 'niff', 'obj', 'obm', 'odt', 'ods', 'odp', 'odg', 'odf', 'oga', 'ogg', 'ogv', 'old', 'p', 'pas', 'pbm', 'pcl', 'pct', 'pcx', 'pdf', 'pgm', 'pic', 'pict', 'png', 'por', 'pov', 'project', 'properties', 'ppa', 'ppm', 'pps', 'ppsx', 'ppt', 'pptx', 'ppz', 'ps', 'psd', 'pwz', 'qt', 'qtc', 'qti', 'qtif', 'r', 'ra', 'ram', 'rar', 'rast', 'rda', 'rev', 'rexx', 'ris', 'rf', 'rgb', 'rm', 'rmd', 'rmi', 'rmm', 'rmp', 'rt', 'rtf', 'rtx', 'rv', 's', 's3m', 'sav', 'sbs', 'sec', 'sdml', 'sgm', 'sgml', 'smi', 'smil', 'srt', 'sps', 'spv', 'stl', 'svg', 'swa', 'swf', 'swz', 'tar', 'tex', 'texi', 'texinfo', 'text', 'tgz', 'tif', 'tiff', 'ttf', 'txt', 'tmp', 'uvproj', 'vdf', 'vimeo', 'viv', 'vivo', 'vrml', 'vsdx', 'vtt', 'wav', 'webm', 'wmv', 'wmx', 'wmz', 'woff', 'wwd', 'xhtml', 'xif', 'xls', 'xlsx', 'xmind', 'xml', 'xsl', 'xsd', 'zip']
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
A component is the most general form of an entity in the UI.
Definition: Component.php:28
This describes a standard filter.
Definition: Standard.php:27
A Column describes the form of presentation for a certain aspect of data, i.e.
Definition: Column.php:28
buildDataRow(string $id, array $record)
An entity that renders components to a string output.
Definition: Renderer.php:31
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static http()
Fetches the global http state from ILIAS.
readonly ilGlobalTemplateInterface $tpl
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
global $lng
Definition: privfeed.php:26