ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
All Data Structures Namespaces Files Functions Variables Modules Pages
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 
4 require_once 'Services/Taxonomy/interfaces/interface.ilTaxAssignedItemInfo.php';
5 
16 {
22  private $db = null;
23 
29  private $lng = null;
30 
36  private $pluginAdmin = null;
37 
43  private $parentObjId = null;
44 
45  private $parentObjType = 'qpl';
46 
52  private $availableTaxonomyIds = array();
53 
59  private $fieldFilters = array();
60 
66  private $taxFilters = array();
67 
73  private $answerStatusActiveId = null;
74 
78  private $forcedQuestionIds = array();
79 
83  const QUESTION_ANSWER_STATUS_NON_ANSWERED = 'nonAnswered';
84  const QUESTION_ANSWER_STATUS_WRONG_ANSWERED = 'wrongAnswered';
85  const QUESTION_ANSWER_STATUS_CORRECT_ANSWERED = 'correctAnswered';
86 
90  const ANSWER_STATUS_FILTER_ALL_NON_CORRECT = 'allNonCorrect';
93 
99  private $answerStatusFilter = null;
100 
106  private $questions = array();
107 
108 
109  const QUESTION_INSTANCE_TYPE_ORIGINALS = 'QST_INSTANCE_TYPE_ORIGINALS';
110  const QUESTION_INSTANCE_TYPE_DUPLICATES = 'QST_INSTANCE_TYPE_DUPLICATES';
111  private $questionInstanceTypeFilter = self::QUESTION_INSTANCE_TYPE_ORIGINALS;
112 
113  private $questionIdsFilter = null;
114 
122  {
123  $this->db = $db;
124  $this->lng = $lng;
125  $this->pluginAdmin = $pluginAdmin;
126  $this->parentObjId = $parentObjId;
127  }
128 
130  {
131  $this->parentObjType = $parentObjType;
132  }
133 
134  public function getParentObjectType()
135  {
136  return $this->parentObjType;
137  }
138 
140  {
141  $this->questionInstanceTypeFilter = $questionInstanceTypeFilter;
142  }
143 
145  {
147  }
148 
150  {
151  $this->questionIdsFilter = $questionIdsFilter;
152  }
153 
154  public function getQuestionIdsFilter()
155  {
157  }
158 
159  public function addFieldFilter($fieldName, $fieldValue)
160  {
161  $this->fieldFilters[$fieldName] = $fieldValue;
162  }
163 
164  public function addTaxonomyFilter($taxId, $taxNodes)
165  {
166  $this->taxFilters[$taxId] = $taxNodes;
167  }
168 
170  {
171  $this->availableTaxonomyIds = $availableTaxonomyIds;
172  }
173 
174  public function getAvailableTaxonomyIds()
175  {
177  }
178 
180  {
181  $this->answerStatusActiveId = $answerStatusActiveId;
182  }
183 
184  public function getAnswerStatusActiveId()
185  {
187  }
188 
190  {
191  $this->answerStatusFilter = $answerStatusFilter;
192  }
193 
194  public function getAnswerStatusFilter()
195  {
197  }
198 
203  {
204  $this->forcedQuestionIds = $forcedQuestionIds;
205  }
206 
210  public function getForcedQuestionIds()
211  {
213  }
214 
215  private function getFieldFilterExpressions()
216  {
217  $expressions = array();
218 
219  foreach($this->fieldFilters as $fieldName => $fieldValue)
220  {
221  switch($fieldName)
222  {
223  case 'title':
224  case 'description':
225  case 'author':
226 
227  $expressions[] = $this->db->like('qpl_questions.' . $fieldName, 'text', "%%$fieldValue%%");
228  break;
229 
230  case 'type':
231 
232  $expressions[] = "qpl_qst_type.type_tag = {$this->db->quote($fieldValue, 'text')}";
233  break;
234 
235  case 'question_id':
236  if ($fieldValue != "" && !is_array($fieldValue))
237  {
238  $fieldValue = array($fieldValue);
239  }
240  $expressions[] = $this->db->in("qpl_questions.question_id", $fieldValue, false, "integer");
241  break;
242  }
243  }
244 
245  return $expressions;
246  }
247 
248  private function getTaxonomyFilterExpressions()
249  {
250  $expressions = array();
251 
252  require_once 'Services/Taxonomy/classes/class.ilTaxonomyTree.php';
253  require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
254 
255  foreach($this->taxFilters as $taxId => $taxNodes)
256  {
257  $questionIds = array();
258 
259  $forceBypass = true;
260 
261  foreach($taxNodes as $taxNode)
262  {
263  $forceBypass = false;
264 
265  $taxTree = new ilTaxonomyTree($taxId);
266 
267  $taxNodeAssignment = new ilTaxNodeAssignment($this->parentObjType, $this->parentObjId, 'quest', $taxId);
268 
269  $subNodes = $taxTree->getSubTreeIds($taxNode);
270  $subNodes[] = $taxNode;
271 
272  $taxItems = $taxNodeAssignment->getAssignmentsOfNode($subNodes);
273 
274  foreach($taxItems as $taxItem)
275  {
276  $questionIds[$taxItem['item_id']] = $taxItem['item_id'];
277  }
278  }
279 
280  if( !$forceBypass )
281  {
282  $expressions[] = $this->db->in('question_id', $questionIds, false, 'integer');
283  }
284  }
285 
286  return $expressions;
287  }
288 
290  {
291  switch( $this->getQuestionInstanceTypeFilter() )
292  {
293  case self::QUESTION_INSTANCE_TYPE_ORIGINALS:
294 
295  return 'qpl_questions.original_id IS NULL';
296 
297  case self::QUESTION_INSTANCE_TYPE_DUPLICATES:
298 
299  return 'qpl_questions.original_id IS NOT NULL';
300  }
301 
302  return null;
303  }
304 
306  {
307  if( is_array($this->getQuestionIdsFilter()) )
308  {
309  return $this->db->in('qpl_questions.question_id', $this->getQuestionIdsFilter(), false, 'integer');
310  }
311 
312  return null;
313  }
314 
316  {
317  if( $this->parentObjId )
318  {
319  return "qpl_questions.obj_fi = {$this->db->quote($this->parentObjId, 'integer')}";
320  }
321 
322  return null;
323  }
324 
326  {
327  $expressions = array();
328 
329  switch( $this->getAnswerStatusFilter() )
330  {
331  case self::ANSWER_STATUS_FILTER_ALL_NON_CORRECT:
332 
333  $expressions[] = '
334  (tst_test_result.question_fi IS NULL OR tst_test_result.points < qpl_questions.points)
335  ';
336  break;
337 
338  case self::ANSWER_STATUS_FILTER_NON_ANSWERED_ONLY:
339 
340  $expressions[] = 'tst_test_result.question_fi IS NULL';
341  break;
342 
343  case self::ANSWER_STATUS_FILTER_WRONG_ANSWERED_ONLY:
344 
345  $expressions[] = 'tst_test_result.question_fi IS NOT NULL';
346  $expressions[] = 'tst_test_result.points < qpl_questions.points';
347  break;
348  }
349 
350  return $expressions;
351  }
352 
353  private function getTableJoinExpression()
354  {
355  $tableJoin = "
356  INNER JOIN qpl_qst_type
357  ON qpl_qst_type.question_type_id = qpl_questions.question_type_fi
358  ";
359 
360  if( $this->getAnswerStatusActiveId() )
361  {
362  $tableJoin .= "
363  LEFT JOIN tst_test_result
364  ON tst_test_result.question_fi = qpl_questions.question_id
365  AND tst_test_result.active_fi = {$this->db->quote($this->getAnswerStatusActiveId(), 'integer')}
366  ";
367  }
368 
369  return $tableJoin;
370  }
371 
373  {
374  $CONDITIONS = array();
375 
376  if( $this->getQuestionInstanceTypeFilterExpression() !== null )
377  {
378  $CONDITIONS[] = $this->getQuestionInstanceTypeFilterExpression();
379  }
380 
381  if( $this->getQuestionIdsFilterExpression() !== null )
382  {
383  $CONDITIONS[] = $this->getQuestionIdsFilterExpression();
384  }
385 
386  if( $this->getParentObjectIdFilterExpression() !== null )
387  {
388  $CONDITIONS[] = $this->getParentObjectIdFilterExpression();
389  }
390 
391  $CONDITIONS = array_merge($CONDITIONS,
392  $this->getFieldFilterExpressions(),
395  );
396 
397  $CONDITIONS = implode(' AND ', $CONDITIONS);
398 
399  return strlen($CONDITIONS) ? 'AND '.$CONDITIONS : '';
400  }
401 
402  private function getSelectFieldsExpression()
403  {
404  $selectFields = array(
405  'qpl_questions.*',
406  'qpl_qst_type.type_tag',
407  'qpl_qst_type.plugin',
408  'qpl_questions.points max_points'
409  );
410 
411  if( $this->getAnswerStatusActiveId() )
412  {
413  $selectFields[] = 'tst_test_result.points reached_points';
414  $selectFields[] = "CASE
415  WHEN tst_test_result.points IS NULL THEN '".self::QUESTION_ANSWER_STATUS_NON_ANSWERED."'
416  WHEN tst_test_result.points < qpl_questions.points THEN '".self::QUESTION_ANSWER_STATUS_WRONG_ANSWERED."'
417  ELSE '".self::QUESTION_ANSWER_STATUS_CORRECT_ANSWERED."'
418  END question_answer_status
419  ";
420  }
421 
422  $selectFields = implode(",\n\t\t\t\t", $selectFields);
423 
424  return "
425  SELECT {$selectFields}
426  ";
427  }
428 
429  private function buildBasicQuery()
430  {
431  return "
432  {$this->getSelectFieldsExpression()}
433 
434  FROM qpl_questions
435 
436  {$this->getTableJoinExpression()}
437 
438  WHERE qpl_questions.tstamp > 0
439  ";
440  }
441 
442  private function buildQuery()
443  {
444  $query = $this->buildBasicQuery()."
445  {$this->getConditionalFilterExpression()}
446  ";
447 
448  if( count($this->getForcedQuestionIds()) )
449  {
450  $query .= "
451  UNION {$this->buildBasicQuery()}
452  AND {$this->db->in('qpl_questions.question_id', $this->getForcedQuestionIds(), false, 'integer')}
453  ";
454  }
455 
456  return $query;
457  }
458 
459  public function load()
460  {
461  $this->checkFilters();
462 
463  $query = $this->buildQuery();
464 
465  #vd($query);
466 
467  $res = $this->db->query($query);
468 
469  //echo $this->db->db->last_query;
470 
471  #vd($this->db->db->last_query);
472 
473  while( $row = $this->db->fetchAssoc($res) )
474  {
475  if( !$this->isActiveQuestionType($row) )
476  {
477  continue;
478  }
479 
480  $row['taxonomies'] = $this->loadTaxonomyAssignmentData($row['question_id']);
481 
482  $row['ttype'] = $this->lng->txt($row['type_tag']);
483 
484  $this->questions[ $row['question_id'] ] = $row;
485  }
486  }
487 
488  private function loadTaxonomyAssignmentData($questionId)
489  {
490  $taxAssignmentData = array();
491 
492  foreach($this->getAvailableTaxonomyIds() as $taxId)
493  {
494  require_once 'Services/Taxonomy/classes/class.ilTaxonomyTree.php';
495  require_once 'Services/Taxonomy/classes/class.ilTaxNodeAssignment.php';
496 
497  $taxTree = new ilTaxonomyTree($taxId);
498 
499  $taxAssignment = new ilTaxNodeAssignment('qpl', $this->parentObjId, 'quest', $taxId);
500 
501  $assignments = $taxAssignment->getAssignmentsOfItem($questionId);
502 
503  foreach($assignments as $assData)
504  {
505  if( !isset($taxAssignmentData[ $assData['tax_id'] ]) )
506  {
507  $taxAssignmentData[ $assData['tax_id'] ] = array();
508  }
509 
510  $nodeData = $taxTree->getNodeData($assData['node_id']);
511 
512  $assData['node_lft'] = $nodeData['lft'];
513 
514  $taxAssignmentData[ $assData['tax_id'] ][ $assData['node_id'] ] = $assData;
515  }
516  }
517 
518  return $taxAssignmentData;
519  }
520 
521  private function isActiveQuestionType($questionData)
522  {
523  if( !isset($questionData['plugin']) )
524  {
525  return false;
526  }
527 
528  if( !$questionData['plugin'] )
529  {
530  return true;
531  }
532 
533  return $this->pluginAdmin->isActive(IL_COMP_MODULE, 'TestQuestionPool', 'qst', $questionData['type_tag']);
534  }
535 
536  public function getQuestionDataArray()
537  {
538  return $this->questions;
539  }
540 
541  public function isInList($questionId)
542  {
543  return isset($this->questions[$questionId]);
544  }
545 
555  public function getTitle($a_comp_id, $a_item_type, $a_item_id)
556  {
557  if( $a_comp_id != 'qpl' || $a_item_type != 'quest' || !(int)$a_item_id )
558  {
559  return '';
560  }
561 
562  if( !isset($this->questions[$a_item_id]) )
563  {
564  return '';
565  }
566 
567  return $this->questions[$a_item_id]['title'];
568  }
569 
570  private function checkFilters()
571  {
572  if( strlen($this->getAnswerStatusFilter()) && !$this->getAnswerStatusActiveId() )
573  {
574  require_once 'Modules/TestQuestionPool/exceptions/class.ilTestQuestionPoolException.php';
575 
576  throw new ilTestQuestionPoolException(
577  'No active id given! You cannot use the answer status filter without giving an active id.'
578  );
579  }
580 
581  }
582 }
setAnswerStatusFilter($answerStatusFilter)
Taxonomy node <-> item assignment.
isActiveQuestionType($questionData)
addTaxonomyFilter($taxId, $taxNodes)
setAnswerStatusActiveId($answerStatusActiveId)
Administration class for plugins.
setParentObjectType($parentObjType)
const IL_COMP_MODULE
setQuestionInstanceTypeFilter($questionInstanceTypeFilter)
const ANSWER_STATUS_FILTER_ALL_NON_CORRECT
answer status filter value domain
Interface for assigned items of taxonomies.
setForcedQuestionIds($forcedQuestionIds)
Database Wrapper.
Definition: class.ilDB.php:28
getTitle($a_comp_id, $a_item_type, $a_item_id)
Get title of an assigned item.
addFieldFilter($fieldName, $fieldValue)
language handling
loadTaxonomyAssignmentData($questionId)
__construct(ilDB $db, ilLanguage $lng, ilPluginAdmin $pluginAdmin, $parentObjId)
Constructor.
const QUESTION_ANSWER_STATUS_NON_ANSWERED
answer status domain for single questions
setAvailableTaxonomyIds($availableTaxonomyIds)
setQuestionIdsFilter($questionIdsFilter)