refactor(arch): enforce gateway compliance and remove service-wrapping gateways
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Service\User\UserAvatarService;
|
||||
|
||||
class AddressBookAvatarGateway
|
||||
{
|
||||
public function __construct(private readonly UserAvatarService $userAvatarService)
|
||||
{
|
||||
}
|
||||
|
||||
public function hasAvatar(string $userUuid): bool
|
||||
{
|
||||
return $this->userAvatarService->hasAvatar($userUuid);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepository;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
|
||||
class AddressBookCustomFieldGateway
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCustomFieldValueService $userCustomFieldValueService
|
||||
) {
|
||||
}
|
||||
|
||||
public function extractFilterSpec(array $query, int $currentUserId): array
|
||||
{
|
||||
return $this->userCustomFieldValueService->extractAddressBookFilterSpec($query, $currentUserId);
|
||||
}
|
||||
|
||||
public function listOptionsByDefinitionIds(array $definitionIds, bool $activeOnly = true): array
|
||||
{
|
||||
return TenantCustomFieldOptionRepository::listByDefinitionIds($definitionIds, $activeOnly);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Service\Access\RoleService;
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
|
||||
class AddressBookDirectoryGateway
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TenantService $tenantService,
|
||||
private readonly DepartmentService $departmentService,
|
||||
private readonly RoleService $roleService,
|
||||
private readonly DirectoryScopeGateway $scopeGateway
|
||||
) {
|
||||
}
|
||||
|
||||
public function listTenants(): array
|
||||
{
|
||||
return $this->tenantService()->list();
|
||||
}
|
||||
|
||||
public function listDepartmentsByTenantIds(array $tenantIds): array
|
||||
{
|
||||
return $this->departmentService()->listByTenantIds($tenantIds);
|
||||
}
|
||||
|
||||
public function listDepartments(): array
|
||||
{
|
||||
return $this->departmentService()->list();
|
||||
}
|
||||
|
||||
public function listActiveRoles(): array
|
||||
{
|
||||
return $this->roleService()->listActive();
|
||||
}
|
||||
|
||||
public function getUserTenantIds(int $userId): array
|
||||
{
|
||||
return $this->scopeGateway()->getUserTenantIds($userId);
|
||||
}
|
||||
|
||||
public function isStrictScope(): bool
|
||||
{
|
||||
return $this->scopeGateway()->isStrict();
|
||||
}
|
||||
|
||||
public function canAccessUser(int $viewerUserId, int $targetUserId): bool
|
||||
{
|
||||
return $this->scopeGateway()->canAccess('users', $targetUserId, $viewerUserId);
|
||||
}
|
||||
|
||||
private function tenantService(): TenantService
|
||||
{
|
||||
return $this->tenantService;
|
||||
}
|
||||
|
||||
private function departmentService(): DepartmentService
|
||||
{
|
||||
return $this->departmentService;
|
||||
}
|
||||
|
||||
private function roleService(): RoleService
|
||||
{
|
||||
return $this->roleService;
|
||||
}
|
||||
|
||||
private function scopeGateway(): DirectoryScopeGateway
|
||||
{
|
||||
return $this->scopeGateway;
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,27 @@
|
||||
|
||||
namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Repository\CustomField\TenantCustomFieldOptionRepository;
|
||||
use MintyPHP\Service\Access\RoleService;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Tenant\TenantScopeService;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserAssignmentService;
|
||||
use MintyPHP\Service\User\UserAvatarService;
|
||||
|
||||
class AddressBookService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserAccountService $userAccountService,
|
||||
private readonly UserAssignmentService $userAssignmentService,
|
||||
private readonly AddressBookDirectoryGateway $directoryGateway,
|
||||
private readonly AddressBookCustomFieldGateway $customFieldGateway,
|
||||
private readonly AddressBookAvatarGateway $avatarGateway
|
||||
private readonly TenantService $tenantService,
|
||||
private readonly DepartmentService $departmentService,
|
||||
private readonly RoleService $roleService,
|
||||
private readonly TenantScopeService $scopeGateway,
|
||||
private readonly UserCustomFieldValueService $customFieldValueService,
|
||||
private readonly UserAvatarService $avatarService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -22,8 +32,8 @@ class AddressBookService
|
||||
$activeRoles = $this->splitCommaValues($query['roles'] ?? '');
|
||||
$activeDepartments = $this->splitCommaValues($query['departments'] ?? '');
|
||||
|
||||
$tenantIds = $this->normalizeIds($this->directoryGateway->getUserTenantIds($currentUserId));
|
||||
$tenants = $this->directoryGateway->listTenants();
|
||||
$tenantIds = $this->normalizeIds($this->scopeGateway->getUserTenantIds($currentUserId));
|
||||
$tenants = $this->tenantService->list();
|
||||
if ($tenantIds) {
|
||||
$allowedTenantMap = array_fill_keys($tenantIds, true);
|
||||
$tenants = array_values(array_filter(
|
||||
@@ -33,7 +43,7 @@ class AddressBookService
|
||||
return $tenantId > 0 && isset($allowedTenantMap[$tenantId]);
|
||||
}
|
||||
));
|
||||
} elseif ($this->directoryGateway->isStrictScope()) {
|
||||
} elseif ($this->scopeGateway->isStrict()) {
|
||||
$tenants = [];
|
||||
}
|
||||
|
||||
@@ -46,12 +56,12 @@ class AddressBookService
|
||||
);
|
||||
|
||||
$departments = $tenantIds
|
||||
? $this->directoryGateway->listDepartmentsByTenantIds($tenantIds)
|
||||
: ($this->directoryGateway->isStrictScope() ? [] : $this->directoryGateway->listDepartments());
|
||||
? $this->departmentService->listByTenantIds($tenantIds)
|
||||
: ($this->scopeGateway->isStrict() ? [] : $this->departmentService->list());
|
||||
|
||||
$roles = $this->directoryGateway->listActiveRoles();
|
||||
$roles = $this->roleService->listActive();
|
||||
|
||||
$customFieldFilterSpec = $this->customFieldGateway->extractFilterSpec($query, $currentUserId);
|
||||
$customFieldFilterSpec = $this->customFieldValueService->extractAddressBookFilterSpec($query, $currentUserId);
|
||||
$customFieldFilterDefinitions = $this->normalizeDefinitions(
|
||||
$customFieldFilterSpec['definitions'] ?? []
|
||||
);
|
||||
@@ -68,7 +78,7 @@ class AddressBookService
|
||||
}
|
||||
$customFieldDefinitionIds = array_values(array_unique($customFieldDefinitionIds));
|
||||
|
||||
$customFieldOptions = $this->customFieldGateway->listOptionsByDefinitionIds(
|
||||
$customFieldOptions = TenantCustomFieldOptionRepository::listByDefinitionIds(
|
||||
$customFieldDefinitionIds,
|
||||
true
|
||||
);
|
||||
@@ -151,7 +161,7 @@ class AddressBookService
|
||||
$tenants = $query['tenants'] ?? '';
|
||||
$departments = $query['departments'] ?? '';
|
||||
$roles = $query['roles'] ?? '';
|
||||
$customFieldFilterSpec = $this->customFieldGateway->extractFilterSpec($query, $currentUserId);
|
||||
$customFieldFilterSpec = $this->customFieldValueService->extractAddressBookFilterSpec($query, $currentUserId);
|
||||
|
||||
$result = $this->userAccountService->listPaged([
|
||||
'limit' => $limit,
|
||||
@@ -195,7 +205,7 @@ class AddressBookService
|
||||
'tenants' => $tenantList,
|
||||
'departments' => $departmentList,
|
||||
'roles' => $roleList,
|
||||
'has_avatar' => $uuid !== '' && $this->avatarGateway->hasAvatar($uuid),
|
||||
'has_avatar' => $uuid !== '' && $this->avatarService->hasAvatar($uuid),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -225,12 +235,12 @@ class AddressBookService
|
||||
// Users can always view their own profile; others require scope access.
|
||||
if (
|
||||
$currentUserId !== $targetUserId
|
||||
&& !$this->directoryGateway->canAccessUser($currentUserId, $targetUserId)
|
||||
&& !$this->scopeGateway->canAccess('users', $targetUserId, $currentUserId)
|
||||
) {
|
||||
return ['status' => 'forbidden'];
|
||||
}
|
||||
|
||||
$viewerTenantIds = $this->normalizeIds($this->directoryGateway->getUserTenantIds($currentUserId));
|
||||
$viewerTenantIds = $this->normalizeIds($this->scopeGateway->getUserTenantIds($currentUserId));
|
||||
$assignments = $this->userAssignmentService->buildAssignmentsForUser($targetUserId);
|
||||
|
||||
$departmentMap = [];
|
||||
@@ -294,7 +304,7 @@ class AddressBookService
|
||||
$roleLabels = array_values($roleLabels);
|
||||
|
||||
$avatarUuid = (string) ($user['uuid'] ?? '');
|
||||
$user['has_avatar'] = $avatarUuid !== '' && $this->avatarGateway->hasAvatar($avatarUuid);
|
||||
$user['has_avatar'] = $avatarUuid !== '' && $this->avatarService->hasAvatar($avatarUuid);
|
||||
$user['tenant_groups'] = $tenantGroups;
|
||||
$user['role_labels'] = $roleLabels;
|
||||
|
||||
|
||||
@@ -4,19 +4,18 @@ namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Service\CustomField\CustomFieldServicesFactory;
|
||||
use MintyPHP\Service\Directory\DirectoryServicesFactory;
|
||||
use MintyPHP\Service\Tenant\TenantScopeService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
|
||||
class AddressBookServicesFactory
|
||||
{
|
||||
private ?AddressBookDirectoryGateway $addressBookDirectoryGateway = null;
|
||||
private ?AddressBookCustomFieldGateway $addressBookCustomFieldGateway = null;
|
||||
private ?AddressBookAvatarGateway $addressBookAvatarGateway = null;
|
||||
private ?AddressBookService $addressBookService = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly UserServicesFactory $userServicesFactory,
|
||||
private readonly DirectoryServicesFactory $directoryServicesFactory,
|
||||
private readonly CustomFieldServicesFactory $customFieldServicesFactory
|
||||
private readonly CustomFieldServicesFactory $customFieldServicesFactory,
|
||||
private readonly TenantScopeService $tenantScopeService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -27,41 +26,16 @@ class AddressBookServicesFactory
|
||||
}
|
||||
|
||||
$userFactory = $this->userServicesFactory;
|
||||
$directoryFactory = $this->directoryServicesFactory;
|
||||
return $this->addressBookService = new AddressBookService(
|
||||
$userFactory->createUserAccountService(),
|
||||
$userFactory->createUserAssignmentService(),
|
||||
$this->createAddressBookDirectoryGateway(),
|
||||
$this->createAddressBookCustomFieldGateway(),
|
||||
$this->createAddressBookAvatarGateway()
|
||||
);
|
||||
}
|
||||
|
||||
public function createAddressBookDirectoryGateway(): AddressBookDirectoryGateway
|
||||
{
|
||||
if ($this->addressBookDirectoryGateway !== null) {
|
||||
return $this->addressBookDirectoryGateway;
|
||||
}
|
||||
|
||||
$directoryFactory = $this->directoryServicesFactory;
|
||||
return $this->addressBookDirectoryGateway = new AddressBookDirectoryGateway(
|
||||
$directoryFactory->createTenantService(),
|
||||
$directoryFactory->createDepartmentService(),
|
||||
$directoryFactory->createRoleService(),
|
||||
$directoryFactory->createDirectoryScopeGateway()
|
||||
);
|
||||
}
|
||||
|
||||
public function createAddressBookCustomFieldGateway(): AddressBookCustomFieldGateway
|
||||
{
|
||||
return $this->addressBookCustomFieldGateway ??= new AddressBookCustomFieldGateway(
|
||||
$this->customFieldServicesFactory->createUserCustomFieldValueService()
|
||||
);
|
||||
}
|
||||
|
||||
public function createAddressBookAvatarGateway(): AddressBookAvatarGateway
|
||||
{
|
||||
return $this->addressBookAvatarGateway ??= new AddressBookAvatarGateway(
|
||||
$this->userServicesFactory->createUserAvatarService()
|
||||
$this->tenantScopeService,
|
||||
$this->customFieldServicesFactory->createUserCustomFieldValueService(),
|
||||
$userFactory->createUserAvatarService()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user