Skip to content

Commit ab371ba

Browse files
committed
fix: withPermissions for users without permissions
1 parent 2d10ed7 commit ab371ba

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

phpstan-baseline.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@
502502
$ignoreErrors[] = [
503503
'rawMessage' => 'Call to an undefined method CodeIgniter\\Shield\\Models\\UserModel::getLastQuery().',
504504
'identifier' => 'method.notFound',
505-
'count' => 7,
505+
'count' => 9,
506506
'path' => __DIR__ . '/tests/Unit/UserTest.php',
507507
];
508508
$ignoreErrors[] = [

src/Authorization/Traits/Authorizable.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ public function syncGroups(string ...$groups): self
117117
*/
118118
public function setGroupsCache(array $groups): void
119119
{
120-
$this->groupCache = $groups === [] ? null : $groups;
120+
$this->groupCache = $groups;
121121
}
122122

123123
/**
124124
* Set permissions cache manually
125125
*/
126126
public function setPermissionsCache(array $permissions): void
127127
{
128-
$this->permissionsCache = $permissions === [] ? null : $permissions;
128+
$this->permissionsCache = $permissions;
129129
}
130130

131131
/**

src/Models/UserModel.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,6 @@ protected function fetchGroups(array $data): array
210210
// Get our groups for all users
211211
$groups = $groupModel->getGroupsByUserIds($userIds);
212212

213-
if ($groups === []) {
214-
return $data;
215-
}
216-
217213
$mappedUsers = $this->assignProperties($data, $groups, 'groups');
218214

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

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

250-
if ($permissions === []) {
251-
return $data;
252-
}
253-
254246
$mappedUsers = $this->assignProperties($data, $permissions, 'permissions');
255247

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

284-
// Now assign the properties to the user
285-
foreach ($properties as $userId => $propertyArray) {
286-
$mappedUsers[$userId]->{$method}($propertyArray);
276+
// Assign properties to all users (empty array if no properties found)
277+
foreach ($mappedUsers as $userId => $user) {
278+
$propertyArray = $properties[$userId] ?? [];
279+
$user->{$method}($propertyArray);
287280
}
288281
unset($properties);
289282

tests/Unit/UserTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,26 @@ public function testModelFindByIdWithGroups(): void
188188
);
189189
}
190190

191+
public function testModelFindByIdWithGroupsWhenUserHasNoGroups(): void
192+
{
193+
// User has no groups in the database
194+
$user = model(UserModel::class)->where('active', 1)->withGroups()->findById(1);
195+
196+
$this->assertInstanceOf(User::class, $user);
197+
198+
// Verify groups cache is set to empty array (not null)
199+
$this->assertSame([], $user->getGroups());
200+
$this->assertFalse($user->inGroup('admin'));
201+
202+
// Verify the last query was the one with WHERE IN
203+
$query = (string) model(UserModel::class)->getLastQuery();
204+
$this->assertMatchesRegularExpression(
205+
'/WHERE\s+.*\s+IN\s+\([^)]+\)/i',
206+
$query,
207+
'Groups were not obtained with the single query (missing "WHERE ... IN" condition)',
208+
);
209+
}
210+
191211
public function testModelFindAllWithPermissionsUserNotExists(): void
192212
{
193213
$users = model(UserModel::class)->where('active', 0)->withPermissions()->findAll();
@@ -244,6 +264,28 @@ public function testModelFindByIdWithPermissions(): void
244264
);
245265
}
246266

267+
public function testModelFindByIdWithPermissionsWhenUserHasNoPermissions(): void
268+
{
269+
// Load both groups and permissions to ensure can() doesn't trigger queries
270+
$user = model(UserModel::class)->where('active', 1)->withGroups()->withPermissions()->findById(1);
271+
272+
$this->assertInstanceOf(User::class, $user);
273+
274+
// Verify permissions cache is set to empty array (not null)
275+
$this->assertSame([], $user->getPermissions());
276+
$this->assertSame([], $user->getGroups());
277+
$this->assertFalse($user->hasPermission('users.delete'));
278+
$this->assertFalse($user->can('users.delete'));
279+
280+
// Verify the last query was the one with WHERE IN
281+
$query = (string) model(UserModel::class)->getLastQuery();
282+
$this->assertMatchesRegularExpression(
283+
'/WHERE\s+.*\s+IN\s+\([^)]+\)/i',
284+
$query,
285+
'Groups and Permissions were not obtained with the single query (missing "WHERE ... IN" condition)',
286+
);
287+
}
288+
247289
public function testModelFindByIdWithGroupsAndPermissions(): void
248290
{
249291
fake(GroupModel::class, ['user_id' => $this->user->id, 'group' => 'superadmin']);

0 commit comments

Comments
 (0)