ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilConditionHandler.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
67 {
68  const UNIQUE_CONDITIONS = 1;
69  const SHARED_CONDITIONS = 0;
70 
71  var $db;
72  var $lng;
73 
74 
76 
83  var $operator;
84  var $value;
86 
87  private $obligatory = true;
88 
90  static $cond_for_target_cache = array();
91  static $cond_target_rows = array();
92 
93 
98  function ilConditionHandler()
99  {
100  global $ilDB,$lng;
101 
102  $this->db =& $ilDB;
103  $this->lng =& $lng;
104  $this->validation = true;
105  }
106 
115  public static function _isReferenceHandlingOptional($a_type)
116  {
117  switch($a_type)
118  {
119  case 'st':
120  return true;
121 
122  default:
123  return false;
124  }
125  }
126 
137  public static function _adjustMovedObjectConditions($a_ref_id)
138  {
139  global $tree;
140 
141  if($tree->checkForParentType($a_ref_id,'crs'))
142  {
143  // Nothing to do
144  return true;
145  }
146 
147  // Need another implementation that has better performance
148  $childs = $tree->getSubTree($tree->getNodeData($a_ref_id),false);
150 
151  foreach(array_intersect($conditions,$childs) as $target_ref)
152  {
153  if(!$tree->checkForParentType($target_ref,'crs'))
154  {
156  }
157  }
158  return true;
159  }
160 
168  public static function _getDistinctTargetRefIds()
169  {
170  global $ilDB;
171 
172  $query = "SELECT DISTINCT target_ref_id ref FROM conditions ";
173  $res = $ilDB->query($query);
174  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
175  {
176  $ref_ids[] = $row->ref;
177  }
178  return $ref_ids ? $ref_ids : array();
179  }
180 
191  public static function _deleteTargetConditionsByRefId($a_target_ref_id)
192  {
193  global $ilDB;
194 
195  $query = "DELETE FROM conditions ".
196  "WHERE target_ref_id = ".$ilDB->quote($a_target_ref_id,'integer')." ".
197  "AND target_type != 'st' ";
198  $res = $ilDB->manipulate($query);
199  return true;
200  }
201 
209  public function setReferenceHandlingType($a_type)
210  {
211  return $this->condition_reference_type = $a_type;
212  }
213 
220  public function getReferenceHandlingType()
221  {
222  return (int) $this->condition_reference_type;
223  }
224 
225  // SET GET
226  function setErrorMessage($a_msg)
227  {
228  $this->error_message = $a_msg;
229  }
230  function getErrorMessage()
231  {
232  return $this->error_message;
233  }
234 
238  function setTargetRefId($a_target_ref_id)
239  {
240  return $this->target_ref_id = $a_target_ref_id;
241  }
242 
246  function getTargetRefId()
247  {
248  return $this->target_ref_id;
249  }
250 
254  function setTargetObjId($a_target_obj_id)
255  {
256  return $this->target_obj_id = $a_target_obj_id;
257  }
258 
262  function getTargetObjId()
263  {
264  return $this->target_obj_id;
265  }
266 
270  function setTargetType($a_target_type)
271  {
272  return $this->target_type = $a_target_type;
273  }
274 
278  function getTargetType()
279  {
280  return $this->target_type;
281  }
282 
286  function setTriggerRefId($a_trigger_ref_id)
287  {
288  return $this->trigger_ref_id = $a_trigger_ref_id;
289  }
290 
294  function getTriggerRefId()
295  {
296  return $this->trigger_ref_id;
297  }
298 
302  function setTriggerObjId($a_trigger_obj_id)
303  {
304  return $this->trigger_obj_id = $a_trigger_obj_id;
305  }
306 
310  function getTriggerObjId()
311  {
312  return $this->trigger_obj_id;
313  }
314 
318  function setTriggerType($a_trigger_type)
319  {
320  return $this->trigger_type = $a_trigger_type;
321  }
322 
326  function getTriggerType()
327  {
328  return $this->trigger_type;
329  }
330 
334  function setOperator($a_operator)
335  {
336  return $this->operator = $a_operator;
337  }
338 
342  function getOperator()
343  {
344  return $this->operator;
345  }
346 
350  function setValue($a_value)
351  {
352  return $this->value = $a_value;
353  }
354 
358  function getValue()
359  {
360  return $this->value;
361  }
362 
367  public function setObligatory($a_obl)
368  {
369  $this->obligatory = $a_obl;
370  }
371 
376  public function getObligatory()
377  {
378  return (bool) $this->obligatory;
379  }
380 
381 
385  function enableAutomaticValidation($a_validate = true)
386  {
387  $this->validation = $a_validate;
388  }
389 
395  function getTriggerTypes()
396  {
397  return array('crs','exc','tst','sahs', 'svy');
398  }
399 
400 
401  function getOperatorsByTargetType($a_type)
402  {
403  switch($a_type)
404  {
405  case 'crs':
406  case 'exc':
407  return array('passed');
408 
409  case 'tst':
410  return array('passed','finished','not_finished');
411 
412  case 'crsg':
413  return array('not_member');
414 
415  case 'sahs':
416  return array('finished');
417 
418  case 'svy':
419  return array('finished');
420 
421  default:
422  return array();
423  }
424  }
425 
431  function storeCondition()
432  {
433  global $ilDB;
434 
435  // first insert, then validate: it's easier to check for circles if the new condition is in the db table
436  $next_id = $ilDB->nextId('conditions');
437  $query = 'INSERT INTO conditions (condition_id,target_ref_id,target_obj_id,target_type,'.
438  'trigger_ref_id,trigger_obj_id,trigger_type,operator,value,ref_handling,obligatory) '.
439  'VALUES ('.
440  $ilDB->quote($next_id,'integer').','.
441  $ilDB->quote($this->getTargetRefId(),'integer').",".
442  $ilDB->quote($this->getTargetObjId(),'integer').",".
443  $ilDB->quote($this->getTargetType(),'text').",".
444  $ilDB->quote($this->getTriggerRefId(),'integer').",".
445  $ilDB->quote($this->getTriggerObjId(),'integer').",".
446  $ilDB->quote($this->getTriggerType(),'text').",".
447  $ilDB->quote($this->getOperator(),'text').",".
448  $ilDB->quote($this->getValue(),'text').", ".
449  $ilDB->quote($this->getReferenceHandlingType(),'integer').', '.
450  $ilDB->quote($this->getObligatory(),'integer').
451  ')';
452 
453  $res = $ilDB->manipulate($query);
454 
455  if ($this->validation && !$this->validate())
456  {
457  $this->deleteCondition($next_id);
458  return false;
459  }
460  return true;
461  }
462 
463  function checkExists()
464  {
465  global $ilDB;
466 
467  $query = "SELECT * FROM conditions ".
468  "WHERE target_ref_id = ".$ilDB->quote($this->getTargetRefId(),'integer')." ".
469  "AND target_obj_id = ".$ilDB->quote($this->getTargetObjId(),'integer')." ".
470  "AND trigger_ref_id = ".$ilDB->quote($this->getTriggerRefId(),'integer')." ".
471  "AND trigger_obj_id = ".$ilDB->quote($this->getTriggerObjId(),'integer')." ".
472  "AND operator = ".$ilDB->quote($this->getOperator(),'text');
473  $res = $ilDB->query($query);
474 
475  return $res->numRows() ? true : false;
476  }
480  function updateCondition($a_id)
481  {
482  global $ilDB;
483 
484  $query = "UPDATE conditions SET ".
485  "target_ref_id = ".$ilDB->quote($this->getTargetRefId(),'integer').", ".
486  "operator = ".$ilDB->quote($this->getOperator(),'text').", ".
487  "value = ".$ilDB->quote($this->getValue(),'text').", ".
488  "ref_handling = ".$this->db->quote($this->getReferenceHandlingType(),'integer').", ".
489  'obligatory = '.$this->db->quote($this->getObligatory(),'integer').' '.
490  "WHERE condition_id = ".$ilDB->quote($a_id,'integer');
491  $res = $ilDB->manipulate($query);
492 
493  return true;
494  }
495 
502  static function updateObligatory($a_id, $a_status)
503  {
504  global $ilDB;
505 
506  $query = "UPDATE conditions SET ".
507  'obligatory = '.$ilDB->quote($a_status,'integer').' '.
508  "WHERE condition_id = ".$ilDB->quote($a_id,'integer');
509  $res = $ilDB->manipulate($query);
510 
511  return true;
512  }
513 
518  function delete($a_ref_id)
519  {
520  global $ilDB;
521 
522  $query = "DELETE FROM conditions WHERE ".
523  "target_ref_id = ".$ilDB->quote($a_ref_id,'integer')." ".
524  "OR trigger_ref_id = ".$ilDB->quote($a_ref_id,'integer');
525  $res = $ilDB->manipulate($query);
526 
527  return true;
528  }
533  function deleteByObjId($a_obj_id)
534  {
535  global $ilDB;
536 
537  $query = "DELETE FROM conditions WHERE ".
538  "target_obj_id = ".$ilDB->quote($a_obj_id,'integer')." ".
539  "OR trigger_obj_id = ".$ilDB->quote($a_obj_id,'integer');
540  $res = $ilDB->manipulate($query);
541 
542  return true;
543  }
544 
548  function deleteCondition($a_id)
549  {
550  global $ilDB;
551 
552  $query = "DELETE FROM conditions ".
553  "WHERE condition_id = ".$ilDB->quote($a_id,'integer');
554  $res = $ilDB->manipulate($query);
555 
556  return true;
557  }
558 
563  function _getConditionsOfTrigger($a_trigger_obj_type, $a_trigger_id)
564  {
565  global $ilDB;
566 
567  $query = "SELECT * FROM conditions ".
568  "WHERE trigger_obj_id = ".$ilDB->quote($a_trigger_id,'integer')." ".
569  " AND trigger_type = ".$ilDB->quote($a_trigger_obj_type,'text');
570 
571  $res = $ilDB->query($query);
572  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
573  {
574  $tmp_array['id'] = $row->condition_id;
575  $tmp_array['target_ref_id'] = $row->target_ref_id;
576  $tmp_array['target_obj_id'] = $row->target_obj_id;
577  $tmp_array['target_type'] = $row->target_type;
578  $tmp_array['trigger_ref_id'] = $row->trigger_ref_id;
579  $tmp_array['trigger_obj_id'] = $row->trigger_obj_id;
580  $tmp_array['trigger_type'] = $row->trigger_type;
581  $tmp_array['operator'] = $row->operator;
582  $tmp_array['value'] = $row->value;
583  $tmp_array['ref_handling'] = $row->ref_handling;
584  $tmp_array['obligatory'] = $row->obligatory;
585 
586  $conditions[] = $tmp_array;
587  unset($tmp_array);
588  }
589 
590  return $conditions ? $conditions : array();
591  }
592 
603  public static function _getConditionsOfTarget($a_target_ref_id,$a_target_obj_id, $a_target_type = "")
604  {
605  global $ilDB, $ilBench;
606 
607  // get type if no type given
608  if ($a_target_type == "")
609  {
610  $a_target_type = ilObject::_lookupType($a_target_obj_id);
611  }
612 
613  // check conditions for target cache
614  if (isset(self::$cond_for_target_cache[$a_target_ref_id.":".$a_target_obj_id.":".
615  $a_target_type]))
616  {
617  return self::$cond_for_target_cache[$a_target_ref_id.":".$a_target_obj_id.":".
618  $a_target_type];
619  }
620 
621  // check rows cache
622  if (isset(self::$cond_target_rows[$a_target_type.":".$a_target_obj_id]))
623  {
624  $rows = self::$cond_target_rows[$a_target_type.":".$a_target_obj_id];
625  }
626  else
627  {
628  // query data from db
629  $query = "SELECT * FROM conditions ".
630  "WHERE target_obj_id = ".$ilDB->quote($a_target_obj_id,'integer')." ".
631  " AND target_type = ".$ilDB->quote($a_target_type,'text');
632 
633  $res = $ilDB->query($query);
634  $rows = array();
635  while ($row = $ilDB->fetchAssoc($res))
636  {
637  $rows[] = $row;
638  }
639  }
640 
641  reset($rows);
642  $conditions = array();
643  foreach ($rows as $row)
644  {
645  if ($row["ref_handling"] == self::UNIQUE_CONDITIONS)
646  {
647  if ($row["target_ref_id"] != $a_target_ref_id)
648  {
649  continue;
650  }
651  }
652 
653  $row["id"] = $row["condition_id"];
654  $conditions[] = $row;
655  }
656 
657  // write conditions for target cache
658  self::$cond_for_target_cache[$a_target_ref_id.":".$a_target_obj_id.":".
659  $a_target_type] = $conditions;
660 
661  return $conditions;
662  }
663 
670  function preloadConditionsForTargetRecords($a_type, $a_obj_ids)
671  {
672  global $ilDB;
673 
674  if (is_array($a_obj_ids) && count($a_obj_ids) > 0)
675  {
676  $res = $ilDB->query("SELECT * FROM conditions ".
677  "WHERE ".$ilDB->in("target_obj_id", $a_obj_ids, false, "integer").
678  " AND target_type = ".$ilDB->quote($a_type,'text'));
679  $rows = array();
680  while ($row = $ilDB->fetchAssoc($res))
681  {
682  self::$cond_target_rows[$a_type.":".$row["target_obj_id"]][]
683  = $row;
684  }
685  // init obj ids without any record
686  foreach ($a_obj_ids as $obj_id)
687  {
688  if (!is_array(self::$cond_target_rows[$a_type.":".$obj_id]))
689  {
690  self::$cond_target_rows[$a_type.":".$obj_id] = array();
691  }
692  }
693  }
694  }
695 
696  function _getCondition($a_id)
697  {
698  global $ilDB;
699 
700  $query = "SELECT * FROM conditions ".
701  "WHERE condition_id = ".$ilDB->quote($a_id,'integer');
702 
703  $res = $ilDB->query($query);
704  while($row = $res->fetchRow(DB_FETCHMODE_OBJECT))
705  {
706  $tmp_array['id'] = $row->condition_id;
707  $tmp_array['target_ref_id'] = $row->target_ref_id;
708  $tmp_array['target_obj_id'] = $row->target_obj_id;
709  $tmp_array['target_type'] = $row->target_type;
710  $tmp_array['trigger_ref_id'] = $row->trigger_ref_id;
711  $tmp_array['trigger_obj_id'] = $row->trigger_obj_id;
712  $tmp_array['trigger_type'] = $row->trigger_type;
713  $tmp_array['operator'] = $row->operator;
714  $tmp_array['value'] = $row->value;
715  $tmp_array['ref_handling'] = $row->ref_handling;
716  $tmp_array['obligatory'] = $row->obligatory;
717 
718  return $tmp_array;
719  }
720  return false;
721  }
722 
723 
724 
730  function _checkCondition($a_id,$a_usr_id = 0)
731  {
732  global $ilUser;
733 
734  $a_usr_id = $a_usr_id ? $a_usr_id : $ilUser->getId();
735 
736  $condition = ilConditionHandler::_getCondition($a_id);
737 
738  switch($condition['trigger_type'])
739  {
740  case "tst":
741  include_once './Modules/Test/classes/class.ilObjTestAccess.php';
742  return ilObjTestAccess::_checkCondition($condition['trigger_obj_id'],$condition['operator'],$condition['value'],$a_usr_id);
743 
744  case "crs":
745  include_once './Modules/Course/classes/class.ilObjCourse.php';
746  return ilObjCourse::_checkCondition($condition['trigger_obj_id'],$condition['operator'],$condition['value'],$a_usr_id);
747 
748  case 'exc':
749  include_once './Modules/Exercise/classes/class.ilObjExercise.php';
750  return ilObjExercise::_checkCondition($condition['trigger_obj_id'],$condition['operator'],$condition['value'],$a_usr_id);
751 
752  case 'crsg':
753  include_once './Modules/Course/classes/class.ilObjCourseGrouping.php';
754  return ilObjCourseGrouping::_checkCondition($condition['trigger_obj_id'],$condition['operator'],$condition['value'],$a_usr_id);
755 
756  case 'sahs':
757  include_once './Services/Tracking/classes/class.ilLPStatus.php';
758  return ilLPStatus::_hasUserCompleted($condition['trigger_obj_id'], $a_usr_id);
759 
760  case 'svy':
761  include_once './Modules/Survey/classes/class.ilObjSurvey.php';
762  return ilObjSurvey::_checkCondition($condition['trigger_obj_id'],$condition['operator'],$condition['value'],$a_usr_id);
763 
764  default:
765  return false;
766 
767  }
768 
769  }
770 
776  public static function getOptionalConditionsOfTarget($a_target_ref_id,$a_target_obj_id,$a_obj_type = '')
777  {
778  $conditions = self::_getConditionsOfTarget($a_target_ref_id,$a_target_obj_id);
779 
780  $opt = array();
781  foreach($conditions as $con)
782  {
783  if($con['obligatory'])
784  {
785  continue;
786  }
787 
788  $opt[] = $con;
789  }
790  return $opt;
791  }
792 
799  public static function calculateRequiredTriggers($a_target_ref_id,$a_target_obj_id,$a_target_obj_type = '', $a_force_update = false)
800  {
801  global $ilDB;
802 
803  // Get all conditions
804  $all = self::_getConditionsOfTarget($a_target_ref_id,$a_target_obj_id,$a_target_obj_type);
805  $opt = self::getOptionalConditionsOfTarget($a_target_ref_id, $a_target_obj_id,$a_target_obj_type);
806 
807  $set_obl = 0;
808  if(isset($all[0]))
809  {
810  $set_obl = $all[0]['num_obligatory'];
811  }
812 
813  // existing value is valid
814  if($set_obl > 0 and
815  $set_obl < count($all) and
816  $set_obl > (count($all) - count($opt) + 1))
817  {
818  return $set_obl;
819  }
820 
821  if(count($opt))
822  {
823  $result = count($all) - count($opt) + 1;
824  }
825  else
826  {
827  $result = count($all);
828  }
829  if($a_force_update)
830  {
831  self::saveNumberOfRequiredTriggers($a_target_ref_id,$a_target_obj_id,$result);
832  }
833  return $result;
834  }
835 
841  public static function saveNumberOfRequiredTriggers($a_target_ref_id,$a_target_obj_id,$a_num)
842  {
843  global $ilDB;
844 
845  $query = 'UPDATE conditions '.
846  'SET num_obligatory = '.$ilDB->quote($a_num,'integer').' '.
847  'WHERE target_ref_id = '.$ilDB->quote($a_target_ref_id,'integer').' '.
848  'AND target_obj_id = '.$ilDB->quote($a_target_obj_id,'integer');
849  $ilDB->manipulate($query);
850  return;
851  }
852 
856  function _checkAllConditionsOfTarget($a_target_ref_id,$a_target_id, $a_target_type = "",$a_usr_id = 0)
857  {
858  global $ilBench,$ilUser,$tree;
859 
860  $a_usr_id = $a_usr_id ? $a_usr_id : $ilUser->getId();
861 
862  $conditions = ilConditionHandler::_getConditionsOfTarget($a_target_ref_id,$a_target_id, $a_target_type);
863 
864  if(!count($conditions))
865  {
866  return true;
867  }
868 
869  // @todo check this
870  include_once './Services/Container/classes/class.ilMemberViewSettings.php';
871  if(ilMemberViewSettings::getInstance()->isActive())
872  {
873  return true;
874  }
875 
876  // First check obligatory conditions
877  $optional = self::getOptionalConditionsOfTarget($a_target_ref_id, $a_target_id, $a_target_type);
878  $num_required = self::calculateRequiredTriggers($a_target_ref_id, $a_target_id, $a_target_type);
879  $passed = 0;
880  foreach($conditions as $condition)
881  {
882  if($tree->isDeleted($condition['trigger_ref_id']))
883  {
884  continue;
885  }
886  $check = ilConditionHandler::_checkCondition($condition['id'],$a_usr_id);
887 
888  if($check)
889  {
890  ++$passed;
891  if($passed >= $num_required)
892  {
893  return true;
894  }
895  }
896  else
897  {
898  if(!count($optional))
899  {
900  return false;
901  }
902  }
903  }
904  // not all optional conditions passed
905  return false;
906  }
907 
908  // PRIVATE
909  function validate()
910  {
911  global $ilDB;
912 
913  // check if obj_id is already assigned
914  $trigger_obj =& ilObjectFactory::getInstanceByRefId($this->getTriggerRefId());
915  $target_obj =& ilObjectFactory::getInstanceByRefId($this->getTargetRefId());
916 
917 
918  $query = "SELECT * FROM conditions WHERE ".
919  "trigger_ref_id = ".$ilDB->quote($trigger_obj->getId(),'integer')." ".
920  "AND target_ref_id = ".$ilDB->quote($target_obj->getId(),'integer');
921 
922  $res = $this->db->query($query);
923  if($res->numRows() > 1)
924  {
925  $this->setErrorMessage($this->lng->txt('condition_already_assigned'));
926 
927  unset($trigger_obj);
928  unset($target_obj);
929  return false;
930  }
931 
932  // check for circle
933  $this->target_obj_id = $target_obj->getId();
934  if($this->checkCircle($this->getTargetRefId(),$target_obj->getId()))
935  {
936  $this->setErrorMessage($this->lng->txt('condition_circle_created'));
937 
938  unset($trigger_obj);
939  unset($target_obj);
940  return false;
941  }
942  return true;
943  }
944 
945  function checkCircle($a_ref_id,$a_obj_id)
946  {
947  foreach(ilConditionHandler::_getConditionsOfTarget($a_ref_id,$a_obj_id) as $condition)
948  {
949  if($condition['trigger_obj_id'] == $this->target_obj_id and $condition['operator'] == $this->getOperator())
950  {
951  $this->circle = true;
952  break;
953  }
954  else
955  {
956  $this->checkCircle($condition['trigger_ref_id'],$condition['trigger_obj_id']);
957  }
958  }
959  return $this->circle;
960  }
961 }
962 
963 ?>