Merge pull request 'feature/task-3 (Users)' (#3) from feature/task-3 into develop

Reviewed-on: #3
This commit is contained in:
klllst 2024-05-06 12:01:32 +04:00
commit fd6e0d967b
54 changed files with 1599 additions and 217 deletions

View File

@ -4,19 +4,23 @@ namespace App\Http\Controllers;
use App\Http\Requests\GradePostRequest;
use App\Models\Grade;
use App\Services\ServiceInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class GradeController extends Controller
{
public function __construct(
protected ServiceInterface $gradeService,
){}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('grades.index', [
'grades' => Grade::filter()->paginate(10)->withQueryString(),
'grades' => $this->gradeService->getAll(),
]);
}
@ -33,9 +37,7 @@ class GradeController extends Controller
*/
public function store(GradePostRequest $request): RedirectResponse
{
$grade = Grade::create($request->validated());
return redirect()->route('grades.show', $grade);
return redirect()->route('grades.show', $this->gradeService->create($request->validated()));
}
/**
@ -63,9 +65,7 @@ class GradeController extends Controller
*/
public function update(GradePostRequest $request, Grade $grade): RedirectResponse
{
$grade->update($request->validated());
return redirect()->route('grades.show', $grade);
return redirect()->route('grades.show', $this->gradeService->update($grade, $request->validated()));
}
/**
@ -73,7 +73,7 @@ class GradeController extends Controller
*/
public function destroy(Grade $grade): RedirectResponse
{
$grade->delete();
$this->gradeService->delete($grade);
return redirect()->route('grades.index');
}

View File

@ -0,0 +1,91 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StudentPostRequest;
use App\Models\Grade;
use App\Models\Student;
use App\Services\ServiceInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class StudentController extends Controller
{
public function __construct(
protected ServiceInterface $studentService
){}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('students.index', [
'students' => $this->studentService->getAll(),
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('students.create', [
'grades' => Grade::all(),
]);
}
/**
* Store a newly created resource in storage.
*/
public function store(StudentPostRequest $request): RedirectResponse
{
return redirect()->route(
'students.show',
$this->studentService->create($request->validated())
);
}
/**
* Display the specified resource.
*/
public function show(Student $student): View
{
return view('students.show', [
'student' => $student,
'grades' => Grade::all(),
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Student $student): View
{
return view('students.edit', [
'student' => $student,
'grades' => Grade::all(),
]);
}
/**
* Update the specified resource in storage.
*/
public function update(StudentPostRequest $request, Student $student): RedirectResponse
{
return redirect()->route(
'students.show',
$this->studentService->update($student, $request->validated())
);
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Student $student): RedirectResponse
{
$this->studentService->delete($student);
return redirect()->route('students.index');
}
}

View File

@ -4,19 +4,23 @@ namespace App\Http\Controllers;
use App\Http\Requests\SubjectPostRequest;
use App\Models\Subject;
use App\Services\ServiceInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class SubjectController extends Controller
{
public function __construct(
protected ServiceInterface $subjectService,
){}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('subjects.index', [
"subjects" => Subject::filter()->paginate(10)->withQueryString(),
"subjects" => $this->subjectService->getAll(),
]);
}
@ -33,9 +37,10 @@ class SubjectController extends Controller
*/
public function store(SubjectPostRequest $request): RedirectResponse
{
$subject = Subject::create($request->validated());
return redirect()->route('subjects.show', $subject);
return redirect()->route(
'subjects.show',
$this->subjectService->create($request->validated())
);
}
/**
@ -63,9 +68,10 @@ class SubjectController extends Controller
*/
public function update(SubjectPostRequest $request, Subject $subject): RedirectResponse
{
$subject->update($request->validated());
return redirect()->route('subjects.show', $subject);
return redirect()->route(
'subjects.show',
$this->subjectService->update($subject, $request->validated())
);
}
/**
@ -73,7 +79,7 @@ class SubjectController extends Controller
*/
public function destroy(Subject $subject): RedirectResponse
{
$subject->delete();
$this->subjectService->delete($subject);
return redirect()->route('subjects.index');
}

View File

@ -0,0 +1,86 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\TeacherPostRequest;
use App\Models\Teacher;
use App\Services\ServiceInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class TeacherController extends Controller
{
public function __construct(
protected ServiceInterface $teacherService
){}
/**
* Display a listing of the resource.
*/
public function index(): View
{
return view('teachers.index', [
'teachers' => $this->teacherService->getAll(),
]);
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('teachers.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(TeacherPostRequest $request): RedirectResponse
{
return redirect()->route(
'teachers.show',
$this->teacherService->create($request->validated())
);
}
/**
* Display the specified resource.
*/
public function show(Teacher $teacher): View
{
return view('teachers.show', [
'teacher' => $teacher,
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Teacher $teacher): View
{
return view('teachers.edit', [
'teacher' => $teacher,
]);
}
/**
* Update the specified resource in storage.
*/
public function update(TeacherPostRequest $request, Teacher $teacher): RedirectResponse
{
return redirect()->route(
'teachers.show',
$this->teacherService->update($teacher, $request->validated())
);
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Teacher $teacher): RedirectResponse
{
$this->teacherService->delete($teacher);
return redirect()->route('teachers.index');
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests;
use App\Enums\RoleEnum;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class StudentPostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|max:255',
'last_name' => 'required|max:255',
'middle_name' => 'required|max:255',
'birthday' => 'required|date',
'grade_id' => 'required|exists:grades,id',
'email' => 'required|max:255|lowercase|unique:users,email',
'password' => 'required|max:255',
];
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use App\Enums\RoleEnum;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class TeacherPostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|max:255',
'last_name' => 'required|max:255',
'middle_name' => 'required|max:255',
'birthday' => 'required|date',
'email' => 'required|max:255|lowercase|unique:users,email',
'password' => 'required|max:255',
];
}
}

17
app/Models/Admin.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
class Admin extends Model
{
use HasFactory;
public function user(): MorphOne
{
return $this->morphOne(User::class, 'userable');
}
}

View File

@ -6,6 +6,7 @@ use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Grade extends Model
{
@ -20,6 +21,16 @@ class Grade extends Model
return $this->belongsToMany(Subject::class);
}
public function students(): HasMany
{
return $this->hasMany(Student::class);
}
public function teachers(): BelongsToMany
{
return $this->belongsToMany(Teacher::class);
}
public function scopeFilter(Builder $query): void
{
$name = request('name');

52
app/Models/Student.php Normal file
View File

@ -0,0 +1,52 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Builder;
class Student extends Model
{
use HasFactory;
protected $fillable = [
'name',
'last_name',
'middle_name',
'birthday',
'grade_id',
];
public function grade(): BelongsTo
{
return $this->belongsTo(Grade::class);
}
public function user(): MorphOne
{
return $this->morphOne(User::class, 'userable');
}
public function scopeFilter(Builder $query): void
{
$name = request('name');
$query->when($name, function (Builder $query, $name){
$query->whereRaw('CONCAT (name, \' \', surname, \' \', patronymic) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (name, \' \', patronymic, \' \', surname) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (surname, \' \', name, \' \', patronymic) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (surname, \' \', patronymic, \' \', name) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (patronymic, \' \', name, \' \', surname) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (patronymic, \' \', surname, \' \', name) ilike ?', ["$name%"]);
});
}
public function fio(): Attribute
{
return Attribute::make(
get: fn () => $this->last_name . " " . $this->name . " " . $this->middle_name,
);
}
}

View File

@ -6,6 +6,7 @@ use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
class Subject extends Model
{
@ -20,6 +21,11 @@ class Subject extends Model
return $this->belongsToMany(Grade::class);
}
public function teachers(): BelongsToMany
{
return $this->belongsToMany(Teacher::class);
}
public function scopeFilter(Builder $query): void
{
$name = request('name');
@ -28,4 +34,9 @@ class Subject extends Model
$query->whereRaw('name ilike ?', ["$name%"]);
});
}
public function user(): MorphOne
{
return $this->morphOne(User::class, 'userable');
}
}

56
app/Models/Teacher.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Builder;
class Teacher extends Model
{
use HasFactory;
protected $fillable = [
'name',
'last_name',
'middle_name',
'birthday',
];
public function subjects(): BelongsToMany
{
return $this->belongsToMany(Subject::class);
}
public function grades(): BelongsToMany
{
return $this->belongsToMany(Grade::class);
}
public function user(): MorphOne
{
return $this->morphOne(User::class, 'userable');
}
public function scopeFilter(Builder $query): void
{
$name = request('name');
$query->when($name, function (Builder $query, $name){
$query->whereRaw('CONCAT (name, \' \', surname, \' \', patronymic) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (name, \' \', patronymic, \' \', surname) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (surname, \' \', name, \' \', patronymic) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (surname, \' \', patronymic, \' \', name) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (patronymic, \' \', name, \' \', surname) ilike ?', ["$name%"]);
$query->orWhereRaw('CONCAT (patronymic, \' \', surname, \' \', name) ilike ?', ["$name%"]);
});
}
public function fio(): Attribute
{
return Attribute::make(
get: fn () => $this->last_name . " " . $this->name . " " . $this->middle_name,
);
}
}

View File

@ -4,6 +4,7 @@ namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
@ -17,7 +18,6 @@ class User extends Authenticatable
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
@ -44,4 +44,9 @@ class User extends Authenticatable
'password' => 'hashed',
];
}
public function userable(): MorphTo
{
return $this->morphTo();
}
}

View File

@ -2,6 +2,7 @@
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@ -19,6 +20,6 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
//
Paginator::useBootstrap();
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Providers;
use App\Http\Controllers\GradeController;
use App\Http\Controllers\StudentController;
use App\Http\Controllers\SubjectController;
use App\Http\Controllers\TeacherController;
use App\Services\GradeService;
use App\Services\ServiceInterface;
use App\Services\StudentService;
use App\Services\SubjectService;
use App\Services\TeacherService;
use Illuminate\Support\ServiceProvider;
class ModelServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->app->when(StudentController::class)
->needs(ServiceInterface::class)
->give(function () {
return new StudentService();
});
$this->app->when(TeacherController::class)
->needs(ServiceInterface::class)
->give(function () {
return new TeacherService();
});
$this->app->when(GradeController::class)
->needs(ServiceInterface::class)
->give(function () {
return new GradeService();
});
$this->app->when(SubjectController::class)
->needs(ServiceInterface::class)
->give(function () {
return new SubjectService();
});
}
/**
* Bootstrap services.
*/
public function boot(): void
{
//
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// Telescope::night();
$this->hideSensitiveRequestDetails();
$isLocal = $this->app->environment('local');
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
return $isLocal ||
$entry->isReportableException() ||
$entry->isFailedRequest() ||
$entry->isFailedJob() ||
$entry->isScheduledTask() ||
$entry->hasMonitoredTag();
});
}
/**
* Prevent sensitive request details from being logged by Telescope.
*/
protected function hideSensitiveRequestDetails(): void
{
if ($this->app->environment('local')) {
return;
}
Telescope::hideRequestParameters(['_token']);
Telescope::hideRequestHeaders([
'cookie',
'x-csrf-token',
'x-xsrf-token',
]);
}
/**
* Register the Telescope gate.
*
* This gate determines who can access Telescope in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
//
]);
});
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Services;
use App\Models\Grade;
use Illuminate\Pagination\LengthAwarePaginator;
class GradeService implements ServiceInterface
{
public function getAll(): LengthAwarePaginator
{
return Grade::filter()->paginate(10)->withQueryString();
}
public function create(array $data): Grade
{
return Grade::create($data);
}
public function update($model, array $data): Grade
{
$model->update($data);
return $model;
}
public function delete($model): void
{
$model->delete();
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Services;
interface ServiceInterface
{
public function getAll();
public function create(array $data);
public function update($model, array $data);
public function delete($model);
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Services;
use App\Models\Student;
use App\Models\Teacher;
use App\Models\User;
use Illuminate\Pagination\LengthAwarePaginator;
class StudentService implements ServiceInterface
{
public function getAll(): LengthAwarePaginator
{
return Student::filter()->paginate(10)->withQueryString();
}
public function create(array $data): Student
{
$user = User::create([
'email' => $data['email'],
'password' => $data['password'],
]);
$student = Student::create([
'name' => $data['name'],
'last_name' => $data['last_name'],
'middle_name' => $data['middle_name'],
'birthday' => $data['birthday'],
'grade_id' => $data['grade_id'],
]);
$student->user()->save($user);
return $student;
}
public function update($model, array $data): Student
{
$model->user()->update([
'email' => $data['email'],
'password' => $data['password'],
]);
$model->update([
'name' => $data['name'],
'last_name' => $data['last_name'],
'middle_name' => $data['middle_name'],
'birthday' => $data['birthday'],
'grade_id' => $data['grade_id'],
]);
return $model;
}
public function delete($model): void
{
$model->user()->delete();
$model->delete();
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Services;
use App\Models\Subject;
use Illuminate\Pagination\LengthAwarePaginator;
class SubjectService implements ServiceInterface
{
public function getAll(): LengthAwarePaginator
{
return Subject::filter()->paginate(10)->withQueryString();
}
public function create(array $data): Subject
{
return Subject::create($data);
}
public function update($model, array $data): Subject
{
$model->update($data);
return $model;
}
public function delete($model): void
{
$model->delete();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Services;
use App\Models\Student;
use App\Models\Teacher;
use App\Models\User;
use Illuminate\Pagination\LengthAwarePaginator;
class TeacherService implements ServiceInterface
{
public function getAll(): LengthAwarePaginator
{
return Teacher::filter()->paginate(2)->withQueryString();
}
public function create(array $data): Teacher
{
$user = User::create([
'email' => $data['email'],
'password' => $data['password'],
]);
$teacher = Teacher::create([
'name' => $data['name'],
'last_name' => $data['last_name'],
'middle_name' => $data['middle_name'],
'birthday' => $data['birthday'],
]);
$teacher->user()->save($user);
return $teacher;
}
public function update($model, array $data): Teacher
{
$model->user()->update([
'email' => $data['email'],
'password' => $data['password'],
]);
$model->update([
'name' => $data['name'],
'last_name' => $data['last_name'],
'middle_name' => $data['middle_name'],
'birthday' => $data['birthday'],
]);
return $model;
}
public function delete($model): void
{
$model->user()->delete();
$model->delete();
}
}

View File

@ -2,4 +2,6 @@
return [
App\Providers\AppServiceProvider::class,
App\Providers\ModelServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
];

View File

@ -7,6 +7,7 @@
"require": {
"php": "^8.2",
"laravel/framework": "^11.0",
"laravel/telescope": "^5.0",
"laravel/tinker": "^2.9",
"laravel/ui": "^4.5"
},

71
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f67fa4f47f4251e2e6b9b94e684924ab",
"content-hash": "efdc2dc61a0b89c1445563f02629c5bd",
"packages": [
{
"name": "brick/math",
@ -1367,6 +1367,75 @@
},
"time": "2023-11-08T14:08:06+00:00"
},
{
"name": "laravel/telescope",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "b5f9783c8e1ec3ec387b289d3ca8a8f85e76b4fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/b5f9783c8e1ec3ec387b289d3ca8a8f85e76b4fb",
"reference": "b5f9783c8e1ec3ec387b289d3ca8a8f85e76b4fb",
"shasum": ""
},
"require": {
"ext-json": "*",
"laravel/framework": "^8.37|^9.0|^10.0|^11.0",
"php": "^8.0",
"symfony/console": "^5.3|^6.0|^7.0",
"symfony/var-dumper": "^5.0|^6.0|^7.0"
},
"require-dev": {
"ext-gd": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"laravel/octane": "^1.4|^2.0|dev-develop",
"orchestra/testbench": "^6.40|^7.37|^8.17|^9.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Telescope\\TelescopeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Telescope\\": "src/",
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mohamed Said",
"email": "mohamed@laravel.com"
}
],
"description": "An elegant debug assistant for the Laravel framework.",
"keywords": [
"debugging",
"laravel",
"monitoring"
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v5.0.4"
},
"time": "2024-04-22T09:19:03+00:00"
},
{
"name": "laravel/tinker",
"version": "v2.9.0",

205
config/telescope.php Normal file
View File

@ -0,0 +1,205 @@
<?php
use Laravel\Telescope\Http\Middleware\Authorize;
use Laravel\Telescope\Watchers;
return [
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => env('TELESCOPE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Telescope Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Telescope will be accessible from. If the
| setting is null, Telescope will reside under the same domain as the
| application. Otherwise, this value will be used as the subdomain.
|
*/
'domain' => env('TELESCOPE_DOMAIN'),
/*
|--------------------------------------------------------------------------
| Telescope Path
|--------------------------------------------------------------------------
|
| This is the URI path where Telescope will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('TELESCOPE_PATH', 'telescope'),
/*
|--------------------------------------------------------------------------
| Telescope Storage Driver
|--------------------------------------------------------------------------
|
| This configuration options determines the storage driver that will
| be used to store Telescope's data. In addition, you may set any
| custom options as needed by the particular driver you choose.
|
*/
'driver' => env('TELESCOPE_DRIVER', 'database'),
'storage' => [
'database' => [
'connection' => env('DB_CONNECTION', 'mysql'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Telescope Queue
|--------------------------------------------------------------------------
|
| This configuration options determines the queue connection and queue
| which will be used to process ProcessPendingUpdate jobs. This can
| be changed if you would prefer to use a non-default connection.
|
*/
'queue' => [
'connection' => env('TELESCOPE_QUEUE_CONNECTION', null),
'queue' => env('TELESCOPE_QUEUE', null),
],
/*
|--------------------------------------------------------------------------
| Telescope Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Telescope route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => [
'web',
Authorize::class,
],
/*
|--------------------------------------------------------------------------
| Allowed / Ignored Paths & Commands
|--------------------------------------------------------------------------
|
| The following array lists the URI paths and Artisan commands that will
| not be watched by Telescope. In addition to this list, some Laravel
| commands, like migrations and queue commands, are always ignored.
|
*/
'only_paths' => [
// 'api/*'
],
'ignore_paths' => [
'livewire*',
'nova-api*',
'pulse*',
],
'ignore_commands' => [
//
],
/*
|--------------------------------------------------------------------------
| Telescope Watchers
|--------------------------------------------------------------------------
|
| The following array lists the "watchers" that will be registered with
| Telescope. The watchers gather the application's profile data when
| a request or task is executed. Feel free to customize this list.
|
*/
'watchers' => [
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
Watchers\CacheWatcher::class => [
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
'hidden' => [],
],
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
Watchers\CommandWatcher::class => [
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
'ignore' => [],
],
Watchers\DumpWatcher::class => [
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
],
Watchers\EventWatcher::class => [
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
'ignore' => [],
],
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
Watchers\GateWatcher::class => [
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
'ignore_abilities' => [],
'ignore_packages' => true,
'ignore_paths' => [],
],
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
Watchers\LogWatcher::class => [
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
'level' => 'error',
],
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
Watchers\ModelWatcher::class => [
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
'events' => ['eloquent.*'],
'hydrations' => true,
],
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
Watchers\QueryWatcher::class => [
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
'ignore_packages' => true,
'ignore_paths' => [],
'slow' => 100,
],
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
Watchers\RequestWatcher::class => [
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
'ignore_http_methods' => [],
'ignore_status_codes' => [],
],
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
],
];

View File

@ -13,10 +13,10 @@ return new class extends Migration
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->nullableMorphs('userable');
$table->rememberToken();
$table->timestamps();
});

