ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilTestQuestionBrowserTableGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Services/Table/classes/class.ilTable2GUI.php';
5 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionList.php';
6 
11 
23 {
25 
27 
28  const CONTEXT_PARAMETER = 'question_browse_context';
29  const CONTEXT_PAGE_VIEW = 'contextPageView';
30  const CONTEXT_LIST_VIEW = 'contextListView';
31 
32  const MODE_PARAMETER = 'question_browse_mode';
33  const MODE_BROWSE_POOLS = 'modeBrowsePools';
34  const MODE_BROWSE_TESTS = 'modeBrowseTests';
35 
36  const CMD_BROWSE_QUESTIONS = 'browseQuestions';
37  const CMD_APPLY_FILTER = 'applyFilter';
38  const CMD_RESET_FILTER = 'resetFilter';
39  const CMD_INSERT_QUESTIONS = 'insertQuestions';
40 
41  protected $writeAccess = false;
42 
46  protected $ctrl;
47  private $ui_factory;
48  private $ui_renderer;
49 
53  protected $mainTpl;
54 
58  protected $tabs;
59 
63  protected $lng;
64 
68  protected $tree;
69 
73  protected $db;
74 
78  protected $pluginAdmin;
79 
83  protected $testOBJ;
84 
88  protected $access;
89 
93  protected $refinery;
94 
107  public function __construct(
108  ilCtrl $ctrl,
112  ilTree $tree,
120  ) {
121  $this->ctrl = $ctrl;
122  $this->mainTpl = $mainTpl;
123  $this->tabs = $tabs;
124  $this->lng = $lng;
125  $this->tree = $tree;
126  $this->db = $db;
127  $this->pluginAdmin = $pluginAdmin;
128  $this->testOBJ = $testOBJ;
129  $this->access = $access;
130  $this->refinery = $refinery;
131  $this->ui_factory = $ui_factory;
132  $this->ui_renderer = $ui_renderer;
133 
134  $this->setId('qpl_brows_tabl_' . $this->testOBJ->getId());
135 
136  parent::__construct($this, self::CMD_BROWSE_QUESTIONS);
137  $this->setFilterCommand(self::CMD_APPLY_FILTER);
138  $this->setResetCommand(self::CMD_RESET_FILTER);
139 
140  $this->setFormName('questionbrowser');
141  $this->setStyle('table', 'fullwidth');
142  $this->addColumn('', '', '1%', true);
143  $this->addColumn($this->lng->txt("tst_question_title"), 'title', '');
144  $this->addColumn($this->lng->txt("description"), 'description', '');
145  $this->addColumn($this->lng->txt("tst_question_type"), 'ttype', '');
146  $this->addColumn($this->lng->txt("author"), 'author', '');
147  $this->addColumn($this->lng->txt('qst_lifecycle'), 'lifecycle', '');
148  $this->addColumn($this->lng->txt("create_date"), 'created', '');
149  $this->addColumn($this->lng->txt("last_update"), 'tstamp', ''); // name of col is proper "updated" but in data array the key is "tstamp"
150  $this->addColumn($this->getParentObjectLabel(), 'qpl', '');
151  $this->addColumn($this->lng->txt("working_time"), 'working_time', '');
152  $this->setSelectAllCheckbox('q_id');
153  $this->setRowTemplate("tpl.il_as_tst_question_browser_row.html", "Modules/Test");
154 
155  $this->setFormAction($this->ctrl->getFormAction($this->getParentObject(), $this->getParentCmd()));
156  $this->setDefaultOrderField("title");
157  $this->setDefaultOrderDirection("asc");
158 
159  $this->enable('sort');
160  //$this->enable('header');
161  $this->enable('select_all');
162  $this->initFilter();
163  $this->setDisableFilterHiding(true);
164  }
165 
166  public function setWriteAccess($value)
167  {
168  $this->writeAccess = $value;
169  }
170 
171  public function hasWriteAccess()
172  {
173  return $this->writeAccess;
174  }
175 
176  public function init()
177  {
178  if ($this->hasWriteAccess()) {
179  $this->addMultiCommand(self::CMD_INSERT_QUESTIONS, $this->lng->txt('insert'));
180  }
181  }
182 
183  public function executeCommand()
184  {
185  $this->handleParameters();
186  $this->handleTabs();
187 
188  switch ($this->ctrl->getNextClass($this)) {
189  case strtolower(__CLASS__):
190  case '':
191 
192  $cmd = $this->ctrl->getCmd() . 'Cmd';
193  return $this->$cmd();
194 
195  default:
196 
197  $this->ctrl->setReturn($this, self::CMD_BROWSE_QUESTIONS);
198  return parent::executeCommand();
199  }
200  }
201 
202  private function browseQuestionsCmd()
203  {
204  $this->setData($this->getQuestionsData());
205 
206  $this->mainTpl->setContent($this->ctrl->getHTML($this));
207  }
208 
209  private function applyFilterCmd()
210  {
211  $this->writeFilterToSession();
212  $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
213  }
214 
215  private function resetFilterCmd()
216  {
217  $this->resetFilter();
218  $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
219  }
220 
221  private function insertQuestionsCmd()
222  {
223  $selected_array = (is_array($_POST['q_id'])) ? $_POST['q_id'] : array();
224  if (!count($selected_array)) {
225  ilUtil::sendInfo($this->lng->txt("tst_insert_missing_question"), true);
226  $this->ctrl->redirect($this, self::CMD_BROWSE_QUESTIONS);
227  }
228 
229  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
230 
231  $testQuestionSetConfig = $this->buildTestQuestionSetConfig();
232 
233  $manscoring = false;
234 
235  foreach ($selected_array as $key => $value) {
236  $last_question_id = $this->testOBJ->insertQuestion($testQuestionSetConfig, $value);
237 
238  if (!$manscoring) {
239  $manscoring = $manscoring | assQuestion::_needsManualScoring($value);
240  }
241  }
242 
243  $this->testOBJ->saveCompleteStatus($testQuestionSetConfig);
244 
245  if ($manscoring) {
246  ilUtil::sendInfo($this->lng->txt("manscoring_hint"), true);
247  } else {
248  ilUtil::sendSuccess($this->lng->txt("tst_questions_inserted"), true);
249  }
250 
251  //$this->ctrl->setParameter($this, 'q_id', $last_question_id); // for page view ?
252 
253  $this->ctrl->redirectByClass($this->getBackTargetCmdClass(), $this->getBackTargetCommand());
254  }
255 
256  private function handleParameters()
257  {
258  $this->ctrl->saveParameter($this, self::CONTEXT_PARAMETER);
259  if (isset($_GET[self::CONTEXT_PARAMETER])) {
260  $this->addHiddenInput(self::CONTEXT_PARAMETER, $_GET[self::CONTEXT_PARAMETER]);
261  } elseif (isset($_POST[self::CONTEXT_PARAMETER])) {
262  $this->addHiddenInput(self::CONTEXT_PARAMETER, $_POST[self::CONTEXT_PARAMETER]);
263  }
264 
265  $this->ctrl->saveParameter($this, self::MODE_PARAMETER);
266  if (isset($_GET[self::MODE_PARAMETER])) {
267  $this->addHiddenInput(self::MODE_PARAMETER, $_GET[self::MODE_PARAMETER]);
268  } elseif (isset($_POST[self::MODE_PARAMETER])) {
269  $this->addHiddenInput(self::MODE_PARAMETER, $_POST[self::MODE_PARAMETER]);
270  }
271  }
272 
273  private function fetchContextParameter()
274  {
275  if (isset($_POST[self::CONTEXT_PARAMETER])) {
276  return $_POST[self::CONTEXT_PARAMETER];
277  }
278 
279  if (isset($_GET[self::CONTEXT_PARAMETER])) {
280  return $_GET[self::CONTEXT_PARAMETER];
281  }
282 
283  return null;
284  }
285 
286  private function fetchModeParameter()
287  {
288  if (isset($_POST[self::MODE_PARAMETER])) {
289  return $_POST[self::MODE_PARAMETER];
290  }
291 
292  if (isset($_GET[self::MODE_PARAMETER])) {
293  return $_GET[self::MODE_PARAMETER];
294  }
295 
296  return null;
297  }
298 
299  private function handleTabs()
300  {
301  $this->tabs->clearTargets();
302  $this->tabs->clearSubTabs();
303 
304  $this->tabs->setBackTarget(
305  $this->getBackTargetLabel(),
306  $this->getBackTargetUrl()
307  );
308 
309  $this->tabs->addTab(
310  'browseQuestions',
312  $this->getBrowseQuestionsTabUrl()
313  );
314  }
315 
316  private function getBackTargetLabel()
317  {
318  return $this->lng->txt('backtocallingtest');
319  }
320 
321  private function getBackTargetUrl()
322  {
323  return $this->ctrl->getLinkTargetByClass(
324  $this->getBackTargetCmdClass(),
325  $this->getBackTargetCommand()
326  );
327  }
328 
329  private function getBackTargetCmdClass()
330  {
331  switch ($this->fetchContextParameter()) {
332  case self::CONTEXT_LIST_VIEW:
333 
334  return 'ilObjTestGUI';
335 
336  case self::CONTEXT_PAGE_VIEW:
337 
338  return 'ilTestExpressPageObjectGUI';
339  }
340 
341  return '';
342  }
343 
344  private function getBackTargetCommand()
345  {
346  switch ($this->fetchContextParameter()) {
347  case self::CONTEXT_LIST_VIEW:
348 
349  return 'questions';
350 
351  case self::CONTEXT_PAGE_VIEW:
352 
353  return 'showPage';
354  }
355 
356  return '';
357  }
358 
359  private function getBrowseQuestionsTabLabel()
360  {
361  switch ($this->fetchModeParameter()) {
362  case self::MODE_BROWSE_POOLS:
363 
364  return $this->lng->txt('tst_browse_for_qpl_questions');
365 
366  case self::MODE_BROWSE_TESTS:
367 
368  return $this->lng->txt('tst_browse_for_tst_questions');
369  }
370 
371  return '';
372  }
373 
374  private function getBrowseQuestionsTabUrl()
375  {
376  return $this->ctrl->getLinkTarget($this, self::CMD_BROWSE_QUESTIONS);
377  }
378 
379  public function initFilter()
380  {
381  // title
382  include_once("./Services/Form/classes/class.ilTextInputGUI.php");
383  $ti = new ilTextInputGUI($this->lng->txt("tst_qbt_filter_question_title"), "title");
384  $ti->setMaxLength(64);
385  $ti->setSize(20);
386  $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
387  $this->addFilterItem($ti);
388  $ti->readFromSession();
389  $this->filter["title"] = $ti->getValue();
390 
391  // description
392  $ti = new ilTextInputGUI($this->lng->txt("description"), "description");
393  $ti->setMaxLength(64);
394  $ti->setSize(20);
395  $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
396  $this->addFilterItem($ti);
397  $ti->readFromSession();
398  $this->filter["description"] = $ti->getValue();
399 
400  // author
401  $ti = new ilTextInputGUI($this->lng->txt("author"), "author");
402  $ti->setMaxLength(64);
403  $ti->setSize(20);
404  $this->addFilterItem($ti);
405  $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
406  $ti->readFromSession();
407  $this->filter["author"] = $ti->getValue();
408 
409  // lifecycle
410  $lifecycleOptions = array_merge(
411  array('' => $this->lng->txt('qst_lifecycle_filter_all')),
412  ilAssQuestionLifecycle::getDraftInstance()->getSelectOptions($this->lng)
413  );
414  $lifecycleInp = new ilSelectInputGUI($this->lng->txt('qst_lifecycle'), 'lifecycle');
415  $lifecycleInp->setOptions($lifecycleOptions);
416  $this->addFilterItem($lifecycleInp);
417  $lifecycleInp->readFromSession();
418  $this->filter['lifecycle'] = $lifecycleInp->getValue();
419 
420  // questiontype
421  include_once("./Services/Form/classes/class.ilSelectInputGUI.php");
422  include_once("./Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php");
424  $options = array();
425  $options[""] = $this->lng->txt('filter_all_question_types');
426  foreach ($types as $translation => $row) {
427  $options[$row['type_tag']] = $translation;
428  }
429 
430  $si = new ilSelectInputGUI($this->lng->txt("question_type"), "type");
431  $si->setOptions($options);
432  $this->addFilterItem($si);
433  $si->readFromSession();
434  $this->filter["type"] = $si->getValue();
435 
436  // question pool
437  $ti = new ilTextInputGUI($this->getParentObjectLabel(), 'parent_title');
438  $ti->setMaxLength(64);
439  $ti->setSize(20);
440  $ti->setValidationRegexp('/(^[^%]+$)|(^$)/is');
441  $this->addFilterItem($ti);
442  $ti->readFromSession();
443  $this->filter['parent_title'] = $ti->getValue();
444 
445  // repo root node
446  require_once 'Services/Form/classes/class.ilRepositorySelectorInputGUI.php';
447  $ri = new ilRepositorySelectorInputGUI($this->lng->txt('repository'), 'repository_root_node');
448  $ri->setHeaderMessage($this->lng->txt('question_browse_area_info'));
449  if ($this->fetchModeParameter() == self::MODE_BROWSE_TESTS) {
450  $ri->setClickableTypes(array('tst'));
451  } else {
452  $ri->setClickableTypes(array('qpl'));
453  }
454  $this->addFilterItem($ri);
455  $ri->readFromSession();
456  $this->filter['repository_root_node'] = $ri->getValue();
457  }
458 
459  private function getParentObjectLabel()
460  {
461  switch ($this->fetchModeParameter()) {
462  case self::MODE_BROWSE_POOLS:
463 
464  return $this->lng->txt('qpl');
465 
466  case self::MODE_BROWSE_TESTS:
467 
468  return $this->lng->txt('tst');
469  }
470 
471  return '';
472  }
473 
474  protected function getTranslatedLifecycle($lifecycle)
475  {
476  try {
477  return ilAssQuestionLifecycle::getInstance($lifecycle)->getTranslation($this->lng);
479  return '';
480  }
481  }
482 
483  public function fillRow($data)
484  {
485  $this->tpl->setVariable("QUESTION_ID", $data["question_id"]);
486  $this->tpl->setVariable("QUESTION_TITLE", $data["title"]);
487  $this->tpl->setVariable("QUESTION_COMMENT", $data["description"]);
488  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
489  $this->tpl->setVariable("QUESTION_TYPE", assQuestion::_getQuestionTypeName($data["type_tag"]));
490  $this->tpl->setVariable("QUESTION_AUTHOR", $data["author"]);
491  $this->tpl->setVariable("QUESTION_LIFECYCLE", $this->getTranslatedLifecycle($data['lifecycle']));
492  $this->tpl->setVariable("QUESTION_CREATED", ilDatePresentation::formatDate(new ilDate($data['created'], IL_CAL_UNIX)));
493  $this->tpl->setVariable("QUESTION_UPDATED", ilDatePresentation::formatDate(new ilDate($data["tstamp"], IL_CAL_UNIX)));
494  $this->tpl->setVariable("QUESTION_POOL", $data['parent_title']);
495  $this->tpl->setVariable(
496  "QUESTION_POOL_OR_TEST_TITLE",
498  (int) $data["obj_fi"],
499  $data["parent_title"]
500  )
501  );
502  $this->tpl->setVariable("WORKING_TIME", $data['working_time']);
503  }
504 
505  private function buildPossiblyLinkedQuestonPoolOrTestTitle(int $obj_id, string $parent_title) : string
506  {
507  switch ($this->fetchModeParameter()) {
508  case self::MODE_BROWSE_POOLS:
509  return $this->buildPossiblyLinkedQuestonPoolTitle(
510  $this->ctrl,
511  $this->access,
512  $this->lng,
513  $this->ui_factory,
514  $this->ui_renderer,
515  $obj_id,
516  $parent_title
517  );
518 
519  case self::MODE_BROWSE_TESTS:
520  return $this->buildPossiblyLinkedTestTitle(
521  $this->ctrl,
522  $this->access,
523  $this->lng,
524  $this->ui_factory,
525  $this->ui_renderer,
526  $obj_id,
527  $parent_title
528  );
529  }
530 
531  return '';
532  }
533 
537  private function buildTestQuestionSetConfig()
538  {
539  require_once 'Modules/Test/classes/class.ilTestQuestionSetConfigFactory.php';
540 
541  $testQuestionSetConfigFactory = new ilTestQuestionSetConfigFactory(
542  $this->tree,
543  $this->db,
544  $this->pluginAdmin,
545  $this->testOBJ
546  );
547 
548  return $testQuestionSetConfigFactory->getQuestionSetConfig();
549  }
550 
554  private function getQuestionsData()
555  {
556  $questionList = new ilAssQuestionList($this->db, $this->lng, $this->refinery, $this->pluginAdmin);
557 
558  $questionList->setQuestionInstanceTypeFilter($this->getQuestionInstanceTypeFilter());
559  $questionList->setExcludeQuestionIdsFilter($this->testOBJ->getExistingQuestions());
560 
561  $repositoryRootNode = self::REPOSITORY_ROOT_NODE_ID;
562 
563  foreach ($this->getFilterItems() as $item) {
564  if ($item->getValue() !== false) {
565  switch ($item->getPostVar()) {
566  case 'title':
567  case 'description':
568  case 'author':
569  case 'lifecycle':
570  case 'type':
571  case 'parent_title':
572 
573  $questionList->addFieldFilter($item->getPostVar(), $item->getValue());
574  break;
575 
576  case 'repository_root_node':
577 
578  $repositoryRootNode = $item->getValue();
579  }
580  }
581  }
582 
583  $parentObjectIds = $this->getQuestionParentObjIds($repositoryRootNode);
584 
585  if (!count($parentObjectIds)) {
586  return array();
587  }
588 
589  $questionList->setParentObjIdsFilter($parentObjectIds);
590  $questionList->setParentObjectType($this->getQuestionParentObjectType());
591 
592  $questionList->load();
593 
594  return $questionList->getQuestionDataArray();
595  }
596 
597  private function getQuestionInstanceTypeFilter()
598  {
599  if ($this->fetchModeParameter() === self::MODE_BROWSE_TESTS) {
601  }
602 
604  }
605 
606  private function getQuestionParentObjIds($repositoryRootNode)
607  {
608  $parents = $this->tree->getSubTree(
609  $this->tree->getNodeData($repositoryRootNode),
610  true,
612  );
613 
614  $parentIds = array();
615 
616  foreach ($parents as $nodeData) {
617  if ($nodeData['obj_id'] == $this->testOBJ->getId()) {
618  continue;
619  }
620 
621  $parentIds[ $nodeData['obj_id'] ] = $nodeData['obj_id'];
622  }
623 
624  $parentIds = array_map('intval', array_values($parentIds));
625 
626  if ($this->fetchModeParameter() == self::MODE_BROWSE_POOLS) {
627  $available_pools = array_map('intval', array_keys(ilObjQuestionPool::_getAvailableQuestionpools(true)));
628  return array_intersect($parentIds, $available_pools);
629  } elseif ($this->fetchModeParameter() == self::MODE_BROWSE_TESTS) {
630  // TODO bheyser: Move this to another place ...
631  return array_filter($parentIds, function ($obj_id) {
632  $refIds = ilObject::_getAllReferences($obj_id);
633  $refId = current($refIds);
634  return $this->access->checkAccess('write', '', $refId);
635  });
636  }
637 
638  // Return no parent ids if the user wants to hack...
639  return array();
640  }
641 
642  private function getQuestionParentObjectType()
643  {
644  if ($this->fetchModeParameter() == self::MODE_BROWSE_TESTS) {
645  return 'tst';
646  }
647 
648  return 'qpl';
649  }
650 }
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.
This class provides processing control methods.
setDefaultOrderField($a_defaultorderfield)
Set Default order field.
addHiddenInput($a_name, $a_value)
Add Hidden Input field.
setStyle($a_element, $a_style)
Tabs GUI.
$_GET["client_id"]
static _needsManualScoring($question_id)
static _getQuestionTypeName($type_tag)
Return the translation for a given question type tag.
addFilterItem($a_input_item, $a_optional=false)
Add filter item.
$refId
Definition: xapitoken.php:40
const IL_CAL_UNIX
getParentCmd()
Get parent command.
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false, $include_seconds=false)
Format a date public.
setId($a_val)
Set id.
static _getAllReferences($a_id)
get all reference ids of object
setDefaultOrderDirection($a_defaultorderdirection)
Set Default order direction.
Administration class for plugins.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
buildPossiblyLinkedQuestonPoolOrTestTitle(int $obj_id, string $parent_title)
Class for single dates.
setResetCommand($a_val, $a_caption=null)
Set reset filter command.
setSelectAllCheckbox($a_select_all_checkbox, $a_select_all_on_top=false)
Set the name of the checkbox that should be toggled with a select all button.
setDisableFilterHiding($a_val=true)
Set disable filter hiding.
addMultiCommand($a_cmd, $a_text)
Add Command button.
enable($a_module_name)
enables particular modules of table
setRowTemplate($a_template, $a_template_dir="")
Set row template.
__construct(ilCtrl $ctrl, ilGlobalTemplateInterface $mainTpl, ilTabsGUI $tabs, ilLanguage $lng, ilTree $tree, ilDBInterface $db, ilPluginAdmin $pluginAdmin, ilObjTest $testOBJ, ilAccessHandler $access, Refinery $refinery, UIFactory $ui_factory, UIRenderer $ui_renderer)
ilTestQuestionBrowserTableGUI constructor.
writeFilterToSession()
Write filter values to session.
setFormAction($a_form_action, $a_multipart=false)
Set Form action parameter.
setFormName($a_formname="")
Set Form name.
__construct(Container $dic, ilPlugin $plugin)
addColumn( $a_text, $a_sort_field="", $a_width="", $a_is_checkbox_action_column=false, $a_class="", $a_tooltip="", $a_tooltip_with_html=false)
Add a column to the header.
filter()
Definition: filter.php:2
getFilterItems($a_optionals=false)
Get filter items.
$_POST["username"]
resetFilter()
Reset filter.
static _getQuestionTypes($all_tags=false, $fixOrder=false, $withDeprecatedTypes=true)
setFilterCommand($a_val, $a_caption=null)
Set filter command.