A documentation section has been added to the admin panel.
This commit is contained in:
15
app/application/app/Dto/Builder/Documentation.php
Normal file
15
app/application/app/Dto/Builder/Documentation.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
final readonly class Documentation
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
}
|
15
app/application/app/Dto/Builder/DocumentationCategory.php
Normal file
15
app/application/app/Dto/Builder/DocumentationCategory.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
final readonly class DocumentationCategory
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
}
|
15
app/application/app/Dto/Builder/DocumentationVersion.php
Normal file
15
app/application/app/Dto/Builder/DocumentationVersion.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Builder;
|
||||
|
||||
final readonly class DocumentationVersion
|
||||
{
|
||||
public function __construct(
|
||||
private ?bool $isPublic = null,
|
||||
) { }
|
||||
|
||||
public function isPublic(): ?bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\Documentation;
|
||||
|
||||
use App\Dto\Builder\Documentation;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private Documentation $documentation,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentation(): Documentation
|
||||
{
|
||||
return $this->documentation;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\Documentation;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private int $sort,
|
||||
private Contents $contents,
|
||||
private ?int $categoryId,
|
||||
) { }
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getCategoryId(): ?int
|
||||
{
|
||||
return $this->categoryId;
|
||||
}
|
||||
|
||||
public function getSort(): int
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
public function getContents(): Contents
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategory;
|
||||
|
||||
use App\Dto\Builder\DocumentationCategory;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private DocumentationCategory $documentationCategory,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentationCategory(): DocumentationCategory
|
||||
{
|
||||
return $this->documentationCategory;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategory;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Contents;
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private int $sort,
|
||||
private Contents $contents,
|
||||
private ?int $parentId,
|
||||
) { }
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getSort(): int
|
||||
{
|
||||
return $this->sort;
|
||||
}
|
||||
|
||||
public function getParentId(): ?int
|
||||
{
|
||||
return $this->parentId;
|
||||
}
|
||||
|
||||
public function getContents(): Contents
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategoryContent;
|
||||
|
||||
final readonly class Content
|
||||
{
|
||||
public function __construct(
|
||||
private int $languageId,
|
||||
private string $title,
|
||||
) { }
|
||||
|
||||
public function getLanguageId(): int
|
||||
{
|
||||
return $this->languageId;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationCategoryContent;
|
||||
|
||||
final class Contents
|
||||
{
|
||||
private array $contents = [];
|
||||
|
||||
public function addContent(Content $content): void
|
||||
{
|
||||
$this->contents[$content->getLanguageId()] = $content;
|
||||
}
|
||||
|
||||
public function getContent(int $languageId): ?Content
|
||||
{
|
||||
return $this->contents[$languageId] ?? null;
|
||||
}
|
||||
|
||||
public function getContents(): array
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
||||
|
||||
final readonly class Content
|
||||
{
|
||||
public function __construct(
|
||||
private int $languageId,
|
||||
private string $title,
|
||||
private string $content,
|
||||
) { }
|
||||
|
||||
public function getLanguageId(): int
|
||||
{
|
||||
return $this->languageId;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationContent;
|
||||
|
||||
final class Contents
|
||||
{
|
||||
private array $contents = [];
|
||||
|
||||
public function addContent(Content $content): void
|
||||
{
|
||||
$this->contents[$content->getLanguageId()] = $content;
|
||||
}
|
||||
|
||||
public function getContent(int $languageId): ?Content
|
||||
{
|
||||
return $this->contents[$languageId] ?? null;
|
||||
}
|
||||
|
||||
public function getContents(): array
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationVersion;
|
||||
|
||||
use App\Dto\Builder\DocumentationVersion;
|
||||
use App\Dto\Service\Pages;
|
||||
|
||||
final readonly class Index extends Pages
|
||||
{
|
||||
public function __construct(
|
||||
private DocumentationVersion $documentationVersionBuildDto,
|
||||
int $page
|
||||
) {
|
||||
parent::__construct($page);
|
||||
}
|
||||
|
||||
public function getDocumentationVersionBuildDto(): DocumentationVersion
|
||||
{
|
||||
return $this->documentationVersionBuildDto;
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\DocumentationVersion;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $title,
|
||||
private string $slug,
|
||||
private bool $isPublic,
|
||||
private DocumentationVersionStatus $status,
|
||||
) { }
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return $this->isPublic;
|
||||
}
|
||||
|
||||
public function getStatus(): DocumentationVersionStatus
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
}
|
36
app/application/app/Enums/DocumentationVersionStatus.php
Normal file
36
app/application/app/Enums/DocumentationVersionStatus.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
enum DocumentationVersionStatus: int
|
||||
{
|
||||
case NotSupported = 0;
|
||||
case Supported = 50;
|
||||
case CurrentVersion = 100;
|
||||
case FutureVersion = 150;
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return __('version-status.' . $this->name);
|
||||
}
|
||||
|
||||
public static function toArray(): array
|
||||
{
|
||||
$items = [];
|
||||
foreach (self::cases() as $item) {
|
||||
$items[] = [
|
||||
'name' => $item->name,
|
||||
'value' => $item->value,
|
||||
'title' => $item->getTitle(),
|
||||
];
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
public static function toCollection(): Collection
|
||||
{
|
||||
return collect(self::toArray());
|
||||
}
|
||||
}
|
@@ -12,6 +12,8 @@ enum Permission: string
|
||||
case ProjectLink = 'project-link';
|
||||
case ProjectTranslation = 'project-translation';
|
||||
case ProjectFeedback = 'project-feedback';
|
||||
case Documentation = 'documentation';
|
||||
case DocumentationCategory = 'documentation-category';
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationCategory;
|
||||
|
||||
final class ParentException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationCategoryContent;
|
||||
|
||||
final class ContentSaveException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services\DocumentationContent;
|
||||
|
||||
final class ContentSaveException extends \Exception
|
||||
{
|
||||
|
||||
}
|
19
app/application/app/Exceptions/Services/ServiceException.php
Normal file
19
app/application/app/Exceptions/Services/ServiceException.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Services;
|
||||
|
||||
use App\Contracts\ServiceResultError as ServiceResultErrorContract;
|
||||
|
||||
final class ServiceException extends \Exception
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ServiceResultErrorContract $serviceResultError
|
||||
) {
|
||||
parent::__construct($this->serviceResultError->getMessage());
|
||||
}
|
||||
|
||||
public function getServiceResultError(): ServiceResultErrorContract
|
||||
{
|
||||
return $this->serviceResultError;
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationCategoryService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationCategoriesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationCategoryService $documentationCategoryService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, int $versionId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationCategoryService->index($projectId, $versionId, $data->getDocumentationCategory(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->create($projectId, $versionId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->edit($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->store($projectId, $versionId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'category' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $versionId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->update($projectId, $versionId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'category' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $versionId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->destroy($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.categories.index', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\DocumentVersions\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentVersions\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationVersionService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationVersionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationVersionService $documentationVersionService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationVersionService->index($projectId, $data->getDocumentationVersionBuildDto(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/index', $result->getData());
|
||||
}
|
||||
|
||||
public function show(int $projectId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->show($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/show', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->create($projectId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->edit($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-versions/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->store($projectId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.edit', [
|
||||
'project' => $projectId,
|
||||
'documentation_version' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->update($projectId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.edit', [
|
||||
'project' => $projectId,
|
||||
'documentation_version' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->destroy($projectId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.index', ['project' => $projectId])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DocumentationsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationService $documentationService,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, int $versionId, IndexRequest $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
$querySettingsDto = new QuerySettingsDto(
|
||||
limit: 20,
|
||||
page: $data->getPage(),
|
||||
queryWith: []
|
||||
);
|
||||
|
||||
$result = $this->documentationService->index($projectId, $versionId, $data->getDocumentation(), $querySettingsDto, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->create($projectId, $versionId, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->edit($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->store($projectId, $versionId, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'documentation' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $versionId, int $id, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->update($projectId, $versionId, $id, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.edit', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
'documentation' => $result->getModel()->id,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $versionId, int $id, Request $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->destroy($projectId, $versionId, $id, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.documentation-versions.documentations.index', [
|
||||
'project' => $projectId,
|
||||
'version' => $versionId,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentVersions;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\DocumentationVersion;
|
||||
use App\Dto\Service\Admin\Project\DocumentationVersion\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentationVersionBuildDto: new DocumentationVersion(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentVersions;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationVersion\StoreUpdate;
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => ['required', 'string', 'max:255'],
|
||||
'slug' => ['required', 'string', 'max:70', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'status' => ['required', new Enum(DocumentationVersionStatus::class)],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
status: DocumentationVersionStatus::from((int) $this->input('status')),
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentationCategories;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\DocumentationCategory;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategory\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentationCategory: new DocumentationCategory(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentationCategories;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategory\StoreUpdate;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Contents;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'slug' => ['required', 'string', 'max:200', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
||||
'parent_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||
'content.*.title' => ['required', 'string', 'max:255'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
$parentId = $this->input('parent_id', null);
|
||||
if (!\is_null($parentId)) {
|
||||
$parentId = (int) $parentId;
|
||||
}
|
||||
|
||||
return new StoreUpdate(
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
sort: (int) $this->input('sort'),
|
||||
contents: $this->getContents(),
|
||||
parentId: $parentId,
|
||||
);
|
||||
}
|
||||
|
||||
private function getContents(): Contents
|
||||
{
|
||||
$contents = new Contents();
|
||||
foreach ($this->input('content', []) as $languageId => $content) {
|
||||
$contents->addContent(new Content(
|
||||
languageId: (int) $languageId,
|
||||
title: $content['title'],
|
||||
));
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\Documentations;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Builder\Documentation;
|
||||
use App\Dto\Service\Admin\Project\Documentation\Index;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class IndexRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'page' => ['nullable', 'numeric', 'min:1']
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): Index
|
||||
{
|
||||
return new Index(
|
||||
documentation: new Documentation(),
|
||||
page: (int) $this->input('page', 1)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\Documentations;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\Documentation\StoreUpdate;
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'slug' => ['required', 'string', 'max:200', 'regex:/^[a-z0-9._-]+$/'],
|
||||
'is_public' => ['required', 'boolean'],
|
||||
'sort' => ['required', 'integer', 'min:-1000', 'max:1000'],
|
||||
'category_id' => ['nullable', 'integer', 'exists:documentation_categories,id'],
|
||||
'content.*.title' => ['required', 'string', 'max:255'],
|
||||
'content.*.content' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
$categoryId = $this->input('category_id', null);
|
||||
if (!\is_null($categoryId)) {
|
||||
$categoryId = (int) $categoryId;
|
||||
}
|
||||
|
||||
return new StoreUpdate(
|
||||
slug: $this->input('slug'),
|
||||
isPublic: (bool) $this->input('is_public', false),
|
||||
sort: (int) $this->input('sort'),
|
||||
contents: $this->getContents(),
|
||||
categoryId: $categoryId,
|
||||
);
|
||||
}
|
||||
|
||||
private function getContents(): Contents
|
||||
{
|
||||
$contents = new Contents();
|
||||
foreach ($this->input('content', []) as $languageId => $content) {
|
||||
$contents->addContent(new Content(
|
||||
languageId: (int) $languageId,
|
||||
title: $content['title'],
|
||||
content: $content['content'] ?? '',
|
||||
));
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
}
|
65
app/application/app/Models/Documentation.php
Normal file
65
app/application/app/Models/Documentation.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class Documentation extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'sort' => 100,
|
||||
'is_public' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'slug',
|
||||
'is_public',
|
||||
'category_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationCategory::class, 'category_id', 'id');
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationContent::class, 'documentation_id', 'id');
|
||||
}
|
||||
|
||||
public function content(): HasOne
|
||||
{
|
||||
return $this->hasOne(DocumentationContent::class, 'documentation_id', 'id');
|
||||
}
|
||||
}
|
75
app/application/app/Models/DocumentationCategory.php
Normal file
75
app/application/app/Models/DocumentationCategory.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Scopes\SortScope;
|
||||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships;
|
||||
|
||||
#[ScopedBy([SortScope::class])]
|
||||
final class DocumentationCategory extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes, HasRecursiveRelationships;
|
||||
|
||||
protected $table = 'documentation_categories';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'sort' => 100,
|
||||
'is_public' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'slug',
|
||||
'sort',
|
||||
'parent_id',
|
||||
'is_public',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationCategory::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationCategoryContent::class, 'category_id');
|
||||
}
|
||||
|
||||
public function content(): HasOne
|
||||
{
|
||||
return $this->hasOne(DocumentationCategoryContent::class, 'category_id');
|
||||
}
|
||||
|
||||
public function version(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DocumentationVersion::class, 'version_id');
|
||||
}
|
||||
}
|
24
app/application/app/Models/DocumentationCategoryContent.php
Normal file
24
app/application/app/Models/DocumentationCategoryContent.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class DocumentationCategoryContent extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation_category_content';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'language_id',
|
||||
];
|
||||
}
|
25
app/application/app/Models/DocumentationContent.php
Normal file
25
app/application/app/Models/DocumentationContent.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class DocumentationContent extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation_content';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'content',
|
||||
'language_id',
|
||||
];
|
||||
}
|
67
app/application/app/Models/DocumentationVersion.php
Normal file
67
app/application/app/Models/DocumentationVersion.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class DocumentationVersion extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'documentation_versions';
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'is_public' => true,
|
||||
'status' => DocumentationVersionStatus::CurrentVersion,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'slug',
|
||||
'is_public',
|
||||
'status',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'is_public' => 'boolean',
|
||||
'status' => DocumentationVersionStatus::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function project(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
|
||||
public function documentations(): HasMany
|
||||
{
|
||||
return $this->hasMany(Documentation::class, 'version_id');
|
||||
}
|
||||
|
||||
public function categories(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationCategory::class, 'version_id');
|
||||
}
|
||||
}
|
@@ -62,4 +62,9 @@ final class Project extends Model implements StorageContract
|
||||
{
|
||||
return $this->hasMany(ProjectFeedback::class);
|
||||
}
|
||||
|
||||
public function documentationVersions(): HasMany
|
||||
{
|
||||
return $this->hasMany(DocumentationVersion::class);
|
||||
}
|
||||
}
|
||||
|
34
app/application/app/Policies/DocumentationCategoryPolicy.php
Normal file
34
app/application/app/Policies/DocumentationCategoryPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationCategoryPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.view');
|
||||
}
|
||||
|
||||
public function view(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.create');
|
||||
}
|
||||
|
||||
public function update(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, DocumentationCategory $category): bool
|
||||
{
|
||||
return $user->hasPermission('documentation-category.delete');
|
||||
}
|
||||
}
|
34
app/application/app/Policies/DocumentationPolicy.php
Normal file
34
app/application/app/Policies/DocumentationPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Documentation;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function view(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.create');
|
||||
}
|
||||
|
||||
public function update(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, Documentation $documentation): bool
|
||||
{
|
||||
return $user->hasPermission('documentation.delete');
|
||||
}
|
||||
}
|
39
app/application/app/Policies/DocumentationVersionPolicy.php
Normal file
39
app/application/app/Policies/DocumentationVersionPolicy.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class DocumentationVersionPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function view(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.create');
|
||||
}
|
||||
|
||||
public function update(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.update');
|
||||
}
|
||||
|
||||
public function delete(User $user, DocumentationVersion $documentationVersion): bool
|
||||
{
|
||||
// Not a mistake or typo. Shared rights with Documentation.
|
||||
return $user->hasPermission('documentation.delete');
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Contracts\Search;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\Services\DocumentationCategory\BuilderCommand;
|
||||
use App\Services\Search\CreateSearchInstanceCommand;
|
||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationCategoryRepository
|
||||
{
|
||||
public function __construct(
|
||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
||||
private BuilderCommand $builderCommand
|
||||
) { }
|
||||
|
||||
public function getCategories(int $versionId, DocumentationCategoryBuilderDto $documentationCategoryBuilderDto, array $with = []): Search
|
||||
{
|
||||
$query = $this->builderCommand->execute(
|
||||
query: DocumentationCategory::query()->where('version_id', $versionId)->with($with),
|
||||
documentationCategoryBuilderDto: $documentationCategoryBuilderDto
|
||||
);
|
||||
|
||||
return $this->createSearchInstanceCommand->execute($query);
|
||||
}
|
||||
|
||||
public function getCategoryById(int $id): ?DocumentationCategory
|
||||
{
|
||||
return DocumentationCategory::query()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
public function getCategoryByCode(string $code): ?DocumentationCategory
|
||||
{
|
||||
return DocumentationCategory::query()->where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function isExistsSlug(int $versionId, string $slug, ?int $exceptId = null): bool
|
||||
{
|
||||
return DocumentationCategory::query()
|
||||
->where('version_id', $versionId)
|
||||
->where('slug', Str::lower($slug))
|
||||
->when($exceptId, function (Builder $query, int $exceptId) {
|
||||
$query->where('id', '!=', $exceptId);
|
||||
})
|
||||
->withTrashed()
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function getForSelect(?ProjectLanguage $defaultLanguage, ?DocumentationCategory $exceptCategory = null, array $withExcepts = []): array
|
||||
{
|
||||
$with = [
|
||||
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
||||
$hasOne->when($defaultLanguage, function (Builder $query, ProjectLanguage $defaultLanguage) {
|
||||
$query->where('language_id', $defaultLanguage->id);
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
$categories = DocumentationCategory::query()
|
||||
->with($with)
|
||||
->when($exceptCategory, function (Builder $query, DocumentationCategory $exceptCategory) {
|
||||
$query->whereNotIn(
|
||||
'id',
|
||||
$exceptCategory->descendantsAndSelf()->pluck('id')->toArray()
|
||||
);
|
||||
})
|
||||
->when($withExcepts, function (Builder $query) use ($withExcepts) {
|
||||
$query->withTrashed()->whereNull('deleted_at')->orWhereIn('id', $withExcepts);
|
||||
})->get();
|
||||
|
||||
return $categories->map(function (DocumentationCategory $documentationCategory) use ($defaultLanguage) {
|
||||
return [
|
||||
'id' => $documentationCategory->id,
|
||||
'title' => $documentationCategory->content?->title ?? $documentationCategory->slug,
|
||||
];
|
||||
})
|
||||
->pluck('title', 'id')
|
||||
->toArray();
|
||||
}
|
||||
}
|
51
app/application/app/Repositories/DocumentationRepository.php
Normal file
51
app/application/app/Repositories/DocumentationRepository.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
||||
use App\Contracts\Search;
|
||||
use App\Models\Documentation;
|
||||
use App\Services\Documentation\BuilderCommand;
|
||||
use App\Services\Search\CreateSearchInstanceCommand;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationRepository
|
||||
{
|
||||
public function __construct(
|
||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
||||
private BuilderCommand $builderCommand
|
||||
) { }
|
||||
|
||||
public function getDocumentations(int $versionId, DocumentationBuilderDto $documentationBuilderDto, array $with = []): Search
|
||||
{
|
||||
$query = $this->builderCommand->execute(
|
||||
query: Documentation::query()->where('version_id', $versionId)->with($with),
|
||||
documentationBuilderDto: $documentationBuilderDto
|
||||
);
|
||||
|
||||
return $this->createSearchInstanceCommand->execute($query);
|
||||
}
|
||||
|
||||
public function getDocumentationById(int $id): ?Documentation
|
||||
{
|
||||
return Documentation::query()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
public function getDocumentationByCode(string $code): ?Documentation
|
||||
{
|
||||
return Documentation::query()->where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function isExistsSlug(int $versionId, string $slug, ?int $exceptId = null): bool
|
||||
{
|
||||
return Documentation::query()
|
||||
->where('version_id', $versionId)
|
||||
->where('slug', Str::lower($slug))
|
||||
->when($exceptId, function (Builder $query, int $exceptId) {
|
||||
$query->where('id', '!=', $exceptId);
|
||||
})
|
||||
->withTrashed()
|
||||
->exists();
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Contracts\Search;
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Services\DocumentationVersion\BuilderCommand;
|
||||
use App\Services\Search\CreateSearchInstanceCommand;
|
||||
use App\Dto\Builder\DocumentationVersion as DocumentationVersionBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationVersionRepository
|
||||
{
|
||||
public function __construct(
|
||||
private CreateSearchInstanceCommand $createSearchInstanceCommand,
|
||||
private BuilderCommand $builderCommand
|
||||
) { }
|
||||
|
||||
public function getVersions(int $projectId, DocumentationVersionBuilderDto $documentationVersionBuilderDto, array $with = []): Search
|
||||
{
|
||||
$query = $this->builderCommand->execute(
|
||||
query: DocumentationVersion::query()->where('project_id', $projectId)->with($with),
|
||||
documentationVersionBuilderDto: $documentationVersionBuilderDto
|
||||
);
|
||||
|
||||
return $this->createSearchInstanceCommand->execute($query);
|
||||
}
|
||||
|
||||
public function getVersionById(int $id): ?DocumentationVersion
|
||||
{
|
||||
return DocumentationVersion::query()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
public function getVersionByCode(string $code): ?DocumentationVersion
|
||||
{
|
||||
return DocumentationVersion::query()->where('code', $code)->first();
|
||||
}
|
||||
|
||||
public function isExistsSlug(int $projectId, string $slug, ?int $exceptId = null): bool
|
||||
{
|
||||
return DocumentationVersion::query()
|
||||
->where('project_id', $projectId)
|
||||
->where('slug', Str::lower($slug))
|
||||
->when($exceptId, function (Builder $query, int $exceptId) {
|
||||
$query->where('id', '!=', $exceptId);
|
||||
})
|
||||
->withTrashed()
|
||||
->exists();
|
||||
}
|
||||
}
|
@@ -0,0 +1,257 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin\Project;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategory\StoreUpdate;
|
||||
use App\Exceptions\Services\DocumentationCategory\ParentException;
|
||||
use App\Exceptions\Services\ServiceException;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\DocumentationCategoryContent;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\Models\User;
|
||||
use App\Repositories\DocumentationCategoryRepository;
|
||||
use App\Repositories\DocumentationVersionRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\DocumentationCategory\DocumentationCategoryCommandHandler;
|
||||
use App\Services\DocumentationCategoryContent\ModelSyncCommand;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class DocumentationCategoryService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DocumentationVersionRepository $documentationVersionRepository,
|
||||
private readonly DocumentationCategoryRepository $documentationCategoryRepository,
|
||||
private readonly DocumentationCategoryCommandHandler $categoryCommandHandler,
|
||||
private readonly ModelSyncCommand $contentSaveCommand,
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, int $versionId, DocumentationCategoryBuilderDto $documentationCategoryBuilderDto, 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', DocumentationCategory::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());
|
||||
|
||||
$categories = $this->documentationCategoryRepository->getCategories(
|
||||
$version->id,
|
||||
$documentationCategoryBuilderDto,
|
||||
$with
|
||||
)->pagination(
|
||||
$querySettingsDto->getLimit(),
|
||||
$querySettingsDto->getPage()
|
||||
);
|
||||
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
'categories' => $categories,
|
||||
]);
|
||||
}
|
||||
|
||||
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', DocumentationCategory::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$defaultLanguage = $project->languages->where('is_default', 1)->first();
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
'category' => new DocumentationCategory(),
|
||||
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $categoryId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
||||
$project = $version?->project;
|
||||
if (\is_null($version) || $project?->id !== $projectId) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
||||
if (\is_null($category)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $category)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$withCategories = [];
|
||||
if ($category->parent_id) {
|
||||
$withCategories[] = $category->parent_id;
|
||||
}
|
||||
$defaultLanguage = $project->languages->where('is_default', 1)->first();
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
'category' => $category,
|
||||
'categories' => $this->documentationCategoryRepository->getForSelect($defaultLanguage, $category, $withCategories),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', DocumentationCategory::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'));
|
||||
}
|
||||
|
||||
try {
|
||||
$category = DB::transaction(function () use ($data, $version, $user, $versionId, $project) {
|
||||
if ($this->documentationCategoryRepository->isExistsSlug($versionId, $data->getSlug()) !== false) {
|
||||
$error = $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
|
||||
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
|
||||
);
|
||||
throw new ServiceException($error);
|
||||
}
|
||||
|
||||
$dataCategory = $this->getDataCategory($data);
|
||||
$category = $this->categoryCommandHandler->handleStore($version, $dataCategory);
|
||||
$this->contentSaveCommand->execute($project, $category, $data->getContents());
|
||||
|
||||
return $category;
|
||||
});
|
||||
} catch (ServiceException $e) {
|
||||
return $e->getServiceResultError();
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($category, __('Category successfully created'));
|
||||
}
|
||||
|
||||
public function update(int $projectId, int $versionId, int $categoryId, 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'));
|
||||
}
|
||||
|
||||
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
||||
if (\is_null($category)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $category)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($data->getParentId() === $category->id) {
|
||||
return $this->errValidate(
|
||||
__('validation.parent', ['attribute' => __('validation.attributes.parent_id')]),
|
||||
['parent_id' => __('validation.parent', ['attribute' => __('validation.attributes.parent_id')])]
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$category = DB::transaction(function () use ($data, $category, $versionId, $project) {
|
||||
if ($this->documentationCategoryRepository->isExistsSlug($versionId, $data->getSlug(), $category->id) !== false) {
|
||||
$error = $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.slug')]),
|
||||
['slug' => __('validation.unique', ['attribute' => __('validation.attributes.slug')])]
|
||||
);
|
||||
throw new ServiceException($error);
|
||||
}
|
||||
|
||||
$dataCategory = $this->getDataCategory($data);
|
||||
$category = $this->categoryCommandHandler->handleUpdate($category, $dataCategory);
|
||||
$this->contentSaveCommand->execute($project, $category, $data->getContents());
|
||||
|
||||
return $category;
|
||||
});
|
||||
} catch (ServiceException $e) {
|
||||
return $e->getServiceResultError();
|
||||
} catch (ParentException $e) {
|
||||
return $this->errValidate(
|
||||
__('validation.parent_cycle_detected', ['attribute' => __('validation.attributes.parent_id')]),
|
||||
['parent_id' => __('validation.parent_cycle_detected', ['attribute' => __('validation.attributes.parent_id')])]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($category, __('Category updated successfully'));
|
||||
}
|
||||
|
||||
public function destroy(int $projectId, int $versionId, int $categoryId, User $user): ServiceResultError|ServiceResultSuccess
|
||||
{
|
||||
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
||||
$project = $version?->project;
|
||||
if (\is_null($version) || $project?->id !== $projectId) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
||||
if (\is_null($category)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('delete', $category)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($category) {
|
||||
$this->categoryCommandHandler->handleDestroy($category);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->ok(__('Category successfully deleted'));
|
||||
}
|
||||
|
||||
private function getDataCategory(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'slug' => $data->getSlug(),
|
||||
'is_public' => $data->isPublic(),
|
||||
'sort' => $data->getSort(),
|
||||
'parent_id' => $data->getParentId(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,239 @@
|
||||
<?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(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,222 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin\Project;
|
||||
|
||||
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\User;
|
||||
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\DocumentationVersion\DocumentationVersionCommandHandler;
|
||||
use App\Services\Service;
|
||||
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,
|
||||
) { }
|
||||
|
||||
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, 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,
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
} 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);
|
||||
});
|
||||
} 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);
|
||||
});
|
||||
} 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(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Documentation;
|
||||
|
||||
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, DocumentationBuilderDto $documentationBuilderDto): Relation | Builder
|
||||
{
|
||||
if ($documentationBuilderDto->isPublic() !== null) {
|
||||
$query->where('is_public', $documentationBuilderDto->isPublic());
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Documentation;
|
||||
|
||||
use App\Models\Documentation;
|
||||
use App\Models\DocumentationVersion;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationCommandHandler
|
||||
{
|
||||
public function handleStore(DocumentationVersion $version, array $data): Documentation
|
||||
{
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
return $version->documentations()->create($data);
|
||||
}
|
||||
|
||||
public function handleUpdate(Documentation $documentation, array $data): Documentation
|
||||
{
|
||||
if (isset($data['slug'])) {
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
}
|
||||
|
||||
$documentation->update($data);
|
||||
$documentation->touch();
|
||||
|
||||
return $documentation;
|
||||
}
|
||||
|
||||
public function handleDestroy(Documentation $documentation): void
|
||||
{
|
||||
$documentation->update([
|
||||
'slug' => $documentation->slug . '#delete:' . $documentation->id,
|
||||
]);
|
||||
$documentation->delete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationCategory;
|
||||
|
||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, DocumentationCategoryBuilderDto $documentationCategoryBuilderDto): Relation | Builder
|
||||
{
|
||||
if ($documentationCategoryBuilderDto->isPublic() !== null) {
|
||||
$query->where('is_public', $documentationCategoryBuilderDto->isPublic());
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationCategory;
|
||||
|
||||
use App\Exceptions\Services\DocumentationCategory\ParentException;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\DocumentationVersion;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationCategoryCommandHandler
|
||||
{
|
||||
public function handleStore(DocumentationVersion $version, array $data): DocumentationCategory
|
||||
{
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
return $version->categories()->create($data);
|
||||
}
|
||||
|
||||
public function handleUpdate(DocumentationCategory $category, array $data): DocumentationCategory
|
||||
{
|
||||
if (!empty($data['parent_id'])) {
|
||||
$category->parent_id = $data['parent_id'];
|
||||
if ($category->ancestors()->withTrashed()->where('id', $category->id)->exists()) {
|
||||
throw new ParentException('Category ID occurs in the parent chain (category: ' . $category->id . ', parent_id: ' . $category->parent_id . ').');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['slug'])) {
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
}
|
||||
|
||||
$category->update($data);
|
||||
$category->touch();
|
||||
|
||||
return $category;
|
||||
}
|
||||
|
||||
public function handleDestroy(DocumentationCategory $category): void
|
||||
{
|
||||
$category->update([
|
||||
'slug' => $category->slug . '#delete:' . $category->id,
|
||||
]);
|
||||
$category->delete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationCategoryContent;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationCategoryContent\Contents;
|
||||
use App\Exceptions\Services\DocumentationCategoryContent\ContentSaveException;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\Project;
|
||||
|
||||
final readonly class ModelSyncCommand
|
||||
{
|
||||
public function execute(Project $project, DocumentationCategory $category, Contents $contents): void
|
||||
{
|
||||
$languages = $project->languages;
|
||||
$categoryContents = $category->contents;
|
||||
|
||||
$newContents = [];
|
||||
foreach ($contents->getContents() as $content) {
|
||||
/** @var Content $content */
|
||||
$language = $languages->firstWhere('id', $content->getLanguageId());
|
||||
if (!$language) {
|
||||
throw new ContentSaveException('Language not found: ' . $content->getLanguageId());
|
||||
}
|
||||
|
||||
$model = $categoryContents->firstWhere('language_id', $language->id);
|
||||
$data = $this->getData($content);
|
||||
if (\is_null($model)) {
|
||||
$newContents[] = array_merge(['language_id' => $content->getLanguageId()], $data);
|
||||
continue;
|
||||
}
|
||||
$model->update($data);
|
||||
}
|
||||
|
||||
if (!empty($newContents)) {
|
||||
$category->contents()->createMany($newContents);
|
||||
}
|
||||
}
|
||||
|
||||
private function getData(Content $content): array
|
||||
{
|
||||
return [
|
||||
'title' => $content->getTitle(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationContent;
|
||||
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Content;
|
||||
use App\Dto\Service\Admin\Project\DocumentationContent\Contents;
|
||||
use App\Exceptions\Services\DocumentationContent\ContentSaveException;
|
||||
use App\Models\Documentation;
|
||||
use App\Models\Project;
|
||||
|
||||
final readonly class ModelSyncCommand
|
||||
{
|
||||
public function execute(Project $project, Documentation $documentation, Contents $contents): void
|
||||
{
|
||||
$languages = $project->languages;
|
||||
$documentationContents = $documentation->contents;
|
||||
|
||||
$newContents = [];
|
||||
foreach ($contents->getContents() as $content) {
|
||||
/** @var Content $content */
|
||||
$language = $languages->firstWhere('id', $content->getLanguageId());
|
||||
if (!$language) {
|
||||
throw new ContentSaveException('Language not found: ' . $content->getLanguageId());
|
||||
}
|
||||
|
||||
$model = $documentationContents->firstWhere('language_id', $language->id);
|
||||
$data = $this->getData($content);
|
||||
if (\is_null($model)) {
|
||||
$newContents[] = array_merge(['language_id' => $content->getLanguageId()], $data);
|
||||
continue;
|
||||
}
|
||||
$model->update($data);
|
||||
}
|
||||
|
||||
if (!empty($newContents)) {
|
||||
$documentation->contents()->createMany($newContents);
|
||||
}
|
||||
}
|
||||
|
||||
private function getData(Content $content): array
|
||||
{
|
||||
return [
|
||||
'title' => $content->getTitle(),
|
||||
'content' => $content->getContent(),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationVersion;
|
||||
|
||||
use App\Dto\Builder\DocumentationVersion as DocumentationVersionBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, DocumentationVersionBuilderDto $documentationVersionBuilderDto): Relation | Builder
|
||||
{
|
||||
if ($documentationVersionBuilderDto->isPublic() !== null) {
|
||||
$query->where('is_public', $documentationVersionBuilderDto->isPublic());
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\DocumentationVersion;
|
||||
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\Project;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class DocumentationVersionCommandHandler
|
||||
{
|
||||
public function handleStore(Project $project, array $data): DocumentationVersion
|
||||
{
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
|
||||
return $project->documentationVersions()->create($data);
|
||||
}
|
||||
|
||||
public function handleUpdate(DocumentationVersion $version, array $data): DocumentationVersion
|
||||
{
|
||||
if (isset($data['slug'])) {
|
||||
$data['slug'] = Str::lower($data['slug']);
|
||||
}
|
||||
|
||||
$version->update($data);
|
||||
$version->touch();
|
||||
|
||||
return $version;
|
||||
}
|
||||
|
||||
public function handleDestroy(DocumentationVersion $version): void
|
||||
{
|
||||
$version->update([
|
||||
'slug' => $version->slug . '#delete:' . $version->id,
|
||||
]);
|
||||
$version->delete();
|
||||
}
|
||||
}
|
@@ -27,12 +27,12 @@ final class Checkbox extends Form
|
||||
|
||||
private function getCheckboxValue(): string
|
||||
{
|
||||
return (string) old($this->getRequestName(), $this->checkboxValue);
|
||||
return (string) $this->checkboxValue;
|
||||
}
|
||||
|
||||
private function getUserValue(): string
|
||||
{
|
||||
return (string) $this->userValue;
|
||||
return (string) old($this->getRequestName(), $this->userValue);
|
||||
}
|
||||
|
||||
private function getNotCheckedValue(): ?string
|
||||
|
@@ -13,6 +13,7 @@ final class Input extends Form
|
||||
private readonly string $type = 'text',
|
||||
private readonly ?string $value = '',
|
||||
private readonly ?string $example = null,
|
||||
private readonly ?string $allowedCharacters = null,
|
||||
) { }
|
||||
|
||||
protected function getName(): string
|
||||
@@ -40,6 +41,11 @@ final class Input extends Form
|
||||
return $this->example;
|
||||
}
|
||||
|
||||
public function getAllowedCharacters(): ?string
|
||||
{
|
||||
return $this->allowedCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -52,6 +58,7 @@ final class Input extends Form
|
||||
'type' => $this->getType(),
|
||||
'value' => $this->getValue(),
|
||||
'example' => $this->getExample(),
|
||||
'allowedCharacters' => $this->getAllowedCharacters(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user