You are here

class TincanContentAnswerAssistant in Opigno module 3.x

Same name and namespace in other branches
  1. 8 ActivityTypes/opigno_tincan_activity/src/TincanContentAnswerAssistant.php \Drupal\opigno_tincan_activity\TincanContentAnswerAssistant

Class TincanContentAnswerAssistant.

Hierarchy

Expanded class hierarchy of TincanContentAnswerAssistant

1 string reference to 'TincanContentAnswerAssistant'
opigno_tincan_activity.services.yml in ActivityTypes/opigno_tincan_activity/opigno_tincan_activity.services.yml
ActivityTypes/opigno_tincan_activity/opigno_tincan_activity.services.yml
1 service uses TincanContentAnswerAssistant
opigno_tincan_activity.answer_assistant in ActivityTypes/opigno_tincan_activity/opigno_tincan_activity.services.yml
Drupal\opigno_tincan_activity\TincanContentAnswerAssistant

File

ActivityTypes/opigno_tincan_activity/src/TincanContentAnswerAssistant.php, line 20

Namespace

Drupal\opigno_tincan_activity
View source
class TincanContentAnswerAssistant {
  protected $connection;

  /**
   * Constructs a new TincanContentAnswerAssistant object.
   *
   * @param \Drupal\Core\Database\Connection $connection
   *   Database connection.
   */
  public function __construct(Connection $connection) {
    $this->connection = $connection;
  }

  /**
   * This method get the registration UUID.
   *
   * It gets it from the database or from the PHPSESSION variable.
   * If it is from the PHPSESSION, the method will save this registration to the
   *   database.
   *
   * @param \Drupal\opigno_module\Entity\OpignoActivityInterface $activity
   *   Activity.
   * @param \Drupal\Core\Session\AccountProxyInterface $user
   *   Account proxy interface.
   *
   * @return bool|string
   *   The registration UUID if success, FALSE if not found.
   */
  public function getRegistration(OpignoActivityInterface $activity, AccountProxyInterface $user) {

    // If we have the RID, try to get the registration from the DB.
    if (!empty($activity) && !empty($user)) {
      $connection = $this->connection;
      $result = $connection
        ->select('opigno_tincan_activity_answers', 't')
        ->fields('t', [])
        ->condition('opigno_activity_id', $activity
        ->id())
        ->condition('uid', $user
        ->id())
        ->execute()
        ->fetchObject();

      // If we have a result, we can return the registration.
      if ($result) {
        return $result->registration;
      }
      else {

        // Create new registration uuid.
        $registration = Util::getUUID();
        $this
          ->saveRegistration($registration, $activity, $user);
        return $registration;
      }
    }

    // If we don't find the registration, return FALSE.
    return FALSE;
  }

