You are here

public function OpignoModuleController::userResult in Opigno module 3.x

Same name and namespace in other branches
  1. 8 src/Controller/OpignoModuleController.php \Drupal\opigno_module\Controller\OpignoModuleController::userResult()

Returns user result.

1 string reference to 'OpignoModuleController::userResult'
opigno_module.routing.yml in ./opigno_module.routing.yml
opigno_module.routing.yml

File

src/Controller/OpignoModuleController.php, line 753

Class

OpignoModuleController
Class OpignoModuleController.

Namespace

Drupal\opigno_module\Controller

Code

public function userResult(OpignoModuleInterface $opigno_module, UserModuleStatus $user_module_status = NULL) {
  $content = [];
  $user_answers = $user_module_status
    ->getAnswers();
  $question_number = 0;
  $module_activities = $opigno_module
    ->getModuleActivities();
  $score = $user_module_status
    ->getScore();
  $moduleHandler = \Drupal::service('module_handler');
  $lp_id = $user_module_status
    ->get('learning_path')->target_id;
  OpignoGroupContext::setGroupId($lp_id);

  // Load more activities for 'skills module' with switched on option 'use all suitable activities from Opigno system'.
  if ($moduleHandler
    ->moduleExists('opigno_skills_system') && $opigno_module
    ->getSkillsActive()) {
    $target_skill = $opigno_module
      ->getTargetSkill();
    $term_storage = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term');
    $skills_tree = array_reverse($term_storage
      ->loadTree('skills', $target_skill));
    $current_skills = [];
    if ($opigno_module
      ->getModuleSkillsGlobal()) {
      foreach ($skills_tree as $skill) {
        $current_skills[] = $skill->tid;
      }
      $module_activities += $opigno_module
        ->getSuitableActivities($current_skills);
    }
  }
  foreach ($user_answers as $answer) {
    $question_number++;
    $answer_activity = $answer
      ->getActivity();
    if (!$answer_activity) {
      continue;
    }
    $content[] = [
      '#theme' => 'opigno_user_result_item',
      '#opigno_answer' => $answer,
      '#opigno_answer_activity' => $answer_activity,
      '#question_number' => $question_number,
      '#answer_max_score' => isset($module_activities[$answer_activity
        ->id()], $module_activities[$answer_activity
        ->id()]->max_score) ? $module_activities[$answer_activity
        ->id()]->max_score : 10,
    ];
  }
  $user = $this
    ->currentUser();
  $uid = $user
    ->id();
  $gid = OpignoGroupContext::getCurrentGroupId();
  if (!empty($gid)) {
    $group = Group::load($gid);
    $latest_cert_date = LPStatus::getTrainingStartDate($group, $uid);
    $steps = LearningPathContent::getAllStepsOnlyModules($gid, $uid, FALSE, NULL, $latest_cert_date);
    if (!empty($_SESSION['step_required_conditions_failed'])) {

      // If guided option set, required conditions exist and didn't met.
      unset($_SESSION['step_required_conditions_failed']);
      $content_type_manager = \Drupal::service('opigno_group_manager.content_types.manager');
      $step_info = opigno_learning_path_get_module_step($gid, $uid, $opigno_module, $latest_cert_date);
      $content = [];
      $content[] = [
        '#type' => 'html_tag',
        '#tag' => 'h1',
        '#value' => $this
          ->t('Next'),
      ];
      if (!empty($step_info)) {
        $course_entity = OpignoGroupManagedContent::load($step_info['cid']);
        $course_content_type = $content_type_manager
          ->createInstance($course_entity
          ->getGroupContentTypeId());
        $current_step_url = $course_content_type
          ->getStartContentUrl($course_entity
          ->getEntityId(), $gid);
        $content[] = [
          '#type' => 'markup',
          '#markup' => $this
            ->t('<p>You should first met required conditions for the step "%step" before going further. <a href=":link">Try again.</a></p>', [
            ':link' => $current_step_url
              ->toString(),
            '%step' => $opigno_module
              ->getName(),
          ]),
        ];
      }
      return $content;
    }

    // Find current step.
    $current_step_key = array_search($opigno_module
      ->id(), array_column($steps, 'id'));
    $current_step = isset($current_step_key) ? $steps[$current_step_key] : NULL;

    // Remove the live meeting and instructor-led training steps.
    $steps = array_filter($steps, function ($step) {
      return !in_array($step['typology'], [
        'Meeting',
        'ILT',
      ]);
    });

    // Get training guided navigation option.
    $freeNavigation = !OpignoGroupManagerController::getGuidedNavigation($group);
    if ($current_step !== NULL) {
      $last_step = end($steps);
      $is_last = $last_step['cid'] === $current_step['cid'];
      $current_step['current attempt score'] = $score;
      $start_time = (int) $user_module_status
        ->get('started')
        ->getValue()[0]['value'];
      $end_time = (int) $user_module_status
        ->get('finished')
        ->getValue()[0]['value'];
      $time = $end_time > $start_time ? $end_time - $start_time : 0;
      $current_step['current attempt time'] = $time;
      if (isset($current_step['parent'])) {
        $current_step['parent']['current attempt time'] = $time;
      }

      // Send notification about manual evaluation.
      $module_id = $opigno_module
        ->id();
      $is_evaluated = $user_module_status
        ->get('evaluated')
        ->getValue()[0]['value'];
      if (!$is_evaluated) {
        $status_id = $user_module_status
          ->id();
        $message = $this
          ->t('Module "@module" need manual evaluating.', [
          '@module' => $current_step['name'],
        ]);
        $url = Url::fromRoute('opigno_module.module_result_form', [
          'opigno_module' => $module_id,
          'user_module_status' => $status_id,
        ])
          ->toString();

        // Get user managers.
        $members = $group
          ->getMembers('learning_path-user_manager');
        $members_entities = array_map(function ($member) {
          return $member
            ->getUser();
        }, $members);

        // Get admins.
        $admins = opigno_module_get_users_by_role('administrator');

        // Get array of all users who must receive notification.
        $users = array_merge($members_entities, $admins);
        foreach ($users as $user) {
          opigno_set_message($user
            ->id(), $message, $url);
        }
      }
      $skip_links = \Drupal::request()->query
        ->get('skip-links');
      if (!$skip_links) {
        if ($score >= $current_step['required score']) {
          $message = $this
            ->t('Successfully completed module "@module" in "@name"', [
            '@module' => $current_step['name'],
            '@name' => $group
              ->label(),
          ]);
          $url = Url::fromRoute('entity.group.canonical', [
            'group' => $group
              ->id(),
          ])
            ->toString();
          opigno_set_message($uid, $message, $url);
          if ($is_last) {
            $message = $this
              ->t('Congratulations! You successfully finished the training "@name"', [
              '@name' => $group
                ->label(),
            ]);
            $url = Url::fromRoute('entity.group.canonical', [
              'group' => $group
                ->id(),
            ])
              ->toString();
            opigno_set_message($uid, $message, $url);
          }
        }

        // Training attempt update/finish.
        // Get mandatory steps.
        $mandatory_steps = array_filter($steps, function ($step) {
          return $step['mandatory'];
        });

        // Steps queue mapping.
        $steps_cids_mapping = array_map(function ($step) {
          return $step['cid'];
        }, $steps);

        // Check if there are more mandatory steps.
        // Get last mandatory step key.
        $last_mandatory_step = end($mandatory_steps);
        $last_mandatory_step_key = array_search($last_mandatory_step["cid"], $steps_cids_mapping);

        // Get current step key.
        $current_step_key = array_search($current_step["cid"], $steps_cids_mapping);
        if ($current_step_key < $last_mandatory_step_key) {

          // There are more mandatory steps.
          $lp_status = 'in progress';
          $finished = 0;
        }
        else {

          // No more mandatory steps.
          // Calculate training attempt status.
          $training_is_passed = opigno_learning_path_is_passed($group, $uid, TRUE);
          if ($training_is_passed) {
            $lp_status = 'passed';
          }
          else {
            $lp_status = 'failed';
          }
          $finished = !empty($end_time) ? $end_time : time();
        }

        // Get training unfinished attempt.
        $attempt_lp = $opigno_module
          ->getTrainingActiveAttempt($this
          ->currentUser(), $group);
        if ($attempt_lp) {

          // Update training unfinished attempt.
          $attempt_lp
            ->setStatus($lp_status);
          $attempt_lp
            ->setFinished($finished);
          if ($lp_status == 'passed') {

            // Save training current attempt score.
            $training_score = opigno_learning_path_get_score($group
              ->id(), $uid, TRUE);
            $attempt_lp
              ->setScore($training_score);
          }
          $attempt_lp
            ->save();

          // Save passed training certificate expire date if set expiration.
          if ($lp_status == 'passed' && LPStatus::isCertificateExpireSet($group)) {
            $expiration_period = LPStatus::getCertificateExpirationPeriod($group);
            if ($expiration_period) {

              // Latest certificate timestamp - existing or new.
              $started = $attempt_lp
                ->getStarted();
              if ($started) {
                $latest_cert_date = $started;
              }
              if (!LPStatus::isCertificateExpired($group, $uid)) {
                if ($existing_cert_date = LPStatus::getLatestCertificateTimestamp($gid, $uid)) {
                  $latest_cert_date = $existing_cert_date;
                }
              }
              $latest_cert_date = !empty($latest_cert_date) ? $latest_cert_date : $start_time;

              // Calculate expiration timestamp.
              $suffix = $expiration_period > 1 ? 's' : '';
              $offset = '+' . $expiration_period . ' month' . $suffix;
              $expiration_timestamp = strtotime($offset, $finished);

              // Set expiration data.
              LPStatus::setCertificateExpireTimestamp($gid, $uid, $latest_cert_date, $expiration_timestamp);
            }
          }
        }

        // Training achievements.
        if (function_exists('opigno_learning_path_save_step_achievements')) {

          // Save current step parent achievements.
          $parent_id = isset($current_step['parent']) ? opigno_learning_path_save_step_achievements($gid, $uid, $current_step['parent']) : 0;

          // Save current step achievements.
          opigno_learning_path_save_step_achievements($gid, $uid, $current_step, $parent_id);
        }
        if (function_exists('opigno_learning_path_save_achievements')) {

          // Save training achievements.
          opigno_learning_path_save_achievements($gid, $uid);
        }

        // Modules notifications and badges.
        if ($current_step['typology'] == 'Module' && $opigno_module->badge_active->value) {
          $badge_notification = '';
          $save_badge = FALSE;

          // Badge notification for finished state.
          if ($opigno_module->badge_criteria->value == 'finished') {
            $badge_notification = $opigno_module->badge_name->value;
            $save_badge = TRUE;
          }

          // Badge notification for successful finished state.
          if ($opigno_module->badge_criteria->value == 'success' && $score >= $current_step['required score']) {
            $badge_notification = $opigno_module->badge_name->value;
            $save_badge = TRUE;
          }
          if (!empty($save_badge)) {

            // Save badge.
            try {
              OpignoModuleBadges::opignoModuleSaveBadge($uid, $gid, $current_step['typology'], $current_step['id']);
            } catch (\Exception $e) {
              $this
                ->messenger()
                ->addMessage($e
                ->getMessage(), 'error');
            }
          }
          if ($badge_notification) {
            $message = $this
              ->t('You earned a badge "@badge" in "@name"', [
              '@badge' => $badge_notification,
              '@name' => $group
                ->label(),
            ]);
            $url = Url::fromRoute('entity.group.canonical', [
              'group' => $group
                ->id(),
            ])
              ->toString();
            opigno_set_message($uid, $message, $url);
          }
        }

        // Courses notifications and badges.
        if ($current_step['typology'] == 'Module' && !empty($current_step['parent']) && $current_step['parent']['typology'] == 'Course') {
          $course = Group::load($current_step['parent']['id']);
          if ($course->badge_active->value) {
            $badge_notification = '';
            $save_badge = FALSE;
            $course_steps = opigno_learning_path_get_steps($current_step['parent']['id'], $uid);
            $course_last_step = end($course_steps);
            $course_is_last = $course_last_step['cid'] === $current_step['cid'];
            if ($course_is_last) {

              // Badge notification for finished state.
              if ($course->badge_criteria->value == 'finished') {
                $badge_notification = $course->badge_name->value;
                $save_badge = TRUE;
              }

              // Badge notification for successful finished state.
              if ($course->badge_criteria->value == 'success' && $score >= $current_step['required score']) {
                $badge_notification = $course->badge_name->value;
                $save_badge = TRUE;
              }
              if (!empty($save_badge)) {

                // Save badge.
                try {
                  OpignoModuleBadges::opignoModuleSaveBadge($uid, $gid, 'Course', $current_step['parent']['id']);
                } catch (\Exception $e) {
                  $this
                    ->messenger()
                    ->addMessage($e
                    ->getMessage(), 'error');
                }
              }
              if ($badge_notification) {
                $message = $this
                  ->t('You earned a badge "@badge" in "@name"', [
                  '@badge' => $badge_notification,
                  '@name' => $group
                    ->label(),
                ]);
                $url = Url::fromRoute('entity.group.canonical', [
                  'group' => $group
                    ->id(),
                ])
                  ->toString();
                opigno_set_message($uid, $message, $url);
              }
            }
          }
        }
      }

      // Get module feedback.
      $feedback_options = $opigno_module
        ->getResultsOptions();
      if ($feedback_options) {
        $feedback_option = array_filter($feedback_options, function ($option) use ($score) {
          $min = (int) $option->option_start;
          $max = (int) $option->option_end;
          if (in_array($score, range($min, $max))) {
            return TRUE;
          }
        });
        if ($feedback_option) {

          // Get only first feedback.
          $feedback_option = reset($feedback_option);
          $feedback['feedback'] = [
            '#type' => 'container',
            '#attributes' => [
              'id' => 'module-feedback',
            ],
            [
              '#type' => 'html_tag',
              '#tag' => 'h4',
              '#attributes' => [
                'class' => [
                  'feedback-summary',
                ],
              ],
              '#value' => $feedback_option->option_summary,
            ],
          ];

          // Put feedback in the beginning of array.
          array_unshift($content, $feedback);
        }
      }

      // Check if user has not results for module but already finished that skills tree.
      if ($moduleHandler
        ->moduleExists('opigno_skills_system') && $opigno_module
        ->getSkillsActive() && $user_module_status
        ->isFinished()) {
        $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');

        // Check if user already finished that skills tree.
        $successfully_finished = TRUE;
        foreach ($skills_tree as $skill) {
          if (!isset($user_skills[$skill->tid]) || $user_skills[$skill->tid]->stage != 0) {
            $successfully_finished = FALSE;
          }
        }
        $target_skill_entity = $term_storage
          ->load($target_skill);
        if ($target_skill_entity) {
          $target_skill_name = $target_skill_entity
            ->getName();
        }
        else {
          $target_skill_name = $this
            ->t('N/A');
        }
        if (isset($_SESSION['successfully_finished'])) {
          if ($successfully_finished) {
            if ($_SESSION['successfully_finished'] == TRUE) {
              $message = $this
                ->t('Congratulations, you master all the skills required by "@target_skill" skill\'s tree.', [
                '@target_skill' => $target_skill_name,
              ]);
            }
            elseif ($user_module_status
              ->getOwnerId() == $uid) {
              $message = $this
                ->t('You already master all the skills required by "@target_skill" skill\'s tree.', [
                '@target_skill' => $target_skill_name,
              ]);
            }
          }
          else {
            $message = $this
              ->t('There are no activities for you right now from the "@target_skill" skill\'s tree. Try again later.', [
              '@target_skill' => $target_skill_name,
            ]);
          }
          $message = [
            '#type' => 'container',
            '#markup' => $message,
            '#attributes' => [
              'class' => [
                'form-module-results-message',
              ],
            ],
          ];
          unset($_SESSION['successfully_finished']);
          array_unshift($content, $message);
          $content['#attached']['library'][] = 'opigno_skills_system/opigno_skills_entity';
        }
      }

      // Check if all activities has 0 score.
      // If has - immediately redirect to next step.
      $has_min_score = FALSE;
      foreach ($module_activities as $activity) {
        if (isset($activity->max_score) && $activity->max_score > 0) {
          $has_min_score = TRUE;
          break;
        }
      }

      // Redirect if module has all activities with 0 min score
      // and HideResults option enabled.
      if (!$has_min_score && $opigno_module
        ->getHideResults()) {
        if (!$is_last && !in_array($current_step['typology'], [
          'Meeting',
          'ITL',
        ])) {

          // Redirect to next step.
          return $this
            ->redirect('opigno_learning_path.steps.next', [
            'group' => $gid,
            'parent_content' => $current_step['cid'],
          ]);
        }
        else {

          // Redirect to homepage.
          return $this
            ->redirect('entity.group.canonical', [
            'group' => $gid,
          ]);
        }
      }

      // Get link.
      $content[] = $this
        ->getLinkOptions(FALSE, $gid, $is_last, $current_step);
    }
    elseif ($freeNavigation) {

      // Get link.
      $content[] = $this
        ->getLinkOptions(TRUE, $gid);
    }
  }
  return $content;
}