View File

@ -0,0 +1,31 @@
<?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('teachers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('last_name');
$table->string('middle_name')->nullable();
$table->date('birthday');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('teachers');
}
};

View File

@ -0,0 +1,31 @@
<?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('students', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('last_name');
$table->string('middle_name')->nullable();
$table->date('birthday');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('students');
}
};

View File

@ -0,0 +1,27 @@
<?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('admins', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('admins');
}
};

View File

@ -0,0 +1,28 @@
<?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('subject_teacher', function (Blueprint $table) {
$table->foreignId('subject_id')->constrained('subjects')->onDelete('cascade');
$table->foreignId('teacher_id')->constrained('teachers')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('subject_teacher');
}
};

View File

@ -0,0 +1,28 @@
<?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('grade_teacher', function (Blueprint $table) {
$table->foreignId('grade_id')->constrained('grades')->onDelete('cascade');
$table->foreignId('teacher_id')->constrained('teachers')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('grade_teacher');
}
};

View File

@ -0,0 +1,28 @@
<?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::table('students', function (Blueprint $table) {
$table->foreignId('grade_id')->constrained('grades')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('students', function (Blueprint $table) {
$table->dropColumn('grade_id');
});
}
};

View File

@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Get the migration connection name.
*/
public function getConnection(): ?string
{
return config('telescope.storage.database.connection');
}
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->getConnection());
$schema->create('telescope_entries', function (Blueprint $table) {
$table->bigIncrements('sequence');
$table->uuid('uuid');
$table->uuid('batch_id');
$table->string('family_hash')->nullable();
$table->boolean('should_display_on_index')->default(true);
$table->string('type', 20);
$table->longText('content');
$table->dateTime('created_at')->nullable();
$table->unique('uuid');
$table->index('batch_id');
$table->index('family_hash');
$table->index('created_at');
$table->index(['type', 'should_display_on_index']);
});
$schema->create('telescope_entries_tags', function (Blueprint $table) {
$table->uuid('entry_uuid');
$table->string('tag');
$table->primary(['entry_uuid', 'tag']);
$table->index('tag');
$table->foreign('entry_uuid')
->references('uuid')
->on('telescope_entries')
->onDelete('cascade');
});
$schema->create('telescope_monitoring', function (Blueprint $table) {
$table->string('tag')->primary();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$schema = Schema::connection($this->getConnection());
$schema->dropIfExists('telescope_entries_tags');
$schema->dropIfExists('telescope_entries');
$schema->dropIfExists('telescope_monitoring');
}
};

