How to produce the correct counting in the test?

There is a test that a little wrong counts the points. Created test, there are two questions. Each question with 4 answers, each one correct answer. If you choose one question correct answer and the other one is not correct, the result is 75 points.. If you choose one question correct answer and the other two incorrect answer, the result is 50 points. Well, accordingly to a choice of correct answers in each question score 100 points.
The question is that why, if you choose one question correct answer and the other one is not correct, 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,
]);
}
}
March 23rd 20 at 19:43
1 answer
March 23rd 20 at 19:45
Solution
This code, where a lot of if, else test is very difficult and it's hard readable. Move all the code logic in separate classes, with methods and test them. For example, a class could be a class QuestionPoint . Methods
public function isAnswerExists($answers){}

and so on..

You get a code if quite primitive

$question = 1;
foreach ($questions as $key => $question) {
$questionPoint = new QuestionPoint($question);
$questionPoint->isAnswerExists($question, $answer)
}


So do the code in OOP and DDD and then you will be happy. In your case it will be hemorrhagic. Especially if the code in the controller. Test it will be extremely difficult and time consuming. These tests run nobody wants. You will have tests to raise the application and the database. Although in your case, it is generally unnecessary!

In General take the code from the controller and get rid of the noodles. Create objects.
Time to sort through anymore.
Here in this part of the problem Here.. I cannot understand.. What you need to change to calculated correctly
$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;
 }
- Elena_Shields commented on March 23rd 20 at 19:48
@Elena_Shields, duck that's the problem that nobody needs to understand your code. To do this, and say that he was urifactory. And if you are using debug, then look at the breakpoints of some data where obtained. If you are not using debug do var_dump(array_key_exists($question->id, $answers)); die(); And see what values work. For example, if you have array_key_exists($question->id, $answers) must cause true and you false, here it is the error. And so on for all the rows and values. See what pass and what you can get.

You Skoda problems) It is difficult to read even you. Where you use the helper to retrieve the value, but somewhere just $answers[$question->id], although you can use ArrayHelper::getValue()... Write code for machines and for humans! Code should read like English sentences... to Create me a new meter points. Check is there .... Get me an ID ...

$questionPoint = QuestionPoint::create($param);
if ($questionPoint->isExists($id)) {
$questionPoint->deleteById($id);
$questionPoint->....;
}

$questionPoint->getAmount(); //get the number of records in the database.


If the procedure described above, you will find the error. And so it is difficult to say what you need and what you get. - lottie_Parisian commented on March 23rd 20 at 19:51

Find more questions by tags Yii