Skip to content

Commit df6fade

Browse files
authored
Merge pull request #1 from LIQRGV/feature/add-sort-by
Allow sort on URL
2 parents 2e7b525 + 109600f commit df6fade

File tree

4 files changed

+102
-4
lines changed

4 files changed

+102
-4
lines changed

src/RequestParser.php

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use LIQRGV\QueryFilter\Exception\NotModelException;
1414
use LIQRGV\QueryFilter\Struct\FilterStruct;
1515
use LIQRGV\QueryFilter\Struct\ModelBuilderStruct;
16+
use LIQRGV\QueryFilter\Struct\SortStruct;
1617

1718
class RequestParser
1819
{
@@ -54,17 +55,23 @@ public function getBuilder(): Builder
5455
$modelBuilderStruct = $this->createModelBuilderStruct($this->request);
5556
$model = $this->createModel($modelBuilderStruct->baseModelName);
5657

57-
return $this->applyFilter($model::query(), $modelBuilderStruct->filters);
58+
$builder = $this->applyFilter($model::query(), $modelBuilderStruct->filters);
59+
$builder = $this->applySorter($builder, $modelBuilderStruct->sorter);
60+
61+
return $builder;
5862
}
5963

6064
private function createModelBuilderStruct(Request $request): ModelBuilderStruct
6165
{
62-
$filterQuery = $request->filter ?: [];
66+
$queryParam = $request->query;
67+
$filterQuery = $queryParam->get('filter') ?? [];
68+
$sortQuery = $queryParam->get('sort') ?? null;
6369

6470
$baseModelName = $this->getBaseModelName($request);
6571
$filters = $this->parseFilter($filterQuery);
72+
$sorter = $this->parseSorter($sortQuery);
6673

67-
return new ModelBuilderStruct($baseModelName, $filters);
74+
return new ModelBuilderStruct($baseModelName, $filters, $sorter);
6875
}
6976

7077
private function getBaseModelName(Request $request): string
@@ -126,6 +133,23 @@ private function parseFilter(array $filterQuery = []): array
126133
return $filters;
127134
}
128135

136+
private function parseSorter(?string $sortQuery): ?SortStruct
137+
{
138+
if(is_null($sortQuery)) {
139+
return null;
140+
}
141+
142+
$fieldPattern = "/^\-?([a-zA-z\_]+)$/";
143+
if(preg_match($fieldPattern, $sortQuery, $match)) {
144+
$fieldName = $match[1];
145+
$direction = $sortQuery[0] == "-" ? "DESC" : "ASC";
146+
147+
return new SortStruct($fieldName, $direction);
148+
}
149+
150+
return null;
151+
}
152+
129153
private function getModelFromNamespaces(string $modelName, array $modelNamespaces)
130154
{
131155
foreach ($modelNamespaces as $modelNamespace) {
@@ -150,6 +174,15 @@ private function applyFilter(Builder $builder, array $filters): Builder
150174
return $builder;
151175
}
152176

177+
private function applySorter(Builder $builder, ?SortStruct $sorter)
178+
{
179+
if(is_null($sorter)) {
180+
return $builder;
181+
}
182+
183+
return $builder->orderBy($sorter->fieldName, $sorter->direction);
184+
}
185+
153186
private function createModel(string $baseModelName)
154187
{
155188
$model = new $baseModelName;

src/Struct/ModelBuilderStruct.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ class ModelBuilderStruct {
1212
* @var array
1313
*/
1414
public $filters;
15+
/**
16+
* @var SortStruct
17+
*/
18+
public $sorter;
1519

16-
public function __construct(string $baseModelName, array $filters) {
20+
public function __construct(string $baseModelName, array $filters, ?SortStruct $sorter) {
1721
$this->baseModelName = $baseModelName;
1822
$this->filters = $filters;
23+
$this->sorter = $sorter;
1924
}
2025
}

src/Struct/SortStruct.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace LIQRGV\QueryFilter\Struct;
4+
5+
class SortStruct {
6+
public $fieldName;
7+
public $direction;
8+
9+
public function __construct($fieldName, $direction) {
10+
$this->fieldName = $fieldName;
11+
$this->direction = $direction;
12+
}
13+
}

tests/RequestParserTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,53 @@ function testRequestViaClosure()
6363
$this->assertEquals('LIQRGV\QueryFilter\Mocks\MockClosureModel', $builderStruct->baseModelName);
6464
}
6565

66+
function testSortBy()
67+
{
68+
$uri = 'some_model';
69+
$controllerClass = MockModelController::class;
70+
$query = new ParameterBag([
71+
"sort" => "-name",
72+
]);
73+
$requestParserOptions = [
74+
'model_namespaces' => [
75+
'LIQRGV\QueryFilter\Mocks',
76+
]
77+
];
78+
79+
$request = $this->createControllerRequest($uri, $controllerClass, $query, $requestParserOptions);
80+
81+
$requestParser = new RequestParser($request);
82+
$builder = $requestParser->getBuilder();
83+
84+
$query = $builder->getQuery();
85+
$this->assertEquals("mock_models", $query->from);
86+
$this->assertEquals("name", $builder->getQuery()->orders[0]['column']);
87+
$this->assertEquals("desc", strtolower($builder->getQuery()->orders[0]['direction']));
88+
}
89+
90+
function testSortByWithInvalidField()
91+
{
92+
$uri = 'some_model';
93+
$controllerClass = MockModelController::class;
94+
$query = new ParameterBag([
95+
"sort" => "-name-with-dash",
96+
]);
97+
$requestParserOptions = [
98+
'model_namespaces' => [
99+
'LIQRGV\QueryFilter\Mocks',
100+
]
101+
];
102+
103+
$request = $this->createControllerRequest($uri, $controllerClass, $query, $requestParserOptions);
104+
105+
$requestParser = new RequestParser($request);
106+
$builder = $requestParser->getBuilder();
107+
108+
$query = $builder->getQuery();
109+
$this->assertEquals("mock_models", $query->from);
110+
$this->assertEmpty($builder->getQuery()->orders);
111+
}
112+
66113
function testFilterKeywordIn()
67114
{
68115
$uri = 'some_model';

0 commit comments

Comments
 (0)