8
public/vendor/telescope/app-dark.css vendored Normal file

File diff suppressed because one or more lines are too long

7
public/vendor/telescope/app.css vendored Normal file

File diff suppressed because one or more lines are too long

2
public/vendor/telescope/app.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
public/vendor/telescope/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,5 @@
{
"/app.js": "/app.js?id=7049e92a398e816f8cd53a915eaea592",
"/app-dark.css": "/app-dark.css?id=1ea407db56c5163ae29311f1f38eb7b9",
"/app.css": "/app.css?id=de4c978567bfd90b38d186937dee5ccf"
}

View File

@ -1,7 +1,7 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-7">
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">{{__('Новый класс')}}</div>

View File

@ -1,20 +1,21 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-5">
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card mt-4">
<div class="card-header" {{ __('Класс') }}}>
<div class="card">
<div class="card-header">{{ ('Класс') }}</div>
<div class="card-body">
<div class="mb-3">
<h4><strong>Название:</strong> {{ $grade->name }}</h4>
<h5><strong>Название: </strong>{{ $grade->name }}</h5>
</div>
<div>
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-warning">Редактировать</a>
</div>
<div class="card-footer">
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-primary">Редактировать</a>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,9 +1,10 @@
<div class="container">
<footer class="footer py-3 my-4">
<ul class="nav justify-content-center pb-3 mb-3">
<li class="nav-item"><a href="{{ route('grades.index') }}" class="nav-link px-2 text-muted">Группы</a></li>
<li class="nav-item"><a href="{{ route('grades.index') }}" class="nav-link px-2 text-muted">Классы</a></li>
<li class="nav-item"><a href="{{ route('subjects.index') }}" class="nav-link px-2 text-muted">Предметы</a></li>
{{-- <li class="nav-item"><a href="{{ route('users.index') }}" class="nav-link px-2 text-muted">Студенты</a></li>--}}
<li class="nav-item"><a href="{{ route('students.index') }}" class="nav-link px-2 text-muted">Студенты</a></li>
<li class="nav-item"><a href="{{ route('teachers.index') }}" class="nav-link px-2 text-muted">Учителя</a></li>
</ul>
<p class="text-center text-muted">&copy; 2024 EduDiary</p>
</footer>