  /**
   * This method will save the given registration UUID to the database.
   *
   * @param string $registration
   *   The UUID to save.
   * @param \Drupal\opigno_module\Entity\OpignoActivityInterface $activity
   *   Activity object.
   * @param \Drupal\Core\Session\AccountProxyInterface $user
   *   User object.
   *
   * @return null|mixed
   *   Exception array.
   */
  public function saveRegistration($registration, OpignoActivityInterface $activity, AccountProxyInterface $user) {
    $connection = $this->connection;
    try {
      $connection
        ->insert('opigno_tincan_activity_answers')
        ->fields([
        'uid' => $user
          ->id(),
        'opigno_activity_id' => $activity
          ->id(),
        'registration' => $registration,
      ])
        ->execute();
    } catch (\Exception $e) {
      return $e;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function score($activity_id, $registration, $max_score) {
    return $this
      ->getScoreFromLrs($activity_id, $registration, $max_score);
  }

  /***************
   *
   * PROTECTED METHODS
   *
   **************************/

  /**
   * This method will return the score from the LRS system for this response.
   *
   * @param string $activity_id
   *   Tincan activity id.
   * @param string $registration
   *   UUID registration.
   * @param int $max_score
   *   Max score for activity.
   *
   * @return int
   *   The score not weighted.
   */
  protected function getScoreFromLrs($activity_id, $registration, $max_score) {
    $messenger = \Drupal::messenger();

    // First, try to get the connection.
    $lrs = $this
      ->getLrsConnection();
    if (!$lrs) {
      $messenger
        ->addWarning(t('Connection to the LRS failed'));
      return 0;
    }

    // If we have the connection, get the statement.
    if (empty($registration)) {
      $messenger
        ->addWarning(t('There was an error while answering the question, please go back and try again.'));
      return 0;
    }
    if (empty($activity_id)) {
      $messenger
        ->addWarning(t('Error while obtaining the activity ID. Maybe a malformed TinCan package.'));
      return 0;
    }
    $score_statement = $this
      ->getStatementFinalScore($lrs, $registration, $activity_id);
    if (!$score_statement) {
      $messenger
        ->addWarning(t('Can not get score from LRS. Check your LRS settings.'));
      return 0;
    }

    // If we have the statement, extract the score and returns it.
    return $this
      ->getScoreFromStatement($score_statement, $max_score);
  }

  /**
   * This method returns the connection to the LRS.
   *
   * If there is a problem, this method will show an error message and
   *   return FALSE.
   *
   * @return bool|\TinCan\RemoteLRS
   *   FALSE in case of error. The LRS connection if connection was success.
   */
  protected function getLrsConnection() {

    // Check first if the TinCanPHP library is installed
    // If not, return FALSE.
    $messenger = \Drupal::messenger();
    if (!class_exists('TinCan\\Version')) {
      $messenger
        ->addError('Please install the @tincanphp_library using Composer, with the command: <em>composer require rusticisoftware/tincan:@stable</em>.', [
        '@tincanphp_library' => Link::fromTextAndUrl('TinCanPHP library', Url::fromUri('https://github.com/RusticiSoftware/TinCanPHP')),
      ]);
      return FALSE;
    }
    $config = \Drupal::config('opigno_tincan_api.settings');
    $endpoint = $config
      ->get('opigno_tincan_api_endpoint');
    $username = $config
      ->get('opigno_tincan_api_username');
    $password = $config
      ->get('opigno_tincan_api_password');
    if (empty($endpoint) || empty($username) || empty($password)) {
      $messenger
        ->addWarning('Please configure first the Opigno TinCan API module. Go to @url', [
        '@url' => Link::createFromRoute(t('the setting page'), 'opigno_tincan_api.settings_form')
          ->toString(),
      ]);
      return FALSE;
    }
    return new RemoteLRS($endpoint, '1.0.1', $username, $password);
  }

  /**
   * Get the statement containing the final score.
   *
   * @param \TinCan\RemoteLRS $lrs
   *   The LRS connection.
   * @param string $registration_uuid
   *   The registration UUID.
   * @param string $activity_id
   *   The activity ID of the statement.
   *
   * @return bool|\TinCan\Statement
   *   The statement. If not found, returns FALSE.
   */
  protected function getStatementFinalScore(RemoteLRS $lrs, $registration_uuid, $activity_id) {
    $activity = new Activity();
    $activity
      ->setId($activity_id);
    $verb_passed = new Verb();
    $verb_passed
      ->setId(OpignoTincanApiTinCanVerbs::$passed['id']);

    // Test with verb "passed".
    $result = $lrs
      ->queryStatements([
      'activity' => $activity,
      'registration' => $registration_uuid,
      'verb' => $verb_passed,
      'limit' => 1,
    ]);
    $statements = [];
    if (!empty($result->content) && is_object($result->content)) {
      $statements = $result->content
        ->getStatements();

      // If nothing with "passed", test with "failed" verb.
      if (count($statements) === 0) {
        $verb_failed = new Verb();
        $verb_failed
          ->setId(OpignoTincanApiTinCanVerbs::$failed['id']);
        $result = $lrs
          ->queryStatements([
          'activity' => $activity,
          'registration' => $registration_uuid,
          'verb' => $verb_failed,
          'limit' => 1,
        ]);
        if (!empty($result->content) && is_object($result->content)) {
          $statements = $result->content
            ->getStatements();
        }
      }
    }
    if (count($statements) > 0) {
      return $statements[0];
    }
    else {
      return FALSE;
    }
  }

  /**
   * This method calculate the score using a statement.
   *
   * @param \TinCan\Statement $statement
   *   The statement that contains the score.
   * @param int $max_score
   *   Max score.
   *
   * @return float|int
   *   The final score ready to be returned for the Quiz module. Can returns 0
   *   if the score is not found in the statement.
   */
  protected function getScoreFromStatement(Statement $statement, $max_score) {
    $result = $statement
      ->getResult();
    if (!isset($result)) {
      return 0;
    }
    $score = $result
      ->getScore();
    if (isset($score)) {
      $scaled = $score
        ->getScaled();
      if (isset($scaled) && $scaled >= 0) {
        return $scaled * $max_score;
      }
      $raw = $score
        ->getRaw();
      $max = $score
        ->getMax();
      $min = $score
        ->getMin();
      if (!isset($min)) {
        $min = 0;
      }
      if (isset($raw) && isset($max)) {
        return (double) ($raw - $min) / ($max - $min) * $max_score;
      }
    }
    $success = $result
      ->getSuccess();
    if (isset($success)) {
      return $max_score;
    }
    return 0;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
TincanContentAnswerAssistant::$connection protected property
TincanContentAnswerAssistant::getLrsConnection protected function This method returns the connection to the LRS.
TincanContentAnswerAssistant::getRegistration public function This method get the registration UUID.
TincanContentAnswerAssistant::getScoreFromLrs protected function This method will return the score from the LRS system for this response.
TincanContentAnswerAssistant::getScoreFromStatement protected function This method calculate the score using a statement.
TincanContentAnswerAssistant::getStatementFinalScore protected function Get the statement containing the final score.
TincanContentAnswerAssistant::saveRegistration public function This method will save the given registration UUID to the database.
TincanContentAnswerAssistant::score public function
TincanContentAnswerAssistant::__construct public function Constructs a new TincanContentAnswerAssistant object.