diff --git a/app/Http/Controllers/admin/Catalog/Direction/SubjectTypeController.php b/app/Http/Controllers/admin/Catalog/Direction/SubjectTypeController.php
new file mode 100644
index 0000000..10fee30
--- /dev/null
+++ b/app/Http/Controllers/admin/Catalog/Direction/SubjectTypeController.php
@@ -0,0 +1,70 @@
+validated();
+
+ $type = new SubjectType();
+ $type->name = $validated['name'];
+ $type->description = $validated['description'];
+ $type->slug = $validated['slug'];
+ $type->position = $validated['position'];
+ $type->save();
+
+ return redirect()->route('subject_types.index');
+ }
+
+ public function show(SubjectType $type): View
+ {
+ return view('admin.catalog.direction.subject_type.show', compact('type'));
+ }
+
+ public function edit(SubjectType $subjectType): View
+ {
+ return view('admin.catalog.direction.subject_type.edit', compact('subjectType'));
+ }
+
+ public function update(UpdateSubjectTypeRequest $request, SubjectType $subjectType): RedirectResponse
+ {
+ $validated = $request->validated();
+
+ $subjectType->name = $validated['name'];
+ $subjectType->description = $validated['description'];
+ $subjectType->slug = $validated['slug'];
+ $subjectType->position = $validated['position'];
+ $subjectType->save();
+
+ return redirect()->route('subject_types.index');
+ }
+
+ public function destroy(SubjectType $subjectType): RedirectResponse
+ {
+ if ($subjectType->entranceExaminations()->exists()) {
+ return back();
+ }
+ $subjectType->delete();
+ return redirect()->route('subject_types.index');
+ }
+}
diff --git a/app/Http/Requests/admin/Catalog/Direction/StoreSubjectTypeRequest.php b/app/Http/Requests/admin/Catalog/Direction/StoreSubjectTypeRequest.php
new file mode 100644
index 0000000..c24294b
--- /dev/null
+++ b/app/Http/Requests/admin/Catalog/Direction/StoreSubjectTypeRequest.php
@@ -0,0 +1,23 @@
+ 'required|int|numeric|max:255',
+ 'name' => 'required|string|max:255|unique:subject_types,name',
+ 'description' => 'string',
+ 'slug' => 'required|string|max:255|unique:subject_types,slug',
+ ];
+ }
+}
diff --git a/app/Http/Requests/admin/Catalog/Direction/UpdateSubjectTypeRequest.php b/app/Http/Requests/admin/Catalog/Direction/UpdateSubjectTypeRequest.php
new file mode 100644
index 0000000..278b5db
--- /dev/null
+++ b/app/Http/Requests/admin/Catalog/Direction/UpdateSubjectTypeRequest.php
@@ -0,0 +1,33 @@
+ 'required|int|numeric|max:255',
+ 'description' => 'string',
+ 'slug' => [
+ 'string',
+ 'required',
+ 'max:255',
+ "unique:subject_types,slug,{$this->subject_type->id}",
+ ],
+ 'name' => [
+ 'required',
+ 'string',
+ 'max:255',
+ "unique:subject_types,name,{$this->subject_type->id}",
+ ],
+ ];
+ }
+}
diff --git a/app/Models/SubjectType.php b/app/Models/SubjectType.php
new file mode 100644
index 0000000..a95c56e
--- /dev/null
+++ b/app/Models/SubjectType.php
@@ -0,0 +1,25 @@
+hasMany('App\Models\EntranceExamination', 'subject_type_id');
+ }
+}
diff --git a/database/factories/SubjectTypeFactory.php b/database/factories/SubjectTypeFactory.php
new file mode 100644
index 0000000..4dcc9e5
--- /dev/null
+++ b/database/factories/SubjectTypeFactory.php
@@ -0,0 +1,18 @@
+ fake()->name(),
+ 'description' => fake()->text(),
+ 'slug' => fake()->slug(),
+ 'position' => fake()->randomDigit(),
+ ];
+ }
+}
diff --git a/database/migrations/2024_02_15_075912_create_subject_types_table.php b/database/migrations/2024_02_15_075912_create_subject_types_table.php
new file mode 100644
index 0000000..5d3aa25
--- /dev/null
+++ b/database/migrations/2024_02_15_075912_create_subject_types_table.php
@@ -0,0 +1,25 @@
+id();
+ $table->integer('position');
+ $table->string('name');
+ $table->text('description')->nullable();
+ $table->string('slug');
+ $table->timestamps();
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::dropIfExists('subject_types');
+ }
+};
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index fb798da..34ab451 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -29,6 +29,7 @@ class DatabaseSeeder extends Seeder
EducationFormSeeder::class,
ExaminationTypeSeeder::class,
SubjectSeeder::class,
+ SubjectTypeSeeder::class,
DirectionSeeder::class,
]);
diff --git a/database/seeders/SubjectTypeSeeder.php b/database/seeders/SubjectTypeSeeder.php
new file mode 100644
index 0000000..6f9dce4
--- /dev/null
+++ b/database/seeders/SubjectTypeSeeder.php
@@ -0,0 +1,28 @@
+insert([
+ [
+ 'name' => 'Обязательные',
+ 'description' => 'compulsory',
+ 'position' => '1',
+ 'slug' => 'compulsory',
+ ],
+ [
+ 'name' => 'Предметы по выбору',
+ 'description' => 'optional',
+ 'position' => '2',
+ 'slug' => 'optional',
+ ],
+ ]);
+ }
+}
diff --git a/resources/views/admin/catalog/direction/subject/index.blade.php b/resources/views/admin/catalog/direction/subject/index.blade.php
index 23888fc..627fd24 100644
--- a/resources/views/admin/catalog/direction/subject/index.blade.php
+++ b/resources/views/admin/catalog/direction/subject/index.blade.php
@@ -1,7 +1,7 @@
@extends('layouts.admin_layout')
@section('content')
-
Тип Экзамена
+
Предметы
Создать предмет
diff --git a/resources/views/admin/catalog/direction/subject_type/create.blade.php b/resources/views/admin/catalog/direction/subject_type/create.blade.php
new file mode 100644
index 0000000..c5fd616
--- /dev/null
+++ b/resources/views/admin/catalog/direction/subject_type/create.blade.php
@@ -0,0 +1,65 @@
+@extends('layouts.admin_layout')
+@section('content')
+ @auth()
+
+
+
Создать Тип предмета
+ {{ Form::open(['url' => route('subject_types.store'), 'method' => 'POST', 'class' => '']) }}
+
+
+ {{ Form::label('name', 'Название') }}
+
+
+ {{ Form::text('name', '', ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('name') }}
+ @endif
+
+
+
+ {{ Form::label('description', 'Описание') }}
+
+
+ {{ Form::text('description', '', ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('description') }}
+ @endif
+
+
+
+ {{ Form::label('slug', 'URL') }}
+
+
+ {{ Form::text('slug', '', ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('slug') }}
+ @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/subject_type/edit.blade.php b/resources/views/admin/catalog/direction/subject_type/edit.blade.php
new file mode 100644
index 0000000..1069c9d
--- /dev/null
+++ b/resources/views/admin/catalog/direction/subject_type/edit.blade.php
@@ -0,0 +1,66 @@
+@extends('layouts.admin_layout')
+@section('content')
+
+ @auth()
+
+
+
Изменить тип предмета
+ {{ Form::open(['url' => route('subject_types.update', $subjectType), 'method' => 'PATCH', 'class' => '']) }}
+
+
+ {{ Form::label('name', 'Название') }}
+
+
+ {{ Form::text('name', $subjectType->name, ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('name') }}
+ @endif
+
+
+
+ {{ Form::label('description', 'Описание') }}
+
+
+ {{ Form::text('description', $subjectType->description, ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('description') }}
+ @endif
+
+
+
+ {{ Form::label('slug', 'URL') }}
+
+
+ {{ Form::text('slug', $subjectType->slug, ['class' => 'form-control']) }}
+
+
+ @if ($errors->any())
+ {{ $errors->first('slug') }}
+ @endif
+
+
+
+ {{ Form::label('position', 'Позиция') }}
+
+
+ {{ Form::text('position', $subjectType->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/subject_type/index.blade.php b/resources/views/admin/catalog/direction/subject_type/index.blade.php
new file mode 100644
index 0000000..98aae2c
--- /dev/null
+++ b/resources/views/admin/catalog/direction/subject_type/index.blade.php
@@ -0,0 +1,41 @@
+@extends('layouts.admin_layout')
+@section('content')
+
+
Тип предмета
+
+
Создать тип предмет
+
+
+
+
+
+ Позиция |
+ Название |
+ Описание |
+ URL |
+ действия |
+ |
+
+
+
+ @foreach($subjectTypes as $subjectType)
+
+ {{ $subjectType->position }} |
+ {{ $subjectType->name }} |
+ {{ Str::words($subjectType->description, 10, '...') }} |
+ {{ $subjectType->slug }} |
+
+ редактировать
+ удалить
+ |
+
+ @endforeach
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/catalog/direction/subject_type/show.blade.php b/resources/views/admin/catalog/direction/subject_type/show.blade.php
new file mode 100644
index 0000000..dea2bd5
--- /dev/null
+++ b/resources/views/admin/catalog/direction/subject_type/show.blade.php
@@ -0,0 +1,19 @@
+@extends('layouts.admin_layout')
+@section('content')
+ @auth()
+
+
Название
+
{{ $type->name }}
+
Описание
+
{{ $type->description }}
+
URL
+
{{ $type->slug }}
+
Позиция
+
{{ $type->position }}
+
Вступительные испытания
+ @foreach($type->entranceExaminations as $entranceExamination)
+
{{ $entranceExamination->name }}
+ @endforeach
+
+ @endauth
+@endsection
diff --git a/resources/views/layouts/admin_layout.blade.php b/resources/views/layouts/admin_layout.blade.php
index c2bda8d..042ae30 100644
--- a/resources/views/layouts/admin_layout.blade.php
+++ b/resources/views/layouts/admin_layout.blade.php
@@ -60,6 +60,7 @@
Формы образования
Типы Экзаменов
Предметы
+
Типы Предметов
@yield('content')
diff --git a/routes/admin.php b/routes/admin.php
index b4016da..abd8ea8 100644
--- a/routes/admin.php
+++ b/routes/admin.php
@@ -6,6 +6,7 @@ use App\Http\Controllers\admin\Catalog\Direction\EducationFormController;
use App\Http\Controllers\admin\Catalog\Direction\EducationLevelController;
use App\Http\Controllers\admin\Catalog\Direction\ExaminationTypeController;
use App\Http\Controllers\admin\Catalog\Direction\SubjectController;
+use App\Http\Controllers\admin\Catalog\Direction\SubjectTypeController;
use App\Http\Controllers\admin\Catalog\DirectionController;
use App\Http\Controllers\admin\Catalog\EducationalInstitutionController;
use App\Http\Controllers\admin\Catalog\FacultyController;
@@ -49,6 +50,9 @@ Route::middleware(['auth', 'verified'])->prefix('admin')->group(function () {
Route::resource('/subjects', SubjectController::class)
->scoped(['subject' => 'slug']);
+ Route::resource('/subject_types', SubjectTypeController::class)
+ ->scoped(['subject_type' => 'slug']);
+
Route::resources([
'/documents' => DocumentController::class,
'/users' => UserController::class,
diff --git a/tests/Feature/admin/catalog/direction/SubjectTypeTest.php b/tests/Feature/admin/catalog/direction/SubjectTypeTest.php
new file mode 100644
index 0000000..cb1ad58
--- /dev/null
+++ b/tests/Feature/admin/catalog/direction/SubjectTypeTest.php
@@ -0,0 +1,102 @@
+type = SubjectType::factory()->create();
+
+ $this->data = SubjectType::factory()->make()->only([
+ 'name',
+ 'description',
+ 'position',
+ 'slug',
+ ]);
+
+ $this->user = User::factory()->create([
+ 'name' => 'admin',
+ 'email' => 'test@example.com',
+ 'password' => 123456
+ ]);
+ }
+
+ public function testIndexSubjectTypesPage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('subject_types.index'));
+
+ $response->assertOk();
+ }
+
+ public function testCreateSubjectTypePage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('subject_types.create'));
+
+ $response->assertOk();
+ }
+
+ public function testStoreSubjectType(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->post(route('subject_types.store', $this->data));
+
+ $response->assertRedirect(route('subject_types.index'));
+
+ $this->assertDatabaseHas('subject_types', $this->data);
+ }
+
+ public function testShowSubjectTypePage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('subject_types.show', $this->type));
+
+ $response->assertOk();
+ }
+
+ public function testEditSubjectTypePage(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->get(route('subject_types.edit', $this->type));
+
+ $response->assertOk();
+ }
+
+ public function testUpdateSubjectType(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->patch(route('subject_types.update', $this->type), $this->data);
+
+ $response->assertRedirect(route('subject_types.index'));
+
+ $this->assertDatabaseHas('subject_types', $this->data);
+ }
+
+ public function testDestroySubjectType(): void
+ {
+ $response = $this->actingAs($this->user)
+ ->withSession(['banned' => false])
+ ->delete(route('subject_types.destroy', $this->type));
+
+ $response->assertRedirect(route('subject_types.index'));
+
+ $this->assertDatabaseMissing('subject_types', $this->type->toArray());
+ }
+}