Files
breadcrumb-the-shire/lib/Service/Tenant/TenantScopeService.php

170 lines
5.2 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\Tenant;
2026-02-04 23:31:53 +01:00
2026-03-05 08:26:51 +01:00
use MintyPHP\Repository\Org\DepartmentRepositoryInterface;
use MintyPHP\Repository\Tenant\TenantRepositoryInterface;
use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
2026-02-23 12:58:19 +01:00
use MintyPHP\Service\Access\PermissionGateway;
2026-02-11 19:28:12 +01:00
use MintyPHP\Service\Access\PermissionService;
2026-02-04 23:31:53 +01:00
class TenantScopeService
{
2026-02-23 12:58:19 +01:00
public function __construct(
2026-03-05 08:26:51 +01:00
private readonly TenantRepositoryInterface $tenantRepository,
private readonly DepartmentRepositoryInterface $departmentRepository,
private readonly UserTenantRepositoryInterface $userTenantRepository,
2026-02-23 12:58:19 +01:00
private readonly PermissionGateway $permissionGateway
) {
}
public function isStrict(): bool
2026-02-04 23:31:53 +01:00
{
return defined('TENANT_SCOPE_STRICT') ? (bool) TENANT_SCOPE_STRICT : true;
}
2026-02-23 12:58:19 +01:00
public function getUserTenantIds(int $userId, bool $onlyActive = true): array
2026-02-04 23:31:53 +01:00
{
if ($userId <= 0) {
return [];
}
2026-02-23 12:58:19 +01:00
if ($this->canBypass($userId)) {
$ids = $this->tenantRepository->listIds();
2026-02-04 23:31:53 +01:00
} else {
2026-02-23 12:58:19 +01:00
$ids = array_values(array_unique(array_map(
'intval',
$this->userTenantRepository->listTenantIdsByUserId($userId)
)));
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
if ($onlyActive) {
2026-02-23 12:58:19 +01:00
return $this->filterActiveTenantIds($ids);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
return $ids;
}
2026-02-23 12:58:19 +01:00
public function canAccess(string $resource, int $resourceId, int $userId): bool
2026-02-04 23:31:53 +01:00
{
if ($resourceId <= 0 || $userId <= 0) {
return false;
}
2026-02-23 12:58:19 +01:00
if ($this->canBypass($userId)) {
2026-02-04 23:31:53 +01:00
return true;
}
2026-02-23 12:58:19 +01:00
$resourceTenantIdsRaw = $this->getResourceTenantIds($resource, $resourceId);
$userTenantIdsRaw = $this->getUserTenantIds($userId, false);
$resourceTenantIds = $this->filterActiveTenantIds($resourceTenantIdsRaw);
$userTenantIds = $this->filterActiveTenantIds($userTenantIdsRaw);
2026-02-04 23:31:53 +01:00
if ($resourceTenantIdsRaw && !$resourceTenantIds) {
return false;
}
if (!$resourceTenantIds) {
2026-02-23 12:58:19 +01:00
return $this->isStrict() ? false : true;
2026-02-04 23:31:53 +01:00
}
if (!$userTenantIds) {
return false;
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
return (bool) array_intersect($resourceTenantIds, $userTenantIds);
}
2026-02-23 12:58:19 +01:00
public function filterTenantIdsForUser(array $tenantIds, int $userId): array
2026-02-04 23:31:53 +01:00
{
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
2026-02-23 12:58:19 +01:00
$userTenantIds = $this->getUserTenantIds($userId);
2026-02-04 23:31:53 +01:00
if (!$userTenantIds) {
return [];
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
return array_values(array_intersect($tenantIds, $userTenantIds));
}
2026-02-23 12:58:19 +01:00
public function mergeTenantIdsPreservingOutOfScope(
array $requestedTenantIds,
array $existingTenantIds,
array $allowedTenantIds
): array {
2026-02-04 23:31:53 +01:00
$requestedTenantIds = array_values(array_unique(array_map('intval', $requestedTenantIds)));
$existingTenantIds = array_values(array_unique(array_map('intval', $existingTenantIds)));
$allowedTenantIds = array_values(array_unique(array_map('intval', $allowedTenantIds)));
if (!$allowedTenantIds) {
return $existingTenantIds;
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
$outOfScope = array_values(array_diff($existingTenantIds, $allowedTenantIds));
return array_values(array_unique(array_merge($requestedTenantIds, $outOfScope)));
}
2026-02-23 12:58:19 +01:00
public function hasGlobalAccess(int $userId): bool
2026-02-04 23:31:53 +01:00
{
2026-02-23 12:58:19 +01:00
return $this->canBypass($userId);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
public function resourceBelongsToTenant(string $resource, int $resourceId, int $tenantId): bool
{
if ($resourceId <= 0 || $tenantId <= 0) {
return false;
}
2026-02-23 12:58:19 +01:00
$resourceTenantIds = $this->getResourceTenantIds($resource, $resourceId);
if (!$resourceTenantIds) {
return false;
}
2026-02-23 12:58:19 +01:00
$activeResourceTenantIds = $this->filterActiveTenantIds($resourceTenantIds);
if (!$activeResourceTenantIds) {
return false;
}
return in_array($tenantId, $activeResourceTenantIds, true);
}
2026-02-23 12:58:19 +01:00
private function getResourceTenantIds(string $resource, int $resourceId): array
2026-02-04 23:31:53 +01:00
{
$resource = strtolower(trim($resource));
if ($resource === 'tenants') {
return $resourceId > 0 ? [$resourceId] : [];
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
if ($resource === 'users') {
2026-02-23 12:58:19 +01:00
return array_values(array_unique(array_map(
'intval',
$this->userTenantRepository->listTenantIdsByUserId($resourceId)
)));
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
if ($resource === 'departments') {
2026-02-23 12:58:19 +01:00
$department = $this->departmentRepository->find($resourceId);
$tenantId = (int) ($department['tenant_id'] ?? 0);
return $tenantId > 0 ? [$tenantId] : [];
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
2026-02-04 23:31:53 +01:00
return [];
}
2026-02-23 12:58:19 +01:00
private function filterActiveTenantIds(array $tenantIds): array
2026-02-04 23:31:53 +01:00
{
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
if (!$tenantIds) {
return [];
}
2026-02-23 12:58:19 +01:00
return $this->tenantRepository->listActiveIdsByIds($tenantIds);
2026-02-04 23:31:53 +01:00
}
2026-02-23 12:58:19 +01:00
private function canBypass(int $userId): bool
2026-02-04 23:31:53 +01:00
{
if ($userId <= 0) {
return false;
}
2026-02-23 12:58:19 +01:00
return $this->permissionGateway->userHas($userId, PermissionService::TENANT_SCOPE_GLOBAL);
2026-02-04 23:31:53 +01:00
}
}