Answer the question
In order to leave comments, you need to log in
How to make the correct calculation in the test?
There is a test that does not calculate points correctly. Created a quiz with two questions. Each question has 4 possible answers, and each has one correct answer. If you choose the correct answer in one question, and one incorrect answer in the other, then the result is 75 points. If you choose the correct answer in one question, and two incorrect answers in the other, then the result is 50 points. Well, respectively, when choosing the correct answers in one and the other question, the result is 100 points.
The question is, why, if you choose the correct answer in one question and the wrong one in the other, then the result is 75 points?
<?php
namespace frontend\controllers;
use common\models\Question;
use common\models\Settings;
use common\models\Test;
use common\models\TestResult;
use common\models\TestResultQuestion;
use common\models\Theme;
use yii\data\Pagination;
use yii\db\ActiveQuery;
use yii\filters\AccessControl;
use yii\helpers\ArrayHelper;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class TestController extends Controller
{
/**
* @inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['index', 'index-theme', 'test', 'result', 'show-result'],
'allow' => true,
'roles' => ['@'],
],
],
]
];
}
public function beforeAction($action)
{
$this->enableCsrfValidation = false;
return parent::beforeAction($action);
}
public function actionIndexTheme($theme_id)
{
$theme = Theme::findOne(['id' => $theme_id]);
$query = Test::find()
->innerJoinWith('testQuestions')
->where(['theme_id' => $theme_id])
->groupBy('test.id');
$countQuery = clone $query;
$pages = new Pagination(['totalCount' => $countQuery->count()]);
$pages->pageSize = 5;
$models = $query->offset($pages->offset)
->limit($pages->limit)
->all();
return $this->render('index-theme', [
'models' => $models,
'pages' => $pages,
'theme' => $theme,
]);
}
public function actionIndex()
{
$query = Test::find()
->innerJoinWith('testQuestions')
->groupBy('test.id');
$countQuery = clone $query;
$pages = new Pagination(['totalCount' => $countQuery->count()]);
$pages->pageSize = 5;
$models = $query->offset($pages->offset)
->limit($pages->limit)
->all();
return $this->render('index', [
'models' => $models,
'pages' => $pages,
]);
}
public function actionTest($id)
{
$time = 300;
/** @var Settings $settings */
$settings = Settings::find()->one();
if ($settings && $settings->time) {
$time = $settings->time;
}
/** @var Test $test */
$test = Test::find()
->where(['test.id' => $id])
->innerJoinWith('testQuestions.question.answers')
->groupBy('test.id')
->one();
if (!$test) throw new NotFoundHttpException();
return $this->render('test', [
'test' => $test,
'time' => $time,
]);
}
public function actionResult($test_id)
{
$points = 100;
$answers = \Yii::$app->request->post();
$answers_id = [];
$questions = Question::find()
->select('question.*')
->innerJoinWith(['testQuestions', 'answers' => function (ActiveQuery $query) {
return $query->where(['answer.is_true' => 1]);
}])
->where(['test_id' => $test_id])
->groupBy('question.id')
->all();
$points_question = $points / count($questions);
$points_result = 0;
foreach ($questions as $key => $question) {
$points_for_question = 0;
if (array_key_exists($question->id, $answers)) {
$answers_id = array_merge($answers_id, $answers[$question->id]);
$true_answers = ArrayHelper::getColumn($question->answers, 'id');
if (count($true_answers) >= count($answers[$question->id])) {
$diff = array_diff($true_answers, $answers[$question->id]);
if (count($diff) > 0) {
$points_for_question = $points_question / 2;
} else {
$points_for_question = $points_question;
}
} else {
$diff = array_diff($answers[$question->id], $true_answers);
if (count($diff) < count($answers[$question->id])) {
$points_for_question = $points_question / 2;
}
}
}
$points_result += $points_for_question;
}
$test_result = new TestResult();
$test_result->result = round($points_result);
$test_result->test_id = $test_id;
$test_result->user_id = \Yii::$app->getUser()->getId();
$test_result->save();
foreach ($answers_id as $answer) {
$testrq = new TestResultQuestion();
$testrq->test_result_id = $test_result->id;
$testrq->answer_id = $answer;
$testrq->save();
}
return $this->redirect(['show-result','test_result_id' =>$test_result->id ]);
}
public function actionShowResult($test_result_id)
{
/** @var TestResult $test_result */
$test_result = TestResult::find()
->joinWith('testResultQuestions')
->where(['test_result.id' => $test_result_id])->one();
$answers_pick = ($test_result->testResultQuestions)
? ArrayHelper::getColumn($test_result->testResultQuestions,'answer_id')
: [];
$test = Test::find()
->where(['test.id' => $test_result->test_id])
->innerJoinWith('testQuestions.question.answers')
->groupBy('test.id')
->one();
return $this->render('result', [
'answers_pick' => $answers_pick,
'test' => $test,
'test_result' => $test_result,
]);
}
}
Answer the question
In order to leave comments, you need to log in
Such code, where there are a lot of if, else, is very difficult to test and it is difficult to read. Take out all the logic code in separate classes, with methods and test them. For example, the class might be the QuestionPoint class . There are methods
and the like in it ..
You will get such a code, if it is completely primitive
$question = 1;
foreach ($questions as $key => $question) {
$questionPoint = new QuestionPoint($question);
$questionPoint->isAnswerExists($question, $answer)
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question