ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilTestSkillEvaluation.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
24
34{
37 private array $questions = [];
38 private array $max_points_by_question = [];
40 private array $skill_point_accounts;
41 private array $reached_skill_levels;
42 private int $user_id;
43 private int $active_id;
44 private int $pass;
46
47
48 public function __construct(
49 private ilDBInterface $db,
50 private TestLogger $logger,
51 int $test_id,
52 private int $refId,
53 private SkillProfileService $skill_profile_service,
54 private SkillPersonalService $skill_personal_service
55 ) {
56 $this->skill_question_assignment_list = new ilAssQuestionSkillAssignmentList($this->db);
57
58 $this->skill_level_threshold_list = new ilTestSkillLevelThresholdList($this->db);
59 $this->skill_level_threshold_list->setTestId($test_id);
60 }
61
62 public function getUserId(): int
63 {
64 return $this->user_id;
65 }
66
67 public function setUserId(int $user_id): void
68 {
69 $this->user_id = $user_id;
70 }
71
72 public function getActiveId(): int
73 {
74 return $this->active_id;
75 }
76
77 public function setActiveId(int $active_id): void
78 {
79 $this->active_id = $active_id;
80 }
81
82 public function getPass(): int
83 {
84 return $this->pass;
85 }
86
87 public function setPass($pass): void
88 {
89 $this->pass = $pass;
90 }
91
93 {
95 }
96
98 {
99 $this->num_required_bookings_for_skill_triggering = $num_required_bookings_for_skill_triggering;
100 }
101
102 public function init(ilAssQuestionList $question_list): void
103 {
104 $this->skill_question_assignment_list->setParentObjId($question_list->getParentObjId());
105 $this->skill_question_assignment_list->loadFromDb();
106
107 $this->skill_level_threshold_list->loadFromDb();
108
109 $this->initTestQuestionData($question_list);
110 }
111
115 public function evaluate(array $test_results): void
116 {
117 $this->reset();
118
119 $this->initTestResultData($test_results);
120
123 }
124
125 public function getReachedSkillLevels(): array
126 {
128 }
129
130 private function reset(): void
131 {
132 $this->reached_points_by_question = [];
133 $this->skill_point_accounts = [];
134 $this->reached_skill_levels = [];
135 }
136
137 private function initTestQuestionData(ilAssQuestionList $question_list): void
138 {
139 foreach ($question_list->getQuestionDataArray() as $question_data) {
140 $this->questions[] = $question_data['question_id'];
141 $this->max_points_by_question[ $question_data['question_id'] ] = $question_data['points'];
142 }
143 }
144
145 private function initTestResultData(array $test_results): void
146 {
147 foreach ($test_results as $key => $result) {
148 if ($key === 'pass' || $key === 'test') { // note: key int 0 IS == 'pass' or 'buxtehude'
149 continue;
150 }
151
152 $this->reached_points_by_question[ $result['qid'] ] = $result['reached'];
153 }
154 }
155
156 private function drawUpSkillPointAccounts(): void
157 {
158 foreach ($this->questions as $question_id) {
159 if (!$this->isAnsweredQuestion($question_id)) {
160 continue;
161 }
162
163 $assignments = $this->skill_question_assignment_list->getAssignmentsByQuestionId($question_id);
164
165 foreach ($assignments as $assignment) {
166 if ($assignment->hasEvalModeBySolution()) {
167 $reached_skill_points = $this->determineReachedSkillPointsWithSolutionCompare(
168 $assignment->getSolutionComparisonExpressionList()
169 );
170 } else {
171 $max_test_points = $this->max_points_by_question[$question_id];
172 $reached_test_points = $this->reached_points_by_question[$question_id];
173 $reached_skill_points = $this->calculateReachedSkillPointsFromTestPoints(
174 $assignment->getSkillPoints(),
175 $max_test_points,
176 $reached_test_points
177 );
178 }
179
181 $assignment->getSkillBaseId(),
182 $assignment->getSkillTrefId(),
183 $assignment->getMaxSkillPoints(),
184 $reached_skill_points
185 );
186 }
187 }
188 }
189
190 private function isAnsweredQuestion(int $question_id): bool
191 {
192 return isset($this->reached_points_by_question[$question_id]);
193 }
194
197 ): ?int {
198 $question_provider = new ilAssLacQuestionProvider();
199 $question_provider->setQuestionId($expression_list->getQuestionId());
200
201 foreach ($expression_list->get() as $expression) {
202 $condition_composite = (new ilAssLacConditionParser())->parse(
203 $expression->getExpression()
204 );
205
206 $composite_evaluator = new ilAssLacCompositeEvaluator(
207 $question_provider,
208 $this->getActiveId(),
209 $this->getPass()
210 );
211 if ($composite_evaluator->evaluate($condition_composite)) {
212 return $expression->getPoints();
213 }
214 }
215
216 return 0;
217 }
218
220 int $skill_points,
221 float $max_test_points,
222 float $reached_test_points
223 ): float {
224 if ($reached_test_points < 0) {
225 $reached_test_points = 0;
226 }
227
228 $factor = 0;
229
230 if ($max_test_points > 0) {
231 $factor = $reached_test_points / $max_test_points;
232 }
233
234 return ($skill_points * $factor);
235 }
236
237 private function bookToSkillPointAccount(
238 int $skill_base_id,
239 int $skill_tref_id,
240 int $max_skill_points,
241 float $reached_skill_points
242 ): void {
243 $skill_key = $skill_base_id . ':' . $skill_tref_id;
244
245 if (!isset($this->skill_point_accounts[$skill_key])) {
246 $this->skill_point_accounts[$skill_key] = new ilTestSkillPointAccount();
247 }
248
249 $this->skill_point_accounts[$skill_key]->addBooking($max_skill_points, $reached_skill_points);
250 }
251
252 private function evaluateSkillPointAccounts(): void
253 {
254 foreach ($this->skill_point_accounts as $skill_key => $skill_point_account) {
255 if (!$this->doesNumBookingsExceedRequiredBookingsBarrier($skill_point_account)) {
256 continue;
257 }
258
259 list($skill_base_id, $skill_tref_id) = explode(':', $skill_key);
260
261 $skill = new ilBasicSkill((int) $skill_base_id);
262 $levels = $skill->getLevelData();
263
264 $reached_level_id = null;
265 foreach ($levels as $level) {
266 $threshold = $this->skill_level_threshold_list->getThreshold($skill_base_id, $skill_tref_id, $level['id']);
267
268 if (!($threshold instanceof ilTestSkillLevelThreshold) || $threshold->getThreshold() === null) {
269 continue;
270 }
271
272 if ($skill_point_account->getTotalReachedSkillPercent() < $threshold->getThreshold()) {
273 break;
274 }
275
276 $reached_level_id = $level['id'];
277 }
278
279 $this->reached_skill_levels[] = [
280 'sklBaseId' => $skill_base_id, 'sklTrefId' => $skill_tref_id, 'sklLevelId' => $reached_level_id
281 ];
282 }
283 }
284
286 {
287 return $skillPointAccount->getNumBookings() >= $this->getNumRequiredBookingsForSkillTriggering();
288 }
289
290 public function handleSkillTriggering(): void
291 {
292 foreach ($this->getReachedSkillLevels() as $reached_skill_level) {
293 $this->invokeSkillLevelTrigger((int) $reached_skill_level['sklLevelId'], (int) $reached_skill_level['sklTrefId']);
294
295 if ($reached_skill_level['sklTrefId'] > 0) {
296 $this->skill_personal_service->addPersonalSkill($this->getUserId(), (int) $reached_skill_level['sklTrefId']);
297 } else {
298 $this->skill_personal_service->addPersonalSkill($this->getUserId(), (int) $reached_skill_level['sklBaseId']);
299 }
300 }
301 //write profile completion entries if fulfilment status has changed
302 $this->skill_profile_service->writeCompletionEntryForAllProfiles($this->getUserId());
303 }
304
305 private function invokeSkillLevelTrigger(int $skill_level_id, int $skill_tref_id): void
306 {
308 $skill_level_id,
309 $this->getUserId(),
310 $this->refId,
311 $skill_tref_id,
313 true,
314 false,
315 (string) $this->getPass()
316 );
317
318 $this->logger->info(
319 "refId={$this->refId} / usrId={$this->getUserId()} / levelId={$skill_level_id} / trefId={$skill_tref_id}"
320 );
321 }
322
323 public function getSkillsMatchingNumAnswersBarrier(): array
324 {
325 $skills_matching_num_answers_barrier = [];
326
327 foreach ($this->skill_point_accounts as $skillKey => $skillPointAccount) {
328 if ($this->doesNumBookingsExceedRequiredBookingsBarrier($skillPointAccount)) {
329 list($skillBaseId, $skillTrefId) = explode(':', $skillKey);
330
331 $skills_matching_num_answers_barrier[$skillKey] = [
332 'base_skill_id' => (int) $skillBaseId,
333 'tref_id' => (int) $skillTrefId
334 ];
335 }
336 }
337
338 return $skills_matching_num_answers_barrier;
339 }
340
341 public function getSkillsInvolvedByAssignment(): array
342 {
343 $unique_skills = [];
344
345 foreach ($this->skill_question_assignment_list->getUniqueAssignedSkills() as $skill) {
346 $skillKey = $skill['skill_base_id'] . ':' . $skill['skill_tref_id'];
347
348 $unique_skills[$skillKey] = [
349 'base_skill_id' => (int) $skill['skill_base_id'],
350 'tref_id' => (int) $skill['skill_tref_id']
351 ];
352 }
353
354 return $unique_skills;
355 }
356
357 public function isAssignedSkill($skill_base_id, $skill_tref_id): void
358 {
359 $this->skill_question_assignment_list->isAssignedSkill($skill_base_id, $skill_tref_id);
360 }
361
363 {
364 $matching_skill_profiles = [];
365 $users_profiles = $this->skill_profile_service->getProfilesOfUser($this->getUserId());
366 foreach ($users_profiles as $profile_data) {
367 $assigned_skill_levels = $this->skill_profile_service->getSkillLevels($profile_data->getId());
368
369 foreach ($assigned_skill_levels as $assigned_skill_level) {
370 $skill_base_id = $assigned_skill_level->getBaseSkillId();
371 $skill_tref_id = $assigned_skill_level->getTrefId();
372
373 if ($this->skill_question_assignment_list->isAssignedSkill($skill_base_id, $skill_tref_id)) {
374 $matching_skill_profiles[$profile_data->getId()] = $profile_data->getTitle();
375 }
376 }
377 }
378
379 return $matching_skill_profiles;
380 }
381
382 public function noProfileMatchingAssignedSkillExists(array $available_skill_profiles): bool
383 {
384 $no_profile_matching_skills = $this->skill_question_assignment_list->getUniqueAssignedSkills();
385
386 foreach (array_keys($available_skill_profiles) as $skill_profile_id) {
387 $assigned_skill_levels = $this->skill_profile_service->getSkillLevels(
388 $this->skill_profile_service->getProfile($skill_profile_id)->getId()
389 );
390
391 foreach ($assigned_skill_levels as $assigned_skill_level) {
392 $skill_base_id = $assigned_skill_level->getBaseSkillId();
393 $skill_tref_id = $assigned_skill_level->getTrefId();
394
395 if ($this->skill_question_assignment_list->isAssignedSkill($skill_base_id, $skill_tref_id)) {
396 unset($no_profile_matching_skills["{$skill_base_id}:{$skill_tref_id}"]);
397 }
398 }
399 }
400
401 return $no_profile_matching_skills !== [];
402 }
403}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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, string $trigger_user_id="")
init(ilAssQuestionList $question_list)
noProfileMatchingAssignedSkillExists(array $available_skill_profiles)
bookToSkillPointAccount(int $skill_base_id, int $skill_tref_id, int $max_skill_points, float $reached_skill_points)
ilTestSkillLevelThresholdList $skill_level_threshold_list
initTestQuestionData(ilAssQuestionList $question_list)
invokeSkillLevelTrigger(int $skill_level_id, int $skill_tref_id)
determineReachedSkillPointsWithSolutionCompare(ilAssQuestionSolutionComparisonExpressionList $expression_list)
doesNumBookingsExceedRequiredBookingsBarrier(ilTestSkillPointAccount $skillPointAccount)
initTestResultData(array $test_results)
calculateReachedSkillPointsFromTestPoints(int $skill_points, float $max_test_points, float $reached_test_points)
setNumRequiredBookingsForSkillTriggering(int $num_required_bookings_for_skill_triggering)
ilAssQuestionSkillAssignmentList $skill_question_assignment_list
isAssignedSkill($skill_base_id, $skill_tref_id)
__construct(private ilDBInterface $db, private TestLogger $logger, int $test_id, private int $refId, private SkillProfileService $skill_profile_service, private SkillPersonalService $skill_personal_service)
Interface ilDBInterface.
if(!file_exists('../ilias.ini.php'))
$refId
Definition: xapitoken.php:58