CoolCMS API

UserRelationManager
in package

Set-based management of a user's many-to-many links to roles and groups, directly through DBAL.

Same approach as UserRolePrivilegeMatrixManager / PrivilegeManager: the entity collection userRoles is #[Transient] (saving from the admin does not overwrite it), so the join tables are synchronized deterministically and set-based. Writes are fail-safe (an error is logged and reported as a failure).

Tables:

  • cms_system_user_role_relations (user × role)
  • cms_system_user_group_relations (user × skupina)

Table of Contents

Constants

EXT_TABLE  : mixed = 'cms_system_user_external_logins'
EXT_USER  : mixed = 'cms_system_users_user_id'
GROUP_GROUP  : mixed = 'cms_system_user_groups_group_id'
GROUP_TABLE  : mixed = 'cms_system_user_group_relations'
GROUP_USER  : mixed = 'cms_system_users_user_id'
ROLE_ROLE  : mixed = 'cms_system_user_roles_user_role_id'
ROLE_TABLE  : mixed = 'cms_system_user_role_relations'
ROLE_USER  : mixed = 'cms_system_users_user_id'

Properties

$connection  : Connection

Methods

__construct()  : mixed
getActiveProtectedHolders()  : array<int, array<int, int>>|null
Maps each protected role (`protect_last_holder = 1`) to the ids of its active holders (activated, not banned, not canceled, no pending cancellation request, since such an account cannot sign in).
getExternalLogins()  : array<int, array{type: string, externalId: string}>
Linked external sign-ins (OAuth) of the user, for the admin listing.
getGroupIds()  : array<int, int>
getRoleCatalogue()  : array<int, array{assignable: bool, default: bool, protectLastHolder: bool}>|null
Role catalog with the flags used by the {@see \App\UI\Api\System\Models\Helpers\UserRolePolicy} gates: `assignable`, `default` (= `set_after_registration`, the role of a new account) and `protectLastHolder`.
getRoleIds()  : array<int, int>
getRoleNames()  : array<int, string>
Names of the roles assigned to the user (explicit links, not implicit roles), for the informational `role` claim in the JWT. The entity `User::getUserRoles()` is unusable for this: it reads an unmapped collection, so the claim was empty in every token.
grantDefaultGroups()  : Result
Adds the default user groups (`set_after_registration = 1`) the account does not have yet, like {@see grantDefaultRoles()}. The flag used to be ignored: a new account got roles only, no group (and so no group discount).
grantDefaultRoles()  : Result
Adds the default roles (`set_after_registration = 1`) the account does not have yet; it deletes nothing and duplicates nothing. Called when an account is created ({@see UserManager::afterSave()} and {@see UserManager::createFromExternalLogin()}); it does not change the roles of existing accounts.
removeExternalLogin()  : Result
Unlinks (deletes) one external sign-in of the user.
syncGroups()  : Result
syncRoles()  : Result
IMPORTANT: writes the set without any permission check. The role-change gates are evaluated by {@see UserManager::beforeSave()} through {@see \App\UI\Api\System\Models\Helpers\UserRolePolicy}, so calling this directly bypasses them.
fetchIds()  : array<int, int>
sync()  : Result
Sets the user's links to exactly the given set of ids (deletes all, then inserts the chosen ones).

Constants

Properties

Methods

__construct()

public __construct(Connection $connection) : mixed
Parameters
$connection : Connection

getActiveProtectedHolders()

Maps each protected role (`protect_last_holder = 1`) to the ids of its active holders (activated, not banned, not canceled, no pending cancellation request, since such an account cannot sign in).

public getActiveProtectedHolders([bool $lock = false ]) : array<int, array<int, int>>|null

Used by the "last holder" gates when deleting an account, removing a role, and deactivating, banning or requesting cancellation of an account. null means the query failed (the caller denies: fail-closed).

$lock = true reads with a locking SELECT ... FOR UPDATE (the links of protected roles and the rows of their holders): it makes sense only inside the caller's transaction. Two concurrent deletions or removals of the last two administrators are then serialized and the second sees the state after the first (a locking read in InnoDB reads the latest committed data).

