Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@
$ignoreErrors[] = [
'rawMessage' => 'Call to an undefined method CodeIgniter\\Shield\\Models\\UserModel::getLastQuery().',
'identifier' => 'method.notFound',
'count' => 7,
'count' => 9,
'path' => __DIR__ . '/tests/Unit/UserTest.php',
];
$ignoreErrors[] = [
Expand Down
4 changes: 2 additions & 2 deletions src/Authorization/Traits/Authorizable.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ public function syncGroups(string ...$groups): self
*/
public function setGroupsCache(array $groups): void
{
$this->groupCache = $groups === [] ? null : $groups;
$this->groupCache = $groups;
}

/**
* Set permissions cache manually
*/
public function setPermissionsCache(array $permissions): void
{
$this->permissionsCache = $permissions === [] ? null : $permissions;
$this->permissionsCache = $permissions;
}

/**
Expand Down
15 changes: 4 additions & 11 deletions src/Models/UserModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,6 @@ protected function fetchGroups(array $data): array
// Get our groups for all users
$groups = $groupModel->getGroupsByUserIds($userIds);

if ($groups === []) {
return $data;
}

$mappedUsers = $this->assignProperties($data, $groups, 'groups');

$data['data'] = $data['singleton'] ? $mappedUsers[$data['id']] : $mappedUsers;
Expand Down Expand Up @@ -247,10 +243,6 @@ protected function fetchPermissions(array $data): array

$permissions = $permissionModel->getPermissionsByUserIds($userIds);

if ($permissions === []) {
return $data;
}

$mappedUsers = $this->assignProperties($data, $permissions, 'permissions');

$data['data'] = $data['singleton'] ? $mappedUsers[$data['id']] : $mappedUsers;
Expand Down Expand Up @@ -281,9 +273,10 @@ private function assignProperties(array $data, array $properties, string $type):
// Build method name
$method = 'set' . ucfirst($type) . 'Cache';

// Now assign the properties to the user
foreach ($properties as $userId => $propertyArray) {
$mappedUsers[$userId]->{$method}($propertyArray);
// Assign properties to all users (empty array if no properties found)
foreach ($mappedUsers as $userId => $user) {
$propertyArray = $properties[$userId] ?? [];
$user->{$method}($propertyArray);
}
unset($properties);

Expand Down
42 changes: 42 additions & 0 deletions tests/Unit/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,26 @@ public function testModelFindByIdWithGroups(): void
);
}

public function testModelFindByIdWithGroupsWhenUserHasNoGroups(): void
{
// User has no groups in the database
$user = model(UserModel::class)->where('active', 1)->withGroups()->findById(1);

$this->assertInstanceOf(User::class, $user);

// Verify groups cache is set to empty array (not null)
$this->assertSame([], $user->getGroups());
$this->assertFalse($user->inGroup('admin'));

// Verify the last query was the one with WHERE IN
$query = (string) model(UserModel::class)->getLastQuery();
$this->assertMatchesRegularExpression(
'/WHERE\s+.*\s+IN\s+\([^)]+\)/i',
$query,
'Groups were not obtained with the single query (missing "WHERE ... IN" condition)',
);
}

public function testModelFindAllWithPermissionsUserNotExists(): void
{
$users = model(UserModel::class)->where('active', 0)->withPermissions()->findAll();
Expand Down Expand Up @@ -244,6 +264,28 @@ public function testModelFindByIdWithPermissions(): void
);
}

public function testModelFindByIdWithPermissionsWhenUserHasNoPermissions(): void
{
// Load both groups and permissions to ensure can() doesn't trigger queries
$user = model(UserModel::class)->where('active', 1)->withGroups()->withPermissions()->findById(1);

$this->assertInstanceOf(User::class, $user);

// Verify permissions cache is set to empty array (not null)
$this->assertSame([], $user->getPermissions());
$this->assertSame([], $user->getGroups());
$this->assertFalse($user->hasPermission('users.delete'));
$this->assertFalse($user->can('users.delete'));

// Verify the last query was the one with WHERE IN
$query = (string) model(UserModel::class)->getLastQuery();
$this->assertMatchesRegularExpression(
'/WHERE\s+.*\s+IN\s+\([^)]+\)/i',
$query,
'Groups and Permissions were not obtained with the single query (missing "WHERE ... IN" condition)',
);
}

public function testModelFindByIdWithGroupsAndPermissions(): void
{
fake(GroupModel::class, ['user_id' => $this->user->id, 'group' => 'superadmin']);
Expand Down
Loading