quiz_maker-1.0.6/src/Service/QuizResultManager.php

src/Service/QuizResultManager.php
<?php

namespace Drupal\quiz_maker\Service;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\quiz_maker\Entity\QuestionType;
use Drupal\quiz_maker\Entity\QuizResultType;
use Drupal\quiz_maker\Event\QuizTakeEvent;
use Drupal\quiz_maker\Event\QuizTakeEvents;
use Drupal\quiz_maker\Event\ResponseEvent;
use Drupal\quiz_maker\Event\ResponseEvents;
use Drupal\quiz_maker\QuestionInterface;
use Drupal\quiz_maker\QuestionResponseInterface;
use Drupal\quiz_maker\QuizInterface;
use Drupal\quiz_maker\QuizResultInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Quiz manager service.
 */
class QuizResultManager {

  use StringTranslationTrait;

  /**
   * The logger channel.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected LoggerChannelInterface $logger;

  /**
   * Constructs a QuizManager object.
   */
  public function __construct(
    protected EntityTypeManagerInterface $entityTypeManager,
    protected RequestStack $requestStack,
    protected TimeInterface $time,
    protected LoggerChannelFactoryInterface $loggerChannelFactory,
    protected EntityTypeBundleInfoInterface $entityTypeBundleInfo,
    protected EventDispatcherInterface $eventDispatcher,
  ) {
    $this->logger = $loggerChannelFactory->get('quiz_maker');
  }

