Skip to content

Commit 9600914

Browse files
committed
feat: add sorting functionality to user list retrieval
1 parent 8485afb commit 9600914

File tree

7 files changed

+65
-18
lines changed

7 files changed

+65
-18
lines changed

contexts/Authorization/Application/Coordinators/UserIdentityCoordinator.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ public function getUserList(GetUserListDTO $data): LengthAwarePaginator
6161
new GlobalPermissionPolicy('user.list'),
6262
])->check();
6363

64-
return $this->repository->paginate($data->currentPage, $data->perPage, $data->toCriteria());
64+
return $this->repository->paginate(
65+
$data->currentPage,
66+
$data->perPage,
67+
$data->toCriteria(),
68+
$data->toSorting()
69+
);
6570
}
6671

6772
public function updateUser(int $id, UpdateUserDTO $data): UserIdentity

contexts/Authorization/Application/DTOs/User/GetUserListDTO.php

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
namespace Contexts\Authorization\Application\DTOs\User;
66

7-
class GetUserListDTO
7+
use Contexts\Shared\Application\BaseGetListDTO;
8+
9+
class GetUserListDTO extends BaseGetListDTO
810
{
11+
protected const ALLOWED_SORT_FIELDS = ['id', 'created_at'];
12+
913
public function __construct(
1014
public readonly ?string $id,
1115
public readonly ?string $email,
@@ -14,21 +18,30 @@ public function __construct(
1418
public readonly ?array $createdAtRange,
1519
public readonly int $currentPage,
1620
public readonly int $perPage,
21+
public readonly ?array $sorting
1722
) {}
1823

1924
public static function fromRequest(array $data): self
2025
{
26+
$merged = array_merge($data, self::convertFiltersToCriteria($data['filters'] ?? []));
27+
2128
return new self(
22-
$data['id'] ?? null,
23-
$data['email'] ?? null,
24-
$data['display_name'] ?? null,
25-
$data['status'] ?? null,
26-
$data['created_at_range'] ?? null,
27-
$data['current_page'] ?? 1,
28-
$data['per_page'] ?? 10,
29+
$merged['id'] ?? null,
30+
$merged['email'] ?? null,
31+
$merged['display_name'] ?? null,
32+
$merged['status'] ?? null,
33+
$merged['created_at_range'] ?? null,
34+
$merged['current_page'] ?? 1,
35+
$merged['per_page'] ?? 10,
36+
self::normalizeAndFilterSorting($merged)
2937
);
3038
}
3139

40+
public function toSorting(): array
41+
{
42+
return $this->sorting;
43+
}
44+
3245
public function toCriteria(): array
3346
{
3447
return [

contexts/Authorization/Domain/Repositories/UserRepository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function getById(UserId $userId): UserIdentity;
1717

1818
public function update(UserIdentity $user): UserIdentity;
1919

20-
public function paginate(int $currentPage = 1, int $perPage = 10, array $criteria = []): LengthAwarePaginator;
20+
public function paginate(int $currentPage = 1, int $perPage = 10, array $criteria = [], array $sorting = []): LengthAwarePaginator;
2121

2222
public function delete(UserIdentity $user): void;
2323

contexts/Authorization/Infrastructure/Persistence/UserPersistence.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,12 @@ public function update(UserIdentity $user): UserIdentity
6767
return $record->toDomain($user->getEvents());
6868
}
6969

70-
public function paginate(int $currentPage = 1, int $perPage = 10, array $criteria = []): LengthAwarePaginator
70+
public function paginate(int $currentPage = 1, int $perPage = 10, array $criteria = [], array $sorting = []): LengthAwarePaginator
7171
{
72-
$paginator = UserRecord::query()->search($criteria)->paginate($perPage, ['*'], 'current_page', $currentPage);
72+
$paginator = UserRecord::query()
73+
->search($criteria)
74+
->sorting($sorting)
75+
->paginate($perPage, ['*'], 'current_page', $currentPage);
7376

7477
$paginator->getCollection()->transform(function ($record) {
7578
return $record->toDomain();

contexts/Authorization/Infrastructure/Records/UserRecord.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Contexts\Authorization\Domain\UserIdentity\Models\UserIdentity;
1414
use Contexts\Authorization\Domain\UserIdentity\Models\UserStatus;
1515
use Contexts\Authorization\Infrastructure\RecordFactories\UserRecordFactory;
16+
use Contexts\Shared\Infrastructure\Traits\HasSortingScopeTrait;
1617
use Illuminate\Database\Eloquent\Builder;
1718
use Illuminate\Database\Eloquent\Factories\Factory;
1819
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -34,6 +35,7 @@ class UserRecord extends Authenticatable
3435
{
3536
use HasApiTokens;
3637
use HasFactory;
38+
use HasSortingScopeTrait;
3739
use Notifiable;
3840

3941
protected $table = 'users';

contexts/Authorization/Presentation/Requests/User/GetUserListRequest.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace Contexts\Authorization\Presentation\Requests\User;
66

7-
use Contexts\Shared\Presentation\Requests\BaseRequest;
7+
use Contexts\Shared\Presentation\Requests\BaseListRequest;
88

9-
class GetUserListRequest extends BaseRequest
9+
class GetUserListRequest extends BaseListRequest
1010
{
1111
public function rules(): array
1212
{
@@ -15,10 +15,11 @@ public function rules(): array
1515
'display_name' => ['string', 'max:255'],
1616
'email' => ['email', 'max:255'],
1717
'status' => ['string', 'in:suspended,active'],
18-
'created_at_range' => ['array', 'size:2'],
19-
'created_at_range.*' => ['date'],
20-
'current_page' => ['integer', 'gt:0'],
21-
'per_page' => ['integer', 'gt:0'],
18+
'created_at' => ['array', 'size:2'],
19+
'created_at.*' => ['date_format:Y-m-d'],
20+
...$this->paginationRule(),
21+
...$this->filtersRule(),
22+
...$this->sortingRule(),
2223
];
2324
}
2425
}

contexts/Authorization/Tests/Feature/UserTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Contexts\Authorization\Domain\Policies\RolePolicy;
66
use Contexts\Authorization\Infrastructure\Records\RoleRecord;
7+
use Contexts\Authorization\Infrastructure\Records\UserRecord;
78

89
beforeEach(function () {
910
Config::set('policies.authorization', [
@@ -74,6 +75,28 @@
7475
$response->assertStatus(200);
7576
});
7677

78+
it('can get a list of users with sorting via api', function () {
79+
$initialCount = UserRecord::count();
80+
81+
UserRecord::factory(3)->create();
82+
83+
$response = $this->get('users?sorting=[{"id":"id","desc":false}]');
84+
85+
$response->assertStatus(200);
86+
$response->assertJsonCount(3 + $initialCount, 'data');
87+
88+
$responseIds = collect($response->json('data'))->pluck('id')->all();
89+
$sortedIds = collect($responseIds)->sort()->values()->all();
90+
expect($responseIds)->toBe($sortedIds);
91+
92+
$response = $this->get('users?sorting=[{"id":"id","desc":true}]');
93+
$response->assertStatus(200);
94+
95+
$responseIds = collect($response->json('data'))->pluck('id')->all();
96+
$sortedIds = collect($responseIds)->sortDesc()->values()->all();
97+
expect($responseIds)->toBe($sortedIds);
98+
});
99+
77100
it('can update a user via api', function () {
78101
$response = $this->postJson('users', [
79102
'email' => 'test@email.com',

0 commit comments

Comments
 (0)