19declare(strict_types=1);
39 protected UIFactory $ui_factory,
40 protected UIRenderer $ui_renderer,
41 protected DataFactory $data_factory,
51 protected TaxonomyService $taxonomy,
52 protected NotesService $notes_service,
53 protected int $parent_obj_id,
54 protected int $request_ref_id
56 $lng->loadLanguageModule(
'qpl');
63 return $this->ui_factory->table()->data(
65 $this->
lng->txt(
'questions'),
69 ->withId(
'qpt' . $this->parent_obj_id .
'_' . $this->request_ref_id);
78 $lifecycle_options = array_merge(
79 [
'' => $this->
lng->txt(
'qst_lifecycle_filter_all')],
82 $question_type_options = [
83 '' => $this->
lng->txt(
'filter_all_question_types')
86 foreach ($question_types as $translation => $row) {
87 $question_type_options[$row[
'type_tag']] = $translation;
90 $field_factory = $this->ui_factory->input()->field();
92 'title' => $field_factory->text($this->
lng->txt(
"title")),
93 'description' => $field_factory->text($this->
lng->txt(
"description")),
94 'author' => $field_factory->text($this->
lng->txt(
"author")),
95 'lifecycle' => $field_factory->select($this->
lng->txt(
"qst_lifecycle"), $lifecycle_options),
96 'type' => $field_factory->select($this->
lng->txt(
"type"), $question_type_options),
97 'commented' => $field_factory->select(
98 $this->
lng->txt(
"ass_comments"),
106 $taxs = $this->taxonomy->getUsageOfObject($this->parent_obj_id,
true);
107 $tax_filter_options = [
108 'null' =>
'<b>' . $this->
lng->txt(
'tax_filter_notax') .
'</b>'
111 foreach ($taxs as $tax_entry) {
112 $tax = new \ilObjTaxonomy($tax_entry[
'tax_id']);
113 $tax_tree = $tax->getTree();
115 $children = $this->
taxNodeReader($tax_tree, $sortfield, $tax_tree->readRootId());
116 $nodes = implode(
'-', array_map(fn($node) => $node[
'obj_id'], $children));
118 $tax_id = $tax_entry[
'tax_id'] .
'-0-' . $nodes;
119 $tax_title =
'<b>' . $tax_entry[
'title'] .
'</b>';
120 if ($children === []) {
123 $tax_filter_options[$tax_id] = $tax_title;
125 foreach ($children as $subtax) {
126 $stax_id = $subtax[
'tax_id'] .
'-' . $subtax[
'obj_id'];
127 $stax_title = str_repeat(
' ', ($subtax[
'depth'] - 2) * 2)
128 .
' └─ '
131 $tax_filter_options[$stax_id] = $stax_title;
134 $filter_inputs[
'taxonomies'] = $field_factory->multiSelect($this->
lng->txt(
"tax_filter"), $tax_filter_options);
136 $active = array_fill(0, count($filter_inputs),
true);
138 $filter = $ui_service->
filter()->standard(
139 "question_table_filter_{$this->request_ref_id}",
152 $f = $this->ui_factory->table()->column();
153 $df = $this->data_factory->dateFormat();
154 $icon_yes = $this->ui_factory->symbol()->icon()->custom(\
ilUtil::getImagePath(
'standard/icon_checked.svg'),
'yes');
155 $icon_no = $this->ui_factory->symbol()->icon()->custom(\
ilUtil::getImagePath(
'standard/icon_unchecked.svg'),
'no');
158 'title' =>
$f->link($this->
lng->txt(
'title')),
159 'description' =>
$f->text($this->
lng->txt(
'description'))->withIsOptional(
true,
true),
160 'ttype' =>
$f->text($this->
lng->txt(
'question_type'))->withIsOptional(
true,
true),
161 'points' =>
$f->number($this->
lng->txt(
'points'))->withDecimals(2)->withIsOptional(
true,
true),
162 'author' =>
$f->text($this->
lng->txt(
'author'))->withIsOptional(
true,
true),
163 'lifecycle' =>
$f->text($this->
lng->txt(
'qst_lifecycle'))->withIsOptional(
true,
true),
164 'taxonomies' =>
$f->text($this->
lng->txt(
'qpl_settings_subtab_taxonomies'))->withIsOptional(
true,
true),
165 'feedback' =>
$f->boolean($this->
lng->txt(
'feedback'), $icon_yes, $icon_no)->withIsOptional(
true,
true),
166 'created' =>
$f->date(
167 $this->
lng->txt(
'create_date'),
168 $this->current_user->getDateTimeFormat()
169 )->withIsOptional(
true,
true),
170 'tstamp' =>
$f->date(
171 $this->
lng->txt(
'last_update'),
172 $this->current_user->getDateTimeFormat()
173 )->withIsOptional(
true,
true),
174 'comments' =>
$f->number($this->
lng->txt(
'comments'))->withIsOptional(
true,
false),
180 $hop = array_shift($stack);
184 if (! array_key_exists($hop, $pointer)) {
187 $this->
treeify($pointer[$hop], $stack);
193 foreach ($nodes as $k => $n) {
200 return $this->ui_renderer->render(
201 $this->ui_factory->listing()->unordered($entries)
208 $nodes = $tree->getChildsByTypeFilter($node_id, [
'taxn']);
211 fn(
$a,
$b) => strcmp(
212 (
string)
$a[$sortfield],
213 (
string)
$b[$sortfield]
217 foreach ($nodes as $node) {
219 foreach ($this->
taxNodeReader($tree, $sortfield, $node[
'obj_id']) as
$c) {
228 array $stored_tax_data,
234 $taxnodes = $this->
taxNodeReader($tax_tree, $sortfield, $tax_tree->readRootId());
237 foreach ($taxnodes as $taxnode) {
238 $taxdata = array_filter(
240 fn($data_child) => $data_child[
'node_id'] === $taxnode[
'obj_id']
243 foreach (array_keys($taxdata) as $node_obj_id) {
245 fn($n) => in_array($n[
'obj_id'], array_keys($stored_tax_data)) ? $check_marker . $n[
'title'] : $n[
'title'],
246 $tax_tree->getPathFull($node_obj_id),
257 $check = $this->ui_renderer->render(
258 $this->ui_factory->symbol()->icon()->custom(\
ilUtil::getImagePath(
'standard/icon_checked.svg'),
'checked')
262 $taxs = $this->taxonomy->getUsageOfObject($this->parent_obj_id,
true);
263 foreach ($taxs as $tax_entry) {
264 $tax_id = $tax_entry[
'tax_id'];
265 if (!array_key_exists($tax_id, $taxonomy_data)) {
268 $taxonomies[] = $this->singleTaxonomyRepresentation(
270 $taxonomy_data[$tax_id],
274 return implode(
'', $taxonomies);
279 array $visible_column_ids,
282 mixed $additional_viewcontrol_data,
284 mixed $additional_parameters
286 $timezone = new \DateTimeZone($this->current_user->getTimeZone());
287 foreach ($this->getData($order,
$range) as $record) {
288 $row_id = (string) $record[
'question_id'];
289 $record[
'created'] = (new \DateTimeImmutable(
"@{$record['created']}"))->setTimezone($timezone);
290 $record[
'tstamp'] = (new \DateTimeImmutable(
"@{$record['tstamp']}"))->setTimezone($timezone);
292 $record[
'lifecycle'] =
$lifecycle->getTranslation($this->
lng);
294 $title = $record[
'title'];
295 $to_question = $this->url_builder
296 ->withParameter($this->action_parameter_token,
'preview')
297 ->withParameter($this->row_id_token, $row_id)
298 ->buildURI()->__toString();
299 if (!(
bool) $record[
'complete']) {
300 $title .=
' (' . $this->
lng->txt(
'warning_question_not_complete') .
')';
302 $record[
'title'] = $this->ui_factory->link()->standard($title, $to_question);
303 $record[
'taxonomies'] = $this->taxonomyRepresentation($record[
'taxonomies']);
305 yield $row_builder->buildDataRow($row_id, $record);
310 mixed $additional_viewcontrol_data,
312 mixed $additional_parameters
314 $this->setParentObjId($this->parent_obj_id);
316 return count($this->getQuestionDataArray());
321 $this->setParentObjId($this->parent_obj_id);
323 $data = $this->postOrder($this->getQuestionDataArray(), $order);
325 $length = $length > 0 ? $length :
null;
326 return array_slice(
$data, $offset, $length);
331 $write_access = $this->
rbac->checkAccess(
'write', $this->request_ref_id);
333 $this->buildAction(
'copy',
'standard'),
334 $write_access ? $this->buildAction(
'move',
'standard') : [],
335 $write_access ? $this->buildAction(
'delete',
'standard') : [],
336 $this->buildAction(
'export',
'multi'),
337 $this->buildAction(
'preview',
'single'),
338 $this->buildAction(
'statistics',
'single'),
339 $write_access ? $this->buildAction(
'edit_question',
'single') : [],
340 $write_access ? $this->buildAction(
'edit_page',
'single') : [],
341 $write_access ? $this->buildAction(
'feedback',
'single') : [],
345 $this->showCommentAction() ? $this->buildAction(
'comments',
'single',
true) : []
349 protected function buildAction(
string $act,
string $type,
bool $async =
false): array
351 $action = $this->ui_factory->table()->action()
353 $this->
lng->txt($act),
354 $this->url_builder->withParameter($this->action_parameter_token, $act),
358 $action = $action->withAsync(
true);
361 return [$act => $action];
366 [$aspect, $direction] = $order->join(
'',
function ($i, $k, $v) {
369 usort($list,
static function (array
$a, array
$b) use ($aspect):
int {
370 if (is_numeric(
$a[$aspect]) || is_bool(
$a[$aspect])) {
371 return $a[$aspect] <=>
$b[$aspect];
373 if (is_array(
$a[$aspect])) {
374 return $a[$aspect] <=>
$b[$aspect];
379 if (
$a[$aspect] !==
null) {
380 $aspect_a =
$a[$aspect];
382 if (
$b[$aspect] !==
null) {
383 $aspect_b =
$b[$aspect];
386 return strcoll($aspect_a, $aspect_b);
389 if ($direction === $order::DESC) {
390 $list = array_reverse($list);
397 return $this->notes_service->domain()->commentsActive($this->parent_obj_id)
398 || $this->
rbac->checkAccess(
'write', $this->request_ref_id);
Builds a Color from either hex- or rgb values.
Both the subject and the direction need to be specified when expressing an order.
A simple class to express a naive range of whole positive numbers.
treeify(&$pointer, $stack)
toNestedList(array $nodes)
buildAction(string $act, string $type, bool $async=false)
__construct(protected UIFactory $ui_factory, protected UIRenderer $ui_renderer, protected DataFactory $data_factory, protected Refinery $refinery, protected URLBuilder $url_builder, protected URLBuilderToken $action_parameter_token, protected URLBuilderToken $row_id_token, protected \ilDBInterface $db, protected \ilLanguage $lng, protected \ilComponentRepository $component_repository, protected \ilRbacSystem $rbac, protected \ilObjUser $current_user, protected TaxonomyService $taxonomy, protected NotesService $notes_service, protected int $parent_obj_id, protected int $request_ref_id)
taxonomyRepresentation(array $taxonomy_data)
singleTaxonomyRepresentation(int $tax_id, array $stored_tax_data, string $check_marker)
getRows(Table\DataRowBuilder $row_builder, array $visible_column_ids, Range $range, Order $order, mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
getTotalRowCount(mixed $additional_viewcontrol_data, mixed $filter_data, mixed $additional_parameters)
getFilter(\ilUIService $ui_service, string $action)
Filters should be part of the Table; for now, since they are not fully integrated,...
getData(Order $order, Range $range)
postOrder(array $list, \ILIAS\Data\Order $order)
taxNodeReader($tree, $sortfield, $node_id)
static getDraftInstance()
static getInstance($identifier)
setAvailableTaxonomyIds(array $availableTaxonomyIds)
const QUESTION_COMMENTED_EXCLUDED
const QUESTION_COMMENTED_ONLY
static _getQuestionTypes($all_tags=false, $fixOrder=false, $withDeprecatedTypes=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupTitle(int $obj_id)
class ilRbacSystem system function like checkAccess, addActiveRole ... Supporting system functions ar...
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
This describes a Data Table.
withActions(array $actions)
An entity that renders components to a string output.
Readable part of repository interface to ilComponentDataDB.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples