This commit is contained in:
F4ilji
2026-04-07 17:54:26 +05:00
parent 04adba6682
commit 936b1fb5b0
468 changed files with 43498 additions and 4176 deletions
@@ -0,0 +1,27 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
use App\Containers\User\Models\User;
use App\Services\App\Cache\DivisionCacheService;
class AttachDivisionWorkerAction
{
public function __construct(
private readonly DivisionCacheService $cacheService,
) {}
public function run(Division $division, User $user, array $data): void
{
$division->workers()->attach($user->id, [
'administrativePosition' => $data['administrativePosition'],
'service_email' => $data['service_email'] ?? null,
'service_phone' => $data['service_phone'] ?? null,
'cabinet' => $data['cabinet'] ?? null,
'sort' => $data['sort'] ?? $division->workers()->count(),
]);
$this->cacheService->clearAllCacheByModel();
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\Dashboard\Tasks\Content\GenerateSearchDataTask;
use App\Containers\InstituteStructure\Models\Division;
use Illuminate\Support\Str;
class CreateDivisionAction
{
public function __construct(
private readonly GenerateSearchDataTask $generateSearchDataTask,
) {}
public function run(array $data): Division
{
// Генерируем slug если не передан
if (empty($data['slug'])) {
$data['slug'] = Str::slug($data['title']);
}
// Генерируем search_data из описания
if (!empty($data['description'])) {
$data['search_data'] = $this->generateSearchDataTask->run($data['description']);
}
$division = Division::create($data);
// Создаем SEO
$this->generateSeo($division, $data);
return $division;
}
private function generateSeo(Division $division, array $data): void
{
$title = $data['title'] ?? '';
$description = null;
// Извлекаем description из первого paragraph блока
if (!empty($data['description'])) {
foreach ($data['description'] as $block) {
if ($block['type'] === 'paragraph') {
$description = strip_tags($block['data']['content']);
break;
}
}
}
$division->seo()->create([
'title' => $title,
'description' => Str::limit(htmlspecialchars($description ?? '', ENT_QUOTES, 'UTF-8'), 160),
]);
}
}
@@ -0,0 +1,13 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
class DeleteDivisionAction
{
public function run(Division $division): void
{
$division->delete();
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
use App\Containers\User\Models\User;
use App\Services\App\Cache\DivisionCacheService;
class DetachDivisionWorkerAction
{
public function __construct(
private readonly DivisionCacheService $cacheService,
) {}
public function run(Division $division, User $worker): void
{
$division->workers()->detach($worker->id);
$this->cacheService->clearAllCacheByModel();
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
use Illuminate\Database\Eloquent\Builder;
class ListDivisionWorkersAction
{
public function run(Division $division, array $filters = []): array
{
$query = $division->workers()
->withPivot(['administrativePosition', 'sort', 'service_email', 'service_phone', 'cabinet'])
->whereHas('userDetail');
// Поиск по ФИО
if (!empty($filters['search'])) {
$query->where('name', 'like', '%' . $filters['search'] . '%');
}
// Фильтр по должности
if (!empty($filters['position'])) {
$query->where('division_user.administrativePosition', 'like', '%' . $filters['position'] . '%');
}
$workers = $query->orderBy('division_user.sort')->paginate(20)->withQueryString();
return [
'workers' => $workers,
'filters' => $filters,
];
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
class ListDivisionsAction
{
public function run(array $filters = []): array
{
$query = Division::query();
// Фильтр по статусу (по умолчанию только активные)
if (isset($filters['is_active']) && $filters['is_active'] !== '') {
$query->where('is_active', (bool) $filters['is_active']);
} elseif (!isset($filters['is_active'])) {
$query->where('is_active', true);
}
// Поиск по названию
if (!empty($filters['search'])) {
$query->where('title', 'like', '%' . $filters['search'] . '%')
->orWhere('slug', 'like', '%' . $filters['search'] . '%');
}
$divisions = $query->orderBy('created_at', 'desc')->paginate(20)->withQueryString();
return [
'divisions' => $divisions,
'filters' => $filters,
];
}
}
@@ -0,0 +1,56 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\Dashboard\Tasks\Content\GenerateSearchDataTask;
use App\Containers\InstituteStructure\Models\Division;
use Illuminate\Support\Str;
class UpdateDivisionAction
{
public function __construct(
private readonly GenerateSearchDataTask $generateSearchDataTask,
) {}
public function run(Division $division, array $data): Division
{
// Генерируем search_data из описания только если описание передано и не пусто
if (isset($data['description']) && !empty($data['description'])) {
$data['search_data'] = $this->generateSearchDataTask->run($data['description']);
}
$division->update($data);
// Обновляем SEO
$this->updateSeo($division, $data);
return $division;
}
private function updateSeo(Division $division, array $data): void
{
$title = $data['title'] ?? $division->title;
$description = null;
// Извлекаем description из первого paragraph блока
if (!empty($data['description'])) {
foreach ($data['description'] as $block) {
if ($block['type'] === 'paragraph') {
$description = strip_tags($block['data']['content']);
break;
}
}
}
$seoData = [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description ?? '', ENT_QUOTES, 'UTF-8'), 160),
];
if ($division->seo) {
$division->seo->update($seoData);
} else {
$division->seo()->create($seoData);
}
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Containers\Dashboard\Actions\Divisions;
use App\Containers\InstituteStructure\Models\Division;
use App\Containers\User\Models\User;
use App\Services\App\Cache\DivisionCacheService;
class UpdateDivisionWorkerAction
{
public function __construct(
private readonly DivisionCacheService $cacheService,
) {}
public function run(Division $division, User $worker, array $data): void
{
$division->workers()->updateExistingPivot($worker->id, [
'administrativePosition' => $data['administrativePosition'],
'service_email' => $data['service_email'] ?? null,
'service_phone' => $data['service_phone'] ?? null,
'cabinet' => $data['cabinet'] ?? null,
]);
$this->cacheService->clearAllCacheByModel();
}
}