inspiren-sem-tool/app/Services/UserHierarchyService.php
brian-inspiren 221d3f8173
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
feat: sem codebase
2026-05-21 11:28:03 +08:00

95 lines
2.3 KiB
PHP

<?php
namespace App\Services;
use App\Models\Client;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
class UserHierarchyService
{
public function visibleUserIds(User $user): array
{
if ($user->hasRole('Admin')) {
return User::query()->pluck('id')->all();
}
$visibleIds = [$user->id];
$frontier = [$user->id];
while ($frontier !== []) {
$directReportIds = User::query()
->whereIn('manager_id', $frontier)
->pluck('id')
->all();
$directReportIds = array_values(array_diff($directReportIds, $visibleIds));
if ($directReportIds === []) {
break;
}
$visibleIds = array_merge($visibleIds, $directReportIds);
$frontier = $directReportIds;
}
return $visibleIds;
}
public function scopeClientsVisibleTo(Builder $query, User $user): Builder
{
if ($user->hasRole('Admin')) {
return $query;
}
$visibleUserIds = $this->visibleUserIds($user);
return $query->whereHas('assignations', function (Builder $query) use ($visibleUserIds) {
$query->whereIn('user_id', $visibleUserIds);
});
}
public function canViewClient(User $user, Client $client): bool
{
if ($user->hasRole('Admin')) {
return true;
}
return $client->assignations()
->whereIn('user_id', $this->visibleUserIds($user))
->exists();
}
public function wouldCreateCycle(User $user, ?int $managerId): bool
{
if ($managerId === null) {
return false;
}
if ($user->id === $managerId) {
return true;
}
$frontier = [$user->id];
$checkedIds = [$user->id];
while ($frontier !== []) {
$directReportIds = User::query()
->whereIn('manager_id', $frontier)
->pluck('id')
->all();
$directReportIds = array_values(array_diff($directReportIds, $checkedIds));
if (in_array($managerId, $directReportIds, true)) {
return true;
}
$checkedIds = array_merge($checkedIds, $directReportIds);
$frontier = $directReportIds;
}
return false;
}
}