View File

@ -1,9 +1,10 @@
<div class="container">
<header class="d-flex justify-content-center py-3">
<ul class="nav nav-pills">
<li class="nav-item"><a href="{{ route('grades.index') }}" class="nav-link @if(request()->is('grades*')) active @endif" aria-current="page">Группы</a></li>
<li class="nav-item"><a href="{{ route('grades.index') }}" class="nav-link @if(request()->is('grades*')) active @endif" aria-current="page">Классы</a></li>
<li class="nav-item"><a href="{{ route('subjects.index') }}" class="nav-link @if(request()->is('subjects*')) active @endif">Предметы</a></li>
{{-- <li class="nav-item"><a href="{{ route('users.index') }}" class="nav-link @if(request()->is('users*')) active @endif">Студенты</a></li>--}}
<li class="nav-item"><a href="{{ route('students.index') }}" class="nav-link @if(request()->is('students*')) active @endif">Ученики</a></li>
<li class="nav-item"><a href="{{ route('teachers.index') }}" class="nav-link @if(request()->is('teachers*')) active @endif">Учителя</a></li>
</ul>
</header>
</div>

View File

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
@include('students.form', ['route' => route('students.store'), 'method' => 'POST'])
@endsection

View File

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
@include('students.form', ['route' => route('students.update', $user), 'method' => 'PUT'])
@endsection

