Moved from "app/src" to "app/application".
Otherwise phpstorm doesn't understand the paths correctly. He thinks that this is not a complete application, but a package. And when creating a class, the namespace indicates “app” with a small letter, but should be “App”.
This commit is contained in:
25
app/application/app/Services/Admin/LanguageService.php
Normal file
25
app/application/app/Services/Admin/LanguageService.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Dto\Service\Admin\Language\NewLanguage;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\ServiceResults\Admin\LanguageService\NewLanguageResult;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\Services\Service;
|
||||
|
||||
final class LanguageService extends Service
|
||||
{
|
||||
public function newLanguage(NewLanguage $data): ServiceResultError | NewLanguageResult
|
||||
{
|
||||
$language = new ProjectLanguage();
|
||||
$language->title = "";
|
||||
$language->code = "";
|
||||
|
||||
return new NewLanguageResult(
|
||||
language: $language,
|
||||
name: $data->getName(),
|
||||
index: $data->getIndex(),
|
||||
);
|
||||
}
|
||||
}
|
199
app/application/app/Services/Admin/ProjectService.php
Normal file
199
app/application/app/Services/Admin/ProjectService.php
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Dto\Builder\Project as ProjectBuilderDto;
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Dto\Service\Admin\Project\StoreUpdate;
|
||||
use App\Enums\Morph;
|
||||
use App\Models\Project;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\Models\User;
|
||||
use App\Repositories\ProjectRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\Project\ProjectCommandHandler;
|
||||
use App\Services\ProjectLanguage\ModelSyncCommand;
|
||||
use App\Services\Role\CreateAdminRoleForProjectCommand;
|
||||
use App\Services\Service;
|
||||
use App\Services\Storage\StorageService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class ProjectService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ProjectRepository $projectRepository,
|
||||
private readonly ProjectCommandHandler $projectCommandHandler,
|
||||
private readonly CreateAdminRoleForProjectCommand $createAdminRoleForProjectCommand,
|
||||
private readonly ModelSyncCommand $languageModelSyncCommand,
|
||||
private readonly StorageService $storageService,
|
||||
) { }
|
||||
|
||||
public function index(ProjectBuilderDto $projectBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('viewAny', Project::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$projects = $this->projectRepository->getProjects(
|
||||
$projectBuilderDto,
|
||||
$querySettingsDto->getQueryWith()
|
||||
)->pagination(
|
||||
$querySettingsDto->getLimit(),
|
||||
$querySettingsDto->getPage()
|
||||
);
|
||||
|
||||
return $this->result([
|
||||
'projects' => $projects,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('create', Project::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$language = new ProjectLanguage();
|
||||
$language->is_default = true;
|
||||
$language->title = $user->lang?->getTitle();
|
||||
$language->code = $user->lang?->getLocale();
|
||||
return $this->result([
|
||||
'project' => new Project(),
|
||||
'languages' => collect([$language])->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $id, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($id);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $project)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
'languages' => $project->languages->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', Project::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($this->projectRepository->isExistsCode($data->getCode())) {
|
||||
return $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.code')]),
|
||||
['code' => __('validation.unique', ['attribute' => __('validation.attributes.code')])]
|
||||
);
|
||||
}
|
||||
|
||||
$storages = $this->storageService->getStoragesAndValidate($data->getStorages(), Morph::Project);
|
||||
if (!$storages->isSuccess()) {
|
||||
return $storages;
|
||||
}
|
||||
|
||||
try {
|
||||
$project = DB::transaction(function () use ($data, $user, $storages) {
|
||||
$dataProject = $this->getDataProject($data);
|
||||
|
||||
$project = $this->projectCommandHandler->handleStore($dataProject);
|
||||
$this->createAdminRoleForProjectCommand->execute($project, $user);
|
||||
$this->languageModelSyncCommand->execute($project, $data->getLanguages());
|
||||
$this->storageService->saveAndDelete($project, $storages);
|
||||
|
||||
return $project;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($project, __('The project was successfully created'));
|
||||
}
|
||||
|
||||
public function update(int $id, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($id);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('update', $project)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($this->projectRepository->isExistsCode($data->getCode(), $project->id)) {
|
||||
return $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.code')]),
|
||||
['code' => __('validation.unique', ['attribute' => __('validation.attributes.code')])]
|
||||
);
|
||||
}
|
||||
|
||||
$storages = $this->storageService->getStoragesAndValidate($data->getStorages(), Morph::Project, $project->id);
|
||||
if (!$storages->isSuccess()) {
|
||||
return $storages;
|
||||
}
|
||||
|
||||
try {
|
||||
$project = DB::transaction(function () use ($data, $project, $storages) {
|
||||
$dataProject = $this->getDataProject($data);
|
||||
|
||||
$project = $this->projectCommandHandler->handleUpdate($project, $dataProject);
|
||||
$this->languageModelSyncCommand->execute($project, $data->getLanguages());
|
||||
$this->storageService->saveAndDelete($project, $storages);
|
||||
|
||||
return $project;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($project, __('The project was successfully updated'));
|
||||
}
|
||||
|
||||
public function destroy(int $id, User $user): ServiceResultError|ServiceResultSuccess
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($id);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('delete', $project)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($project) {
|
||||
$this->projectCommandHandler->handleDestroy($project);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->ok(__('The project has been deleted'));
|
||||
}
|
||||
|
||||
private function getDataProject(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'name' => $data->getName(),
|
||||
'code' => $data->getCode(),
|
||||
'http_host' => $data->getHttpHost(),
|
||||
'is_public' => $data->isPublic(),
|
||||
];
|
||||
}
|
||||
}
|
165
app/application/app/Services/Admin/RoleService.php
Normal file
165
app/application/app/Services/Admin/RoleService.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Dto\Builder\Role as RoleBuilderDto;
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Dto\Service\Admin\Role\StoreUpdate;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use App\Repositories\RoleRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\Role\RoleCommandHandler;
|
||||
use App\Services\Role\RoleSyncPermissionsCommandHandler;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class RoleService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RoleRepository $roleRepository,
|
||||
private readonly RoleCommandHandler $roleCommandHandler,
|
||||
private readonly RoleSyncPermissionsCommandHandler $roleSyncPermissionsCommandHandler
|
||||
) { }
|
||||
|
||||
public function index(RoleBuilderDto $roleBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('viewAny', Role::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$roles = $this->roleRepository->getRoles(
|
||||
$roleBuilderDto,
|
||||
$querySettingsDto->getQueryWith()
|
||||
)->pagination(
|
||||
$querySettingsDto->getLimit(),
|
||||
$querySettingsDto->getPage()
|
||||
);
|
||||
|
||||
return $this->result([
|
||||
'roles' => $roles
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('create', Role::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'role' => new Role(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $id, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$role = $this->roleRepository->getRoleById($id);
|
||||
|
||||
if (is_null($role)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $role)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'role' => $role,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', Role::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($this->roleRepository->isExistsCode($data->getCode())) {
|
||||
return $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.code')]),
|
||||
['code' => __('validation.unique', ['attribute' => __('validation.attributes.code')])]
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$role = DB::transaction(function () use ($data) {
|
||||
$dataRole = $this->getDataRole($data);
|
||||
$dataRole['code'] = $data->getCode();
|
||||
|
||||
$role = $this->roleCommandHandler->handleStore($dataRole);
|
||||
$role = $this->roleSyncPermissionsCommandHandler->handle($role, $data->getPermissions());
|
||||
|
||||
return $role;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($role, __('The group was successfully created'));
|
||||
}
|
||||
|
||||
public function update(int $id, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
$role = $this->roleRepository->getRoleById($id);
|
||||
|
||||
if (is_null($role)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('update', $role)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
$role = DB::transaction(function () use ($data, $role) {
|
||||
$dataRole = $this->getDataRole($data);
|
||||
|
||||
$role = $this->roleCommandHandler->handleUpdate($role, $dataRole);
|
||||
$role = $this->roleSyncPermissionsCommandHandler->handle($role, $data->getPermissions());
|
||||
|
||||
return $role;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($role, __('The group was successfully updated'));
|
||||
}
|
||||
|
||||
public function destroy(int $id, User $user): ServiceResultError|ServiceResultSuccess
|
||||
{
|
||||
$role = $this->roleRepository->getRoleById($id);
|
||||
|
||||
if (is_null($role)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('delete', $role)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($role) {
|
||||
$this->roleCommandHandler->handleDestroy($role);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->ok(__('The group has been deleted'));
|
||||
}
|
||||
|
||||
private function getDataRole(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'name' => $data->getName(),
|
||||
];
|
||||
}
|
||||
}
|
200
app/application/app/Services/Admin/UserService.php
Normal file
200
app/application/app/Services/Admin/UserService.php
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use App\Dto\Builder\User as UserBuilderDto;
|
||||
use App\Dto\Service\Admin\User\StoreUpdate;
|
||||
use App\Dto\Service\User\UpdatePassword;
|
||||
use App\Helpers\Helpers;
|
||||
use App\Models\User;
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Repositories\RoleRepository;
|
||||
use App\Repositories\UserRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\Service;
|
||||
use App\Services\User\UserCommandHandler;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class UserService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository,
|
||||
private readonly UserCommandHandler $userCommandHandler,
|
||||
private readonly RoleRepository $roleRepository
|
||||
) { }
|
||||
|
||||
public function index(UserBuilderDto $userBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('viewAny', User::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$users = $this->userRepository->getUsers(
|
||||
$userBuilderDto,
|
||||
$querySettingsDto->getQueryWith()
|
||||
)->pagination(
|
||||
$querySettingsDto->getLimit(),
|
||||
$querySettingsDto->getPage()
|
||||
);
|
||||
|
||||
return $this->result([
|
||||
'users' => $users,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('create', User::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'user' => new User(),
|
||||
'roles' => $this->roleRepository->getRolesForSelect(),
|
||||
'userRoles' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $id, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$modelUser = $this->userRepository->getUserById($id);
|
||||
|
||||
if (is_null($modelUser)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $modelUser)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$userRoles = $modelUser->roles()->withTrashed()->pluck('id')->toArray();
|
||||
return $this->result([
|
||||
'user' => $modelUser,
|
||||
'roles' => $this->roleRepository->getRolesForSelect($userRoles),
|
||||
'userRoles' => $userRoles,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', User::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($this->userRepository->isExistsEmail($data->getEmail())) {
|
||||
return $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.email')]),
|
||||
['code' => __('validation.unique', ['attribute' => __('validation.attributes.email')])]
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$modelUser = DB::transaction(function () use ($data) {
|
||||
$dataUser = $this->getDataUser($data);
|
||||
|
||||
$modelUser = $this->userCommandHandler->handleStore($dataUser, $data->getPassword());
|
||||
$this->userCommandHandler->handleSyncRoles($modelUser, $data->getRoles());
|
||||
|
||||
return $modelUser;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($modelUser, __('The user was successfully created'));
|
||||
}
|
||||
|
||||
public function update(int $id, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
$modelUser = $this->userRepository->getUserById($id);
|
||||
|
||||
if (is_null($modelUser)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('update', $modelUser)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($this->userRepository->isExistsEmail($data->getEmail(), $modelUser->id)) {
|
||||
return $this->errValidate(
|
||||
__('validation.unique', ['attribute' => __('validation.attributes.email')]),
|
||||
['code' => __('validation.unique', ['attribute' => __('validation.attributes.email')])]
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$modelUser = DB::transaction(function () use ($data, $modelUser) {
|
||||
$dataUser = $this->getDataUser($data);
|
||||
|
||||
$modelUser = $this->userCommandHandler->handleUpdate($modelUser, $dataUser);
|
||||
$this->userCommandHandler->handleSyncRoles($modelUser, $data->getRoles());
|
||||
|
||||
return $modelUser;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($modelUser, __('The user was successfully updated'));
|
||||
}
|
||||
|
||||
public function updatePassword(int $id, UpdatePassword $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
$modelUser = $this->userRepository->getUserById($id);
|
||||
|
||||
if (is_null($modelUser)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('update', $modelUser)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->userCommandHandler->handleUpdatePassword($modelUser, $data->getPassword());
|
||||
} catch (\Throwable $e) {
|
||||
report($e->getMessage());
|
||||
return $this->errService($e->getMessage());
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($modelUser, __('The password has been changed'));
|
||||
}
|
||||
|
||||
public function destroy(int $id, User $user): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
$modelUser = $this->userRepository->getUserById($id);
|
||||
|
||||
if (is_null($modelUser)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('delete', $modelUser)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($modelUser) {
|
||||
$this->userCommandHandler->handleDestroy($modelUser);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->ok(__('The user has been deleted'));
|
||||
}
|
||||
|
||||
private function getDataUser(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'name' => $data->getName(),
|
||||
'email' => $data->getEmail(),
|
||||
];
|
||||
}
|
||||
}
|
37
app/application/app/Services/AuthService.php
Normal file
37
app/application/app/Services/AuthService.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Dto\Service\Authorization;
|
||||
use App\Repositories\UserRepository;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
final class AuthService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepository $userRepository
|
||||
) { }
|
||||
|
||||
public function authorization(Authorization $authorization): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
$user = $this->userRepository->getUserByEmail($authorization->getEmail());
|
||||
if (is_null($user)) {
|
||||
return $this->errUnauthorized(__('auth.failed'));
|
||||
}
|
||||
if (Hash::check($authorization->getPassword(), $user->password) !== true) {
|
||||
return $this->errUnauthorized(__('auth.password'));
|
||||
}
|
||||
|
||||
try {
|
||||
Auth::login($user, $authorization->getRemember());
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->ok(__('auth.success'));
|
||||
}
|
||||
}
|
59
app/application/app/Services/Private/ProfileService.php
Normal file
59
app/application/app/Services/Private/ProfileService.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Private;
|
||||
|
||||
use App\Dto\Service\Private\Profile\Update;
|
||||
use App\Dto\Service\Private\Profile\UpdateSettings;
|
||||
use App\Dto\Service\User\UpdatePassword;
|
||||
use App\Models\User;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\Services\Service;
|
||||
use App\Services\User\UserCommandHandler;
|
||||
|
||||
final class ProfileService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCommandHandler $userCommandHandler
|
||||
) { }
|
||||
|
||||
public function update(Update $update, User $user): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
try {
|
||||
$data = [
|
||||
'name' => $update->getName()
|
||||
];
|
||||
$this->userCommandHandler->handleUpdate($user, $data);
|
||||
} catch (\Throwable $e) {
|
||||
report($e->getMessage());
|
||||
return $this->errService($e->getMessage());
|
||||
}
|
||||
return $this->ok(__('Profile saved successfully'));
|
||||
}
|
||||
|
||||
public function updatePassword(UpdatePassword $update, User $user): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
try {
|
||||
$this->userCommandHandler->handleUpdatePassword($user, $update->getPassword());
|
||||
} catch (\Throwable $e) {
|
||||
report($e->getMessage());
|
||||
return $this->errService($e->getMessage());
|
||||
}
|
||||
return $this->ok(__('The password has been changed'));
|
||||
}
|
||||
|
||||
public function updateSettings(UpdateSettings $update, User $user): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
try {
|
||||
$data = [
|
||||
'lang' => $update->getLang(),
|
||||
'timezone' => $update->getTimezone(),
|
||||
];
|
||||
$this->userCommandHandler->handleUpdate($user, $data);
|
||||
} catch (\Throwable $e) {
|
||||
report($e->getMessage());
|
||||
return $this->errService($e->getMessage());
|
||||
}
|
||||
return $this->ok(__('The settings have been saved'));
|
||||
}
|
||||
}
|
15
app/application/app/Services/Project/BuilderCommand.php
Normal file
15
app/application/app/Services/Project/BuilderCommand.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Project;
|
||||
|
||||
use App\Dto\Builder\Project as ProjectBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, ProjectBuilderDto $projectBuilderDto): Relation | Builder
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Project;
|
||||
|
||||
use App\Models\Project;
|
||||
|
||||
final readonly class ProjectCommandHandler
|
||||
{
|
||||
public function handleStore(array $data): Project
|
||||
{
|
||||
return Project::create($data);
|
||||
}
|
||||
|
||||
public function handleUpdate(Project $project, array $data): Project
|
||||
{
|
||||
$project->update($data);
|
||||
$project->touch();
|
||||
|
||||
return $project;
|
||||
}
|
||||
|
||||
public function handleDestroy(Project $project): void
|
||||
{
|
||||
$project->delete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\ProjectLanguage;
|
||||
|
||||
use App\Dto\Service\Admin\Project\Language;
|
||||
use App\Dto\Service\Admin\Project\Languages;
|
||||
use App\Models\Project;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
final readonly class ModelSyncCommand
|
||||
{
|
||||
public function execute(Project $project, Languages $languages): void
|
||||
{
|
||||
$projectLanguages = $project->languages()->get();
|
||||
$this->deleteLanguages($languages, $projectLanguages);
|
||||
|
||||
$languagesInsert = [];
|
||||
$languagesUpdate = [];
|
||||
foreach ($languages->getLanguages() as $language) {
|
||||
/** @var Language $language */
|
||||
$data = [
|
||||
'code' => $language->getCode(),
|
||||
'title' => $language->getTitle(),
|
||||
'sort' => $language->getSort(),
|
||||
'is_default' => $language->isDefault(),
|
||||
];
|
||||
|
||||
if ($language->getId() !== null) {
|
||||
$projectLanguage = $projectLanguages->firstWhere('id', $language->getId());
|
||||
if ($projectLanguage !== null) {
|
||||
|
||||
$projectLanguageFix = $projectLanguages->firstWhere('code', $language->getCode());
|
||||
if ($projectLanguageFix !== null && !in_array($projectLanguageFix->id, $languagesUpdate)) {
|
||||
// Fixing a bug when language codes are swapped.
|
||||
$projectLanguageFix->update([
|
||||
'code' => $projectLanguageFix->code . '-' . $projectLanguageFix->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$projectLanguage->update($data);
|
||||
$languagesUpdate[] = $projectLanguage->id;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$languagesInsert[] = $data;
|
||||
}
|
||||
|
||||
if (!empty($languagesInsert)) {
|
||||
$project->languages()->createMany($languagesInsert);
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteLanguages(Languages $languages, Collection $projectLanguages): void
|
||||
{
|
||||
$languagesIdUpdate = [];
|
||||
foreach ($languages->getLanguages() as $language) {
|
||||
/** @var Language $language */
|
||||
if ($language->getId() === null) {
|
||||
continue;
|
||||
}
|
||||
$languagesIdUpdate[] = $language->getId();
|
||||
}
|
||||
|
||||
foreach ($projectLanguages as $projectLanguage) {
|
||||
if (in_array($projectLanguage->id, $languagesIdUpdate)) {
|
||||
continue;
|
||||
}
|
||||
$projectLanguage->update([
|
||||
'code' => $projectLanguage->code . '-' . $projectLanguage->id,
|
||||
]);
|
||||
$projectLanguage->delete();
|
||||
}
|
||||
}
|
||||
}
|
15
app/application/app/Services/Role/BuilderCommand.php
Normal file
15
app/application/app/Services/Role/BuilderCommand.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Role;
|
||||
|
||||
use App\Dto\Builder\Role as RoleBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, RoleBuilderDto $roleBuilderDto): Relation | Builder
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Role;
|
||||
|
||||
use App\Enums\SystemRole;
|
||||
use App\Models\Project;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use App\Services\User\UserCommandHandler;
|
||||
|
||||
final readonly class CreateAdminRoleForProjectCommand
|
||||
{
|
||||
public function __construct(
|
||||
private UserCommandHandler $userCommandHandler,
|
||||
){ }
|
||||
|
||||
public function execute(Project $project, User $user): Role
|
||||
{
|
||||
$data = [
|
||||
'name' => 'Administrator',
|
||||
'code' => SystemRole::AdminProject->value,
|
||||
|
||||
];
|
||||
$role = $project->roles()->create($data);
|
||||
$this->userCommandHandler->attachRole($user, $role);
|
||||
|
||||
return $role;
|
||||
}
|
||||
}
|
26
app/application/app/Services/Role/RoleCommandHandler.php
Normal file
26
app/application/app/Services/Role/RoleCommandHandler.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Role;
|
||||
|
||||
use App\Models\Role;
|
||||
|
||||
final readonly class RoleCommandHandler
|
||||
{
|
||||
public function handleStore(array $data): Role
|
||||
{
|
||||
return Role::create($data);
|
||||
}
|
||||
|
||||
public function handleUpdate(Role $role, array $data): Role
|
||||
{
|
||||
$role->update($data);
|
||||
$role->touch();
|
||||
|
||||
return $role;
|
||||
}
|
||||
|
||||
public function handleDestroy(Role $role): void
|
||||
{
|
||||
$role->delete();
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Role;
|
||||
|
||||
use App\Enums\Permission;
|
||||
use App\Exceptions\Rule\RoleSyncPermissionsCommandHandlerException;
|
||||
use App\Models\Role;
|
||||
use App\Models\RolePermission;
|
||||
|
||||
final readonly class RoleSyncPermissionsCommandHandler
|
||||
{
|
||||
public function handle(Role $role, array $dataPermissions): Role
|
||||
{
|
||||
$rolePermissions = $role->permissions->pluck('id', 'permission')->toArray();
|
||||
|
||||
$data = $this->getInsertDeleteData($role->id, $rolePermissions, $dataPermissions);
|
||||
|
||||
if (!empty($data['insert'])) {
|
||||
RolePermission::query()->insert($data['insert']);
|
||||
}
|
||||
|
||||
if (!empty($data['delete'])) {
|
||||
RolePermission::query()->whereIn('id', $data['delete'])->delete();
|
||||
}
|
||||
|
||||
return $role;
|
||||
}
|
||||
|
||||
private function getInsertDeleteData(int $roleId, array $rolePermissions, array $permissionsData): array
|
||||
{
|
||||
$data = [
|
||||
'insert' => [],
|
||||
'delete' => []
|
||||
];
|
||||
|
||||
$permissions = Permission::toArrayListCodes();
|
||||
foreach ($permissionsData as $permission) {
|
||||
if (array_search($permission, $permissions) === false) {
|
||||
throw new RoleSyncPermissionsCommandHandlerException('Таких разрешений в системе нет: ' . $permission);
|
||||
}
|
||||
|
||||
if (isset($rolePermissions[$permission])) {
|
||||
unset($rolePermissions[$permission]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['insert'][] = [
|
||||
'role_id' => $roleId,
|
||||
'permission' => $permission,
|
||||
];
|
||||
}
|
||||
|
||||
$data['delete'] = array_values($rolePermissions);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use App\Contracts\Search;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class CreateSearchInstanceCommand
|
||||
{
|
||||
public function __construct(
|
||||
private string $abstract
|
||||
) { }
|
||||
|
||||
public function execute(Relation | Builder $query): Search
|
||||
{
|
||||
return new $this->abstract($query);
|
||||
}
|
||||
}
|
80
app/application/app/Services/Search/Search.php
Normal file
80
app/application/app/Services/Search/Search.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use App\Models\Role;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Pagination\CursorPaginator;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Contracts\Search as SearchContract;
|
||||
|
||||
final readonly class Search implements SearchContract
|
||||
{
|
||||
public function __construct(
|
||||
private Relation|Builder $query
|
||||
) { }
|
||||
|
||||
public function all(): Collection
|
||||
{
|
||||
return $this->query->get();
|
||||
}
|
||||
|
||||
public function get(int $limit): Collection
|
||||
{
|
||||
return $this->query->limit($limit)->get();
|
||||
}
|
||||
|
||||
public function pagination(int $limit, int $page = 1): LengthAwarePaginator
|
||||
{
|
||||
if ($page > 100) {
|
||||
return $this->paginationPerfomance($limit, $page);
|
||||
}
|
||||
return $this->query->paginate($limit, page: $page)->withQueryString();
|
||||
}
|
||||
|
||||
public function cursorPaginate(int $limit): CursorPaginator
|
||||
{
|
||||
return $this->query->cursorPaginate($limit);
|
||||
}
|
||||
|
||||
private function paginationPerfomance(int $limit, int $page = 1): LengthAwarePaginator
|
||||
{
|
||||
$total = $this->query->clone()->count();
|
||||
$options = [
|
||||
'path' => Paginator::resolveCurrentPath(),
|
||||
'pageName' => 'page',
|
||||
];
|
||||
|
||||
$result = collect();
|
||||
if ($total > 0) {
|
||||
$result = $this->subQuery($limit, $page);
|
||||
}
|
||||
|
||||
$pagination = Container::getInstance()->makeWith(LengthAwarePaginator::class, [
|
||||
'items' => $result,
|
||||
'total' => $total,
|
||||
'perPage' => $limit,
|
||||
'currentPage' => $page,
|
||||
'options' => $options
|
||||
]);
|
||||
|
||||
return $pagination->withQueryString();
|
||||
}
|
||||
|
||||
private function subQuery(int $limit, int $page): Collection
|
||||
{
|
||||
$table = $this->query->getModel()->getTable();
|
||||
return $this->query->getModel()::query()
|
||||
->select($table.'.*')
|
||||
->with($this->query->getEagerLoads())
|
||||
->from(
|
||||
clone $this->query->select('id')->forPage($page, $limit),
|
||||
'q'
|
||||
)->join($table.' as '.$table, $table.'.id', '=', 'q.id')
|
||||
->get();
|
||||
}
|
||||
}
|
67
app/application/app/Services/Service.php
Normal file
67
app/application/app/Services/Service.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
abstract class Service
|
||||
{
|
||||
final protected function errValidate(string $message, array $errors = []): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_UNPROCESSABLE_ENTITY, $message, $errors);
|
||||
}
|
||||
|
||||
final protected function errFobidden(string $message): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_FORBIDDEN, $message);
|
||||
}
|
||||
|
||||
final protected function errNotFound(string $message): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_NOT_FOUND, $message);
|
||||
}
|
||||
|
||||
final protected function errService(string $message): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_INTERNAL_SERVER_ERROR, $message);
|
||||
}
|
||||
|
||||
final protected function notAcceptable(string $message): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_NOT_ACCEPTABLE, $message);
|
||||
}
|
||||
|
||||
final protected function errUnauthorized(string $message): ServiceResultError
|
||||
{
|
||||
return $this->error(Response::HTTP_UNAUTHORIZED, $message);
|
||||
}
|
||||
|
||||
final protected function ok(string $message = 'OK'): ServiceResultSuccess
|
||||
{
|
||||
return new ServiceResultSuccess($message);
|
||||
}
|
||||
|
||||
final protected function resultStoreUpdateModel(Model $model, string $message = 'OK'): StoreUpdateResult
|
||||
{
|
||||
return new StoreUpdateResult($model, $message);
|
||||
}
|
||||
|
||||
final protected function result(array $data = []): ServiceResultArray
|
||||
{
|
||||
return new ServiceResultArray(data: $data);
|
||||
}
|
||||
|
||||
final protected function error(int $code, string $message, array $errors = []): ServiceResultError
|
||||
{
|
||||
return new ServiceResultError(
|
||||
message: $message,
|
||||
errors: $errors,
|
||||
code: $code
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Storage\Image;
|
||||
|
||||
use App\Models\Storage;
|
||||
use Intervention\Image\Laravel\Facades\Image as InterventionImage;
|
||||
|
||||
final readonly class ResizeCommandHandler
|
||||
{
|
||||
public function resize(Storage $storage, int $width, int $height): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
if ($image->width() < $width && $image->height() < $height) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
$image->scale($width, $height)
|
||||
->save($storage->path);
|
||||
|
||||
$storage->touch();
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function width(Storage $storage, int $width): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
if ($image->width() < $width) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
$image->scale(width: $width)
|
||||
->save($storage->path);
|
||||
|
||||
$storage->touch();
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function height(Storage $storage, int $height): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
if ($image->height() < $height) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
$image->scale(height: $height)
|
||||
->save($storage->path);
|
||||
|
||||
$storage->touch();
|
||||
return $storage;
|
||||
}
|
||||
}
|
65
app/application/app/Services/Storage/ImageService.php
Normal file
65
app/application/app/Services/Storage/ImageService.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Storage;
|
||||
|
||||
use app\Dto\Service\Storage\Upload;
|
||||
use App\Models\Storage;
|
||||
use App\Models\User;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\Storage\UploadResult;
|
||||
use App\Services\Service;
|
||||
use App\Services\Storage\Image\ResizeCommandHandler;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class ImageService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly StorageCommandHandler $storageCommandHandler,
|
||||
private readonly ResizeCommandHandler $resizeCommandHandler,
|
||||
private readonly int $maxImageWidth,
|
||||
private readonly int $maxImageHeight,
|
||||
) { }
|
||||
|
||||
public function uploadAndResize(Upload $upload, User $user): ServiceResultError | UploadResult
|
||||
{
|
||||
if ($user->cannot('upload', $upload->getMorph()->getPathModel())) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
if ($upload->getStorageType()->isImage() !== true) {
|
||||
return $this->errValidate(__('storage.Trying to upload a wrong image'));
|
||||
}
|
||||
|
||||
try {
|
||||
$storage = DB::transaction(function () use ($upload, $user) {
|
||||
$storage = $this->storageCommandHandler->handleStore(
|
||||
upload: $upload,
|
||||
user: $user,
|
||||
);
|
||||
return $this->imageResize($storage, $this->maxImageWidth, $this->maxImageHeight);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return new UploadResult($storage);
|
||||
}
|
||||
|
||||
private function imageResize(Storage $storage, ?int $width, ?int $height): Storage
|
||||
{
|
||||
if (empty($width) && empty($height)) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
if (!empty($width) && !empty($height)) {
|
||||
return $this->resizeCommandHandler->resize($storage, $width, $height);
|
||||
}
|
||||
|
||||
if (!empty($height)) {
|
||||
return $this->resizeCommandHandler->height($storage, $height);
|
||||
}
|
||||
|
||||
return $this->resizeCommandHandler->width($storage, $width);
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Storage;
|
||||
|
||||
use App\Dto\Service\Storage\Upload;
|
||||
use App\Enums\StorageType;
|
||||
use app\Exceptions\Services\Storage\StorageCommandHandlerException;
|
||||
use App\Exceptions\Services\Storage\StorageSaveFileException;
|
||||
use App\Models\Storage;
|
||||
use App\Models\User;
|
||||
use App\Contracts\Models\Storage as ModelStorageContract;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class StorageCommandHandler
|
||||
{
|
||||
public function __construct(
|
||||
private string $disc,
|
||||
) { }
|
||||
|
||||
public function handleStore(Upload $upload, User $user, array $data = []): Storage
|
||||
{
|
||||
$folder = '/' . $upload->getMorph()->getFolderName();
|
||||
$folder .= date("/Y/m/d");
|
||||
$folder .= '/' . $upload->getStorageType()->getFolderName();
|
||||
$folder = Str::lower($folder);
|
||||
$path = $upload->getFile()->store($folder, $this->disc);
|
||||
|
||||
if ($path === false) {
|
||||
throw new StorageSaveFileException('Could not save the file: ' . $upload->getFile()->getFilename() . '.');
|
||||
}
|
||||
|
||||
$storage = new Storage();
|
||||
$storage->created_user_id = $user->id;
|
||||
$storage->file = '/' . $path;
|
||||
$storage->type = $upload->getStorageType();
|
||||
$storage->morph_type = $upload->getMorph()->value;
|
||||
|
||||
if (!empty($data)) {
|
||||
$storage->fill($data);
|
||||
}
|
||||
$storage->save();
|
||||
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function handleStorageAttachModel(Storage $storage, ModelStorageContract $model): Storage
|
||||
{
|
||||
if ($storage->morph_id === $model->id) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
if (!\is_null($storage->morph_id)) {
|
||||
throw new StorageCommandHandlerException('The model is already attached!');
|
||||
}
|
||||
|
||||
$storage->morph_id = $model->id;
|
||||
$storage->save();
|
||||
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function handleUpdate(Storage $storage, array $data = []): Storage
|
||||
{
|
||||
$storage->update($data);
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function handleDestroy(Storage $storage): void
|
||||
{
|
||||
$storage->delete();
|
||||
}
|
||||
|
||||
public function handleDestroyByIds(array $ids): void
|
||||
{
|
||||
if (!empty($ids)) {
|
||||
Storage::whereIn('id', $ids)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
public function handleDestroyByModel(ModelStorageContract $model, StorageType $type): void
|
||||
{
|
||||
$model->storage()->where('type', $type)->delete();
|
||||
}
|
||||
|
||||
public function handleDestroyByModelStorageIds(ModelStorageContract $model, array $ids, StorageType $type): void
|
||||
{
|
||||
if (!empty($ids)) {
|
||||
$model->storage()->whereIn('id', $ids)->where('type', $type)->delete();
|
||||
}
|
||||
}
|
||||
}
|
72
app/application/app/Services/Storage/StorageService.php
Normal file
72
app/application/app/Services/Storage/StorageService.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Storage;
|
||||
|
||||
use App\Dto\Service\Storage\Storage;
|
||||
use App\Dto\Service\Storage\Storages;
|
||||
use App\Enums\Morph;
|
||||
use App\Contracts\Models\Storage as ModelStorageContract;
|
||||
use App\Repositories\StorageRepository;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\Storage\SaveDeleteStorageResult;
|
||||
use App\Services\Service;
|
||||
|
||||
class StorageService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly StorageRepository $storageRepository,
|
||||
private readonly ValidationService $storageValidation,
|
||||
private readonly StorageCommandHandler $storageCommandHandler,
|
||||
) { }
|
||||
|
||||
public function getStoragesAndValidate(Storages $storages, Morph $morph, ?int $modelId = null): ServiceResultError | SaveDeleteStorageResult
|
||||
{
|
||||
$storageModels = $this->storageRepository->getStoregsByIds($storages->getAllStorageIds())->all();
|
||||
$result = new SaveDeleteStorageResult();
|
||||
|
||||
foreach ($storages->getAllStorages() as $storage) {
|
||||
/** @var Storage $storage */
|
||||
if ($storage->isDelete()) {
|
||||
$result->addDelete($storage);
|
||||
continue;
|
||||
}
|
||||
if (!$storage->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storageModel = $storageModels->firstWhere('id', $storage->getFile()->getId());
|
||||
if (\is_null($storageModel)) {
|
||||
return $this->errValidate(__('storage.File_not_found'));
|
||||
}
|
||||
$validate = $this->storageValidation->execute($storageModel, $morph, $storage->getStorageType(), $modelId);
|
||||
if (!$validate->isSuccess()) {
|
||||
return $this->errValidate($validate->getMessage());
|
||||
}
|
||||
|
||||
$result->addSave($storageModel, $storage);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function saveAndDelete(ModelStorageContract $model, SaveDeleteStorageResult $storageResult): void
|
||||
{
|
||||
foreach ($storageResult->getStoragesForDelete() as $dataStorage) {
|
||||
$type = $dataStorage['type'];
|
||||
if ($dataStorage['isDeleteType']) {
|
||||
$this->storageCommandHandler->handleDestroyByModel($model, $type);
|
||||
}
|
||||
if ($dataStorage['isDeleteType'] || empty($dataStorage['ids'])) {
|
||||
continue;
|
||||
}
|
||||
$this->storageCommandHandler->handleDestroyByModelStorageIds($model, $dataStorage['ids'], $type);
|
||||
}
|
||||
foreach ($storageResult->getStoragesForSave() as $dataStorage) {
|
||||
$storage = $dataStorage['storage'];
|
||||
if ($dataStorage['isMany'] !== true && $storage->morph_id !== $model->id) {
|
||||
$this->storageCommandHandler->handleDestroyByModel($model, $storage->type);
|
||||
}
|
||||
$this->storageCommandHandler->handleStorageAttachModel($storage, $model);
|
||||
}
|
||||
}
|
||||
}
|
48
app/application/app/Services/Storage/ValidationService.php
Normal file
48
app/application/app/Services/Storage/ValidationService.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace app\Services\Storage;
|
||||
|
||||
use App\Enums\Morph;
|
||||
use App\Enums\StorageType;
|
||||
use App\Models\Storage as StorageModel;
|
||||
use App\ServiceResults\ServiceResultError;
|
||||
use App\ServiceResults\ServiceResultSuccess;
|
||||
use App\Services\Service;
|
||||
|
||||
final class ValidationService extends Service
|
||||
{
|
||||
public function execute(StorageModel $storageModel, Morph $morph, StorageType $storageType, ?int $modelId = null): ServiceResultError | ServiceResultSuccess
|
||||
{
|
||||
if (! $this->isMorphMatched($storageModel, $morph, $modelId)) {
|
||||
return $this->errValidate(__('storage.Attempt to replace a file'));
|
||||
}
|
||||
|
||||
if (! $this->isTypeMatched($storageModel, $storageType)) {
|
||||
return $this->errValidate(__('storage.Wrong file type'));
|
||||
}
|
||||
|
||||
return $this->ok(__('OK'));
|
||||
}
|
||||
|
||||
private function isMorphMatched(StorageModel $storageModel, Morph $morph, ?int $modelId = null): bool
|
||||
{
|
||||
if ($storageModel->morph_type !== $morph->value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!\is_null($storageModel->morph_id) && $storageModel->morph_id !== $modelId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isTypeMatched(StorageModel $storageModel, StorageType $type): bool
|
||||
{
|
||||
if ($storageModel->type !== $type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
15
app/application/app/Services/User/BuilderCommand.php
Normal file
15
app/application/app/Services/User/BuilderCommand.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\User;
|
||||
|
||||
use App\Dto\Builder\User as UserBuilderDto;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
final readonly class BuilderCommand
|
||||
{
|
||||
public function execute(Relation | Builder $query, UserBuilderDto $userBuilderDto): Relation | Builder
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
}
|
73
app/application/app/Services/User/UserCommandHandler.php
Normal file
73
app/application/app/Services/User/UserCommandHandler.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\User;
|
||||
|
||||
use App\Dto\User\ManyRoleDto;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class UserCommandHandler
|
||||
{
|
||||
public function handleStore(array $data, int|string $password): User
|
||||
{
|
||||
$data['email'] = Str::lower($data['email']);
|
||||
$data['password'] = $this->hashPassword($password);
|
||||
$user = User::create($data);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function handleUpdate(User $user, array $data): User
|
||||
{
|
||||
if (isset($data['email'])) {
|
||||
$data['email'] = Str::lower($data['email']);
|
||||
}
|
||||
|
||||
if (isset($data['password'])) {
|
||||
unset($data['password']);
|
||||
}
|
||||
|
||||
$user->update($data);
|
||||
$user->touch();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function handleConfirmationByEmail(User $user): void
|
||||
{
|
||||
$user->update(['email_verified_at' => new Carbon('NOW')]);
|
||||
}
|
||||
|
||||
public function handleUpdatePassword(User $user, int|string $password): void
|
||||
{
|
||||
$user->update(['password' => $this->hashPassword($password)]);
|
||||
}
|
||||
|
||||
public function handleSyncRoles(User $user, ManyRoleDto $roles): void
|
||||
{
|
||||
$user->roles()->sync($roles->toArray());
|
||||
}
|
||||
|
||||
public function attachRole(User $user, Role $role): void
|
||||
{
|
||||
$user->roles()->attach($role);
|
||||
}
|
||||
|
||||
public function detachRole(User $user, Role $role): void
|
||||
{
|
||||
$user->roles()->detach($user);
|
||||
}
|
||||
|
||||
private function hashPassword(int|string $password): string
|
||||
{
|
||||
return Hash::make($password);
|
||||
}
|
||||
|
||||
public function handleDestroy(User $user): void
|
||||
{
|
||||
$user->delete();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user