1
0
Files
breadcrumb-the-shire/core/Service/Access/RoleService.php

186 lines
6.1 KiB
PHP
Raw Normal View History

2026-02-04 23:31:53 +01:00
<?php
2026-02-11 19:28:12 +01:00
namespace MintyPHP\Service\Access;
2026-02-04 23:31:53 +01:00
2026-03-05 08:26:51 +01:00
use MintyPHP\Repository\Access\RoleRepositoryInterface;
use MintyPHP\Service\Audit\AuditRecorderInterface;
2026-02-23 12:58:19 +01:00
use MintyPHP\Service\Directory\DirectorySettingsGateway;
2026-02-04 23:31:53 +01:00
class RoleService
{
2026-02-23 12:58:19 +01:00
public function __construct(
2026-03-05 08:26:51 +01:00
private readonly RoleRepositoryInterface $roleRepository,
2026-03-04 15:56:58 +01:00
private readonly DirectorySettingsGateway $settingsGateway,
private readonly AuditRecorderInterface $systemAuditService
2026-02-23 12:58:19 +01:00
) {
}
public function list(): array
2026-02-04 23:31:53 +01:00
{
2026-03-04 15:56:58 +01:00
return $this->roleRepository->list();
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function listActive(): array
2026-02-11 19:28:12 +01:00
{
2026-03-04 15:56:58 +01:00
return $this->roleRepository->listActive();
2026-02-11 19:28:12 +01:00
}
2026-02-23 12:58:19 +01:00
public function listPaged(array $options): array
2026-02-04 23:31:53 +01:00
{
2026-03-04 15:56:58 +01:00
return $this->roleRepository->listPaged($options);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function findByUuid(string $uuid): ?array
2026-02-04 23:31:53 +01:00
{
2026-03-04 15:56:58 +01:00
return $this->roleRepository->findByUuid($uuid);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function findById(int $id): ?array
2026-02-04 23:31:53 +01:00
{
2026-03-04 15:56:58 +01:00
return $this->roleRepository->find($id);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function createFromAdmin(array $input, int $currentUserId = 0): array
2026-02-04 23:31:53 +01:00
{
2026-02-23 12:58:19 +01:00
$form = $this->sanitizeBase($input);
$errors = $this->validateBase($form);
$warnings = $this->warningsForCode($form, 0);
2026-02-04 23:31:53 +01:00
if ($errors) {
return ['ok' => false, 'errors' => $errors, 'warnings' => $warnings, 'form' => $form];
2026-02-04 23:31:53 +01:00
}
2026-03-04 15:56:58 +01:00
$createdId = $this->roleRepository->create([
2026-02-04 23:31:53 +01:00
'description' => $form['description'],
2026-02-11 19:28:12 +01:00
'code' => $form['code'] ?: null,
'active' => $form['active'],
2026-02-04 23:31:53 +01:00
'created_by' => $currentUserId > 0 ? $currentUserId : null,
]);
if (!$createdId) {
return ['ok' => false, 'errors' => [t('Role can not be created')], 'form' => $form];
}
2026-03-04 15:56:58 +01:00
$createdRole = $this->roleRepository->find((int) $createdId);
2026-02-04 23:31:53 +01:00
$uuid = $createdRole['uuid'] ?? null;
if (!empty($input['is_default'])) {
2026-03-04 15:56:58 +01:00
$this->settingsGateway->setDefaultRoleId((int) $createdId);
2026-02-04 23:31:53 +01:00
}
2026-03-04 15:56:58 +01:00
$this->systemAuditService->record('admin.roles.create', 'success', [
'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
'target_type' => 'role',
'target_id' => (int) $createdId,
'target_uuid' => is_string($uuid) ? $uuid : '',
'metadata' => ['active' => $form['active']],
]);
return ['ok' => true, 'form' => $form, 'warnings' => $warnings, 'uuid' => $uuid, 'id' => (int) $createdId];
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function updateFromAdmin(int $roleId, array $input, int $currentUserId = 0): array
2026-02-04 23:31:53 +01:00
{
2026-02-23 12:58:19 +01:00
$form = $this->sanitizeBase($input);
$errors = $this->validateBase($form);
$warnings = $this->warningsForCode($form, $roleId);
2026-02-04 23:31:53 +01:00
if ($errors) {
return ['ok' => false, 'errors' => $errors, 'warnings' => $warnings, 'form' => $form];
2026-02-04 23:31:53 +01:00
}
2026-03-04 15:56:58 +01:00
$existingBefore = $this->roleRepository->find($roleId) ?? [];
$updated = $this->roleRepository->update($roleId, [
2026-02-04 23:31:53 +01:00
'description' => $form['description'],
2026-02-11 19:28:12 +01:00
'code' => $form['code'] ?: null,
'active' => $form['active'],
2026-02-04 23:31:53 +01:00
'modified_by' => $currentUserId > 0 ? $currentUserId : null,
]);
if (!$updated) {
return ['ok' => false, 'errors' => [t('Role can not be updated')], 'form' => $form];
}
2026-03-04 15:56:58 +01:00
$this->systemAuditService->record('admin.roles.update', 'success', [
'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
'target_type' => 'role',
'target_id' => $roleId,
'target_uuid' => (string) ($existingBefore['uuid'] ?? ''),
'before' => ['active' => $existingBefore['active'] ?? null],
'after' => ['active' => $form['active']],
]);
return ['ok' => true, 'form' => $form, 'warnings' => $warnings];
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function deleteByUuid(string $uuid): array
2026-02-04 23:31:53 +01:00
{
$uuid = trim($uuid);
if ($uuid === '') {
return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
}
2026-03-04 15:56:58 +01:00
$role = $this->roleRepository->findByUuid($uuid);
2026-02-04 23:31:53 +01:00
if (!$role || !isset($role['id'])) {
return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
}
if (($role['description'] ?? '') === 'Admin') {
return ['ok' => false, 'status' => 403, 'error' => 'admin_role_protected'];
}
2026-03-04 15:56:58 +01:00
$deleted = $this->roleRepository->delete((int) $role['id']);
2026-02-04 23:31:53 +01:00
if (!$deleted) {
return ['ok' => false, 'status' => 500, 'error' => 'delete_failed'];
}
2026-03-04 15:56:58 +01:00
$this->systemAuditService->record('admin.roles.delete', 'success', [
'target_type' => 'role',
'target_id' => (int) $role['id'],
'target_uuid' => (string) ($role['uuid'] ?? ''),
]);
2026-02-04 23:31:53 +01:00
return ['ok' => true, 'role' => $role];
}
2026-02-23 12:58:19 +01:00
private function sanitizeBase(array $input): array
2026-02-04 23:31:53 +01:00
{
return [
'description' => trim((string) ($input['description'] ?? '')),
2026-02-11 19:28:12 +01:00
'code' => trim((string) ($input['code'] ?? '')),
2026-02-23 12:58:19 +01:00
'active' => $this->normalizeActive($input['active'] ?? 1),
2026-02-04 23:31:53 +01:00
];
}
private function validateBase(array $form): array
2026-02-04 23:31:53 +01:00
{
$errors = [];
if ($form['description'] === '') {
$errors[] = t('Description cannot be empty');
}
return $errors;
}
// Duplicate codes are a warning, not a hard error — codes are optional identifiers,
// not unique keys, so duplicates are allowed but surfaced to the user.
private function warningsForCode(array $form, int $excludeId): array
{
$warnings = [];
2026-02-11 19:28:12 +01:00
$code = $form['code'] ?? '';
2026-03-04 15:56:58 +01:00
if ($code !== '' && $this->roleRepository->existsByCode($code, $excludeId)) {
$warnings[] = t('Role code already exists');
2026-02-11 19:28:12 +01:00
}
return $warnings;
2026-02-04 23:31:53 +01:00
}
2026-02-11 19:28:12 +01:00
2026-02-23 12:58:19 +01:00
private function normalizeActive($value): int
2026-02-11 19:28:12 +01:00
{
$value = strtolower(trim((string) $value));
if (in_array($value, ['0', 'false', 'inactive'], true)) {
return 0;
}
return 1;
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
}