ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilTestSkillEvaluation.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 'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
5 require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacQuestionProvider.php';
6 require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacConditionParser.php';
7 require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacCompositeEvaluator.php';
8 require_once 'Modules/Test/classes/class.ilTestSkillPointAccount.php';
9 require_once 'Modules/Test/classes/class.ilTestSkillLevelThresholdList.php';
10 
18 {
22  private $db;
23 
27  private $refId;
28 
33 
38 
42  private $questions;
43 
48 
53 
58 
63 
67  private $userId;
68 
72  private $activeId;
73 
77  private $pass;
78 
83 
84  public function __construct(ilDBInterface $db, $testId, $refId)
85  {
86  $this->db = $db;
87  $this->refId = $refId;
88 
89  $this->skillQuestionAssignmentList = new ilAssQuestionSkillAssignmentList($this->db);
90 
91  $this->skillLevelThresholdList = new ilTestSkillLevelThresholdList($this->db);
92  $this->skillLevelThresholdList->setTestId($testId);
93 
94  $this->questions = array();
95  $this->maxPointsByQuestion = array();
96  }
97 
98  public function getUserId()
99  {
100  return $this->userId;
101  }
102 
103  public function setUserId($userId)
104  {
105  $this->userId = $userId;
106  }
107 
108  public function getActiveId()
109  {
110  return $this->activeId;
111  }
112 
113  public function setActiveId($activeId)
114  {
115  $this->activeId = $activeId;
116  }
117 
118  public function getPass()
119  {
120  return $this->pass;
121  }
122 
123  public function setPass($pass)
124  {
125  $this->pass = $pass;
126  }
127 
129  {
131  }
132 
134  {
135  $this->numRequiredBookingsForSkillTriggering = $numRequiredBookingsForSkillTriggering;
136  }
137 
138  public function init(ilAssQuestionList $questionList)
139  {
140  $this->skillQuestionAssignmentList->setParentObjId($questionList->getParentObjId());
141  $this->skillQuestionAssignmentList->loadFromDb();
142 
143  $this->skillLevelThresholdList->loadFromDb();
144 
145  $this->initTestQuestionData($questionList);
146  }
147 
151  public function evaluate($testResults)
152  {
153  $this->reset();
154 
155  $this->initTestResultData($testResults);
156 
157  $this->drawUpSkillPointAccounts();
159  }
160 
161  public function getReachedSkillLevels()
162  {
164  }
165 
166  private function reset()
167  {
168  $this->reachedPointsByQuestion = array();
169  $this->skillPointAccounts = array();
170  $this->reachedSkillLevels = array();
171  }
172 
173  private function initTestQuestionData(ilAssQuestionList $questionList)
174  {
175  foreach ($questionList->getQuestionDataArray() as $questionData) {
176  $this->questions[] = $questionData['question_id'];
177 
178  $this->maxPointsByQuestion[ $questionData['question_id'] ] = $questionData['points'];
179  }
180  }
181 
185  private function initTestResultData($testResults)
186  {
187  foreach ($testResults as $key => $result) {
188  if ($key === 'pass' || $key === 'test') { // note: key int 0 IS == 'pass' or 'buxtehude'
189  continue;
190  }
191 
192  if (!$result['workedthrough']) {
193  continue;
194  }
195 
196  $this->reachedPointsByQuestion[ $result['qid'] ] = $result['reached'];
197  }
198  }
199 
200  private function drawUpSkillPointAccounts()
201  {
202  foreach ($this->questions as $questionId) {
203  if (!$this->isAnsweredQuestion($questionId)) {
204  continue;
205  }
206 
207  $assignments = $this->skillQuestionAssignmentList->getAssignmentsByQuestionId($questionId);
208 
209  foreach ($assignments as $assignment) {
210  if ($assignment->hasEvalModeBySolution()) {
211  $reachedSkillPoints = $this->determineReachedSkillPointsWithSolutionCompare(
212  $assignment->getSolutionComparisonExpressionList()
213  );
214  } else {
215  $maxTestPoints = $this->maxPointsByQuestion[$questionId];
216  $reachedTestPoints = $this->reachedPointsByQuestion[$questionId];
217 
218  $reachedSkillPoints = $this->calculateReachedSkillPointsFromTestPoints(
219  $assignment->getSkillPoints(),
220  $maxTestPoints,
221  $reachedTestPoints
222  );
223  }
224 
226  $assignment->getSkillBaseId(),
227  $assignment->getSkillTrefId(),
228  $assignment->getMaxSkillPoints(),
229  $reachedSkillPoints
230  );
231  }
232  }
233  }
234 
235  private function isAnsweredQuestion($questionId)
236  {
237  return isset($this->reachedPointsByQuestion[$questionId]);
238  }
239 
241  {
242  $questionProvider = new ilAssLacQuestionProvider();
243  $questionProvider->setQuestionId($expressionList->getQuestionId());
244 
245  foreach ($expressionList->get() as $expression) {
246  /* @var ilAssQuestionSolutionComparisonExpression $expression */
247 
248  $conditionParser = new ilAssLacConditionParser();
249  $conditionComposite = $conditionParser->parse($expression->getExpression());
250 
251  $compositeEvaluator = new ilAssLacCompositeEvaluator(
252  $questionProvider,
253  $this->getActiveId(),
254  $this->getPass()
255  );
256 
257  if ($compositeEvaluator->evaluate($conditionComposite)) {
258  return $expression->getPoints();
259  }
260  }
261 
262  return 0;
263  }
264 
265  private function calculateReachedSkillPointsFromTestPoints($skillPoints, $maxTestPoints, $reachedTestPoints)
266  {
267  if ($reachedTestPoints < 0) {
268  $reachedTestPoints = 0;
269  }
270 
271  $factor = 0;
272 
273  if ($maxTestPoints > 0) {
274  $factor = $reachedTestPoints / $maxTestPoints;
275  }
276 
277  return ($skillPoints * $factor);
278  }
279 
280  private function bookToSkillPointAccount($skillBaseId, $skillTrefId, $maxSkillPoints, $reachedSkillPoints)
281  {
282  $skillKey = $skillBaseId . ':' . $skillTrefId;
283 
284  if (!isset($this->skillPointAccounts[$skillKey])) {
285  $this->skillPointAccounts[$skillKey] = new ilTestSkillPointAccount();
286  }
287 
288  $this->skillPointAccounts[$skillKey]->addBooking($maxSkillPoints, $reachedSkillPoints);
289  }
290 
291  private function evaluateSkillPointAccounts()
292  {
293  foreach ($this->skillPointAccounts as $skillKey => $skillPointAccount) {
294  /* @var ilTestSkillPointAccount $skillPointAccount */
295 
296  if (!$this->doesNumBookingsExceedRequiredBookingsBarrier($skillPointAccount)) {
297  continue;
298  }
299 
300  list($skillBaseId, $skillTrefId) = explode(':', $skillKey);
301 
302  $skill = new ilBasicSkill($skillBaseId);
303  $levels = $skill->getLevelData();
304 
305  $reachedLevelId = null;
306 
307  foreach ($levels as $level) {
308  $threshold = $this->skillLevelThresholdList->getThreshold($skillBaseId, $skillTrefId, $level['id']);
309 
310  if (!($threshold instanceof ilTestSkillLevelThreshold) || !$threshold->getThreshold()) {
311  continue;
312  }
313 
314  $reachedLevelId = $level['id'];
315 
316  if ($skillPointAccount->getTotalReachedSkillPercent() <= $threshold->getThreshold()) {
317  break;
318  }
319  }
320 
321  if ($reachedLevelId) {
322  $this->reachedSkillLevels[] = array(
323  'sklBaseId' => $skillBaseId, 'sklTrefId' => $skillTrefId, 'sklLevelId' => $reachedLevelId
324  );
325  }
326  }
327  }
328 
330  {
331  return $skillPointAccount->getNumBookings() >= $this->getNumRequiredBookingsForSkillTriggering();
332  }
333 
334  public function handleSkillTriggering()
335  {
336  foreach ($this->getReachedSkillLevels() as $reachedSkillLevel) {
337  $this->invokeSkillLevelTrigger($reachedSkillLevel['sklLevelId'], $reachedSkillLevel['sklTrefId']);
338 
339  if ($reachedSkillLevel['sklTrefId'] > 0) {
340  ilPersonalSkill::addPersonalSkill($this->getUserId(), $reachedSkillLevel['sklTrefId']);
341  } else {
342  ilPersonalSkill::addPersonalSkill($this->getUserId(), $reachedSkillLevel['sklBaseId']);
343  }
344  }
345  }
346 
347  private function invokeSkillLevelTrigger($skillLevelId, $skillTrefId)
348  {
350  $skillLevelId,
351  $this->getUserId(),
352  $this->refId,
353  $skillTrefId,
355  true,
356  0,
357  $this->getPass()
358  );
359 
360  /* @var ILIAS\DI\Container $DIC */ global $DIC;
361 
362  $DIC->logger()->root()->info(
363  "refId={$this->refId} / usrId={$this->getUserId()} / levelId={$skillLevelId} / trefId={$skillTrefId}"
364  );
365 
366  //mail('bheyser@databay.de', "trigger skill level $skillLevelId for user {$this->getUserId()}", '');
367  }
368 
370  {
371  $skillsMatchingNumAnswersBarrier = array();
372 
373  foreach ($this->skillPointAccounts as $skillKey => $skillPointAccount) {
374  if ($this->doesNumBookingsExceedRequiredBookingsBarrier($skillPointAccount)) {
375  list($skillBaseId, $skillTrefId) = explode(':', $skillKey);
376 
377  $skillsMatchingNumAnswersBarrier[$skillKey] = array(
378  'base_skill_id' => (int) $skillBaseId,
379  'tref_id' => (int) $skillTrefId
380  );
381  }
382  }
383 
384  return $skillsMatchingNumAnswersBarrier;
385  }
386 
388  {
389  $uniqueSkills = array();
390 
391  foreach ($this->skillQuestionAssignmentList->getUniqueAssignedSkills() as $skill) {
392  $skillKey = $skill['skill_base_id'] . ':' . $skill['skill_tref_id'];
393 
394  $uniqueSkills[$skillKey] = array(
395  'base_skill_id' => (int) $skill['skill_base_id'],
396  'tref_id' => (int) $skill['skill_tref_id']
397  );
398  }
399 
400  return $uniqueSkills;
401  }
402 
403  public function isAssignedSkill($skillBaseId, $skillTrefId)
404  {
405  $this->skillQuestionAssignmentList->isAssignedSkill($skillBaseId, $skillTrefId);
406  }
407 
409  {
410  $matchingSkillProfiles = array();
411 
412  $usersProfiles = ilSkillProfile::getProfilesOfUser($this->getUserId());
413 
414  foreach ($usersProfiles as $profileData) {
415  $profile = new ilSkillProfile($profileData['id']);
416  $assignedSkillLevels = $profile->getSkillLevels();
417 
418  foreach ($assignedSkillLevels as $assignedSkillLevel) {
419  $skillBaseId = $assignedSkillLevel['base_skill_id'];
420  $skillTrefId = $assignedSkillLevel['tref_id'];
421 
422  if ($this->skillQuestionAssignmentList->isAssignedSkill($skillBaseId, $skillTrefId)) {
423  $matchingSkillProfiles[$profileData['id']] = $profile->getTitle();
424  }
425  }
426  }
427 
428  return $matchingSkillProfiles;
429  }
430 
431  public function noProfileMatchingAssignedSkillExists($availableSkillProfiles)
432  {
433  $noProfileMatchingSkills = $this->skillQuestionAssignmentList->getUniqueAssignedSkills();
434 
435  foreach ($availableSkillProfiles as $skillProfileId => $skillProfileTitle) {
436  $profile = new ilSkillProfile($skillProfileId);
437  $assignedSkillLevels = $profile->getSkillLevels();
438 
439  foreach ($assignedSkillLevels as $assignedSkillLevel) {
440  $skillBaseId = $assignedSkillLevel['base_skill_id'];
441  $skillTrefId = $assignedSkillLevel['tref_id'];
442 
443  if ($this->skillQuestionAssignmentList->isAssignedSkill($skillBaseId, $skillTrefId)) {
444  unset($noProfileMatchingSkills["{$skillBaseId}:{$skillTrefId}"]);
445  }
446  }
447  }
448 
449  return count($noProfileMatchingSkills);
450  }
451 }
init(ilAssQuestionList $questionList)
setNumRequiredBookingsForSkillTriggering($numRequiredBookingsForSkillTriggering)
invokeSkillLevelTrigger($skillLevelId, $skillTrefId)
calculateReachedSkillPointsFromTestPoints($skillPoints, $maxTestPoints, $reachedTestPoints)
$result
__construct(ilDBInterface $db, $testId, $refId)
static writeUserSkillLevelStatus(int $a_level_id, int $a_user_id, int $a_trigger_ref_id, int $a_tref_id=0, int $a_status=ilBasicSkill::ACHIEVED, bool $a_force=false, bool $a_self_eval=false, string $a_unique_identifier="", float $a_next_level_fulfilment=0.0)
static getProfilesOfUser($a_user_id)
Get profiles of a user.
isAssignedSkill($skillBaseId, $skillTrefId)
noProfileMatchingAssignedSkillExists($availableSkillProfiles)
global $DIC
Definition: goto.php:24
bookToSkillPointAccount($skillBaseId, $skillTrefId, $maxSkillPoints, $reachedSkillPoints)
static addPersonalSkill($a_user_id, $a_skill_node_id)
Add personal skill.
Class ilParserQuestionProvider.
initTestQuestionData(ilAssQuestionList $questionList)
doesNumBookingsExceedRequiredBookingsBarrier(ilTestSkillPointAccount $skillPointAccount)
Basic Skill.
determineReachedSkillPointsWithSolutionCompare(ilAssQuestionSolutionComparisonExpressionList $expressionList)