240 lines
9.7 KiB
PHP

<?php declare(strict_types=1);
namespace App\Services\Admin\Project;
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
use App\Dto\QuerySettingsDto;
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
use App\Models\Documentation;
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\Documentation\DocumentationCommandHandler;
use App\Services\DocumentationContent\ModelSyncCommand;
use App\Services\Service;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\DB;
final class DocumentationService extends Service
{
public function __construct(
private readonly DocumentationVersionRepository $documentationVersionRepository,
private readonly DocumentationCategoryRepository $documentationCategoryRepository,
private readonly DocumentationRepository $documentationRepository,
private readonly DocumentationCommandHandler $documentationCommandHandler,
private readonly ModelSyncCommand $contentSaveCommand,
) { }
public function index(int $projectId, int $versionId, DocumentationBuilderDto $documentationBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
{
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
if ($user->cannot('viewAny', Documentation::class)) {
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);
});
}
];
$with = array_merge($with, $querySettingsDto->getQueryWith());
$documentations = $this->documentationRepository->getDocumentations(
$version->id,
$documentationBuilderDto,
$with
)->pagination(
$querySettingsDto->getLimit(),
$querySettingsDto->getPage()
);
return $this->result([
'version' => $version,
'project' => $project,
'documentations' => $documentations,
]);
}
public function create(int $projectId, int $versionId, User $user): ServiceResultError | ServiceResultArray
{
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
if ($user->cannot('create', Documentation::class)) {
return $this->errFobidden(__('Access is denied'));
}
$defaultLanguage = $project->languages->where('is_default', 1)->first();
return $this->result([
'version' => $version,
'project' => $project,
'documentation' => new Documentation(),
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage),
]);
}
public function edit(int $projectId, int $versionId, int $documentationId, User $user): ServiceResultError | ServiceResultArray
{
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
$documentation = $this->documentationRepository->getDocumentationById($documentationId);
if (\is_null($documentation)) {
return $this->errNotFound(__('Not Found'));
}
if ($user->cannot('view', $documentation)) {
return $this->errFobidden(__('Access is denied'));
}
$withCategories = [];
if ($documentation->category_id) {
$withCategories[] = $documentation->category_id;
}
$defaultLanguage = $project->languages->where('is_default', 1)->first();
return $this->result([
'version' => $version,
'project' => $project,
'documentation' => $documentation,
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage, null, $withCategories),
]);
}
public function store(int $projectId, int $versionId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
{
if ($user->cannot('create', Documentation::class)) {
return $this->errFobidden(__('Access is denied'));
}
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
if ($this->documentationRepository->isExistsSlug($versionId, $data->getSlug()) !== false) {
return $this->errValidate(
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
);
}
try {
$documentation = DB::transaction(function () use ($data, $version, $user, $project) {
$dataDocumentation = $this->getDataDocumentation($data);
$documentation = $this->documentationCommandHandler->handleStore($version, $dataDocumentation);
$this->contentSaveCommand->execute($project, $documentation, $data->getContents());
return $documentation;
});
} catch (\Throwable $e) {
report($e);
return $this->errService(__('Server Error'));
}
return $this->resultStoreUpdateModel($documentation, __('Documentation created successfully'));
}
public function update(int $projectId, int $versionId, int $documentationId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
{
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
$documentation = $this->documentationRepository->getDocumentationById($documentationId);
if (\is_null($documentation)) {
return $this->errNotFound(__('Not Found'));
}
if ($user->cannot('view', $documentation)) {
return $this->errFobidden(__('Access is denied'));
}
if ($this->documentationRepository->isExistsSlug($versionId, $data->getSlug(), $documentation->id) !== false) {
return $this->errValidate(
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
);
}
try {
$documentation = DB::transaction(function () use ($data, $documentation, $project) {
$dataDocumentation = $this->getDataDocumentation($data);
$documentation = $this->documentationCommandHandler->handleUpdate($documentation, $dataDocumentation);
$this->contentSaveCommand->execute($project, $documentation, $data->getContents());
return $documentation;
});
} catch (\Throwable $e) {
report($e);
return $this->errService(__('Server Error'));
}
return $this->resultStoreUpdateModel($documentation, __('Documentation updated successfully'));
}
public function destroy(int $projectId, int $versionId, int $documentationId, User $user): ServiceResultError|ServiceResultSuccess
{
$version = $this->documentationVersionRepository->getVersionById($versionId);
$project = $version?->project;
if (\is_null($version) || $project?->id !== $projectId) {
return $this->errNotFound(__('Not Found'));
}
$documentation = $this->documentationRepository->getDocumentationById($documentationId);
if (\is_null($documentation)) {
return $this->errNotFound(__('Not Found'));
}
if ($user->cannot('delete', $documentation)) {
return $this->errFobidden(__('Access is denied'));
}
try {
DB::transaction(function () use ($documentation) {
$this->documentationCommandHandler->handleDestroy($documentation);
});
} catch (\Throwable $e) {
report($e);
return $this->errService(__('Server Error'));
}
return $this->ok(__('Documentation successfully removed'));
}
private function getDataDocumentation(StoreUpdate $data): array
{
return [
'slug' => $data->getSlug(),
'is_public' => $data->isPublic(),
'sort' => $data->getSort(),
'category_id' => $data->getCategoryId(),
];
}
}