# PHP, MySQL quiz application

I'm working on a quiz application for training purposes and I think I'm done with most of it.

However, I'm not comfortable with what I've done: it seems to be too complicated and unprofessional, and I would like to make it more organized and simple to understand.

## first, the database contains a three simple tables:

quiz table:

id | name

questions table:

id | question | quiz_id (FK from quiz table) |

id | name | questions_id (FK from questions table) | state (right or wrong)

## 1. the first task is a page to show all available quizzes:

the data part

public function getQuizes() {
$stmt =$this->dbconn->prepare("SELECT id, name FROM {$this->table}");$stmt->execute();
return $stmt->fetchAll(); }  the controller part // get all quizes$quizes = $this->quizModel->getQuizes(); // pass the data to the view$this->callView('quiz/index',$quizes);  the view part to display data <?php include VIEWS . 'templates/header.php'; ?> <h3>Available Quizes:</h3> <ul class="links-list"> <?php foreach ($records as $record): ?> <li> <a href=" <?= BASEPATH . 'quiz/getquiz/' .$record['id']?>">
<?= $record['name']; ?> </a> </li> <?php endforeach; ?> </ul> <?php include VIEWS . 'templates/footer.php'; ?>  ## 2. the second task is a page to show quiz and it's questions and possible answers the data part public function getQuizById($id) {
$results = [];$stmt = $this->dbconn->prepare( "SELECT DISTINCT quiz.name quizName, questions.question question, answers.name answer, answers.id answerId FROM quiz inner Join questions ON quiz.id = questions.quiz_id inner join answers on questions.id = answers.question_id where quiz.id = :id" );$stmt->bindParam(':id', $id);$stmt->execute();

// group the information
while( $row =$stmt->fetch(PDO::FETCH_ASSOC) ){
$results[$row['quizName']][$row['question']][] = [$row['answerId'], $row['answer']]; } return$results;
}


controller part

// get single quiz
public function getquiz($id) { // get the quiz$quizes = $this->quizModel->getQuizById($id);
// pass the data to the view
$this->callView('quiz/single',$quizes);

}


single.php view to display the data

<?php include VIEWS . 'templates/header.php'; ?>

<?php
foreach ($records as$quiz => $questions): ?> <h3> <?=$quiz ?> quiz:</h3>

<form action="<?= BASEPATH . 'quiz/postanswers' ?>" method="post">

<?php
foreach ($questions as$question => $answers): ?> <li class="highlight-panel"> <?=$question ?>
</li>

<?php
foreach ($answers as$answer):
?>

<li>
<input type="radio" name="<?= $question ?>" value="<?=$answer[0] ?>"/>
<?= $answer[1] ?> </li> <?php endforeach; ?> <?php endforeach; ?> </ul> <br> <input type="submit" value="submit answers" /> </form> <?php endforeach; ?> <?php include VIEWS . 'templates/footer.php'; ?>  ## 3. the third task is a report page to show the final results to the user after posting the answers the model part  public function getAnswerInfo($id) {
$stmt =$this->dbconn->prepare(
FROM quiz
inner Join questions
ON quiz.id = questions.quiz_id
);
$stmt->bindParam(':id',$id);
$stmt->execute(); return$stmt->fetch(PDO::FETCH_ASSOC) ;
}

public function getrightanswer($qid) {$stmt = $this->dbconn->prepare( "SELECT name from answers where state = 1 and question_id = :qid" );$stmt->bindParam(':qid', $qid);$stmt->execute();

return $stmt->fetch(PDO::FETCH_ASSOC); }  the controller part public function postanswers() {$results = [];
$groupedResults = [];$counter = 0;

if( isset($_POST) ){ foreach ($_POST as $answerid) {$results[] = $this->quizModel->getAnswerInfo($answerid);
}

foreach ($results as$key => $value){ if($value['state'] == 1){

$counter++;$useranswer = 1;

} else {
$useranswer = 0; }$groupedResults[$value['question']][$value['answer']][] = ['rightanswer' => $this->quizModel->getrightanswer($value['question_id']), 'useranswerscore' => $useranswer]; }$quizname = $results[0]['quizname'];$data = [$groupedResults,$quizname, $counter, count($results)];
$this->callView('quiz/report',$data);
}
}


the view part to display the final report

<?php include VIEWS . 'templates/header.php'; ?>

<h3> Your answers for <?= $records[1] ?> quiz: </h3> <table> <thead> <tr> <td>Question</td> <td>Your answer</td> <td>Right answer</td> <td>Points</td> </tr> </thead> <tbody> <?php // loop through the questions foreach ($records[0] as $question =>$answer):
?>
<tr>
<td><?= $question ?></td> <?php // loop through the answers foreach ($answer as $useranswer =>$answersinfo):
?>

<td><?= $useranswer ?></td> <?php // the answers info foreach ($answersinfo as $value): ?> <td><?=$value['rightanswer']['name'] ?></td>
<td><?= $value['useranswerscore'] ?></td> <?php endforeach; ?> <?php endforeach; ?> </tr> <?php endforeach; ?> <tr> <td> Final results : <?=$records[2] . '/' . $records[3]; ?> </td> </tr> </tbody> </table> <?php include VIEWS . 'templates/footer.php'; ?>  That's what I've done with the app so far and as I said I would like to find a better way to organize everything. I would like to hear your suggestions on how to improve it. ## 1 Answer ## Structure I'm not comfortable with what I've done: it seems to be complicated and unprofessional Honestly, you shouldn't be. Structurally, this seems far better than the average PHP code. You use an MVC structure as is typical in web development, and you do it correctly. Neither the view nor the controller are doing things that they shouldn't be doing. Model Your models are currently really data access objects. You might consider adding actual models with fields and getters. That way, your controller and view would be decoupled from the database and you would have self-documented objects that you pass around, which would also avoid accessing some magic array where you are not sure what it actually contains (eg $answer[0]).

View

Your views are mostly well structured.

But you shouldn't include header and footer in the index, single, etc views, as it makes them not reusable. You may for example need to display a single question in multiple different contexts.

## Misc

• Your function names are not consistently using camelCase.
• You sometimes hardcode the quiz tablename, and sometimes use a variable, which is confusing and can lead to bugs in case you actually do decide to change the table name.
• Your variable names are sometimes not consistent and thus confusing. For example, what's a record?
• upper-case all your SQL keywords, not just some of them.
• some of your comments are not adding any information, eg get the quiz or pass the data to the view.
• You should HTML encode your output to avoid XSS (not everyone who is allowed to add questions or answers should necessarily be allowed to execute JavaSCript).
• [you didn't post the code, but your database connect code is not ideal. For one, you shouldn't just die in a class as the calling code can't recover from that. Secondly, your models currently extend your database, but models aren't a kind of database. The database should be injected into the class. And finally, you open a new connection for each model]