1
0

add more question types

This commit is contained in:
Rokas Puzonas 2023-11-24 23:28:36 +02:00
parent 039163e53a
commit f53f5914fc
19 changed files with 640 additions and 30 deletions

View File

@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers;
use App\Models\MultipleChoiceAnswers;
use Illuminate\Http\Request;
class MultipleChoiceAnswersController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(MultipleChoiceAnswers $multipleChoiceAnswers)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(MultipleChoiceAnswers $multipleChoiceAnswers)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, MultipleChoiceAnswers $multipleChoiceAnswers)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(MultipleChoiceAnswers $multipleChoiceAnswers)
{
//
}
}

View File

@ -2,7 +2,10 @@
namespace App\Http\Controllers;
use App\Models\MultipleChoiceAnswers;
use App\Models\Question;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use Illuminate\Http\Request;
@ -31,12 +34,44 @@ class QuestionController extends Controller
{
$validated = $request->validate([
"question" => "required|string",
"answer" => "required|string",
"points" => "required|integer|min:1",
"test_id" => "required|integer",
"answer_type" => "required|string",
]);
Question::create($validated);
if ($request->answer_type == "single_answer") {
$validated_answer = $request->validate([
"answer" => "required|string",
]);
} else if ($request->answer_type == "single_choice") {
$validated_answer = $request->validate([
"correct_answer" => "required|string",
"incorrect_answer1" => "required|string",
"incorrect_answer2" => "nullable|string",
"incorrect_answer3" => "nullable|string",
]);
} else if ($request->answer_type == "multiple_choice") {
$validated_answer = $request->validate([
"answer1" => "required|string",
"answer2" => "required|string",
"answer3" => "nullable|string",
"answer4" => "nullable|string",
"is_answer1_correct" => "nullable|boolean",
"is_answer2_correct" => "nullable|boolean",
"is_answer3_correct" => "nullable|boolean",
"is_answer4_correct" => "nullable|boolean",
]);
}
$question = Question::create($validated);
$validated_answer["question_id"] = $question->id;
if ($request->answer_type == "single_answer") {
SingleQuestionAnswers::create($validated_answer);
} else if ($request->answer_type == "single_choice") {
SingleChoiceAnswer::create($validated_answer);
} else if ($request->answer_type == "multiple_choice") {
MultipleChoiceAnswers::create($validated_answer);
}
return redirect(route("tests.edit", [
"test" => Test::where("id", $validated["test_id"])->first()
@ -56,8 +91,30 @@ class QuestionController extends Controller
*/
public function edit(Question $question)
{
$question_answer = $question;
if ($question->answer_type == "single_answer") {
$answer = SingleQuestionAnswers::where("question_id", $question->id)->first();
$question_answer->answer = $answer->answer;
} else if ($question->answer_type == "single_choice") {
$answer = SingleChoiceAnswer::where("question_id", $question->id)->first();
$question_answer->correct_answer = $answer->correct_answer;
$question_answer->incorrect_answer1 = $answer->incorrect_answer1;
$question_answer->incorrect_answer2 = $answer->incorrect_answer2;
$question_answer->incorrect_answer3 = $answer->incorrect_answer3;
} else if ($question->answer_type == "multiple_choice") {
$answer = MultipleChoiceAnswers::where("question_id", $question->id)->first();
$question_answer->answer1 = $answer->answer1;
$question_answer->is_answer1_correct = $answer->is_answer1_correct;
$question_answer->answer2 = $answer->answer2;
$question_answer->is_answer2_correct = $answer->is_answer2_correct;
$question_answer->answer3 = $answer->answer3;
$question_answer->is_answer3_correct = $answer->is_answer3_correct;
$question_answer->answer4 = $answer->answer4;
$question_answer->is_answer4_correct = $answer->is_answer4_correct;
}
return view("questions.edit", [
"question" => $question,
"question" => $question_answer,
]);
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreSingleChoiceAnswerRequest;
use App\Http\Requests\UpdateSingleChoiceAnswerRequest;
use App\Models\SingleChoiceAnswer;
class SingleChoiceAnswerController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(StoreSingleChoiceAnswerRequest $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(SingleChoiceAnswer $singleChoiceAnswer)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(SingleChoiceAnswer $singleChoiceAnswer)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateSingleChoiceAnswerRequest $request, SingleChoiceAnswer $singleChoiceAnswer)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(SingleChoiceAnswer $singleChoiceAnswer)
{
//
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers;
use App\Models\SingleQuestionAnswers;
use Illuminate\Http\Request;
class SingleQuestionAnswersController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(SingleQuestionAnswers $singleQuestionAnswers)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(SingleQuestionAnswers $singleQuestionAnswers)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, SingleQuestionAnswers $singleQuestionAnswers)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(SingleQuestionAnswers $singleQuestionAnswers)
{
//
}
}

View File

@ -2,6 +2,9 @@
namespace App\Http\Controllers;
use App\Models\MultipleChoiceAnswers;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use Illuminate\Http\Request;
@ -12,8 +15,9 @@ class TestController extends Controller
*/
public function index(Request $request)
{
$tests = $request->user()->tests()->get();
return view("tests.index", [
"tests" => $request->user()->tests()->get()
"tests" => $tests
]);
}
@ -52,8 +56,36 @@ class TestController extends Controller
*/
public function edit(Test $test)
{
$questions = $test->questions()->get();
foreach ($questions as $question) {
if ($question->answer_type == "single_answer") {
$answer = SingleQuestionAnswers::where("question_id", $question->id)->first();
$question->answer = $answer->answer;
} else if ($question->answer_type == "single_choice") {
$answer = SingleChoiceAnswer::where("question_id", $question->id)->first();
$question->answer = $answer->correct_answer;
} else if ($question->answer_type == "multiple_choice") {
$answer = MultipleChoiceAnswers::where("question_id", $question->id)->first();
$valid_answer = array();
if ($answer->is_answer1_correct) {
array_push($valid_answer, $answer->answer1);
}
if ($answer->is_answer2_correct) {
array_push($valid_answer, $answer->answer2);
}
if ($answer->is_answer3_correct) {
array_push($valid_answer, $answer->answer3);
}
if ($answer->is_answer4_correct) {
array_push($valid_answer, $answer->answer4);
}
$question->answer = join(", ", $valid_answer);
}
}
return view("tests.edit", [
"test" => $test,
"questions" => $questions,
]);
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class MultipleChoiceAnswers extends Model
{
use HasFactory;
protected $fillable = [
'question_id',
'answer1',
'answer2',
'answer3',
'answer4',
'is_answer1_correct',
'is_answer2_correct',
'is_answer3_correct',
'is_answer4_correct',
];
public function question(): BelongsTo
{
return $this->belongsTo(Question::class);
}
}

View File

@ -13,7 +13,7 @@ class Question extends Model
protected $fillable = [
"test_id",
'question',
'answer',
'answer_type',
'points',
];

View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class SingleChoiceAnswer extends Model
{
use HasFactory;
protected $fillable = [
'question_id',
'correct_answer',
'incorrect_answer1',
'incorrect_answer2',
'incorrect_answer3',
];
public function question(): BelongsTo
{
return $this->belongsTo(Question::class);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class SingleQuestionAnswers extends Model
{
use HasFactory;
protected $fillable = [
"question_id",
'answer',
];
public function question(): BelongsTo
{
return $this->belongsTo(Question::class);
}
}

View File

@ -15,7 +15,7 @@ return new class extends Migration
$table->id();
$table->foreignId("test_id")->references("id")->on("tests")->constrained()->cascadeOnDelete();
$table->string("question");
$table->string("answer");
$table->enum("answer_type", ["single_answer", "single_choice", "multiple_choice"]);
$table->unsignedInteger("points")->default(1);
$table->timestamps();
});

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('single_question_answers', function (Blueprint $table) {
$table->id();
$table->foreignId("question_id")->references("id")->on("questions")->constrained()->cascadeOnDelete();
$table->string("answer");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('single_question_answers');
}
};

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('single_choice_answers', function (Blueprint $table) {
$table->id();
$table->foreignId("question_id")->references("id")->on("questions")->constrained()->cascadeOnDelete();
$table->string("correct_answer");
$table->string("incorrect_answer1");
$table->string("incorrect_answer2")->nullable();
$table->string("incorrect_answer3")->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('single_choice_answers');
}
};

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('multiple_choice_answers', function (Blueprint $table) {
$table->id();
$table->foreignId("question_id")->references("id")->on("questions")->constrained()->cascadeOnDelete();
$table->string("answer1");
$table->string("answer2");
$table->string("answer3")->nullable();
$table->string("answer4")->nullable();
$table->boolean("is_answer1_correct")->default(false);
$table->boolean("is_answer2_correct")->default(false);
$table->boolean("is_answer3_correct")->default(false);
$table->boolean("is_answer4_correct")->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('multiple_choice_answers');
}
};

View File

@ -4,6 +4,11 @@ namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\MultipleChoiceAnswers;
use App\Models\Question;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
@ -21,7 +26,7 @@ class DatabaseSeeder extends Seeder
'password' => Hash::make("admin"),
'role' => "admin"
]);
User::create([
$teacher = User::create([
'name' => "Bob teacher",
'email' => "bob@teacher",
'password' => Hash::make("bob"),
@ -33,5 +38,51 @@ class DatabaseSeeder extends Seeder
'password' => Hash::make("alice"),
'role' => "student"
]);
$test = Test::create([
"name" => "Matematika",
"user_id" => $teacher->id
]);
{
$question = Question::create([
"test_id" => $test->id,
"question" => "1+1=?",
"answer_type" => "single_answer",
]);
SingleQuestionAnswers::create([
"question_id" => $question->id,
"answer" => "2"
]);
}
{
$question = Question::create([
"test_id" => $test->id,
"question" => "Gyvenimo prasme",
"answer_type" => "single_choice",
]);
SingleChoiceAnswer::create([
"question_id" => $question->id,
"correct_answer" => "42",
"incorrect_answer1" => "Kates",
"incorrect_answer3" => "Sunys",
]);
}
{
$question = Question::create([
"test_id" => $test->id,
"question" => "Siandienos orai",
"answer_type" => "multiple_choice",
]);
MultipleChoiceAnswers::create([
"question_id" => $question->id,
"answer1" => "Sninga", "is_answer1_correct" => true,
"answer2" => "Lija", "is_answer2_correct" => true,
"answer4" => "Idk, paziurek per langa", "is_answer4_correct" => false,
]);
}
}
}

View File

@ -0,0 +1,7 @@
@props([
'disabled' => false,
'checked' => false
])
<input
type="checkbox" {{ $checked ? 'checked' : '' }} {{ $disabled ? 'disabled' : '' }} {!! $attributes->merge(['class' => 'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm']) !!}>

View File

@ -0,0 +1,91 @@
@props([
'test_id' => '',
'default_question' => '',
'default_points' => 1,
'default_answer_type' => 'single_answer',
'default_answer' => '',
'default_correct_answer' => '',
'default_incorrect_answer1' => '',
'default_incorrect_answer2' => '',
'default_incorrect_answer3' => '',
'default_answer1' => '',
'default_is_answer1_correct' => '',
'default_answer2' => '',
'default_is_answer2_correct' => '',
'default_answer3' => '',
'default_is_answer3_correct' => '',
'default_answer4' => '',
'default_is_answer4_correct' => ''
])
<input type="hidden" value="{{ $test_id }}" name="test_id">
<x-input-label>{{ __("Question") }}</x-input-label>
<x-text-input name="question" placeholder="{{ __('Question') }}" value="{{ old('question', $default_question) }}" />
<x-input-error :messages="$errors->get('question')" class="mt-2" />
<x-input-label>{{ __("Points") }}</x-input-label>
<x-text-input name="points" placeholder="{{ __('Points') }}" value="{{ old('points', $default_points) }}" />
<x-input-error :messages="$errors->get('points')" class="mt-2" />
<x-input-label>{{ __("Answer type") }}</x-input-label>
<x-select name="answer_type" value="single_answer" id="answer_type">
<option value="single_answer" {{ old("answer_type", $default_answer_type) == "single_answer" ? "selected" : "" }} >{{ __('Single') }}</option>
<option value="single_choice" {{ old("answer_type", $default_answer_type) == "single_choice" ? "selected" : "" }} >{{ __('Single choice') }}</option>
<option value="multiple_choice" {{ old("answer_type", $default_answer_type) == "multiple_choice" ? "selected" : "" }} >{{ __('Multiple choice') }}</option>
</x-select>
<div class="w-full" id="answer_single">
<x-input-label>{{ __("Answer") }}</x-input-label>
<x-text-input class="w-full" name="answer" placeholder="{{ __('Answer') }}" value="{{ old('answer', $default_answer) }}" />
<x-input-error :messages="$errors->get('answer')" class="mt-2" />
</div>
<div class="w-full" id="answer_single_choice">
<x-input-label>{{ __("Correct answer") }}</x-input-label>
<x-text-input class="w-full" name="correct_answer" placeholder="{{ __('Correct answer') }}" value="{{ old('correct_answer', $default_correct_answer) }}" />
<x-input-error :messages="$errors->get('correct_answer')" class="mt-2" />
@for ($idx = 1; $idx <= 3; $idx++)
<x-input-label>{{ __("Incorrect answer ".$idx) }}</x-input-label>
<x-text-input class="w-full" name="incorrect_answer{{$idx}}" placeholder="{{ __('Incorrect answer '.$idx) }}" value="{{ old('incorrect_answer'.$idx, ${'default_incorrect_answer'.$idx}) }}" />
<x-input-error :messages="$errors->get('incorrect_answer{{$idx}}')" class="mt-2" />
@endfor
</div>
<div class="w-full flex flex-col" id="answer_multiple_choice">
@for ($idx = 1; $idx <= 4; $idx++)
<div>
<x-input-label>{{ __("Answer ".$idx) }}</x-input-label>
<x-text-input class="w-full" name="answer{{ $idx }}" placeholder="{{ __('Answer '.$idx) }}" value="{{ old('answer'.$idx, ${'default_answer'.$idx}) }}" />
<x-input-error :messages="$errors->get('answer{{ $idx }}')" class="mt-2" />
<x-bool-input name="is_answer{{$idx}}_correct" checked="{{ old('is_answer'.$idx.'_correct', ${'default_is_answer'.$idx.'_correct'}) }}" />
</div>
@endfor
</div>
<script>
function show(value) {
if (value == "single_answer") {
$("#answer_single").removeClass("hidden")
$("#answer_single_choice").addClass("hidden")
$("#answer_multiple_choice").addClass("hidden")
} else if (value == "single_choice") {
$("#answer_single").addClass("hidden")
$("#answer_single_choice").removeClass("hidden")
$("#answer_multiple_choice").addClass("hidden")
} else if (value == "multiple_choice") {
$("#answer_single").addClass("hidden")
$("#answer_single_choice").addClass("hidden")
$("#answer_multiple_choice").removeClass("hidden")
}
}
$("#answer_type").on("change", function() {
show(this.value)
})
show("{{ $default_answer_type }}")
</script>

View File

@ -12,6 +12,7 @@
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="font-sans antialiased">

View File

@ -4,17 +4,29 @@
@csrf
@method("patch")
<div class="flex flex-col gap-1">
<x-input-label>{{ __("Question") }}</x-input-label>
<x-text-input name="question" placeholder="{{ __('Question') }}" value="{{ old('question', $question->question) }}" />
<x-input-error :messages="$errors->get('question')" class="mt-2" />
{{ $question->answer_type }}
<x-question-fields
:test_id="$question->test_id"
:default_question="$question->question"
:default_points="$question->points"
:default_answer_type="$question->answer_type"
<x-input-label>{{ __("Answer") }}</x-input-label>
<x-text-input name="answer" placeholder="{{ __('Answer') }}" value="{{ old('answer', $question->answer) }}" />
<x-input-error :messages="$errors->get('answer')" class="mt-2" />
:default_answer="$question->answer"
<x-input-label>{{ __("Points") }}</x-input-label>
<x-text-input name="points" placeholder="{{ __('Points') }}" value="{{ old('points', $question->points) }}" />
<x-input-error :messages="$errors->get('points')" class="mt-2" />
:default_correct_answer="$question->correct_answer"
:default_incorrect_answer1="$question->incorrect_answer1"
:default_incorrect_answer2="$question->incorrect_answer2"
:default_incorrect_answer3="$question->incorrect_answer3"
:default_answer1="$question->answer1"
:default_is_answer1_correct="$question->is_answer1_correct"
:default_answer2="$question->answer2"
:default_is_answer2_correct="$question->is_answer2_correct"
:default_answer3="$question->answer3"
:default_is_answer3_correct="$question->is_answer3_correct"
:default_answer4="$question->answer4"
:default_is_answer4_correct="$question->is_answer4_correct"
/>
</div>
<div class="mt-4 space-x-2">

View File

@ -20,19 +20,9 @@
<form method="POST" action="{{ route('questions.store') }}">
@csrf
<div class="flex flex-col gap-1">
<input type="hidden" value="{{ $test->id }}" name="test_id">
<x-input-label>{{ __("Question") }}</x-input-label>
<x-text-input name="question" placeholder="{{ __('Question') }}" value="{{ old('question') }}" />
<x-input-error :messages="$errors->get('question')" class="mt-2" />
<x-input-label>{{ __("Answer") }}</x-input-label>
<x-text-input name="answer" placeholder="{{ __('Answer') }}" value="{{ old('answer') }}" />
<x-input-error :messages="$errors->get('answer')" class="mt-2" />
<x-input-label>{{ __("Points") }}</x-input-label>
<x-text-input name="points" placeholder="{{ __('Points') }}" value="{{ old('points', 1) }}" />
<x-input-error :messages="$errors->get('points')" class="mt-2" />
<x-question-fields
:test_id="$test->id"
/>
</div>
<div class="mt-4 space-x-2">
@ -48,7 +38,7 @@
<th class="border border-gray-300 p-1"></th>
</tr>
@foreach ($test->questions()->get() as $question)
@foreach ($questions as $question)
<tr>
<td class="border border-gray-300 p-1">{{ $question->question }}</td>
<td class="border border-gray-300 p-1">{{ $question->answer }}</td>