View File

@ -0,0 +1,48 @@
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card mt-4">
<div class="card-body">
<form action="{{ $route }}" method="POST">
@csrf
@method($method)
<div class="mb-3">
<label for="name" class="form-label">Имя:</label>
<input type="text" id="name" name="name" class="form-control" value="{{ isset($student) ? $student->name : old('name') }}" required>
</div>
<div class="mb-3">
<label for="last_name" class="form-label">Фамилия:</label>
<input type="text" id="last_name" name="last_name" class="form-control" value="{{ isset($student) ? $student->last_name : old('last_name') }}" required>
</div>
<div class="mb-3">
<label for="middle_name" class="form-label">Отчество:</label>
<input type="text" id="middle_name" name="middle_name" class="form-control" value="{{ isset($student) ? $student->middle_name : old('middle_name') }}" required>
</div>
<div class="mb-3">
<label for="birthday" class="form-label">Дата рождения:</label>
<input type="date" id="birthday" name="birthday" class="form-control" value="{{ isset($student) ? $student->birthday : old('birthday') }}" required>
</div>
<div class="mb-3">
<label for="grade_id" class="form-label">Класс:</label>
<select id="grade_id" name="grade_id" class="form-select" required>
<option value="">Выберите класс</option>
@foreach($grades as $grade)
<option value="{{ $grade->id }}" {{ isset($student) && $student->grade_id == $grade->id ? 'selected' : '' }}>
{{ $grade->name }}
</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label for="email" class="form-label">Эл. почта:</label>
<input type="text" id="email" name="email" class="form-control" value="{{ isset($student) ? $student->email : old('email') }}" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль:</label>
<input type="text" id="password" name="password" class="form-control" value="{{ isset($student) ? $student->password : old('password') }}" required>
</div>
<button type="submit" class="btn btn-success">Подтвердить</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,66 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">{{__('Новый ученик')}}</div>
<div class="card-body">
<a href="{{ route('students.create') }}" class="btn btn-success">Добавить</a>
</div>
</div>
<div class="card mt-4">
<div class="card-header">{{__('Поиск ученика')}}</div>
<div class="card-body">
<form action="{{ route('students.index') }}" method="GET">
<div class="mb-3">
<label for="name" class="form-label">ФИО:</label>
<input type="text" id="name" name="name" class="form-control" value="{{ request('name') ?? '' }}">
</div>
<div>
<button type="submit" class="btn btn-primary">Фильтр</button>
</div>
</form>
</div>
</div>
@if (count($students))
<div class="card mt-4">
<div class="card-header">{{__('Ученики')}}</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<th>ФИО</th>
<th>&nbsp;</th>
</thead>
<tbody>
@foreach ($students as $student)
<tr>
<td class="table-text">
<div>
<a href="{{ route('students.show', $student) }}" class="btn btn-block col-8">{{ $student->last_name }} {{ $student->name }} {{ $student->middle_name }}</a>
</div>
</td>
<td>
<div>
<a href="{{ route('students.edit', $student) }}" class="btn btn-warning">Редактировать</a>
</div>
</td>
<td>
<form action="{{ route('students.destroy', $student) }}" method="POST" style="display: inline-block;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger">Удалить</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="card-footer">{{ $students->links() }}</div>
</div>
@endif
</div>
</div>
@endsection

