Migrate backend to Porto architecture and fix minor bugs

- Fully transitioned the backend to the Porto architectural pattern
- Improved code organization and maintainability
- Fixed minor bugs and inconsistencies
This commit is contained in:
F4ilji
2025-05-12 08:47:43 +05:00
parent 76deaf75f3
commit c01016a154
620 changed files with 16218 additions and 6073 deletions
@@ -0,0 +1,105 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Controllers;
use App\Containers\InstituteStructure\Models\Department;
use App\Containers\InstituteStructure\Models\Faculty;
use App\Containers\InstituteStructure\UI\WEB\Transformers\DepartmentPreviewResource;
use App\Containers\InstituteStructure\UI\WEB\Transformers\DepartmentResource;
use App\Ship\Contracts\SeoServiceInterface;
use App\Ship\Controllers\Controller;
use App\Ship\Enums\CacheKeys;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
class ClientDepartmentController extends Controller
{
public function __construct(readonly SeoServiceInterface $seoPageProvider){}
public function show(string $facultySlug, string $departmentSlug)
{
// Ключ для кеширования
$cacheKey = "{$facultySlug}_{$departmentSlug}";
// Кешируем факультет
$faculty = Cache::remember(
CacheKeys::FACULTY_PREFIX->value . $facultySlug,
now()->addDay(),
function () use ($facultySlug) {
return Faculty::query()
->where('slug', $facultySlug)
->first();
}
);
// Кешируем список активных кафедр факультета
$departments = Cache::remember(
CacheKeys::DEPARTMENTS_PREFIX->value . 'active_' . $faculty->id,
now()->addDay(),
function () use ($faculty) {
return DepartmentPreviewResource::collection(
Department::query()
->where('is_active', true)
->where('faculty_id', $faculty->id)
->get()
);
}
);
$departmentModel = Cache::remember(
CacheKeys::DEPARTMENT_PREFIX->value . $cacheKey,
now()->addDay(),
function () use ($departmentSlug) {
return Department::query()
->where('slug', $departmentSlug)
->where('is_active', true)
->with([
'faculty',
'workers.userDetail',
'teachers.userDetail',
'programs.directionStudy',
'seo'
])
->firstOrFail();
}
);
$seo = Cache::remember(
CacheKeys::DEPARTMENT_PREFIX->value . 'seo_' . $cacheKey,
now()->addDay(),
function () use ($departmentModel) {
return $this->seoPageProvider->getSeoForModel($departmentModel);
}
);
$department = new DepartmentResource($departmentModel);
$directions = Cache::remember(
CacheKeys::DEPARTMENT_PREFIX->value . 'directions_' . $cacheKey,
now()->addDay(),
function () use ($department) {
return $this->groupProgramsByDirection($department->programs);
}
);
return Inertia::render('Client/Departments/Show', compact(
'department',
'departments',
'directions',
'seo',
));
}
private function groupProgramsByDirection(Collection $programs): Collection
{
// Группируем программы по имени направления
return $programs->groupBy(function ($program) {
return $program->directionStudy->code . " " . $program->directionStudy->name; // Используем имя направления как ключ
});
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Controllers;
use App\Containers\InstituteStructure\Models\Division;
use App\Containers\InstituteStructure\UI\WEB\Transformers\DivisionResource;
use App\Ship\Contracts\SeoServiceInterface;
use App\Ship\Controllers\Controller;
use App\Ship\Enums\CacheKeys;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
class ClientDivisionController extends Controller
{
public function __construct(readonly SeoServiceInterface $seoPageProvider){}
public function index()
{
$divisions = Cache::remember(CacheKeys::DIVISIONS_PREFIX->value . 'list', now()->addDay(), function () {
return DivisionResource::collection(
Division::query()->where('is_active', true)->get()
);
});
$seo = Cache::remember(CacheKeys::DIVISIONS_PREFIX->value . 'seo', now()->addDay(), function () {
return $this->seoPageProvider->getSeoForCurrentPage();
});
return Inertia::render('Client/Divisions/Index', compact('divisions', 'seo'));
}
public function show(string $slug): \Inertia\Response
{
$divisions = Cache::remember(CacheKeys::DIVISIONS_PREFIX->value . 'list', now()->addDay(), function () {
return DivisionResource::collection(
Division::query()->where('is_active', true)->get()
);
});
$divisionData = Cache::remember(CacheKeys::DIVISION_PREFIX->value . $slug, now()->addDay(), function () use ($slug) {
return Division::with(['workers.userDetail', 'seo'])->where('is_active', true)->where('slug', $slug)->firstOrFail();
});
$seo = $this->seoPageProvider->getSeoForModel($divisionData);
$division = new DivisionResource($divisionData);
return Inertia::render('Client/Divisions/Show', compact('divisions', 'division', 'seo'));
}
}
@@ -0,0 +1,83 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Controllers;
use App\Containers\InstituteStructure\Models\Faculty;
use App\Containers\InstituteStructure\UI\WEB\Transformers\FacultyPreviewResource;
use App\Containers\InstituteStructure\UI\WEB\Transformers\FacultyResource;
use App\Ship\Contracts\SeoServiceInterface;
use App\Ship\Controllers\Controller;
use App\Ship\Enums\CacheKeys;
use App\Ship\Requests\Request;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
class ClientFacultyController extends Controller
{
public function __construct(readonly SeoServiceInterface $seoPageProvider){}
public function index(Request $request)
{
$faculties = Cache::remember(
CacheKeys::FACULTIES_PREFIX->value . 'active_list',
now()->addDay(), // Кешируем на 1 день
function () {
return FacultyPreviewResource::collection(
Faculty::query()
->where('is_active', true)
->get()
);
}
);
$seo = $this->seoPageProvider->getSeoForCurrentPage();
return Inertia::render('Client/Faculties/Index', compact('faculties', 'seo'));
}
public function show(string $slug)
{
// Кешируем список факультетов
$faculties = Cache::remember(
CacheKeys::FACULTIES_PREFIX->value . 'active_list',
now()->addDay(),
function () {
return FacultyPreviewResource::collection(
Faculty::query()
->where('is_active', true)
->get()
);
}
);
// Кешируем данные конкретного факультета
$faculty = Cache::remember(
CacheKeys::FACULTY_PREFIX->value . $slug,
now()->addDay(),
function () use ($slug) {
return Faculty::where('slug', $slug)
->where('is_active', true)
->with(['departments.faculty', 'workers', 'seo'])
->firstOrFail();
}
);
$seo = Cache::remember(
CacheKeys::FACULTY_PREFIX->value . "SEO_" . $slug,
now()->addDay(),
function () use ($faculty) {
return $this->seoPageProvider->getSeoForModel($faculty);
}
);
$faculty = new FacultyResource($faculty);
return Inertia::render('Client/Faculties/Show', compact('faculty', 'faculties', 'seo'));
}
}
@@ -0,0 +1,21 @@
<?php
use App\Containers\InstituteStructure\UI\WEB\Controllers\ClientDepartmentController;
use App\Containers\InstituteStructure\UI\WEB\Controllers\ClientDivisionController;
use App\Containers\InstituteStructure\UI\WEB\Controllers\ClientFacultyController;
use Illuminate\Support\Facades\Route;
Route::middleware('access-check')->group(function () {
// Факультеты и кафедры
Route::get('/faculties', [ClientFacultyController::class, 'index'])->name('client.faculty.index');
Route::get('/faculties/{slug}', [ClientFacultyController::class, 'show'])->name('client.faculty.show');
Route::get('/faculties/{facultySlug}/{departmentSlug}', [ClientDepartmentController::class, 'show'])->name('client.department.show');
// Подразделения института
Route::get('/divisions', [ClientDivisionController::class, 'index'])->name('client.division.index');
Route::get('/divisions/{slug}', [ClientDivisionController::class, 'show'])->name('client.division.show');
});
@@ -0,0 +1,23 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Transformers;
use App\Ship\Resources\JsonResource;
class DepartmentPreviewResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
];
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Transformers;
use App\Containers\User\UI\WEB\Transformers\PersonDepartmentPreviewResource;
use App\Containers\User\UI\WEB\Transformers\PersonDepartmentTeachPreviewResource;
use App\Ship\Resources\JsonResource;
class DepartmentResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'faculty' => $this->faculty,
'slug' => $this->slug,
'workers' => PersonDepartmentPreviewResource::collection($this->workers),
'teachers' => PersonDepartmentTeachPreviewResource::collection($this->teachers),
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Transformers;
use App\Containers\User\UI\WEB\Transformers\PersonDivisionPreviewResource;
use App\Ship\Resources\JsonResource;
class DivisionResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'workers' => PersonDivisionPreviewResource::collection($this->whenLoaded('workers')),
'description' => $this->description,
];
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Transformers;
use App\Ship\Resources\JsonResource;
class FacultyPreviewResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'shortTitle' => $this->abbreviation,
'slug' => $this->slug,
];
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Containers\InstituteStructure\UI\WEB\Transformers;
use App\Containers\User\UI\WEB\Transformers\PersonFacultyPreviewResource;
use App\Ship\Resources\JsonResource;
class FacultyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'shortTitle' => $this->abbreviation,
'slug' => $this->slug,
'workers' => PersonFacultyPreviewResource::collection($this->workers),
'departments' => DepartmentPreviewResource::collection($this->departments)
];
}
}