ILIAS  release_8 Revision v8.24
Data.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use Psr\Http\Message\ServerRequestInterface;
31use ILIAS\Data\Factory as DataFactory;
38
39class Data extends Table implements T\Data, JSBindable
40{
42
43 public const VIEWCONTROL_KEY_PAGINATION = 'range';
44 public const VIEWCONTROL_KEY_ORDERING = 'order';
45 public const VIEWCONTROL_KEY_FIELDSELECTION = 'selected_optional';
46
47 public const STORAGE_ID_PREFIX = self::class . '_';
48
52 protected array $columns = [];
53
57 protected array $actions_single = [];
58
62 protected array $actions_multi = [];
63
67 protected array $actions_std = [];
68
72 protected ?ServerRequestInterface $request = null;
73 protected int $number_of_rows = 800;
77 protected ?array $selected_optional_column_ids = null;
78 protected ?Range $range = null;
79 protected ?Order $order = null;
80 protected ?array $filter = null;
81 protected ?array $additional_parameters = null;
82 protected ?string $id = null;
85 protected DataFactory $data_factory;
87 protected T\DataRetrieval $data_retrieval;
88 protected \ArrayAccess $storage;
89
93 public function __construct(
97 DataFactory $data_factory,
99 string $title,
100 array $columns,
102 \ArrayAccess $storage
103 ) {
104 $this->checkArgListElements('columns', $columns, [Column::class]);
105 if ($columns === []) {
106 throw new \InvalidArgumentException('cannot construct a table without columns.');
107 }
109 $this->multi_action_signal = $signal_generator->create();
110 $this->selection_signal = $signal_generator->create();
111 $this->async_action_signal = $signal_generator->create();
112
113 $this->columns = $this->enumerateColumns($columns);
114 $this->view_control_factory = $view_control_factory;
115 $this->view_control_container_factory = $view_control_container_factory;
116 $this->data_factory = $data_factory;
117 $this->data_row_builder = $data_row_builder;
118 $this->data_retrieval = $data_retrieval;
119 $this->storage = $storage;
120 }
121
126 private function enumerateColumns(array $columns): array
127 {
128 $ret = [];
129 $idx = 0;
130 foreach ($columns as $id => $col) {
131 $ret[$id] = $col->withIndex($idx++);
132 }
133 return $ret;
134 }
135
136 private function initialOrder(): string
137 {
138 $visible_cols = $this->getVisibleColumns();
139 $sortable_visible_cols = array_filter(
140 $visible_cols,
141 static fn ($c): bool => $c->isSortable()
142 );
143 if ($sortable_visible_cols === []) {
144 return array_key_first($visible_cols);
145 }
146 return array_key_first($sortable_visible_cols);
147 }
148
152 public function getColumns(): array
153 {
154 return $this->columns;
155 }
156
158 {
160 }
161
165 public function withActions(array $actions): self
166 {
167 $this->checkArgListElements('actions', $actions, [T\Action\Action::class]);
168 $clone = clone $this;
169
170 foreach ($actions as $id => $action) {
171 switch (true) {
172 case ($action instanceof T\Action\Single):
173 $clone->actions_single[$id] = $action;
174 break;
175 case ($action instanceof T\Action\Multi):
176 $clone->actions_multi[$id] = $action;
177 break;
178 case ($action instanceof T\Action\Standard):
179 $clone->actions_std[$id] = $action;
180 break;
181 }
182 }
183 return $clone;
184 }
185
186 public function withRequest(ServerRequestInterface $request): self
187 {
188 $clone = clone $this;
189 $clone->request = $request;
190 return $clone;
191 }
192
193 public function getRequest(): ?ServerRequestInterface
194 {
195 return $this->request;
196 }
197
198 public function withNumberOfRows(int $number_of_rows): self
199 {
200 $clone = clone $this;
201 $clone->number_of_rows = $number_of_rows;
202 return $clone;
203 }
204
205 public function getNumberOfRows(): int
206 {
208 }
209
210 public function withOrder(?Order $order): self
211 {
212 $clone = clone $this;
213 $clone->order = $order;
214 return $clone;
215 }
216
217 public function getOrder(): Order
218 {
219 return $this->order ?? $this->data_factory->order($this->initialOrder(), Order::ASC);
220 }
221
222 public function withRange(?Range $range): self
223 {
224 $clone = clone $this;
225 $clone->range = $range;
226 return $clone;
227 }
228
229 public function getRange(): Range
230 {
231 return $this->range ?? $this->data_factory->range(0, $this->number_of_rows);
232 }
233
234 public function withFilter(?array $filter): self
235 {
236 $clone = clone $this;
237 $clone->filter = $filter;
238 return $clone;
239 }
240
241 public function getFilter(): ?array
242 {
243 return $this->filter;
244 }
245
247 {
248 $clone = clone $this;
249 $clone->additional_parameters = $additional_parameters;
250 return $clone;
251 }
252
253 public function getAdditionalParameters(): ?array
254 {
256 }
257
258 public function getMultiActionSignal(): Signal
259 {
261 }
262
263 public function getSelectionSignal(): Signal
264 {
266 }
267
268 public function getAsyncActionSignal(): Signal
269 {
271 }
272
273 public function hasSingleActions(): bool
274 {
275 return $this->getSingleActions() !== [];
276 }
277
278 public function hasMultiActions(): bool
279 {
280 return $this->getMultiActions() !== [];
281 }
282
286 public function getMultiActions(): array
287 {
288 return array_merge($this->actions_multi, $this->actions_std);
289 }
290
294 public function getSingleActions(): array
295 {
296 return array_merge($this->actions_single, $this->actions_std);
297 }
298
302 public function getAllActions(): array
303 {
304 return array_merge($this->actions_single, $this->actions_multi, $this->actions_std);
305 }
306
307 public function getColumnCount(): int
308 {
309 return count($this->columns);
310 }
311
316 {
317 $clone = clone $this;
318 $clone->selected_optional_column_ids = $selected_optional_column_ids;
319 return $clone;
320 }
321
325 public function getSelectedOptionalColumns(): array
326 {
327 if (is_null($this->selected_optional_column_ids)) {
328 return array_keys($this->getInitiallyVisibleColumns());
329 }
331 }
332
336 protected function getOptionalColumns(): array
337 {
338 return array_filter(
339 $this->getColumns(),
340 static fn ($c): bool => $c->isOptional()
341 );
342 }
343
347 protected function getInitiallyVisibleColumns(): array
348 {
349 return array_filter(
350 $this->getOptionalColumns(),
351 static fn ($c): bool => $c->isInitiallyVisible()
352 );
353 }
354
358 public function getVisibleColumns(): array
359 {
361 return array_filter(
362 $this->getColumns(),
363 fn (Column $col, string $col_id): bool => !$col->isOptional() || in_array($col_id, $visible_optional_columns, true),
364 ARRAY_FILTER_USE_BOTH
365 );
366 }
367
368 public function getRowBuilder(): DataRowBuilder
369 {
370 return $this->data_row_builder
372 ->withSingleActions($this->getSingleActions())
373 ->withVisibleColumns($this->getVisibleColumns());
374 }
375
376 protected function getStorageData(): ?array
377 {
378 if (null !== ($storage_id = $this->getStorageId())) {
379 return $this->storage[$storage_id] ?? null;
380 }
381 return null;
382 }
383
384 protected function setStorageData(array $data): void
385 {
386 if (null !== ($storage_id = $this->getStorageId())) {
387 $this->storage[$storage_id] = $data;
388 }
389 }
390
391 protected function applyValuesToViewcontrols(
392 ViewControlContainer\ViewControl $view_controls,
393 ServerRequestInterface $request
395 $stored_values = new ArrayInputData($this->getStorageData() ?? []);
396 $view_controls = $view_controls
397 ->withStoredInput($stored_values)
398 ->withRequest($request);
399 $this->setStorageData($view_controls->getComponentInternalValues());
400 return $view_controls;
401 }
402
406 public function applyViewControls(
407 array $filter_data,
408 ?array $additional_parameters = []
409 ): array {
410 $table = $this;
411 $total_count = $this->getDataRetrieval()->getTotalRowCount($filter_data, $additional_parameters);
412 $view_controls = $this->getViewControls($total_count);
413
414 if ($request = $this->getRequest()) {
415 # This retrieves container data from the request
416 $data = $this->applyValuesToViewcontrols($view_controls, $request)->getData();
417 $range = $data[self::VIEWCONTROL_KEY_PAGINATION];
418 $range = ($range instanceof Range) ? $range->croppedTo($total_count ?? PHP_INT_MAX) : null;
419 $table = $table
420 ->withRange($range)
421 ->withOrder($data[self::VIEWCONTROL_KEY_ORDERING] ?? null)
422 ->withSelectedOptionalColumns($data[self::VIEWCONTROL_KEY_FIELDSELECTION] ?? null);
423
424 # This retrieves the view controls that should be displayed
425 $view_controls = $table->applyValuesToViewcontrols($table->getViewControls($total_count), $request);
426 }
427
428 return [
429 $table->withFilter($filter_data),
430 $view_controls
431 ];
432 }
433
434 protected function getViewControls(?int $total_count = null): ViewControlContainer\ViewControl
435 {
436 $view_controls = [
437 self::VIEWCONTROL_KEY_PAGINATION => $this->getViewControlPagination($total_count),
438 self::VIEWCONTROL_KEY_ORDERING => $this->getViewControlOrdering(),
439 self::VIEWCONTROL_KEY_FIELDSELECTION => $this->getViewControlFieldSelection(),
440 ];
441 $view_controls = array_filter($view_controls);
442 return $this->view_control_container_factory->standard($view_controls);
443 }
444
445 protected function getViewControlPagination(?int $total_count = null): ViewControlContainer\ViewControlInput
446 {
447 $smallest_option = current(Pagination::DEFAULT_LIMITS);
448 if (is_null($total_count) || $total_count >= $smallest_option) {
449 $range = $this->getRange();
450 return
451 $this->view_control_factory->pagination()
452 ->withTotalCount($total_count)
453 ->withValue([
454 Pagination::FNAME_OFFSET => $range->getStart(),
455 Pagination::FNAME_LIMIT => $range->getLength()
456 ]);
457 }
458 return $this->view_control_factory->group([
459 $this->view_control_factory->nullControl(),
460 $this->view_control_factory->nullControl()
461 ]);
462 }
463
465 {
466 $sortable_visible_cols = array_filter(
467 $this->getVisibleColumns(),
468 static fn ($c): bool => $c->isSortable()
469 );
470
471 if ($sortable_visible_cols === []) {
472 return null;
473 }
474
475 $sort_options = [];
476 foreach ($sortable_visible_cols as $col_id => $col) {
477
478 $order_asc = $this->data_factory->order($col_id, Order::ASC);
479 $order_desc = $this->data_factory->order($col_id, Order::DESC);
480
481 $labels = $col->getOrderingLabels();
482 $sort_options[$labels[0]] = $order_asc;
483 $sort_options[$labels[1]] = $order_desc;
484 }
485 return $this->view_control_factory->sortation($sort_options);
486 }
487
489 {
490 $optional_cols = $this->getOptionalColumns();
491 if ($optional_cols === []) {
492 return null;
493 }
494
495 return $this->view_control_factory
496 ->fieldSelection(array_map(
497 static fn ($c): string => $c->getTitle(),
498 $optional_cols
499 ))
500 ->withValue($this->getSelectedOptionalColumns());
501 }
502
503 public function withId(string $id): self
504 {
505 $clone = clone $this;
506 $clone->id = $id;
507 return $clone;
508 }
509
510 protected function getStorageId(): ?string
511 {
512 if (null !== ($id = $this->getId())) {
513 return self::STORAGE_ID_PREFIX . $id;
514 }
515 return null;
516 }
517
518 protected function getId(): ?string
519 {
520 return $this->id;
521 }
522}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
range(CardinalDimension $cardinal_dimension)
Definition: Factory.php:36
Builds data types.
Definition: Factory.php:21
order(string $subject, string $direction)
Definition: Factory.php:145
Both the subject and the direction need to be specified when expressing an order.
Definition: Order.php:13
A simple class to express a range of whole positive numbers.
Definition: Range.php:31
croppedTo(int $max)
This will create a range that is guaranteed to not exceed $max.
Definition: Range.php:104
int()
Contains constraints and transformations on numbers.
Definition: Factory.php:78
string()
Contains constraints for string.
Definition: Factory.php:86
bool()
Get a kind transformation to a bool.
Definition: Group.php:159
withSelectedOptionalColumns(?array $selected_optional_column_ids)
Definition: Data.php:315
ViewControl Factory $view_control_factory
Definition: Data.php:83
withNumberOfRows(int $number_of_rows)
Definition: Data.php:198
getViewControls(?int $total_count=null)
Definition: Data.php:434
applyViewControls(array $filter_data, ?array $additional_parameters=[])
Definition: Data.php:406
applyValuesToViewcontrols(ViewControlContainer\ViewControl $view_controls, ServerRequestInterface $request)
Definition: Data.php:391
withRequest(ServerRequestInterface $request)
Definition: Data.php:186
ViewControlContainer Factory $view_control_container_factory
Definition: Data.php:84
getViewControlPagination(?int $total_count=null)
Definition: Data.php:445
withAdditionalParameters(?array $additional_parameters)
Definition: Data.php:246
__construct(SignalGeneratorInterface $signal_generator, ViewControl\Factory $view_control_factory, ViewControlContainer\Factory $view_control_container_factory, DataFactory $data_factory, DataRowBuilder $data_row_builder, string $title, array $columns, T\DataRetrieval $data_retrieval, \ArrayAccess $storage)
Definition: Data.php:93
ViewControlContainerFactory $view_control_container_factory
Definition: Factory.php:37
Psr Http Message ServerRequestInterface $request
clone(ilDclStandardField $original_record)
$c
Definition: cli.php:38
storage()
Fetches the storage filesystem.
This is what a factory for View Control Containers looks like.
Definition: Factory.php:27
This describes the basis of all View Control Inputs.
This describes the factory for (view-)controls.
Definition: Factory.php:27
This describes a Field Selection View Control.
This describes a Sortation View Control.
Definition: Sortation.php:29
This is a legacy support of Component\Input\ViewControl\ViewControl that has been moved to Component\...
Definition: ViewControl.php:32
Interface to be extended by components that have the possibility to bind to Javascript.
A Column describes the form of presentation for a certain aspect of data, i.e.
Definition: Column.php:28
create(string $class='')
Create a signal, each created signal MUST have a unique ID.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Factory.php:21
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
trait JavaScriptBindable
Trait for components implementing JavaScriptBindable providing standard implementation.