You are here

opigno_tincan_learning_path.module in Opigno TinCan API 3.x

File

modules/opigno_tincan_learning_path/opigno_tincan_learning_path.module
View source
<?php

/**
 * @file
 * Contains opigno_tincan_learning_path.module.
 */
use Drupal\Core\Url;
use Drupal\group\Entity\Group;
use Drupal\opigno_certificate\Entity\OpignoCertificate;
use Drupal\opigno_group_manager\OpignoGroupContext;
use Drupal\opigno_tincan_api\OpignoTinCanApiStatements;
use Drupal\opigno_tincan_api\OpignoTincanApiTinCanActivityDefinitionTypes;
use Drupal\opigno_tincan_api\OpignoTincanApiTinCanVerbs;
use Drupal\Core\Entity\EntityInterface;
use TinCan\Context;
use TinCan\Statement;

/**
 * Implements hook_ENTITY_TYPE_presave().
 *
 * {@inheritdoc}
 *
 * @throws \Exception
 */
function opigno_tincan_learning_path_user_module_status_presave(EntityInterface $entity) {

  // Check if Tincan PHP library is installed.
  $has_library = opigno_tincan_api_tincanphp_is_installed();
  if (!$has_library) {
    return;
  }
  $route = \Drupal::routeMatch();

  // Must work only after user answer on all questions.
  if ($route
    ->getRouteName() == 'opigno_module.take_module') {

    /* @var $user_module_status UserModuleStatus */
    $user_module_status = $entity;
    $is_finished = $user_module_status
      ->get('finished')
      ->getValue()[0]['value'];
    if (!$is_finished) {

      // Module is not finished yet.
      return;
    }

    // Get training context.
    $gid = OpignoGroupContext::getCurrentGroupId();
    $cid = OpignoGroupContext::getCurrentGroupContentId();
    if (!$gid || !$cid) {
      return;
    }
    $user = \Drupal::currentUser();
    $uid = $user
      ->id();
    $steps = opigno_learning_path_get_steps($gid, $user
      ->id());
    $last_step = end($steps);
    if ($last_step['cid'] != $cid) {

      // It is not training last step, so return.
      return;
    }
    _opigno_tincan_learning_path_create_and_send_training_statements($gid, $cid, $steps, $user);
  }
  return $entity;
}

/**
 * Creates and sends training statement.
 */
function _opigno_tincan_learning_path_create_and_send_training_statements($gid, $cid, $steps, $user) {

  /****
   * - When user finish a training
   * Actor: user
   * Verb: xAPI/passed || xAPI/failed
   * Object: xAPI/course
   * Result: Get final training result
   * Context: Class if there is one
   */

  // Get group entity.
  $group = Group::load($gid);

  // Know if the user has passed or failed this Learning Path.
  $is_passed = opigno_learning_path_is_passed($group, $user
    ->id());

  // Statement creation.
  $statement = OpignoTinCanApiStatements::statementBaseCreation($is_passed ? OpignoTincanApiTinCanVerbs::$passed : OpignoTincanApiTinCanVerbs::$failed, OpignoTincanApiTinCanActivityDefinitionTypes::$course, $group);
  if ($statement === FALSE) {
    return;
  }

  // Context creation.
  $context = new Context();

  // Get classes if exits.
  $classes = $group
    ->getContent('subgroup:opigno_class');
  if (!empty($classes)) {

    // Set parents if exist.
    $parent_ids = [];
    foreach ($classes as $cid => $class) {
      $class_entity = $class
        ->getEntity();
      $parent_ids[] = $class_entity
        ->id();
    }
    OpignoTinCanApiStatements::contextSetGrouping($context, $parent_ids);
  }

  // Set language in context.
  OpignoTinCanApiStatements::contextSetLanguage($context, $group
    ->language()
    ->getId());

  // Get duration, user_score.
  $duration_s = NULL;
  $user_score = 0;
  foreach ($steps as $step) {
    $duration_s += intval($step['time spent']);
    $user_score += intval($step['best score']);
  }

  // Set user_score in persents.
  $user_score = round($user_score / count($steps));

  // Raw score can not be negative.
  $user_score = $user_score > 0 ? $user_score : 0;

  // Set result.
  $response = NULL;
  OpignoTinCanApiStatements::setResult($statement, $user_score, 100, NULL, $is_passed, $response, $duration_s);

  // Set statement context.
  $statement
    ->setContext($context);

  // Send statements for certificate if exits.
  _opigno_tincan_learning_path_send_statemets_certificate($group);

  // Sending statement.
  OpignoTinCanApiStatements::sendStatement($statement);
}

/**
 * Sends statements certificate.
 *
 * @param \Drupal\group\Entity\Group $group
 *   Group.
 *
 * @throws \Exception
 */
function _opigno_tincan_learning_path_send_statemets_certificate(Group $group) {

  /****
   * - When user get a certificate
   * Actor: user
   * Verb: activitystrea.ms/received
   * Object: Opigno/Certificate
   * Result: None
   * Context: Training
   */
  $certificate_id = $group
    ->get('field_certificate')->target_id;
  if (!$certificate_id) {

    // There is no certificate.
    return;
  }
  $certificate = OpignoCertificate::load($certificate_id);
  $statement = new Statement();

  // Set Actor.
  OpignoTinCanApiStatements::setActor($statement);

  // Set verb.
  OpignoTinCanApiStatements::setVerb($statement, OpignoTincanApiTinCanVerbs::$received);

  // Set certificate entity.
  $url = Url::fromRoute('entity.opigno_certificate.canonical', [
    'opigno_certificate' => $certificate
      ->id(),
  ], [
    'absolute' => TRUE,
  ])
    ->toString();
  $statement
    ->setObject([
    'id' => $url,
    'definition' => [
      'name' => [
        'en-US' => 'Certificate for: ' . $group
          ->label(),
      ],
      'type' => OpignoTincanApiTinCanActivityDefinitionTypes::$certificate,
    ],
  ]);

  // Context creation.
  $context = new Context();

  // Get parents.
  $parent_ids = [
    $group
      ->id(),
  ];
  OpignoTinCanApiStatements::contextSetGrouping($context, $parent_ids, OpignoTincanApiTinCanActivityDefinitionTypes::$group);

  // Set statement context.
  $statement
    ->setContext($context);

  // Sending statement.
  OpignoTinCanApiStatements::sendStatement($statement);
}