dataBaseAccess = $dataBaseAccess; $this->strategy = $strategy; $this->eventManager = $eventManager; } public function saveResourcePermissionsRecursive( core_kernel_classes_Resource $resource, array $privilegesToSet ):void { $this->saveResourcePermissions($resource, $privilegesToSet, true); } private function saveResourcePermissions( core_kernel_classes_Resource $resource, array $privilegesToSet, bool $isRecursive ): void { $currentPrivileges = $this->dataBaseAccess->getResourcePermissions($resource->getUri()); $addRemove = $this->strategy->normalizeRequest($currentPrivileges, $privilegesToSet); if (empty($addRemove)) { return; } $resourcesToUpdate = $this->getResourcesToUpdate($resource, $isRecursive); $permissionsList = $this->getResourcesPermissions($resourcesToUpdate); $actions = $this->getActions($resourcesToUpdate, $permissionsList, $addRemove); $this->dryRun($actions, $permissionsList); $this->wetRun($actions); $this->triggerEvents($addRemove, $resource->getUri(), $isRecursive); } /** * @deprecated use saveResourcePermissions */ public function savePermissions( bool $isRecursive, core_kernel_classes_Class $class, array $privilegesToSet ): void { $this->saveResourcePermissions($class, $privilegesToSet, $isRecursive); } private function getActions(array $resourcesToUpdate, array $permissionsList, array $addRemove): array { $actions = ['remove' => [], 'add' => []]; foreach ($resourcesToUpdate as $resource) { $currentPrivileges = $permissionsList[$resource->getUri()]; $remove = $this->strategy->getPermissionsToRemove($currentPrivileges, $addRemove); if ($remove) { $actions['remove'][] = ['permissions' => $remove, 'resource' => $resource]; } $add = $this->strategy->getPermissionsToAdd($currentPrivileges, $addRemove); if ($add) { $actions['add'][] = ['permissions' => $add, 'resource' => $resource]; } } return $actions; } private function dryRun(array $actions, array $permissionsList): void { $resultPermissions = $permissionsList; foreach ($actions['remove'] as $item) { $this->dryRemove($item['permissions'], $item['resource'], $resultPermissions); } foreach ($actions['add'] as $item) { $this->dryAdd($item['permissions'], $item['resource'], $resultPermissions); } $this->validateResources($resultPermissions); } private function wetRun(array $actions): void { if(!empty($actions['remove'])){ $this->dataBaseAccess->removeMultiplePermissions($actions['remove']); } if(!empty($actions['add'])){ $this->dataBaseAccess->addMultiplePermissions($actions['add']); } } private function dryRemove(array $remove, core_kernel_classes_Resource $resource, array &$resultPermissions): void { foreach ($remove as $userToRemove => $permissionToRemove) { if (!empty($resultPermissions[$resource->getUri()][$userToRemove])) { $resultPermissions[$resource->getUri()][$userToRemove] = array_diff( $resultPermissions[$resource->getUri()][$userToRemove], $permissionToRemove ); } } } private function dryAdd(array $add, core_kernel_classes_Resource $resource, array &$resultPermissions): void { foreach ($add as $userToAdd => $permissionToAdd) { if (empty($resultPermissions[$resource->getUri()][$userToAdd])) { $resultPermissions[$resource->getUri()][$userToAdd] = $permissionToAdd; } else { $resultPermissions[$resource->getUri()][$userToAdd] = array_merge( $resultPermissions[$resource->getUri()][$userToAdd], $permissionToAdd ); } } } private function getResourcesToUpdate(core_kernel_classes_Resource $resource, bool $isRecursive): array { $resources = [$resource]; if ($isRecursive && $resource->isClass()) { return array_merge($resources, $resource->getSubClasses(true), $resource->getInstances(true)); } return $resources; } private function getResourcesPermissions(array $resources): array { if (empty($resources)) { return []; } $resourceIds = []; foreach ($resources as $resource) { $resourceIds[] = $resource->getUri(); } return $this->dataBaseAccess->getResourcesPermissions($resourceIds); } private function validateResources(array $resultPermissions): void { // check if all resources after all actions are applied will have al least one user with GRANT permission foreach ($resultPermissions as $resultResources => $resultUsers) { $grunt = false; foreach ($resultUsers as $permissions) { if (in_array(PermissionProvider::PERMISSION_GRANT, $permissions, true)) { $grunt = true; break; } } if (!$grunt) { throw new PermissionsServiceException( sprintf( 'Resource %s should have at least one user with GRANT access', $resultResources ) ); } } } /** * @param array $addRemove * @param string $resourceId * @param bool $isRecursive */ private function triggerEvents(array $addRemove, string $resourceId, bool $isRecursive): void { if (!empty($addRemove['add'])) { foreach ($addRemove['add'] as $userId => $rights) { $this->eventManager->trigger(new DacRootAddedEvent($userId, $resourceId, (array)$rights)); } } if (!empty($addRemove['remove'])) { foreach ($addRemove['remove'] as $userId => $rights) { $this->eventManager->trigger(new DacRootRemovedEvent($userId, $resourceId, (array)$rights)); } } $this->eventManager->trigger( new DacAffectedUsersEvent( array_keys($addRemove['add'] ?? []), array_keys($addRemove['remove'] ?? []) ) ); $this->eventManager->trigger( new DataAccessControlChangedEvent( $resourceId, $addRemove, $isRecursive ) ); } }