ILIAS  release_7 Revision v7.30-3-g800a261c036
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
4require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionSkillAssignmentList.php';
5require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacQuestionProvider.php';
6require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacConditionParser.php';
7require_once 'Modules/TestQuestionPool/classes/questions/LogicalAnswerCompare/ilAssLacCompositeEvaluator.php';
8require_once 'Modules/Test/classes/class.ilTestSkillPointAccount.php';
9require_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
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}
$result
An exception for terminatinating execution or to throw for unit testing.
Class ilParserQuestionProvider.
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 addPersonalSkill($a_user_id, $a_skill_node_id)
Add personal skill.
static getProfilesOfUser($a_user_id)
Get profiles of a user.
init(ilAssQuestionList $questionList)
initTestQuestionData(ilAssQuestionList $questionList)
calculateReachedSkillPointsFromTestPoints($skillPoints, $maxTestPoints, $reachedTestPoints)
determineReachedSkillPointsWithSolutionCompare(ilAssQuestionSolutionComparisonExpressionList $expressionList)
setNumRequiredBookingsForSkillTriggering($numRequiredBookingsForSkillTriggering)
noProfileMatchingAssignedSkillExists($availableSkillProfiles)
isAssignedSkill($skillBaseId, $skillTrefId)
bookToSkillPointAccount($skillBaseId, $skillTrefId, $maxSkillPoints, $reachedSkillPoints)
invokeSkillLevelTrigger($skillLevelId, $skillTrefId)
doesNumBookingsExceedRequiredBookingsBarrier(ilTestSkillPointAccount $skillPointAccount)
__construct(ilDBInterface $db, $testId, $refId)
global $DIC
Definition: goto.php:24
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...