View File

@ -0,0 +1,26 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">{{ ('Ученик') }}</div>
<div class="card-body">
<div class="mb-3">
<h5><strong>ФИО: </strong>{{ $student->fio }}</h5>
</div>
<div class="mb-3">
<h5><strong>Класс: </strong>{{ $student->grade->name }}</h5>
</div>
<div class="mb-3">
<h5><strong>Дата рождения: </strong>{{ $student->birthday }}</h5>
</div>
</div>
<div class="card-footer">
<a href="{{ route('students.edit', $student) }}" class="btn btn-primary">Редактировать</a>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,16 +1,17 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card mt-4 col-4">
<div class="card-header" {{ __('Предмет') }}>
<div class="card">
<div class="card-header">{{ ('Предмет') }}</div>
<div class="card-body">
<div class="mb-3">
<h4><strong>Название:</strong> {{ $subject->name }}</h4>
<h5><strong>Название: </strong>{{ $subject->name }}</h5>
</div>
<div>
<a href="{{ route('subjects.edit', $subject) }}" class="btn btn-warning">Редактировать</a>
</div>
<div class="card-footer">
<a href="{{ route('subjects.edit', $subject) }}" class="btn btn-primary">Редактировать</a>
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
@include('teachers.form', ['route' => route('teachers.store'), 'method' => 'POST'])
@endsection

