ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilAssQuestionList.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Taxonomy/interfaces/interface.ilTaxAssignedItemInfo.php';
5require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssQuestionType.php';
6
17{
23 protected $db = null;
24
30 private $lng = null;
31
37 private $pluginAdmin = null;
38
44 private $parentObjIdsFilter = array();
45
51 private $parentObjId = null;
52
58 private $parentObjType = 'qpl';
59
65 private $availableTaxonomyIds = array();
66
72 private $fieldFilters = array();
73
79 private $taxFilters = array();
80
86 private $taxParentIds = array();
87
93 private $taxParentTypes = array();
94
100 private $answerStatusActiveId = null;
101
105 private $forcedQuestionIds = array();
106
111 protected $join_obj_data = true;
112
113
120
127
133 private $answerStatusFilter = null;
134
135 const QUESTION_INSTANCE_TYPE_ORIGINALS = 'QST_INSTANCE_TYPE_ORIGINALS';
136 const QUESTION_INSTANCE_TYPE_DUPLICATES = 'QST_INSTANCE_TYPE_DUPLICATES';
138
141
144 const QUESTION_COMPLETION_STATUS_BOTH = 'complete/incomplete';
146
152 protected $questions = array();
153
162 {
163 $this->db = $db;
164 $this->lng = $lng;
165 $this->pluginAdmin = $pluginAdmin;
166 }
167
168 public function getParentObjId()
169 {
170 return $this->parentObjId;
171 }
172
174 {
175 $this->parentObjId = $parentObjId;
176 }
177
178 public function getParentObjectType()
179 {
181 }
182
184 {
185 $this->parentObjType = $parentObjType;
186 }
187
191 public function getParentObjIdsFilter()
192 {
194 }
195
200 {
201 $this->parentObjIdsFilter = $parentObjIdsFilter;
202 }
203
205 {
206 $this->questionInstanceTypeFilter = $questionInstanceTypeFilter;
207 }
208
210 {
212 }
213
214 public function setIncludeQuestionIdsFilter($questionIdsFilter)
215 {
216 $this->includeQuestionIdsFilter = $questionIdsFilter;
217 }
218
220 {
222 }
223
225 {
227 }
228
230 {
231 $this->excludeQuestionIdsFilter = $excludeQuestionIdsFilter;
232 }
233
235 {
237 }
238
240 {
241 $this->questionCompletionStatusFilter = $questionCompletionStatusFilter;
242 }
243
244 public function addFieldFilter($fieldName, $fieldValue)
245 {
246 $this->fieldFilters[$fieldName] = $fieldValue;
247 }
248
249 public function addTaxonomyFilter($taxId, $taxNodes, $parentObjId, $parentObjType)
250 {
251 $this->taxFilters[$taxId] = $taxNodes;
252 $this->taxParentIds[$taxId] = $parentObjId;
253 $this->taxParentTypes[$taxId] = $parentObjType;
254 }
255
257 {
258 $this->availableTaxonomyIds = $availableTaxonomyIds;
259 }
260
261 public function getAvailableTaxonomyIds()
262 {
264 }
265
267 {
268 $this->answerStatusActiveId = $answerStatusActiveId;
269 }
270
271 public function getAnswerStatusActiveId()
272 {
274 }
275
277 {
278 $this->answerStatusFilter = $answerStatusFilter;
279 }
280
281 public function getAnswerStatusFilter()
282 {
284 }
285
291 public function setJoinObjectData($a_val)
292 {
293 $this->join_obj_data = $a_val;
294 }
295
301 public function getJoinObjectData()
302 {
304 }
305
310 {
311 $this->forcedQuestionIds = $forcedQuestionIds;
312 }
313
317 public function getForcedQuestionIds()
318 {
320 }
321
323 {
324 if ($this->getParentObjId()) {
325 return 'qpl_questions.obj_fi = ' . $this->db->quote($this->getParentObjId(), 'integer');
326 }
327
328 if (count($this->getParentObjIdsFilter())) {
329 return $this->db->in('qpl_questions.obj_fi', $this->getParentObjIdsFilter(), false, 'integer');
330 }
331
332 return null;
333 }
334
335 private function getFieldFilterExpressions()
336 {
337 $expressions = array();
338
339 foreach ($this->fieldFilters as $fieldName => $fieldValue) {
340 switch ($fieldName) {
341 case 'title':
342 case 'description':
343 case 'author':
344 case 'lifecycle':
345
346 $expressions[] = $this->db->like('qpl_questions.' . $fieldName, 'text', "%%$fieldValue%%");
347 break;
348
349 case 'type':
350
351 $expressions[] = "qpl_qst_type.type_tag = {$this->db->quote($fieldValue, 'text')}";
352 break;
353
354 case 'question_id':
355 if ($fieldValue != "" && !is_array($fieldValue)) {
356 $fieldValue = array($fieldValue);
357 }
358 $expressions[] = $this->db->in("qpl_questions.question_id", $fieldValue, false, "integer");
359 break;
360
361 case 'parent_title':
362 if ($this->join_obj_data) {
363 $expressions[] = $this->db->like('object_data.title', 'text', "%%$fieldValue%%");
364 }
365 break;
366 }
367 }
368
369 return $expressions;
370 }
371
373 {
374 $expressions = array();
375
376 require_once 'Services/Taxonomy/classes/class.ilTaxonomyTree.php';
377 require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
378
379 foreach ($this->taxFilters as $taxId => $taxNodes) {
380 $questionIds = array();
381
382 $forceBypass = true;
383
384 foreach ($taxNodes as $taxNode) {
385 $forceBypass = false;
386
387 $taxItemsByTaxParent = $this->getTaxItems(
388 $this->taxParentTypes[$taxId],
389 $this->taxParentIds[$taxId],
390 $taxId,
391 $taxNode
392 );
393
394 $taxItemsByParent = $this->getTaxItems(
395 $this->parentObjType,
396 $this->parentObjId,
397 $taxId,
398 $taxNode
399 );
400
401 $taxItems = array_merge($taxItemsByTaxParent, $taxItemsByParent);
402 foreach ($taxItems as $taxItem) {
403 $questionIds[$taxItem['item_id']] = $taxItem['item_id'];
404 }
405 }
406
407 if (!$forceBypass) {
408 $expressions[] = $this->db->in('question_id', $questionIds, false, 'integer');
409 }
410 }
411
412 return $expressions;
413 }
414
422 protected function getTaxItems($parentType, $parentObjId, $taxId, $taxNode)
423 {
424 $taxTree = new ilTaxonomyTree($taxId);
425
426 $taxNodeAssignment = new ilTaxNodeAssignment(
427 $parentType,
429 'quest',
430 $taxId
431 );
432
433 $subNodes = $taxTree->getSubTreeIds($taxNode);
434 $subNodes[] = $taxNode;
435
436 return $taxNodeAssignment->getAssignmentsOfNode($subNodes);
437 }
438
440 {
441 switch ($this->getQuestionInstanceTypeFilter()) {
443
444 return 'qpl_questions.original_id IS NULL';
445
447
448 return 'qpl_questions.original_id IS NOT NULL';
449 }
450
451 return null;
452 }
453
455 {
456 $expressions = array();
457
458 if (is_array($this->getIncludeQuestionIdsFilter())) {
459 $expressions[] = $this->db->in(
460 'qpl_questions.question_id',
462 false,
463 'integer'
464 );
465 }
466
467 if (is_array($this->getExcludeQuestionIdsFilter())) {
468 $IN = $this->db->in(
469 'qpl_questions.question_id',
471 true,
472 'integer'
473 );
474
475 if ($IN == ' 1=2 ') {
476 $IN = ' 1=1 ';
477 } // required for ILIAS < 5.0
478
479 $expressions[] = $IN;
480 }
481
482 return $expressions;
483 }
484
486 {
487 if ($this->parentObjId) {
488 return "qpl_questions.obj_fi = {$this->db->quote($this->parentObjId, 'integer')}";
489 }
490
491 return null;
492 }
493
495 {
496 $expressions = array();
497
498 switch ($this->getAnswerStatusFilter()) {
500
501 $expressions[] = '
502 (tst_test_result.question_fi IS NULL OR tst_test_result.points < qpl_questions.points)
503 ';
504 break;
505
507
508 $expressions[] = 'tst_test_result.question_fi IS NULL';
509 break;
510
512
513 $expressions[] = 'tst_test_result.question_fi IS NOT NULL';
514 $expressions[] = 'tst_test_result.points < qpl_questions.points';
515 break;
516 }
517
518 return $expressions;
519 }
520
521 private function getTableJoinExpression()
522 {
523 $tableJoin = "
524 INNER JOIN qpl_qst_type
525 ON qpl_qst_type.question_type_id = qpl_questions.question_type_fi
526 ";
527
528 if ($this->join_obj_data) {
529 $tableJoin .= "
530 INNER JOIN object_data
531 ON object_data.obj_id = qpl_questions.obj_fi
532 ";
533 }
534
535 if ($this->getAnswerStatusActiveId()) {
536 $tableJoin .= "
537 LEFT JOIN tst_test_result
538 ON tst_test_result.question_fi = qpl_questions.question_id
539 AND tst_test_result.active_fi = {$this->db->quote($this->getAnswerStatusActiveId(), 'integer')}
540 ";
541 }
542
543 return $tableJoin;
544 }
545
547 {
548 $CONDITIONS = array();
549
550 if ($this->getQuestionInstanceTypeFilterExpression() !== null) {
551 $CONDITIONS[] = $this->getQuestionInstanceTypeFilterExpression();
552 }
553
554 if ($this->getParentObjFilterExpression() !== null) {
555 $CONDITIONS[] = $this->getParentObjFilterExpression();
556 }
557
558 if ($this->getParentObjectIdFilterExpression() !== null) {
559 $CONDITIONS[] = $this->getParentObjectIdFilterExpression();
560 }
561
562 $CONDITIONS = array_merge(
563 $CONDITIONS,
568 );
569
570 $CONDITIONS = implode(' AND ', $CONDITIONS);
571
572 return strlen($CONDITIONS) ? 'AND ' . $CONDITIONS : '';
573 }
574
575 private function getSelectFieldsExpression()
576 {
577 $selectFields = array(
578 'qpl_questions.*',
579 'qpl_qst_type.type_tag',
580 'qpl_qst_type.plugin',
581 'qpl_qst_type.plugin_name',
582 'qpl_questions.points max_points'
583 );
584
585 if ($this->join_obj_data) {
586 $selectFields[] = 'object_data.title parent_title';
587 }
588
589 if ($this->getAnswerStatusActiveId()) {
590 $selectFields[] = 'tst_test_result.points reached_points';
591 $selectFields[] = "CASE
592 WHEN tst_test_result.points IS NULL THEN '" . self::QUESTION_ANSWER_STATUS_NON_ANSWERED . "'
593 WHEN tst_test_result.points < qpl_questions.points THEN '" . self::QUESTION_ANSWER_STATUS_WRONG_ANSWERED . "'
594 ELSE '" . self::QUESTION_ANSWER_STATUS_CORRECT_ANSWERED . "'
595 END question_answer_status
596 ";
597 }
598
599 $selectFields = implode(",\n\t\t\t\t", $selectFields);
600
601 return "
602 SELECT {$selectFields}
603 ";
604 }
605
606 private function buildBasicQuery()
607 {
608 return "
609 {$this->getSelectFieldsExpression()}
610
611 FROM qpl_questions
612
613 {$this->getTableJoinExpression()}
614
615 WHERE qpl_questions.tstamp > 0
616 ";
617 }
618
619 private function buildQuery()
620 {
621 $query = $this->buildBasicQuery() . "
622 {$this->getConditionalFilterExpression()}
623 ";
624
625 if (count($this->getForcedQuestionIds())) {
626 $query .= "
627 UNION {$this->buildBasicQuery()}
628 AND {$this->db->in('qpl_questions.question_id', $this->getForcedQuestionIds(), false, 'integer')}
629 ";
630 }
631
632 return $query;
633 }
634
635 public function load()
636 {
637 $this->checkFilters();
638
639 $query = $this->buildQuery();
640
641 #vd($query);
642
643 $res = $this->db->query($query);
644
645 //echo $this->db->db->last_query;
646
647 #vd($this->db->db->last_query);
648
649 while ($row = $this->db->fetchAssoc($res)) {
651
652 if (!$this->isActiveQuestionType($row)) {
653 continue;
654 }
655
656 $row['taxonomies'] = $this->loadTaxonomyAssignmentData($row['obj_fi'], $row['question_id']);
657
658 $row['ttype'] = $this->lng->txt($row['type_tag']);
659
660 $this->questions[ $row['question_id'] ] = $row;
661 }
662 }
663
664 private function loadTaxonomyAssignmentData($parentObjId, $questionId)
665 {
666 $taxAssignmentData = array();
667
668 foreach ($this->getAvailableTaxonomyIds() as $taxId) {
669 require_once 'Services/Taxonomy/classes/class.ilTaxonomyTree.php';
670 require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
671
672 $taxTree = new ilTaxonomyTree($taxId);
673
674 $taxAssignment = new ilTaxNodeAssignment('qpl', $parentObjId, 'quest', $taxId);
675
676 $assignments = $taxAssignment->getAssignmentsOfItem($questionId);
677
678 foreach ($assignments as $assData) {
679 if (!isset($taxAssignmentData[ $assData['tax_id'] ])) {
680 $taxAssignmentData[ $assData['tax_id'] ] = array();
681 }
682
683 $nodeData = $taxTree->getNodeData($assData['node_id']);
684
685 $assData['node_lft'] = $nodeData['lft'];
686
687 $taxAssignmentData[ $assData['tax_id'] ][ $assData['node_id'] ] = $assData;
688 }
689 }
690
691 return $taxAssignmentData;
692 }
693
694 private function isActiveQuestionType($questionData)
695 {
696 if (!isset($questionData['plugin'])) {
697 return false;
698 }
699
700 if (!$questionData['plugin']) {
701 return true;
702 }
703
704 return $this->pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $questionData['plugin_name']);
705 }
706
707 public function getDataArrayForQuestionId($questionId)
708 {
709 return $this->questions[$questionId];
710 }
711
712 public function getQuestionDataArray()
713 {
714 return $this->questions;
715 }
716
717 public function isInList($questionId)
718 {
719 return isset($this->questions[$questionId]);
720 }
721
731 public function getTitle($a_comp_id, $a_item_type, $a_item_id)
732 {
733 if ($a_comp_id != 'qpl' || $a_item_type != 'quest' || !(int) $a_item_id) {
734 return '';
735 }
736
737 if (!isset($this->questions[$a_item_id])) {
738 return '';
739 }
740
741 return $this->questions[$a_item_id]['title'];
742 }
743
744 private function checkFilters()
745 {
746 if (strlen($this->getAnswerStatusFilter()) && !$this->getAnswerStatusActiveId()) {
747 require_once 'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
748
750 'No active id given! You cannot use the answer status filter without giving an active id.'
751 );
752 }
753 }
754}
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_MODULE
setAnswerStatusActiveId($answerStatusActiveId)
const ANSWER_STATUS_FILTER_ALL_NON_CORRECT
answer status filter value domain
setExcludeQuestionIdsFilter($excludeQuestionIdsFilter)
getDataArrayForQuestionId($questionId)
setParentObjectType($parentObjType)
getTaxItems($parentType, $parentObjId, $taxId, $taxNode)
setIncludeQuestionIdsFilter($questionIdsFilter)
setQuestionCompletionStatusFilter($questionCompletionStatusFilter)
setForcedQuestionIds($forcedQuestionIds)
addTaxonomyFilter($taxId, $taxNodes, $parentObjId, $parentObjType)
isActiveQuestionType($questionData)
setAvailableTaxonomyIds($availableTaxonomyIds)
getJoinObjectData()
Get if object data table should be joined.
setAnswerStatusFilter($answerStatusFilter)
__construct(ilDBInterface $db, ilLanguage $lng, ilPluginAdmin $pluginAdmin)
Constructor.
setJoinObjectData($a_val)
Set if object data table should be joined.
setParentObjIdsFilter($parentObjIdsFilter)
loadTaxonomyAssignmentData($parentObjId, $questionId)
setQuestionInstanceTypeFilter($questionInstanceTypeFilter)
const QUESTION_ANSWER_STATUS_NON_ANSWERED
answer status domain for single questions
addFieldFilter($fieldName, $fieldValue)
getTitle($a_comp_id, $a_item_type, $a_item_id)
Get title of an assigned item.
static completeMissingPluginName($questionTypeData)
language handling
Administration class for plugins.
Taxonomy node <-> item assignment.
Interface ilDBInterface.
Interface for assigned items of taxonomies.
$query
foreach($_POST as $key=> $value) $res