ILIAS  release_8 Revision v8.24
class.ilTestQuestionBrowserTableGUI.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
21use ILIAS\UI\Factory as UIFactory;
22use ILIAS\UI\Renderer as UIRenderer;
23use ILIAS\Refinery\Factory as Refinery;
24use ILIAS\Modules\Test\QuestionPoolLinkedTitleBuilder;
25
31{
32 use QuestionPoolLinkedTitleBuilder;
33 private const REPOSITORY_ROOT_NODE_ID = 1;
34
35 public const CONTEXT_PARAMETER = 'question_browse_context';
36 public const CONTEXT_PAGE_VIEW = 'contextPageView';
37 public const CONTEXT_LIST_VIEW = 'contextListView';
38
39 public const MODE_PARAMETER = 'question_browse_mode';
40 public const MODE_BROWSE_POOLS = 'modeBrowsePools';
41 public const MODE_BROWSE_TESTS = 'modeBrowseTests';
42
43 public const CMD_BROWSE_QUESTIONS = 'browseQuestions';
44 public const CMD_APPLY_FILTER = 'applyFilter';
45 public const CMD_RESET_FILTER = 'resetFilter';
46 public const CMD_INSERT_QUESTIONS = 'insertQuestions';
47
48 private \ILIAS\Test\InternalRequestService $testrequest;
49 private \ILIAS\HTTP\GlobalHttpState $httpState;
50 private \ILIAS\Refinery\Factory $refinery;
51 private bool $writeAccess = false;
54 private ilTree $tree;
59
60 private UIFactory $ui_factory;
61 private UIRenderer $ui_renderer;
62
64 private array $filter = [];
65
66 public function __construct(
76 ILIAS\HTTP\GlobalHttpState $httpState,
77 Refinery $refinery,
78 UIFactory $ui_factory,
79 UIRenderer $ui_renderer
80 ) {
81 $this->ctrl = $ctrl;
82 $this->mainTpl = $mainTpl;
83 $this->tabs = $tabs;
84 $this->lng = $lng;
85 $this->tree = $tree;
86 $this->db = $db;
87 $this->component_repository = $component_repository;
88 $this->testOBJ = $testOBJ;
89 $this->access = $access;
90 $this->httpState = $httpState;
91 $this->refinery = $refinery;
92 $this->ui_factory = $ui_factory;
93 $this->ui_renderer = $ui_renderer;
94
95 $this->setId('qpl_brows_tabl_' . $this->testOBJ->getId());
96 global $DIC;
97 $this->testrequest = $DIC->test()->internal()->request();
98 parent::__construct($this, self::CMD_BROWSE_QUESTIONS);
99 $this->setFilterCommand(self::CMD_APPLY_FILTER);
100 $this->setResetCommand(self::CMD_RESET_FILTER);
101
102 $this->setFormName('questionbrowser');
103 $this->setStyle('table', 'fullwidth');
104 $this->addColumn('', '', '1%', true);
105 $this->addColumn($this->lng->txt("tst_question_title"), 'title', '');
106 $this->addColumn($this->lng->txt("description"), 'description', '');
107 $this->addColumn($this->lng->txt("tst_question_type"), 'ttype', '');
108 $this->addColumn($this->lng->txt("author"), 'author', '');
109 $this->addColumn($this->lng->txt('qst_lifecycle'), 'lifecycle', '');
110 $this->addColumn($this->lng->txt("create_date"), 'created', '');
111 $this->addColumn(
112 $this->lng->txt("last_update"),
113 'tstamp',
114 ''
115 ); // name of col is proper "updated" but in data array the key is "tstamp"
116 $this->addColumn($this->getParentObjectLabel(), 'qpl', '');
117 $this->setSelectAllCheckbox('q_id');
118 $this->setRowTemplate("tpl.il_as_tst_question_browser_row.html", "Modules/Test");
119
120 $this->setFormAction($this->ctrl->getFormAction($this->getParentObject(), $this->getParentCmd()));
121 $this->setDefaultOrderField("title");
122 $this->setDefaultOrderDirection("asc");
123
124 $this->enable('sort');
125 $this->enable('select_all');
126 $this->initFilter();
127 $this->setDisableFilterHiding(true);
128 }
129
130 public function setWriteAccess(bool $value): void
131 {
132 $this->writeAccess = $value;
133 }
134
135 public function hasWriteAccess(): bool
136 {
137 return $this->writeAccess;
138 }
139
140 public function init(): void
141 {
142 if ($this->hasWriteAccess()) {
143 $this->addMultiCommand(self::CMD_INSERT_QUESTIONS, $this->lng->txt('insert'));
144 }
145 }
146
147 public function executeCommand(): bool
148 {
149 $this->handleParameters();
150 $this->handleTabs();
151
152 switch (strtolower((string) $this->ctrl->getNextClass($this))) {
153 case strtolower(__CLASS__):
154 case '':
155
156 $cmd = $this->ctrl->getCmd() . 'Cmd';
157 return $this->$cmd();
158
159 default:
160
161 $this->ctrl->setReturn($this, self::CMD_BROWSE_QUESTIONS);
162 return parent::executeCommand();
163 }
164 }
165
166 private function browseQuestionsCmd(): bool
167 {
168 $this->setData($this->getQuestionsData());
169
170 $this->mainTpl->setContent($this->ctrl->getHTML($this));
171 return true;
172 }
173
174 private function applyFilterCmd(): void
175 {
176 $this->writeFilterToSession();
177 $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
178 }
179
180 private function resetFilterCmd(): void
181 {
182 $this->resetFilter();
183 $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
184 }
185
186 private function insertQuestionsCmd(): void
187 {
188 $selected_array = [];
189 if ($this->httpState->wrapper()->post()->has('q_id')) {
190 $selected_array = $this->httpState->wrapper()->post()->retrieve(
191 'q_id',
192 $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
193 );
194 }
195
196 if ($selected_array === []) {
197 $this->mainTpl->setOnScreenMessage('info', $this->lng->txt("tst_insert_missing_question"), true);
198 $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
199 }
200
201 $testQuestionSetConfig = $this->buildTestQuestionSetConfig();
202
203 $manscoring = false;
204
205 foreach ($selected_array as $key => $value) {
206 $last_question_id = $this->testOBJ->insertQuestion($testQuestionSetConfig, $value);
207
208 if (!$manscoring) {
209 $manscoring |= assQuestion::_needsManualScoring($value);
210 }
211 }
212
213 $this->testOBJ->saveCompleteStatus($testQuestionSetConfig);
214
215 if ($manscoring) {
216 $this->mainTpl->setOnScreenMessage('info', $this->lng->txt("manscoring_hint"), true);
217 } else {
218 $this->mainTpl->setOnScreenMessage('success', $this->lng->txt("tst_questions_inserted"), true);
219 }
220
221 $this->ctrl->redirectByClass($this->getBackTargetCmdClass(), $this->getBackTargetCommand());
222 }
223
224 private function handleParameters(): void
225 {
226 if ($this->testrequest->isset(self::CONTEXT_PARAMETER)) {
227 $this->ctrl->setParameterByClass(
228 self::class,
229 self::CONTEXT_PARAMETER,
230 $this->testrequest->raw(self::CONTEXT_PARAMETER)
231 );
232 $this->addHiddenInput(self::CONTEXT_PARAMETER, $this->testrequest->raw(self::CONTEXT_PARAMETER));
233 }
234
235 if ($this->testrequest->isset(self::MODE_PARAMETER)) {
236 $this->ctrl->setParameterByClass(
237 self::class,
238 self::MODE_PARAMETER,
239 $this->testrequest->raw(self::MODE_PARAMETER)
240 );
241 $this->addHiddenInput(self::MODE_PARAMETER, $this->testrequest->raw(self::MODE_PARAMETER));
242 }
243 }
244
248 private function fetchContextParameter()
249 {
250 if ($this->testrequest->isset(self::CONTEXT_PARAMETER)) {
251 return $this->testrequest->raw(self::CONTEXT_PARAMETER);
252 }
253
254 return null;
255 }
256
260 private function fetchModeParameter()
261 {
262 if ($this->testrequest->isset(self::MODE_PARAMETER)) {
263 return $this->testrequest->raw(self::MODE_PARAMETER);
264 }
265
266 return null;
267 }
268
269 private function handleTabs(): void
270 {
271 $this->tabs->clearTargets();
272 $this->tabs->clearSubTabs();
273
274 $this->tabs->setBackTarget(
275 $this->getBackTargetLabel(),
276 $this->getBackTargetUrl()
277 );
278
279 $this->tabs->addTab(
280 'browseQuestions',
283 );
284 $this->tabs->activateTab('browseQuestions');
285 }
286
287 private function getBackTargetLabel(): string
288 {
289 return $this->lng->txt('backtocallingtest');
290 }
291
292 private function getBackTargetUrl(): string
293 {
294 return $this->ctrl->getLinkTargetByClass(
295 $this->getBackTargetCmdClass(),
296 $this->getBackTargetCommand()
297 );
298 }
299
300 private function getBackTargetCmdClass(): string
301 {
302 switch ($this->fetchContextParameter()) {
304
305 return 'ilTestExpressPageObjectGUI';
307 default:
308 return 'ilObjTestGUI';
309 }
310 }
311
312 private function getBackTargetCommand(): string
313 {
314 switch ($this->fetchContextParameter()) {
316
317 return 'questions';
318
320
321 return 'showPage';
322 }
323
324 return '';
325 }
326
327 private function getBrowseQuestionsTabLabel(): string
328 {
329 switch ($this->fetchModeParameter()) {
331
332 return $this->lng->txt('tst_browse_for_qpl_questions');
333
335
336 return $this->lng->txt('tst_browse_for_tst_questions');
337 }
338
339 return '';
340 }
341
342 private function getBrowseQuestionsTabUrl(): string
343 {
344 return $this->ctrl->getLinkTarget($this, self::CMD_BROWSE_QUESTIONS);
345 }
346
347 public function initFilter(): void
348 {
349 $ti = new ilTextInputGUI($this->lng->txt("tst_qbt_filter_question_title"), "title");
350 $ti->setMaxLength(64);
351 $ti->setSize(20);
352 $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
353 $this->addFilterItem($ti);
354 $ti->readFromSession();
355 $this->filter["title"] = $ti->getValue();
356
357 $ti = new ilTextInputGUI($this->lng->txt("description"), "description");
358 $ti->setMaxLength(64);
359 $ti->setSize(20);
360 $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
361 $this->addFilterItem($ti);
362 $ti->readFromSession();
363 $this->filter["description"] = $ti->getValue();
364
365 $ti = new ilTextInputGUI($this->lng->txt("author"), "author");
366 $ti->setMaxLength(64);
367 $ti->setSize(20);
368 $this->addFilterItem($ti);
369 $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
370 $ti->readFromSession();
371 $this->filter["author"] = $ti->getValue();
372
373 $lifecycleOptions = array_merge(
374 ['' => $this->lng->txt('qst_lifecycle_filter_all')],
375 ilAssQuestionLifecycle::getDraftInstance()->getSelectOptions($this->lng)
376 );
377 $lifecycleInp = new ilSelectInputGUI($this->lng->txt('qst_lifecycle'), 'lifecycle');
378 $lifecycleInp->setOptions($lifecycleOptions);
379 $this->addFilterItem($lifecycleInp);
380 $lifecycleInp->readFromSession();
381 $this->filter['lifecycle'] = $lifecycleInp->getValue();
382
384 $options = [];
385 $options[""] = $this->lng->txt('filter_all_question_types');
386 foreach ($types as $translation => $row) {
387 $options[$row['type_tag']] = $translation;
388 }
389
390 $si = new ilSelectInputGUI($this->lng->txt("question_type"), "type");
391 $si->setOptions($options);
392 $this->addFilterItem($si);
393 $si->readFromSession();
394 $this->filter["type"] = $si->getValue();
395
396 $ti = new ilTextInputGUI($this->getParentObjectLabel(), 'parent_title');
397 $ti->setMaxLength(64);
398 $ti->setSize(20);
399 $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
400 $this->addFilterItem($ti);
401 $ti->readFromSession();
402 $this->filter['parent_title'] = $ti->getValue();
403
404 $ri = new ilRepositorySelectorInputGUI($this->lng->txt('repository'), 'repository_root_node');
405 $ri->setHeaderMessage($this->lng->txt('question_browse_area_info'));
406 if ($this->fetchModeParameter() === self::MODE_BROWSE_TESTS) {
407 $ri->setClickableTypes(['tst']);
408 } else {
409 $ri->setClickableTypes(['qpl']);
410 }
411 $this->addFilterItem($ri);
412 $ri->readFromSession();
413 $this->filter['repository_root_node'] = $ri->getValue();
414 }
415
416 private function getParentObjectLabel(): string
417 {
418 switch ($this->fetchModeParameter()) {
420
421 return $this->lng->txt('qpl');
422
424
425 return $this->lng->txt('tst');
426 }
427
428 return '';
429 }
430
431 protected function getTranslatedLifecycle(?string $lifecycle): string
432 {
433 try {
434 return ilAssQuestionLifecycle::getInstance($lifecycle)->getTranslation($this->lng);
436 return '';
437 }
438 }
439
440 public function fillRow(array $a_set): void
441 {
442 $this->tpl->setVariable("QUESTION_ID", $a_set["question_id"]);
443 $this->tpl->setVariable("QUESTION_TITLE", $a_set["title"]);
444 $this->tpl->setVariable("QUESTION_COMMENT", $a_set["description"]);
445 $this->tpl->setVariable("QUESTION_TYPE", assQuestion::_getQuestionTypeName($a_set["type_tag"]));
446 $this->tpl->setVariable("QUESTION_AUTHOR", $a_set["author"]);
447 $this->tpl->setVariable("QUESTION_LIFECYCLE", $this->getTranslatedLifecycle($a_set['lifecycle']));
448 $this->tpl->setVariable(
449 "QUESTION_CREATED",
450 ilDatePresentation::formatDate(new ilDate($a_set['created'], IL_CAL_UNIX))
451 );
452 $this->tpl->setVariable(
453 "QUESTION_UPDATED",
455 );
456 $this->tpl->setVariable(
457 "QUESTION_POOL_OR_TEST_TITLE",
459 (int) $a_set["obj_fi"],
460 $a_set["parent_title"]
461 )
462 );
463 }
464
465 private function buildPossiblyLinkedQuestonPoolOrTestTitle(int $obj_id, string $parent_title): string
466 {
467 switch ($this->fetchModeParameter()) {
469 return $this->buildPossiblyLinkedQuestonPoolTitle(
470 $this->ctrl,
471 $this->access,
472 $this->lng,
473 $this->ui_factory,
474 $this->ui_renderer,
475 $obj_id,
476 $parent_title
477 );
478
480 return $this->buildPossiblyLinkedTestTitle(
481 $this->ctrl,
482 $this->access,
483 $this->lng,
484 $this->ui_factory,
485 $this->ui_renderer,
486 $obj_id,
487 $parent_title
488 );
489 }
490
491 return '';
492 }
493
495 {
496 $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory(
497 $this->tree,
498 $this->db,
499 $this->component_repository,
500 $this->testOBJ
501 );
502
503 return $testQuestionSetConfigFactory->getQuestionSetConfig();
504 }
505
506 private function getQuestionsData(): array
507 {
508 $questionList = new ilAssQuestionList($this->db, $this->lng, $this->refinery, $this->component_repository);
509
510 $questionList->setQuestionInstanceTypeFilter($this->getQuestionInstanceTypeFilter());
511 $questionList->setExcludeQuestionIdsFilter($this->testOBJ->getExistingQuestions());
512
513 $repositoryRootNode = self::REPOSITORY_ROOT_NODE_ID;
514
515 foreach ($this->getFilterItems() as $item) {
516 if (!in_array($item->getValue(), [false, null, ''], true)) {
517 switch ($item->getPostVar()) {
518 case 'title':
519 case 'description':
520 case 'author':
521 case 'lifecycle':
522 case 'type':
523 case 'parent_title':
524 $questionList->addFieldFilter($item->getPostVar(), $item->getValue());
525 break;
526
527 case 'repository_root_node':
528 $repositoryRootNode = (int) $item->getValue();
529 }
530 }
531 }
532 if ($repositoryRootNode < 1) {
533 $repositoryRootNode = self::REPOSITORY_ROOT_NODE_ID;
534 }
535
536 $parentObjectIds = $this->getQuestionParentObjIds($repositoryRootNode);
537
538 if (!count($parentObjectIds)) {
539 return [];
540 }
541
542 $questionList->setParentObjIdsFilter($parentObjectIds);
543 $questionList->setParentObjectType($this->getQuestionParentObjectType());
544
545 $questionList->load();
546
547 return $questionList->getQuestionDataArray();
548 }
549
550 private function getQuestionInstanceTypeFilter(): string
551 {
552 if ($this->fetchModeParameter() === self::MODE_BROWSE_TESTS) {
554 }
555
557 }
558
563 private function getQuestionParentObjIds(int $repositoryRootNode): array
564 {
565 $parents = $this->tree->getSubTree(
566 $this->tree->getNodeData($repositoryRootNode),
567 true,
568 [$this->getQuestionParentObjectType()]
569 );
570
571 $parentIds = [];
572
573 foreach ($parents as $nodeData) {
574 if ((int) $nodeData['obj_id'] === $this->testOBJ->getId()) {
575 continue;
576 }
577
578 $parentIds[$nodeData['obj_id']] = $nodeData['obj_id'];
579 }
580
581 $parentIds = array_map('intval', array_values($parentIds));
582
583 if ($this->fetchModeParameter() === self::MODE_BROWSE_POOLS) {
584 $available_pools = array_map('intval', array_keys(ilObjQuestionPool::_getAvailableQuestionpools(true)));
585 return array_intersect($parentIds, $available_pools);
586 } elseif ($this->fetchModeParameter() === self::MODE_BROWSE_TESTS) {
587 return array_filter($parentIds, function ($obj_id): bool {
588 $refIds = ilObject::_getAllReferences($obj_id);
589 $refId = current($refIds);
590 return $this->access->checkAccess('write', '', $refId);
591 });
592 }
593
594 // Return no parent ids if the user wants to hack...
595 return [];
596 }
597
598 private function getQuestionParentObjectType(): string
599 {
600 if ($this->fetchModeParameter() === self::MODE_BROWSE_TESTS) {
601 return 'tst';
602 }
603
604 return 'qpl';
605 }
606}
Builds data types.
Definition: Factory.php:21
const IL_CAL_UNIX
static _getQuestionTypeName($type_tag)
static _needsManualScoring(int $question_id)
Class ilCtrl provides processing control methods.
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
Class for single dates.
language handling
static _getQuestionTypes($all_tags=false, $fixOrder=false, $withDeprecatedTypes=true)
static _getAvailableQuestionpools($use_object_id=false, $equal_points=false, $could_be_offline=false, $showPath=false, $with_questioncount=false, $permission="read", $usr_id="")
Returns the available question pools for the active user.
static _getAllReferences(int $id)
get all reference ids for object ID
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a selection list property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setFilterCommand(string $a_val, string $a_caption="")
addFilterItem(ilTableFilterItem $a_input_item, bool $a_optional=false)
setFormName(string $a_name="")
addHiddenInput(string $a_name, string $a_value)
addMultiCommand(string $a_cmd, string $a_text)
setFormAction(string $a_form_action, bool $a_multipart=false)
addColumn(string $a_text, string $a_sort_field="", string $a_width="", bool $a_is_checkbox_action_column=false, string $a_class="", string $a_tooltip="", bool $a_tooltip_with_html=false)
setDefaultOrderField(string $a_defaultorderfield)
setSelectAllCheckbox(string $a_select_all_checkbox, bool $a_select_all_on_top=false)
setDisableFilterHiding(bool $a_val=true)
getFilterItems(bool $a_optionals=false)
setRowTemplate(string $a_template, string $a_template_dir="")
Set row template.
setId(string $a_val)
setDefaultOrderDirection(string $a_defaultorderdirection)
setResetCommand(string $a_val, string $a_caption="")
setData(array $a_data)
Set table data.
ilLanguage $lng
enable(string $a_module_name)
setStyle(string $a_element, string $a_style)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
buildPossiblyLinkedQuestonPoolOrTestTitle(int $obj_id, string $parent_title)
fillRow(array $a_set)
Standard Version of Fill Row.
ILIAS Test InternalRequestService $testrequest
__construct(ilCtrl $ctrl, ilGlobalTemplateInterface $mainTpl, ilTabsGUI $tabs, ilLanguage $lng, ilTree $tree, ilDBInterface $db, ilComponentRepository $component_repository, ilObjTest $testOBJ, ilAccessHandler $access, ILIAS\HTTP\GlobalHttpState $httpState, Refinery $refinery, UIFactory $ui_factory, UIRenderer $ui_renderer)
This class represents a text property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $DIC
Definition: feed.php:28
This is how the factory for UI elements looks.
Definition: Factory.php:38
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...
Readable part of repository interface to ilComponentDataDB.
Interface ilDBInterface.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193
Class ChatMainBarProvider \MainMenu\Provider.
$refId
Definition: xapitoken.php:58