View File

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
@include('teachers.form', ['route' => route('teachers.update', $user), 'method' => 'PUT'])
@endsection

View File

@ -0,0 +1,37 @@
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card mt-4">
<div class="card-body">
<form action="{{ $route }}" method="POST">
@csrf
@method($method)
<div class="mb-3">
<label for="name" class="form-label">Имя:</label>
<input type="text" id="name" name="name" class="form-control" value="{{ isset($teacher) ? $teacher->name : old('name') }}" required>
</div>
<div class="mb-3">
<label for="last_name" class="form-label">Фамилия:</label>
<input type="text" id="last_name" name="last_name" class="form-control" value="{{ isset($teacher) ? $teacher->last_name : old('last_name') }}" required>
</div>
<div class="mb-3">
<label for="middle_name" class="form-label">Отчество:</label>
<input type="text" id="middle_name" name="middle_name" class="form-control" value="{{ isset($teacher) ? $teacher->middle_name : old('middle_name') }}" required>
</div>
<div class="mb-3">
<label for="birthday" class="form-label">Дата рождения:</label>
<input type="date" id="birthday" name="birthday" class="form-control" value="{{ isset($teacher) ? $teacher->birthday : old('birthday') }}" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Эл. почта:</label>
<input type="text" id="email" name="email" class="form-control" value="{{ isset($teacher) ? $teacher->email : old('email') }}" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль:</label>
<input type="text" id="password" name="password" class="form-control" value="{{ isset($teacher) ? $teacher->password : old('password') }}" required>
</div>
<button type="submit" class="btn btn-success">Подтвердить</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,66 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">{{__('Новый учитель')}}</div>
<div class="card-body">
<a href="{{ route('teachers.create') }}" class="btn btn-success">Добавить</a>
</div>
</div>
<div class="card mt-4">
<div class="card-header">{{__('Поиск учителя')}}</div>
<div class="card-body">
<form action="{{ route('teachers.index') }}" method="GET">
<div class="mb-3">
<label for="name" class="form-label">ФИО:</label>
<input type="text" id="name" name="name" class="form-control" value="{{ request('name') ?? '' }}">
</div>
<div>
<button type="submit" class="btn btn-primary">Фильтр</button>
</div>
</form>
</div>
</div>
@if (count($teachers))
<div class="card mt-4">
<div class="card-header">{{__('Учителя')}}</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<th>ФИО</th>
<th>&nbsp;</th>
</thead>
<tbody>
@foreach ($teachers as $teacher)
<tr>
<td class="table-text">
<div>
<a href="{{ route('teachers.show', $teacher) }}" class="btn btn-block col-8">{{ $teacher->last_name }} {{ $teacher->name }} {{ $teacher->middle_name }}</a>
</div>
</td>
<td>
<div>
<a href="{{ route('teachers.edit', $teacher) }}" class="btn btn-warning">Редактировать</a>
</div>
</td>
<td>
<form action="{{ route('teachers.destroy', $teacher) }}" method="POST" style="display: inline-block;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger">Удалить</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="card-footer">{{ $teachers->links() }}</div>
</div>
@endif
</div>
</div>
@endsection

View File

@ -0,0 +1,23 @@
@extends('layouts.app')
@section('content')
<div class="container col-md-6">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">{{ ('Учитель') }}</div>
<div class="card-body">
<div class="mb-3">
<h5><strong>ФИО: </strong>{{ $teacher->fio }}</h5>
</div>
<div class="mb-3">
<h5><strong>Дата рождения: </strong>{{ $teacher->birthday }}</h5>
</div>
</div>
<div class="card-footer">
<a href="{{ route('teachers.edit', $teacher) }}" class="btn btn-primary">Редактировать</a>
</div>
</div>
</div>
</div>
@endsection

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,16 @@
<?php
use App\Http\Controllers\GradeController;
use App\Http\Controllers\StudentController;
use App\Http\Controllers\SubjectController;
use App\Http\Controllers\TeacherController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
return redirect()->route('grades.index');
});
Route::resource('grades', GradeController::class);
Route::resource('subjects', SubjectController::class);
Route::resource('students', StudentController::class);
Route::resource('teachers', TeacherController::class);