public function OpignoModuleController::takeModule in Opigno module 8
Same name and namespace in other branches
- 3.x src/Controller/OpignoModuleController.php \Drupal\opigno_module\Controller\OpignoModuleController::takeModule()
Method for Take module tab route.
1 string reference to 'OpignoModuleController::takeModule'
File
- src/
Controller/ OpignoModuleController.php, line 153
Class
- OpignoModuleController
- Class OpignoModuleController.
Namespace
Drupal\opigno_module\ControllerCode
public function takeModule(Request $request, Group $group, OpignoModuleInterface $opigno_module) {
/* @var $opigno_module \Drupal\opigno_module\Entity\OpignoModule */
/* @var $query_options \Symfony\Component\HttpFoundation\ParameterBag */
$query_options = $request->query;
// Set current ID of group
OpignoGroupContext::setGroupId($group
->id());
// Check Module availability.
$availability = $opigno_module
->checkModuleAvailability();
if (!$availability['open']) {
// Module is not available. Based on availability time.
\Drupal::messenger()
->addWarning($availability['message']);
return $this
->redirect('entity.group.canonical', [
'group' => $group
->id(),
]);
}
// Check Module attempts.
if ($this
->currentUser()
->id() != 1 && !in_array('administrator', $this
->currentUser()
->getAccount()
->getRoles())) {
$allowed_attempts = $opigno_module
->get('takes')->value;
if ($allowed_attempts > 0) {
// It means, that module attempts are limited.
// Need to check User attempts.
$user_attempts = $opigno_module
->getModuleAttempts($this
->currentUser());
if (count($user_attempts) >= $allowed_attempts) {
// User has more attempts then allowed.
// Check for not finished attempt.
$active_attempt = $opigno_module
->getModuleActiveAttempt($this
->currentUser());
if ($active_attempt == NULL) {
// There is no not finished attempt.
\Drupal::messenger()
->addWarning($this
->t('Maximum attempts for this module reached.'));
return $this
->redirect('entity.group.canonical', [
'group' => $group
->id(),
]);
}
}
}
}
// Check if module in skills system.
$skills_active = $opigno_module
->getSkillsActive();
// Get activities from the Module.
$activities = $opigno_module
->getModuleActivities();
$target_skill = $opigno_module
->getTargetSkill();
$term_storage = \Drupal::entityTypeManager()
->getStorage('taxonomy_term');
$moduleHandler = \Drupal::service('module_handler');
if ($moduleHandler
->moduleExists('opigno_skills_system') && $skills_active) {
$skills_tree = array_reverse($term_storage
->loadTree('skills', $target_skill));
$db_connection = \Drupal::service('database');
// Get current user's skills.
$uid = $this
->currentUser()
->id();
$query = $db_connection
->select('opigno_skills_statistic', 'o_s_s');
$query
->fields('o_s_s', [
'tid',
'score',
'progress',
'stage',
]);
$query
->condition('o_s_s.uid', $uid);
$user_skills = $query
->execute()
->fetchAllAssoc('tid');
// Find skills which needs to level-up.
$depth_of_skills_tree = $skills_tree[0]->depth;
$current_skills = [];
if (!isset($depth_of_skills_tree)) {
$depth_of_skills_tree = 0;
}
// Set default successfully finished this skills tree for user.
// If the system finds any skill which is not successfully finished then change this variable to FALSE.
$successfully_finished = TRUE;
while ($depth_of_skills_tree >= 0) {
foreach ($skills_tree as $key => $skill) {
$tid = $skill->tid;
$skill_entity = $term_storage
->load($tid);
$minimum_score = $skill_entity
->get('field_minimum_score')
->getValue()[0]['value'];
$children = $term_storage
->loadChildren($tid);
$skill_access = TRUE;
// Check if the skill was successfully finished.
if (!isset($user_skills[$skill->tid])) {
$successfully_finished = FALSE;
}
else {
if ($minimum_score > $user_skills[$skill->tid]->score || $user_skills[$skill->tid]->progress < 100) {
$successfully_finished = FALSE;
}
}
if (!empty($children)) {
$children_ids = array_keys($children);
foreach ($children_ids as $child_id) {
if (!isset($user_skills[$child_id])) {
$skill_access = FALSE;
break;
}
if ($user_skills[$child_id]->progress < 100 || $user_skills[$child_id]->score < $minimum_score) {
$skill_access = FALSE;
}
}
}
if ($skill->depth == $depth_of_skills_tree && $skill_access == TRUE && !$successfully_finished) {
$current_skills[] = $skill->tid;
}
}
$depth_of_skills_tree--;
}
// Check if Opigno system could load all suitable activities not included in the current module.
$use_all_activities = $opigno_module
->getModuleSkillsGlobal();
if ($use_all_activities && !empty($current_skills)) {
$activities += $opigno_module
->getSuitableActivities($current_skills);
}
}
// Create new attempt or resume existing one.
$attempt = $opigno_module
->getModuleActiveAttempt($this
->currentUser());
if ($attempt == NULL) {
// No existing attempt, create new one.
$attempt = UserModuleStatus::create([]);
$attempt
->setModule($opigno_module);
$attempt
->setFinished(0);
$attempt
->save();
}
// Get training unfinished attempt.
$attempt_lp = $opigno_module
->getTrainingActiveAttempt($this
->currentUser(), $group);
if ($attempt_lp == NULL) {
// No unfinished attempt. Create training new attempt
// only if current step is mandatory.
$steps = LearningPathContent::getAllStepsOnlyModules($group
->id());
$step_module_info = array_filter($steps, function ($step) use ($opigno_module) {
return $step['id'] == $opigno_module
->id();
});
if (!empty($step_module_info)) {
$step_module_info = array_shift($step_module_info);
// Get started time for training attempt.
$started = $attempt
->get('started')
->getValue();
$started = !empty($started[0]['value']) ? $started[0]['value'] : time();
// Create training new attempt.
$attempt_lp = LPStatus::create([
'uid' => $this
->currentUser()
->id(),
'gid' => $group
->id(),
'status' => 'in progress',
'started' => $started,
'finished' => 0,
]);
$attempt_lp
->save();
}
}
// Redirect to the module results page with message 'successfully finished'.
if (isset($successfully_finished) && $successfully_finished) {
if ($attempt
->isFinished()) {
$this
->messenger()
->addWarning($this
->t('You already successfully finished this skill\'s tree.'));
}
else {
$sum_score = 0;
foreach ($user_skills as $skill) {
$sum_score += $skill->score;
}
$avg_score = $sum_score / count($user_skills);
$attempt
->setFinished(\Drupal::time()
->getRequestTime());
$attempt
->setScore($avg_score);
$attempt
->setEvaluated(1);
$attempt
->setMaxScore($avg_score);
$attempt
->save();
}
$_SESSION['successfully_finished'] = TRUE;
return $this
->redirect('opigno_module.module_result', [
'opigno_module' => $opigno_module
->id(),
'user_module_status' => $attempt
->id(),
]);
}
// Set context variable for the type of activity answer link.
// It's necessary for detecting manual/direct activity answer link.
// Here we prepare Opigno flow activity link type.
OpignoGroupContext::setActivityLinkType('flow');
if (count($activities) > 0) {
// Get activity that will be answered.
$next_activity_id = NULL;
$last_activity_id = $attempt
->getLastActivityId();
$get_next = FALSE;
// Check if Skills system is activated for this module.
if ($moduleHandler
->moduleExists('opigno_skills_system') && $skills_active) {
// Load user's answers for current skills.
$activities_ids = array_keys($activities);
$query = $db_connection
->select('opigno_answer_field_data', 'o_a_f_d');
$query
->leftJoin('opigno_module_relationship', 'o_m_r', 'o_a_f_d.activity = o_m_r.child_id');
$query
->addExpression('MAX(o_a_f_d.score)', 'score');
$query
->addExpression('MAX(o_a_f_d.changed)', 'changed');
$query
->addExpression('MAX(o_a_f_d.skills_mode)', 'skills_mode');
$query
->addField('o_a_f_d', 'activity');
$query
->condition('o_a_f_d.user_id', $uid)
->condition('o_a_f_d.activity', $activities_ids, 'IN')
->condition('o_a_f_d.skills_mode', NULL, 'IS NOT NULL');
$answers = $query
->groupBy('o_a_f_d.activity')
->orderBy('score')
->orderBy('changed')
->execute()
->fetchAllAssoc('activity');
$answers_ids = array_keys($answers);
$available_activities = count($activities_ids) > count($answers_ids) ? TRUE : FALSE;
if (!is_null($last_activity_id)) {
$last_skill_activity = \Drupal::entityTypeManager()
->getStorage('opigno_activity')
->load($last_activity_id);
$last_skill_id = $last_skill_activity
->getSkillId();
}
foreach ($activities as $activity) {
// Get initial level. This is equal to the count of levels.
$initial_level = $term_storage
->load($activity->skills_list);
if ($initial_level) {
$initial_level = count($initial_level
->get('field_level_names')
->getValue());
}
// Check if the skill level of activity matches the current skill level of the user.
if (isset($user_skills[$activity->skills_list]) && $user_skills[$activity->skills_list]->stage != $activity->skill_level || !isset($user_skills[$activity->skills_list]) && $activity->skill_level != $initial_level) {
continue;
}
if (in_array($activity->skills_list, $current_skills) && !in_array($activity->id, $answers_ids)) {
$next_activity_id = $activity->id;
// If we don't have ID of last activity then set next activity by default.
if (!isset($last_skill_id)) {
break;
}
elseif ($last_skill_id == $activity->skills_list) {
break;
}
}
}
// If user already answered at all questions of available skills.
if ($next_activity_id == NULL) {
foreach ($answers as $answer) {
if (in_array($answer->skills_mode, $current_skills) && $answer->score != $activities[$answer->activity]->max_score) {
$next_activity_id = $answer->activity;
// If we don't have ID of last activity then set next activity by default.
if (!isset($last_skill_id)) {
break;
}
elseif ($last_skill_id == $answer->skills_mode) {
break;
}
}
}
}
// Redirect user to the next activity(answer).
if (isset($next_activity_id)) {
return $this
->redirect('opigno_module.group.answer_form', [
'group' => $group
->id(),
'opigno_activity' => $next_activity_id,
'opigno_module' => $opigno_module
->id(),
]);
}
else {
$_SESSION['successfully_finished'] = FALSE;
}
}
// Get additional module settings.
$backwards_param = $query_options
->get('backwards');
// Take into account randomization options.
$randomization = $opigno_module
->getRandomization();
if ($randomization > 0) {
// Get random activity and put it in a sequence.
$random_activity = $opigno_module
->getRandomActivity($attempt);
if ($random_activity) {
$next_activity_id = $random_activity
->id();
}
}
else {
foreach ($activities as $activity_id => $activity) {
// Check for backwards navigation submit.
if ($opigno_module
->getBackwardsNavigation() && isset($prev_activity_id) && $last_activity_id == $activity_id && $backwards_param) {
$next_activity_id = $prev_activity_id;
break;
}
if (is_null($last_activity_id) || $get_next) {
// Get the first activity.
$next_activity_id = $activity_id;
break;
}
if ($last_activity_id == $activity_id) {
// Get the next activity after this one.
$get_next = TRUE;
}
$prev_activity_id = $activity_id;
}
// Check if user navigate to previous module with "back" button.
$from_first_activity = key($activities) == $last_activity_id || key($activities) == $attempt
->getCurrentActivityId() || $last_activity_id == NULL;
if ($opigno_module
->getBackwardsNavigation() && $from_first_activity && $backwards_param) {
return $this
->redirect('opigno_module.get_previous_module', [
'opigno_module' => $opigno_module
->id(),
]);
}
}
// Get group context.
$cid = OpignoGroupContext::getCurrentGroupContentId();
$gid = OpignoGroupContext::getCurrentGroupId();
if ($gid) {
$steps = LearningPathContent::getAllStepsOnlyModules($gid);
foreach ($steps as $step) {
if ($step['id'] == $opigno_module
->id() && $step['cid'] != $cid) {
// Update content cid.
OpignoGroupContext::setCurrentContentId($step['cid']);
}
}
}
$activities_storage = static::entityTypeManager()
->getStorage('opigno_activity');
if (!is_null($next_activity_id)) {
// Means that we have some activity to answer.
$attempt
->setCurrentActivity($activities_storage
->load($next_activity_id));
$attempt
->save();
return $this
->redirect('opigno_module.group.answer_form', [
'group' => $group
->id(),
'opigno_activity' => $next_activity_id,
'opigno_module' => $opigno_module
->id(),
]);
}
else {
// If a user clicks "Back" button,
// show the last question instead of summary page.
$previous = $query_options
->get('previous');
if ($previous) {
return $this
->redirect('opigno_module.group.answer_form', [
'group' => $group
->id(),
'opigno_activity' => $last_activity_id,
'opigno_module' => $opigno_module
->id(),
]);
}
else {
$attempt
->finishAttempt();
return $this
->redirect('opigno_module.module_result', [
'opigno_module' => $opigno_module
->id(),
'user_module_status' => $attempt
->id(),
]);
}
}
}
if ($target_skill) {
$target_skill_entity = $term_storage
->load($target_skill);
$warning = $this
->t('There are not enough activities in the Opigno System to complete "@target_skill" skills tree!', [
'@target_skill' => $target_skill_entity
->getName(),
]);
return [
'#markup' => "<div class='lp_step_explanation'>{$warning}</div>",
'#attached' => [
'library' => [
'opigno_learning_path/creation_steps',
],
],
];
}
\Drupal::messenger()
->addWarning($this
->t('Module @module_label does not contain any activity.', [
'@module_label' => $opigno_module
->label(),
]));
return $this
->redirect('entity.group.canonical', [
'group' => $group
->id(),
]);
}