diff --git a/app/Http/Controllers/admin/Catalog/Direction/EntranceExaminationController.php b/app/Http/Controllers/admin/Catalog/Direction/EntranceExaminationController.php
new file mode 100644
index 0000000..fba5a32
--- /dev/null
+++ b/app/Http/Controllers/admin/Catalog/Direction/EntranceExaminationController.php
@@ -0,0 +1,105 @@
+validated();
+
+ $entranceExamination = new EntranceExamination();
+ $entranceExamination->examination_type_id = $validated['examination_type_id'];
+ $entranceExamination->direction_id = $validated['direction_id'];
+ $entranceExamination->subject_id = $validated['subject_id'];
+ $entranceExamination->scores = $validated['scores'];
+ $entranceExamination->position = $validated['position'];
+ $entranceExamination->subject_type_id = $validated['subject_type_id'];
+ $entranceExamination->save();
+
+ return redirect()->route('entrance_examinations.index');
+ }
+
+ public function show(EntranceExamination $entranceExamination): View
+ {
+ return view(
+ 'admin.catalog.direction.entrance_examination.show',
+ compact('entranceExamination')
+ );
+ }
+
+ public function edit(EntranceExamination $entranceExamination): View
+ {
+ $directions = Direction::pluck('name', 'id');
+ $examination_types = ExaminationType::pluck('name', 'id');
+ $subjects = Subject::pluck('name', 'id');
+ $subjectTypes = SubjectType::pluck('name', 'id');
+ return view(
+ 'admin.catalog.direction.entrance_examination.edit',
+ compact(
+ 'entranceExamination',
+ 'directions',
+ 'examination_types',
+ 'subjects',
+ 'subjectTypes',
+ )
+ );
+ }
+
+ public function update(
+ UpdateEntranceExaminationRequest $request,
+ EntranceExamination $entranceExamination
+ ): RedirectResponse {
+ $validated = $request->validated();
+
+ $entranceExamination->examination_type_id = $validated['examination_type_id'];
+ $entranceExamination->direction_id = $validated['direction_id'];
+ $entranceExamination->subject_id = $validated['subject_id'];
+ $entranceExamination->scores = $validated['scores'];
+ $entranceExamination->position = $validated['position'];
+ $entranceExamination->subject_type_id = $validated['subject_type_id'];
+ $entranceExamination->save();
+
+ return redirect()->route('entrance_examinations.index');
+ }
+
+ public function destroy(EntranceExamination $entranceExamination): RedirectResponse
+ {
+ $entranceExamination->delete();
+ return redirect()->route('entrance_examinations.index');
+ }
+}
diff --git a/app/Http/Controllers/admin/Catalog/DirectionController.php b/app/Http/Controllers/admin/Catalog/DirectionController.php
index 0672c4a..c8c0fd3 100644
--- a/app/Http/Controllers/admin/Catalog/DirectionController.php
+++ b/app/Http/Controllers/admin/Catalog/DirectionController.php
@@ -93,6 +93,9 @@ class DirectionController extends Controller
public function destroy(Direction $direction): RedirectResponse
{
+ if ($direction->entranceExaminations()->exists()) {
+ return back();
+ }
$direction->delete();
return redirect()->route('directions.index');
}
diff --git a/app/Http/Requests/admin/Catalog/Direction/StoreEntranceExaminationRequest.php b/app/Http/Requests/admin/Catalog/Direction/StoreEntranceExaminationRequest.php
new file mode 100644
index 0000000..f4e535d
--- /dev/null
+++ b/app/Http/Requests/admin/Catalog/Direction/StoreEntranceExaminationRequest.php
@@ -0,0 +1,25 @@
+ 'required|numeric|int|max:1000',
+ 'examination_type_id' => 'required|numeric|int|max:1000',
+ 'subject_id' => 'required|numeric|int|max:1000',
+ 'subject_type_id' => 'required|numeric|int|max:1000',
+ 'scores' => 'required|numeric|int|max:1000',
+ 'position' => 'required|numeric|int|max:1000',
+ ];
+ }
+}
diff --git a/app/Http/Requests/admin/Catalog/Direction/UpdateEntranceExaminationRequest.php b/app/Http/Requests/admin/Catalog/Direction/UpdateEntranceExaminationRequest.php
index fef7be6..883f336 100644
--- a/app/Http/Requests/admin/Catalog/Direction/UpdateEntranceExaminationRequest.php
+++ b/app/Http/Requests/admin/Catalog/Direction/UpdateEntranceExaminationRequest.php
@@ -8,13 +8,18 @@ class UpdateEntranceExaminationRequest extends FormRequest
{
public function authorize(): bool
{
- return false;
+ return true;
}
public function rules(): array
{
return [
-
+ 'direction_id' => 'required|numeric|int|max:1000',
+ 'examination_type_id' => 'required|numeric|int|max:1000',
+ 'subject_id' => 'required|numeric|int|max:1000',
+ 'subject_type_id' => 'required|numeric|int|max:1000',
+ 'scores' => 'required|numeric|int|max:1000',
+ 'position' => 'required|numeric|int|max:1000',
];
}
}
diff --git a/app/Models/Direction.php b/app/Models/Direction.php
index 34df08c..3a302fd 100644
--- a/app/Models/Direction.php
+++ b/app/Models/Direction.php
@@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
class Direction extends Model
{
@@ -33,4 +34,9 @@ class Direction extends Model
{
return $this->belongsTo(EducationForm::class);
}
+
+ public function entranceExaminations(): HasMany
+ {
+ return $this->hasMany('App\Models\EntranceExamination', 'direction_id');
+ }
}
diff --git a/app/Models/EntranceExamination.php b/app/Models/EntranceExamination.php
new file mode 100644
index 0000000..9ca35cc
--- /dev/null
+++ b/app/Models/EntranceExamination.php
@@ -0,0 +1,42 @@
+belongsTo(ExaminationType::class);
+ }
+
+ public function direction(): BelongsTo
+ {
+ return $this->belongsTo(Direction::class);
+ }
+
+ public function subject(): BelongsTo
+ {
+ return $this->belongsTo(Subject::class);
+ }
+
+ public function subjectType(): BelongsTo
+ {
+ return $this->belongsTo(SubjectType::class);
+ }
+}
diff --git a/database/factories/EntranceExaminationFactory.php b/database/factories/EntranceExaminationFactory.php
new file mode 100644
index 0000000..2e6c13c
--- /dev/null
+++ b/database/factories/EntranceExaminationFactory.php
@@ -0,0 +1,20 @@
+ 1,
+ 'direction_id' => 1,
+ 'subject_id' => 1,
+ 'scores' => 45,
+ 'position' => fake()->randomDigit(),
+ 'subject_type_id' => 1,
+ ];
+ }
+}
diff --git a/database/migrations/2024_02_15_075913_create_entrance_examinations_table.php b/database/migrations/2024_02_15_075913_create_entrance_examinations_table.php
new file mode 100644
index 0000000..a18dcf1
--- /dev/null
+++ b/database/migrations/2024_02_15_075913_create_entrance_examinations_table.php
@@ -0,0 +1,27 @@
+id();
+ $table->foreignId('examination_type_id')->constrained('examination_types');
+ $table->foreignId('direction_id')->constrained('directions');
+ $table->foreignId('subject_id')->constrained('subjects');
+ $table->integer('scores');
+ $table->integer('position');
+ $table->foreignId('subject_type_id')->constrained('subject_types');
+ $table->timestamps();
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::dropIfExists('entrance_examinations');
+ }
+};
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index 6437501..e3e6d62 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -31,6 +31,7 @@ class DatabaseSeeder extends Seeder
SubjectSeeder::class,
SubjectTypeSeeder::class,
DirectionSeeder::class,
+ EntranceExaminationSeeder::class,
]);
$this->call([
diff --git a/database/seeders/EntranceExaminationSeeder.php b/database/seeders/EntranceExaminationSeeder.php
new file mode 100644
index 0000000..ec50ae6
--- /dev/null
+++ b/database/seeders/EntranceExaminationSeeder.php
@@ -0,0 +1,40 @@
+insert([
+ [
+ 'examination_type_id' => 1,
+ 'direction_id' => 1,
+ 'subject_id' => 1,
+ 'scores' => 40,
+ 'position' => 1,
+ 'subject_type_id' => 1,
+ ],
+ [
+ 'examination_type_id' => 1,
+ 'direction_id' => 1,
+ 'subject_id' => 2,
+ 'scores' => 45,
+ 'position' => 2,
+ 'subject_type_id' => 1,
+ ],
+ [
+ 'examination_type_id' => 1,
+ 'direction_id' => 1,
+ 'subject_id' => 3,
+ 'scores' => 50,
+ 'position' => 3,
+ 'subject_type_id' => 1,
+ ],
+ ]);
+ }
+}
diff --git a/resources/views/admin/catalog/direction/entrance_examination/create.blade.php b/resources/views/admin/catalog/direction/entrance_examination/create.blade.php
new file mode 100644
index 0000000..8165235
--- /dev/null
+++ b/resources/views/admin/catalog/direction/entrance_examination/create.blade.php
@@ -0,0 +1,90 @@
+@extends('layouts.admin_layout')
+@section('content')
+ @auth()
+
+
+
Создать вступительный экзамен
+ {{ Form::open(['url' => route('entrance_examinations.store'), 'method' => 'POST', 'class' => '']) }}
+
+
+ {{ Form::label('direction_id', 'Направление подготовки') }}
+
+
+ {{ Form::select('direction_id', $directions, null, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('direction_id') }}
+ @endif
+
+
+
+ {{ Form::label('examination_type_id', 'Тип экзамена') }}
+
+
+ {{ Form::select('examination_type_id', $examination_types, null, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('examination_type_id') }}
+ @endif
+
+
+
+ {{ Form::label('subject_id', 'Предмет') }}
+
+
+ {{ Form::select('subject_id', $subjects, null, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('subject_id') }}
+ @endif
+
+
+
+ {{ Form::label('subject_type_id', 'Тип предмета') }}
+
+
+ {{ Form::select('subject_type_id', $subjectTypes, null, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('subject_type_id') }}
+ @endif
+
+
+
+
+ {{ Form::label('scores', 'Кол-во баллов') }}
+
+
+ {{ Form::text('scores', '', ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('scores') }}
+ @endif
+
+
+
+ {{ Form::label('position', 'Позиция') }}
+
+
+ {{ Form::text('position', '', ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('position') }}
+ @endif
+
+
+
+ {{ Form::submit('Создать', ['class' => 'btn btn-primary']) }}
+
+
+ {{ Form::close() }}
+
+
+ @endauth
+@endsection
diff --git a/resources/views/admin/catalog/direction/entrance_examination/edit.blade.php b/resources/views/admin/catalog/direction/entrance_examination/edit.blade.php
new file mode 100644
index 0000000..fb2c11b
--- /dev/null
+++ b/resources/views/admin/catalog/direction/entrance_examination/edit.blade.php
@@ -0,0 +1,90 @@
+@extends('layouts.admin_layout')
+@section('content')
+ @auth()
+
+
+
Изменить вступительный экзамен
+ {{ Form::open(['url' => route('entrance_examinations.update', $entranceExamination), 'method' => 'PATCH', 'class' => '']) }}
+
+
+ {{ Form::label('direction_id', 'Направление подготовки') }}
+
+
+ {{ Form::select('direction_id', $directions, $entranceExamination->direction->id, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('direction_id') }}
+ @endif
+
+
+
+ {{ Form::label('examination_type_id', 'Тип экзамена') }}
+
+
+ {{ Form::select('examination_type_id', $examination_types, $entranceExamination->examinationType->id, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('examination_type_id') }}
+ @endif
+
+
+
+ {{ Form::label('subject_id', 'Предмет') }}
+
+
+ {{ Form::select('subject_id', $subjects, $entranceExamination->subject->id, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('subject_id') }}
+ @endif
+
+
+
+ {{ Form::label('subject_type_id', 'Тип предмета') }}
+
+
+ {{ Form::select('subject_type_id', $subjectTypes, $entranceExamination->subjectType->id, ['class' => 'form-select']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('subject_type_id') }}
+ @endif
+
+
+
+
+ {{ Form::label('scores', 'Кол-во баллов') }}
+
+
+ {{ Form::text('scores', $entranceExamination->scores, ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('scores') }}
+ @endif
+
+
+
+ {{ Form::label('position', 'Позиция') }}
+
+
+ {{ Form::text('position', $entranceExamination->position, ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('position') }}
+ @endif
+
+
+
+ {{ Form::submit('Изменить', ['class' => 'btn btn-primary']) }}
+
+
+ {{ Form::close() }}
+
+
+ @endauth
+@endsection
diff --git a/resources/views/admin/catalog/direction/entrance_examination/index.blade.php b/resources/views/admin/catalog/direction/entrance_examination/index.blade.php
new file mode 100644
index 0000000..bc04285
--- /dev/null
+++ b/resources/views/admin/catalog/direction/entrance_examination/index.blade.php
@@ -0,0 +1,47 @@
+@extends('layouts.admin_layout')
+@section('content')
+
+@endsection
diff --git a/resources/views/admin/catalog/direction/entrance_examination/show.blade.php b/resources/views/admin/catalog/direction/entrance_examination/show.blade.php
new file mode 100644
index 0000000..cea7b15
--- /dev/null
+++ b/resources/views/admin/catalog/direction/entrance_examination/show.blade.php
@@ -0,0 +1,19 @@
+@extends('layouts.admin_layout')
+@section('content')
+ @auth()
+
+
Направление подготовки
+
{{ $entranceExamination->direction->name }}
+
Тип экзамена
+
{{ $entranceExamination->examinationType->name }}
+
Предмет
+
{{ $entranceExamination->subject->name }}
+
Тип предмета
+
{{ $entranceExamination->subjectType->name }}
+
Мин. кол-во баллов
+
{{ $entranceExamination->scores }}
+
Позиция
+
{{ $entranceExamination->position }}
+
+ @endauth
+@endsection
diff --git a/resources/views/layouts/admin_layout.blade.php b/resources/views/layouts/admin_layout.blade.php
index 042ae30..b17d99b 100644
--- a/resources/views/layouts/admin_layout.blade.php
+++ b/resources/views/layouts/admin_layout.blade.php
@@ -56,6 +56,7 @@
Факультеты
Кафедры
Направления
+ Вступ. экзамены
Уровни образования
Формы образования
Типы Экзаменов
diff --git a/routes/admin.php b/routes/admin.php
index abd8ea8..57cb228 100644
--- a/routes/admin.php
+++ b/routes/admin.php
@@ -4,6 +4,7 @@ use App\Http\Controllers\admin\AdmissionController;
use App\Http\Controllers\admin\Catalog\DepartmentController;
use App\Http\Controllers\admin\Catalog\Direction\EducationFormController;
use App\Http\Controllers\admin\Catalog\Direction\EducationLevelController;
+use App\Http\Controllers\admin\Catalog\Direction\EntranceExaminationController;
use App\Http\Controllers\admin\Catalog\Direction\ExaminationTypeController;
use App\Http\Controllers\admin\Catalog\Direction\SubjectController;
use App\Http\Controllers\admin\Catalog\Direction\SubjectTypeController;
@@ -53,6 +54,8 @@ Route::middleware(['auth', 'verified'])->prefix('admin')->group(function () {
Route::resource('/subject_types', SubjectTypeController::class)
->scoped(['subject_type' => 'slug']);
+ Route::resource('/entrance_examinations', EntranceExaminationController::class);
+
Route::resources([
'/documents' => DocumentController::class,
'/users' => UserController::class,
diff --git a/tests/Feature/admin/catalog/DirectionTest.php b/tests/Feature/admin/catalog/DirectionTest.php
index cd5425e..7625bc8 100644
--- a/tests/Feature/admin/catalog/DirectionTest.php
+++ b/tests/Feature/admin/catalog/DirectionTest.php
@@ -7,7 +7,11 @@ use App\Models\Direction;
use App\Models\EducationalInstitution;
use App\Models\EducationForm;
use App\Models\EducationLevel;
+use App\Models\EntranceExamination;
+use App\Models\ExaminationType;
use App\Models\Faculty;
+use App\Models\Subject;
+use App\Models\SubjectType;
use App\Models\User;
use Tests\TestCase;
@@ -15,7 +19,9 @@ class DirectionTest extends TestCase
{
private User $user;
private Direction $direction;
+ private EntranceExamination $entranceExamination;
private array $data;
+
protected function setUp(): void
{
parent::setUp();
@@ -26,6 +32,12 @@ class DirectionTest extends TestCase
EducationForm::factory()->create();
$this->direction = Direction::factory()->create();
+
+ ExaminationType::factory()->create();
+ Subject::factory()->create();
+ SubjectType::factory()->create();
+ $this->entranceExamination = EntranceExamination::factory()->create();
+
$this->data = Direction::factory()->make()->only([
'position',
'name',
@@ -104,6 +116,7 @@ class DirectionTest extends TestCase
public function testDestroyDirection(): void
{
+ $this->entranceExamination->delete();
$response = $this->actingAs($this->user)
->withSession(['banned' => false])
->delete(route('directions.destroy', $this->direction));
@@ -112,4 +125,27 @@ class DirectionTest extends TestCase
$this->assertDatabaseMissing('directions', $this->direction->toArray());
}
+
+ public function testNotDestroyDirectionWithEntranceExamination(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->delete(route('directions.destroy', $this->direction));
+
+ $response->assertStatus(302);
+
+ $this->assertDatabaseHas(
+ 'directions',
+ $this->direction->only([
+ 'position',
+ 'name',
+ 'description',
+ 'code',
+ 'slug',
+ 'education_level_id',
+ 'education_form_id',
+ 'department_id',
+ ])
+ );
+ }
}
diff --git a/tests/Feature/admin/catalog/direction/EntranceExaminationTest.php b/tests/Feature/admin/catalog/direction/EntranceExaminationTest.php
new file mode 100644
index 0000000..ba4804b
--- /dev/null
+++ b/tests/Feature/admin/catalog/direction/EntranceExaminationTest.php
@@ -0,0 +1,123 @@
+create();
+ Faculty::factory()->create();
+ Department::factory()->create();
+ EducationLevel::factory()->create();
+ EducationForm::factory()->create();
+ Direction::factory()->create();
+ ExaminationType::factory()->create();
+ Subject::factory()->create();
+ SubjectType::factory()->create();
+
+ $this->entranceExamination = EntranceExamination::factory()->create();
+
+
+ $this->data = EntranceExamination::factory()->make()->only([
+ 'direction_id',
+ 'examination_type_id',
+ 'subject_id',
+ 'subject_type_id',
+ 'scores',
+ 'position',
+ ]);
+
+ $this->user = User::factory()->create([
+ 'name' => 'admin',
+ 'email' => 'test@example.com',
+ 'password' => 123456
+ ]);
+ }
+
+ public function testIndexEntranceExaminationsPage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('entrance_examinations.index'));
+
+ $response->assertOk();
+ }
+
+ public function testCreateEntranceExaminationPage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('entrance_examinations.create'));
+
+ $response->assertOk();
+ }
+
+ public function testStoreEntranceExamination(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->post(route('entrance_examinations.store', $this->data));
+
+ $response->assertRedirect(route('entrance_examinations.index'));
+
+ $this->assertDatabaseHas('entrance_examinations', $this->data);
+ }
+
+ public function testShowEntranceExaminationPage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('entrance_examinations.show', $this->entranceExamination));
+
+ $response->assertOk();
+ }
+
+ public function testEditEntranceExaminationPage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('entrance_examinations.edit', $this->entranceExamination));
+
+ $response->assertOk();
+ }
+
+ public function testUpdateEntranceExamination(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->patch(route('entrance_examinations.update', $this->entranceExamination), $this->data);
+
+ $response->assertRedirect(route('entrance_examinations.index'));
+
+ $this->assertDatabaseHas('entrance_examinations', $this->data);
+ }
+
+ public function testEntranceExaminationDirection(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->delete(route('entrance_examinations.destroy', $this->entranceExamination));
+
+ $response->assertRedirect(route('entrance_examinations.index'));
+
+ $this->assertDatabaseMissing('entrance_examinations', $this->entranceExamination->toArray());
+ }
+}