- Introduce routes and controller actions for displaying and managing documentation by category. - Adjust views to incorporate category-specific information and actions. - Update services to handle category retrieval and validation. - Add localized strings for new functionality in English and Russian.
277 lines
11 KiB
PHP
277 lines
11 KiB
PHP
<?php declare(strict_types=1);
|
|
|
|
namespace App\Services\Admin\Project;
|
|
|
|
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
|
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
|
use App\Dto\QuerySettingsDto;
|
|
use App\Dto\Builder\DocumentationVersion as DocumentationVersionBuilderDto;
|
|
use App\Dto\Service\Admin\Project\DocumentationVersion\StoreUpdate;
|
|
use App\Enums\DocumentationVersionStatus;
|
|
use App\Models\DocumentationVersion;
|
|
use App\Models\ProjectLanguage;
|
|
use App\Models\User;
|
|
use App\Repositories\DocumentationCategoryRepository;
|
|
use App\Repositories\DocumentationRepository;
|
|
use App\Repositories\DocumentationVersionRepository;
|
|
use App\Repositories\ProjectRepository;
|
|
use App\ServiceResults\ServiceResultArray;
|
|
use App\ServiceResults\ServiceResultError;
|
|
use App\ServiceResults\ServiceResultSuccess;
|
|
use App\ServiceResults\StoreUpdateResult;
|
|
use App\Services\ClearCacheCommandHandler;
|
|
use App\Services\DocumentationVersion\DocumentationVersionCommandHandler;
|
|
use App\Services\Service;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
final class DocumentationVersionService extends Service
|
|
{
|
|
public function __construct(
|
|
private readonly ProjectRepository $projectRepository,
|
|
private readonly DocumentationVersionRepository $documentationVersionRepository,
|
|
private readonly DocumentationVersionCommandHandler $documentationVersionCommandHandler,
|
|
private readonly ClearCacheCommandHandler $clearCacheCommandHandler,
|
|
|
|
private readonly DocumentationCategoryRepository $documentationCategoryRepository,
|
|
private readonly DocumentationRepository $documentationRepository
|
|
) { }
|
|
|
|
public function index(int $projectId, DocumentationVersionBuilderDto $documentationVersionBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('viewAny', DocumentationVersion::class)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
$versions = $this->documentationVersionRepository->getVersions(
|
|
$project->id,
|
|
$documentationVersionBuilderDto,
|
|
$querySettingsDto->getQueryWith()
|
|
)->pagination(
|
|
$querySettingsDto->getLimit(),
|
|
$querySettingsDto->getPage()
|
|
);
|
|
|
|
return $this->result([
|
|
'versions' => $versions,
|
|
'project' => $project,
|
|
]);
|
|
}
|
|
|
|
public function show(int $projectId, int $versionId, ?int $categoryId, User $user): ServiceResultError | ServiceResultArray
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
|
if (\is_null($version)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('view', $version)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
$category = null;
|
|
if (!\is_null($categoryId)) {
|
|
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
|
if (\is_null($category) || $category->version_id !== $version->id) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
if ($user->cannot('view', $category)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
}
|
|
|
|
$defaultLanguage = $project->languages()->where('is_default', 1)->first();
|
|
$with = [
|
|
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
|
/** @var ?ProjectLanguage $defaultLanguage */
|
|
$hasOne->when($defaultLanguage, function (Builder $query, ProjectLanguage $defaultLanguage) {
|
|
$query->where('language_id', $defaultLanguage->id);
|
|
});
|
|
}
|
|
];
|
|
|
|
$categoryDto = new DocumentationCategoryBuilderDto\Category($category->id ?? null);
|
|
$categories = $this->documentationCategoryRepository
|
|
->getCategories(
|
|
$version->id,
|
|
new DocumentationCategoryBuilderDto(parentId: $categoryDto),
|
|
$with
|
|
)->all();
|
|
$documents = $this->documentationRepository
|
|
->getDocumentations(
|
|
$version->id,
|
|
new DocumentationBuilderDto(categoryId: $categoryDto),
|
|
$with
|
|
)->all();
|
|
|
|
return $this->result([
|
|
'version' => $version,
|
|
'project' => $project,
|
|
|
|
'category' => $category,
|
|
'categories' => $categories,
|
|
'documentations' => $documents,
|
|
]);
|
|
}
|
|
|
|
public function create(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('create', DocumentationVersion::class)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
return $this->result([
|
|
'version' => new DocumentationVersion(),
|
|
'statuses' => DocumentationVersionStatus::toCollection()->pluck( 'title', 'value')->toArray(),
|
|
'project' => $project,
|
|
]);
|
|
}
|
|
|
|
public function edit(int $projectId, int $versionId, User $user): ServiceResultError | ServiceResultArray
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
|
if (\is_null($version)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('view', $version)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
return $this->result([
|
|
'version' => $version,
|
|
'statuses' => DocumentationVersionStatus::toCollection()->pluck( 'title', 'value')->toArray(),
|
|
'project' => $project,
|
|
]);
|
|
}
|
|
|
|
public function store(int $projectId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
|
{
|
|
if ($user->cannot('create', DocumentationVersion::class)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($this->documentationVersionRepository->isExistsSlug($projectId, $data->getSlug()) !== false) {
|
|
return $this->errValidate(
|
|
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
|
|
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
|
|
);
|
|
}
|
|
|
|
try {
|
|
$version = DB::transaction(function () use ($data, $project, $user) {
|
|
$dataVersion = $this->getDataVersion($data);
|
|
return $this->documentationVersionCommandHandler->handleStore($project, $dataVersion);
|
|
});
|
|
$this->clearCacheCommandHandler->all();
|
|
} catch (\Throwable $e) {
|
|
report($e);
|
|
return $this->errService(__('Server Error'));
|
|
}
|
|
|
|
return $this->resultStoreUpdateModel($version, __('Documentation version created successfully'));
|
|
}
|
|
|
|
public function update(int $projectId, int $versionId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
|
if (\is_null($version)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('update', $version)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
if ($this->documentationVersionRepository->isExistsSlug($projectId, $data->getSlug(), $version->id) !== false) {
|
|
return $this->errValidate(
|
|
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
|
|
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
|
|
);
|
|
}
|
|
|
|
try {
|
|
$version = DB::transaction(function () use ($data, $version) {
|
|
$dataVersion = $this->getDataVersion($data);
|
|
return $this->documentationVersionCommandHandler->handleUpdate($version, $dataVersion);
|
|
});
|
|
$this->clearCacheCommandHandler->all();
|
|
} catch (\Throwable $e) {
|
|
report($e);
|
|
return $this->errService(__('Server Error'));
|
|
}
|
|
|
|
return $this->resultStoreUpdateModel($version, __('Documentation version updated successfully'));
|
|
}
|
|
|
|
public function destroy(int $projectId, int $versionId, User $user): ServiceResultError|ServiceResultSuccess
|
|
{
|
|
$project = $this->projectRepository->getProjectById($projectId);
|
|
if (\is_null($project)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
|
if (\is_null($version)) {
|
|
return $this->errNotFound(__('Not Found'));
|
|
}
|
|
|
|
if ($user->cannot('delete', $version)) {
|
|
return $this->errFobidden(__('Access is denied'));
|
|
}
|
|
|
|
try {
|
|
DB::transaction(function () use ($version) {
|
|
$this->documentationVersionCommandHandler->handleDestroy($version);
|
|
});
|
|
$this->clearCacheCommandHandler->all();
|
|
} catch (\Throwable $e) {
|
|
report($e);
|
|
return $this->errService(__('Server Error'));
|
|
}
|
|
|
|
return $this->ok(__('Documentation version successfully removed'));
|
|
}
|
|
|
|
private function getDataVersion(StoreUpdate $data): array
|
|
{
|
|
return [
|
|
'title' => $data->getTitle(),
|
|
'slug' => $data->getSlug(),
|
|
'is_public' => $data->isPublic(),
|
|
'status' => $data->getStatus(),
|
|
];
|
|
}
|
|
}
|