  /**
   * Create quiz result.
   *
   * @param \Drupal\Core\Session\AccountInterface $user
   *   The user (quiz participant).
   * @param \Drupal\quiz_maker\QuizInterface $quiz
   *   The quiz.
   * @param string $langcode
   *   The langcode.
   * @param string|null $session_id
   *   The user session id.
   *
   * @return \Drupal\quiz_maker\QuizResultInterface|null
   *   The quiz result or null.
   */
  public function createQuizResult(AccountInterface $user, QuizInterface $quiz, string $langcode, string|null $session_id = NULL): ?QuizResultInterface {
    $conditions = [
      'state' => QuizResultType::DRAFT,
    ];

    if ($session_id) {
      $conditions['session_id'] = $session_id;
    }

    $draft_results = $quiz->getResults($user, $conditions);
    if ($draft_results) {
      // Return the newest draft result.
      /** @var \Drupal\quiz_maker\QuizResultInterface $result */
      $result = end($draft_results);
      if ($result->hasTranslation($langcode)) {
        $quiz_event = new QuizTakeEvent($quiz, $result);
        $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_START);
        return $result->getTranslation($langcode);
      }
      else {
        $quiz_event = new QuizTakeEvent($quiz, $result);
        $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_START);
        return $result;
      }
    }
    $quiz_result_type = $quiz->getResultType();
    try {
      $quiz_result = $this->entityTypeManager->getStorage('quiz_result')->create([
        'bundle' => $quiz_result_type,
        'label' => $this->t('Result of "@quiz_label"', ['@quiz_label' => $quiz->label()]),
        'state' => QuizResultType::DRAFT,
        'quiz' => $quiz,
        'uid' => $user->id(),
        'attempt' => $quiz->getCompletedAttempts($user) + 1,
        'langcode' => $langcode,
        'session_id' => $session_id,
      ]);
      $quiz_result->save();
    }
    catch (InvalidPluginDefinitionException | PluginNotFoundException | EntityStorageException $e) {
      $this->logger->error($e->getMessage());
      return NULL;
    }

    if ($quiz_result instanceof QuizResultInterface) {
      $quiz_event = new QuizTakeEvent($quiz, $quiz_result);
      $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_START);
      return $quiz_result;
    }

    return NULL;
  }

  /**
   * Update quiz result.
   *
   * @param \Drupal\quiz_maker\QuizResultInterface $result
   *   The quiz result.
   * @param \Drupal\quiz_maker\QuestionInterface $question
   *   The question plugin instance.
   * @param array $response_data
   *   The response data.
   * @param string $langcode
   *   The langcode.
   */
  public function updateQuizResult(
    QuizResultInterface $result,
    QuestionInterface $question,
    array $response_data,
    string $langcode,
  ): void {
    // Get question response from result, if it doesn't exist - create new
    // response, otherwise - update current response.
    $response = $result->getResponse($question);
    if (!$response) {
      $response = $this->createResponse($result, $question, $response_data, $langcode);
      if ($response) {
        try {
          $result->addResponse($response)->save();
        }
        catch (EntityStorageException $e) {
          $this->logger->error($e->getMessage());
        }
      }
    }
    else {
      try {
        /** @var \Drupal\quiz_maker\Entity\QuestionResponse $response */
        $response->setResponseData($response_data)
          ->setCorrect($question->isResponseCorrect($response_data))
          ->setScore($question, $question->isResponseCorrect($response_data), $question->getMaxScore(), $response_data);
        // Save response.
        $response->save();
        // Dispatch 'Response create' event.
        $response_event = new ResponseEvent($result, $response);
        $this->eventDispatcher->dispatch($response_event, ResponseEvents::RESPONSE_UPDATE);
      }
      catch (EntityStorageException $e) {
        $this->logger->error($e->getMessage());
      }
    }

    // Dispatch 'Quiz update' event.
    $quiz_event = new QuizTakeEvent($result->getQuiz(), $result);
    $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_UPDATE);
  }

  /**
   * Set quiz as finished.
   *
   * @param \Drupal\quiz_maker\QuizResultInterface $result
   *   The quiz result.
   * @param string $langcode
   *   The langcode.
   */
  public function completeQuizResult(QuizResultInterface $result, string $langcode): void {
    $questions = $result->getQuiz()->getQuestions();
    // Create empty responses if question was skipped by user.
    foreach ($questions as $question) {
      $response = $result->getResponse($question);
      if (!$response) {
        $response = $this->createResponse($result, $question, [], $langcode);
        if ($response) {
          try {
            $result->addResponse($response)->save();
            $quiz_event = new QuizTakeEvent($result->getQuiz(), $result);
            $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_FINISH);
          }
          catch (EntityStorageException $e) {
            $this->logger->error($e->getMessage());
          }
        }
      }
    }

    $score = $this->calculateScore($result);
    $state = $result->getQuiz()->requireManualAssessment() ? QuizResultType::ON_REVIEW : QuizResultType::COMPLETED;
    try {
      $result->setScore($score)
        ->setPassed($score >= $result->getQuiz()->getPassRate())
        ->setState($state)
        ->setFinishedTime($this->time->getCurrentTime())
        ->save();
      $quiz_event = new QuizTakeEvent($result->getQuiz(), $result);
      $this->eventDispatcher->dispatch($quiz_event, QuizTakeEvents::QUIZ_FINISH);
    }
    catch (EntityStorageException $e) {
      $this->logger->error($e->getMessage());
    }
  }

  /**
   * Calculate quiz result score.
   *
   * @param \Drupal\quiz_maker\QuizResultInterface $quiz_result
   *   The quiz result.
   */
  public function calculateScore(QuizResultInterface $quiz_result): int {
    $responses = $quiz_result->getResponses();
    $score = 0;
    foreach ($responses as $response) {
      $score = $score + $response->getScore();
    }
    return (int) round(($score / $quiz_result->getQuiz()->getMaxScore()) * 100);
  }

  /**
   * Create question response.
   *
   * @param \Drupal\quiz_maker\QuizResultInterface $result
   *   The quiz result.
   * @param \Drupal\quiz_maker\QuestionInterface $question
   *   The question instance.
   * @param array $response_data
   *   The response data.
   * @param string $langcode
   *   The langcode.
   *
   * @return ?\Drupal\quiz_maker\QuestionResponseInterface
   *   The response.
   */
  protected function createResponse(QuizResultInterface $result, QuestionInterface $question, array $response_data, string $langcode): ?QuestionResponseInterface {
    try {
      /** @var \Drupal\quiz_maker\Entity\Question $question */
      $question_type = QuestionType::load($question->bundle());
      /** @var \Drupal\quiz_maker\Entity\QuestionResponse $response */
      $response = $this->entityTypeManager->getStorage('question_response')->create([
        'bundle' => $question_type->getResponseType(),
        'label' => $this->t('Response of "@question_label"', ['@question_label' => $question->label()]),
        'langcode' => $langcode,
      ]);

      $response->setQuiz($result->getQuiz())
        ->setQuestion($question)
        ->setResponseData($response_data)
        ->setCorrect($question->isResponseCorrect($response_data))
        ->setScore($question, $question->isResponseCorrect($response_data), $question->getMaxScore(), $response_data);

      $response->save();

      // Dispatch 'Response create' event.
      $question_event = new ResponseEvent($result, $response);
      $this->eventDispatcher->dispatch($question_event, ResponseEvents::RESPONSE_CREATE);
      return $response;
    }
    catch (InvalidPluginDefinitionException | PluginNotFoundException | EntityStorageException $e) {
      $this->logger->error($e->getMessage());
    }

    return NULL;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc