Есть сущность проекты. У проекта есть свойство со списком пользователей, которые работают с этим проектом.
Соответственно есть такие операции(permissions):
1. projects.view - просмотр списка проектов, в которых ты участвуешь.
2. projects.users.view - просмотр списка участников проекта
3. projects.users.edit - редактирование списка участников проекта
Получается, пользователи, имеющие permission projects.view, видят список проектов, в которых они участвуют.
Некоторые из пользователей, имеющие permission projects.users.view, могут видеть еще и всех участников этого проекта.
Вот роут:
$options = ['only' => ['index', 'store', 'destroy']];
Route::resource('/projects/{projectId}/users', 'ProjectUsersController', $options)->names('projects.users');
Можем посмотреть список пользователей, добавить пользователя в проект и удалить из проекта.
Вот как контроллер выглядит сейчас
class ProjectUsersController extends Controller
{
public function index(ProfileRepository $profileRepository, $projectId)
{
$this->authorize('projects.users.view');
$project = Project::find($projectId);
$this->authorize('access', $project);
$userIds = $project->users()->select('id')->pluck('id')->toArray();
$users = $profileRepository->getByIds($userIds);
return $users;
}
}
На всякий случай скину "политику" для операции access
class ProjectPolicy
{
use HandlesAuthorization;
public function access(User $user, Project $project)
{
if ($user->can('projects.view') == false) {
return false;
}
if ($user->id == $project->created_by) {
return true;
}
if ($project->users()->pluck('id')->contains($user->id)) {
return true;
}
return false;
}
}
Вот собственно вопрос. Хочу вынести "получение списка пользователей проекта" в отдельный сервис. И в контроллере вызвать этот сервис, например ProjectUsersService::getUsers($projectId). Операцию projects.users.view я могу проверить прямо в контроллере. А операцию access могу проверить только после получения объекта проекта. Просто не хотелось бы получать проект вне сервиса:
$this->authorize('projects.users.view');
$project = Project::find($projectId);
$this->authorize('access', $project);
$projectUsersService->getUsers($project);
// далее еще будут добавление и удаление участников
$this->authorize('projects.users.edit');
$project = Project::find($projectId);
$this->authorize('access', $project);
$projectUsersService->addUser($project, $userId);
А авторизация внутри сервиса не всегда нужна. Получается нужно в метод getUsers/addUser/removeUser нужно добавлять флаг, о том делать проверку или нет. Или можно как-то еще?
UPD
Вот код сервиса, который получается, если проверку операции access добавить в сервис
class ProjectUsersService
{
public function getUsers(ProfileRepository $profileRepository, int $projectId)
{
$project = Project::find($projectId);
if (\Auth::user()->can('access', $project) == false) {
throw new \Exception();
}
$userIds = $project->users()->select('id')->pluck('id')->toArray();
$users = $profileRepository->getByIds($userIds);
return $users;
}
public function addUserInProject(int $projectId, int $userId)
{
$project = Project::find($projectId);
if (\Auth::user()->can('access', $project) == false) {
throw new \Exception();
}
$project->users()->attach($userId);
}
public function deleteUserFromProject(int $projectId, int $userId)
{
$project = Project::find($projectId);
if (\Auth::user()->can('access', $project) == false) {
throw new \Exception();
}
$project->users()->detach($userId);
}
}