Skip to content
Merged
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
11 changes: 11 additions & 0 deletions docs-v2/content/en/api/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -819,3 +819,14 @@ public static $withs = ['posts'];
`withs` is not a typo. Laravel uses the `with` property on models, on repositories we use `$withs`, it's not a typo.

</alert>

## Group by

The group by filter is useful when you want to group the results by a certain column.

```php
class PostRepository extends Repository
{
public static array $groupBy = ['user_id'];
}
```
5 changes: 5 additions & 0 deletions src/Http/Requests/RestifyRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ public function filters(): array
? $this->input('filters', [])
: (json_decode(base64_decode($this->input('filters')), true) ?? []);
}

public function groupBy(): ?string
{
return $this->input('group_by');
}
}
5 changes: 5 additions & 0 deletions src/Repositories/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ class Repository implements JsonSerializable, RestifySearchable
*/
public static array $sort;

/**
* The list of fields that can be used for grouping.
*/
public static array $groupBy = [];

/**
* Attribute that should be used for displaying single model.
*/
Expand Down
25 changes: 25 additions & 0 deletions src/Services/Search/RepositorySearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public function search(RestifyRequest $request, Repository $repository): Builder

$query = $this->applyFilters($request, $repository, $query);

$query = $this->applyGroupBy($request, $repository, $query);

$ordersBuilder = $this->prepareOrders($request, $query);

return tap(
Expand Down Expand Up @@ -217,6 +219,29 @@ protected function applyFilters(RestifyRequest $request, Repository $repository,
return $query;
}

protected function applyGroupBy(RestifyRequest $request, Repository $repository, $query)
{
if (! $request->has('group_by')) {
return $query;
}

$model = $query->getModel();
$groupByColumns = explode(',', $request->input('group_by'));

foreach ($groupByColumns as $column) {
if (! in_array($column, $repository::$groupBy)) {
abort(422, sprintf(
'The column [%s] is not allowed for grouping. Allowed columns are: %s',
$column,
implode(', ', $repository::$groupBy)
));
}
$query->groupBy($model->qualifyColumn($column));
}

return $query;
}

public static function make(): static
{
return new static;
Expand Down
57 changes: 57 additions & 0 deletions tests/Feature/RepositoryGroupByTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Binaryk\LaravelRestify\Tests\Feature;

use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
use Binaryk\LaravelRestify\Tests\Fixtures\User\UserRepository;
use Binaryk\LaravelRestify\Tests\IntegrationTestCase;

class RepositoryGroupByTest extends IntegrationTestCase
{
public function test_it_can_group_by_the_results(): void
{
User::factory(4)->create([
'name' => 'John Doe',
]);

User::factory(4)->create([
'name' => 'Second John Doe',
]);

UserRepository::$groupBy = ['name'];

$this->getJson(UserRepository::route(query: ['group_by' => 'name']))->assertJsonCount(2, 'data');
}

public function test_it_can_group_by_the_results_multiple_columns(): void
{
User::factory(3)->create([
'name' => 'John Doe',
'avatar' => 'image.jpg',
]);

User::factory(1)->create([
'name' => 'Another John Doe',
'avatar' => 'image.jpg',
]);

UserRepository::$groupBy = ['name', 'avatar'];

$this->getJson(UserRepository::route(query: ['group_by' => 'name,avatar']))->assertJsonCount(2, 'data');
}

public function test_it_can_not_group_by_the_results_because_wrong_column(): void
{
User::factory(4)->create([
'name' => 'John Doe',
]);

User::factory(4)->create([
'name' => 'Second John Doe',
]);

UserRepository::$groupBy = ['email'];

$this->getJson(UserRepository::route(query: ['group_by' => 'name']))->assertUnprocessable();
}
}
Loading