Parameters
$lock : bool = false
Return values
array<int, array<int, int>>|null

getExternalLogins()

Linked external sign-ins (OAuth) of the user, for the admin listing.

public getExternalLogins(int $userId) : array<int, array{type: string, externalId: string}>
Parameters
$userId : int
Return values
array<int, array{type: string, externalId: string}>

getGroupIds()

public getGroupIds(int $userId) : array<int, int>
Parameters
$userId : int
Return values
array<int, int> —

ids of the groups assigned to the user

getRoleCatalogue()

Role catalog with the flags used by the {@see \App\UI\Api\System\Models\Helpers\UserRolePolicy} gates: `assignable`, `default` (= `set_after_registration`, the role of a new account) and `protectLastHolder`.

public getRoleCatalogue() : array<int, array{assignable: bool, default: bool, protectLastHolder: bool}>|null

null means the query failed (the caller denies: fail-closed).

Return values
array<int, array{assignable: bool, default: bool, protectLastHolder: bool}>|null

getRoleIds()

public getRoleIds(int $userId) : array<int, int>
Parameters
$userId : int
Return values
array<int, int> —

ids of the roles assigned to the user

getRoleNames()

Names of the roles assigned to the user (explicit links, not implicit roles), for the informational `role` claim in the JWT. The entity `User::getUserRoles()` is unusable for this: it reads an unmapped collection, so the claim was empty in every token.

public getRoleNames(int $userId) : array<int, string>
Parameters
$userId : int
Return values
array<int, string>

grantDefaultGroups()

Adds the default user groups (`set_after_registration = 1`) the account does not have yet, like {@see grantDefaultRoles()}. The flag used to be ignored: a new account got roles only, no group (and so no group discount).

public grantDefaultGroups(int $userId) : Result
Parameters
$userId : int
Return values
Result

grantDefaultRoles()

Adds the default roles (`set_after_registration = 1`) the account does not have yet; it deletes nothing and duplicates nothing. Called when an account is created ({@see UserManager::afterSave()} and {@see UserManager::createFromExternalLogin()}); it does not change the roles of existing accounts.

public grantDefaultRoles(int $userId) : Result

The entity collection userRoles is not involved: it is #[Transient], so saving through the hydrator does not write it. Only this set-based path manages the links.

Parameters
$userId : int
Return values
Result

removeExternalLogin()

Unlinks (deletes) one external sign-in of the user.

public removeExternalLogin(int $userId, string $type, string $externalId) : Result
Parameters
$userId : int
$type : string
$externalId : string
Return values
Result

syncGroups()

public syncGroups(int $userId, array<string|int, mixed> $groupIds) : Result
Parameters
$userId : int
$groupIds : array<string|int, mixed>
Return values
Result

syncRoles()

IMPORTANT: writes the set without any permission check. The role-change gates are evaluated by {@see UserManager::beforeSave()} through {@see \App\UI\Api\System\Models\Helpers\UserRolePolicy}, so calling this directly bypasses them.

public syncRoles(int $userId, array<string|int, mixed> $roleIds) : Result
Parameters
$userId : int
$roleIds : array<string|int, mixed>
Return values
Result

fetchIds()

private fetchIds(string $table, string $idColumn, string $userColumn, int $userId) : array<int, int>
Parameters
$table : string
$idColumn : string
$userColumn : string
$userId : int
Return values
array<int, int>

sync()

Sets the user's links to exactly the given set of ids (deletes all, then inserts the chosen ones).

private sync(string $table, string $userColumn, string $idColumn, int $userId, array<string|int, mixed> $ids) : Result

IMPORTANT: returns a Result, which is always truthy; the caller must check ->isSuccess(), not if ($result).

Parameters
$table : string
$userColumn : string
$idColumn : string
$userId : int
$ids : array<string|int, mixed>
Return values
Result
On this page

Search results