Skip to content

Commit ec9410a

Browse files
authored
Add support callback sort (#654)
* Add support sort callback * Add sort callback test
1 parent 1fadd28 commit ec9410a

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

src/AllowedSort.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Spatie\QueryBuilder\Enums\SortDirection;
66
use Spatie\QueryBuilder\Exceptions\InvalidDirection;
77
use Spatie\QueryBuilder\Sorts\Sort;
8+
use Spatie\QueryBuilder\Sorts\SortsCallback;
89
use Spatie\QueryBuilder\Sorts\SortsField;
910

1011
class AllowedSort
@@ -54,6 +55,11 @@ public static function custom(string $name, Sort $sortClass, ?string $internalNa
5455
return new static($name, $sortClass, $internalName);
5556
}
5657

58+
public static function callback(string $name, $callback, ?string $internalName = null): self
59+
{
60+
return new static($name, new SortsCallback($callback), $internalName);
61+
}
62+
5763
public function getName(): string
5864
{
5965
return $this->name;

src/Sorts/SortsCallback.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Spatie\QueryBuilder\Sorts;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
7+
class SortsCallback implements Sort
8+
{
9+
/**
10+
* @var callable a PHP callback of the following signature:
11+
* `function (\Illuminate\Database\Eloquent\Builder $builder, bool $descending, string $property)`
12+
*/
13+
private $callback;
14+
15+
public function __construct($callback)
16+
{
17+
$this->callback = $callback;
18+
}
19+
20+
/** {@inheritdoc} */
21+
public function __invoke(Builder $query, bool $descending, string $property)
22+
{
23+
return call_user_func($this->callback, $query, $descending, $property);
24+
}
25+
}

tests/SortsCallbackTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Spatie\QueryBuilder\Tests;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
use Illuminate\Support\Facades\DB;
7+
use Spatie\QueryBuilder\AllowedSort;
8+
use Spatie\QueryBuilder\QueryBuilder;
9+
use Spatie\QueryBuilder\Tests\Concerns\AssertsCollectionSorting;
10+
use Spatie\QueryBuilder\Tests\TestClasses\Models\TestModel;
11+
use Illuminate\Http\Request;
12+
13+
class SortsCallbackTest extends TestCase
14+
{
15+
use AssertsCollectionSorting;
16+
17+
/** @var \Illuminate\Support\Collection */
18+
protected $models;
19+
20+
public function setUp(): void
21+
{
22+
parent::setUp();
23+
24+
DB::enableQueryLog();
25+
26+
$this->models = factory(TestModel::class, 5)->create();
27+
}
28+
29+
/** @test */
30+
public function it_should_sort_by_closure()
31+
{
32+
$sortedModels = $this
33+
->createQueryFromSortRequest('callback')
34+
->allowedSorts(AllowedSort::callback('callback', function (Builder $query, $descending) {
35+
$query->orderBy('name', $descending ? 'DESC' : 'ASC');
36+
}))
37+
->get();
38+
39+
$this->assertQueryExecuted('select * from `test_models` order by `name` asc');
40+
$this->assertSortedAscending($sortedModels, 'name');
41+
}
42+
43+
/** @test */
44+
public function it_should_sort_by_array_callback()
45+
{
46+
$sortedModels = $this
47+
->createQueryFromSortRequest('callback')
48+
->allowedSorts(AllowedSort::callback('callback', [$this, 'sortCallback']))
49+
->get();
50+
51+
$this->assertQueryExecuted('select * from `test_models` order by `name` asc');
52+
$this->assertSortedAscending($sortedModels, 'name');
53+
}
54+
55+
public function sortCallback(Builder $query, $descending)
56+
{
57+
$query->orderBy('name', $descending ? 'DESC' : 'ASC');
58+
}
59+
60+
protected function createQueryFromSortRequest(string $sort): QueryBuilder
61+
{
62+
$request = new Request([
63+
'sort' => $sort,
64+
]);
65+
66+
return QueryBuilder::for(TestModel::class, $request);
67+
}
68+
69+
protected function assertQueryExecuted(string $query)
70+
{
71+
$queries = array_map(function ($queryLogItem) {
72+
return $queryLogItem['query'];
73+
}, DB::getQueryLog());
74+
75+
$this->assertContains($query, $queries);
76+
}
77+
}

0 commit comments

Comments
 (0)