Skip to content

Commit ddb8636

Browse files
committed
add general search
1 parent da8f732 commit ddb8636

File tree

5 files changed

+121
-36
lines changed

5 files changed

+121
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ These default config file that will be published:
2424
## Usage
2525
- use `HasFilter` trait in the model
2626
- add fields in the implementation of the abstract function `setupFilter`
27-
- call `filter` scope in your controller
27+
- call the `filter` scope in your controller
2828
```php
2929
class Order extends Model
3030
{

config/advanced_filter.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,16 @@
4848

4949
/*
5050
|--------------------------------------------------------------------------
51-
| Default Operator
51+
| Default Operators
5252
|--------------------------------------------------------------------------
5353
|
54-
| Default operator if the field sent in the request without operator
54+
| The Default operators if the field sent in the request without operator
55+
| or for general search
5556
|
5657
*/
5758

58-
'default_operator' => 'Equals',
59+
'default_operator' => 'equals',
60+
'default_general_search_operator' => 'startsWith',
5961

6062
/*
6163
|--------------------------------------------------------------------------
@@ -126,16 +128,18 @@
126128
|
127129
*/
128130

129-
// name of the parameter that contains the fields
131+
// the parameter name that contains the fields
130132
'param_filter_name' => 'filters', // or as prefix in "separate" query format
131-
// name of the parameter that set the conjunction
133+
// the parameter name that set the conjunction
132134
'param_conjunction_name' => 'conjunction',
133-
// names of the parameters that define the field
135+
// the parameters names that define the field
134136
'field_params' => [
135137
'field' => 'field', // filed name, only used in "json" query format
136138
'operator' => 'operator', // field operator
137139
'value' => 'value', // field value
138140
],
141+
// the parameter name that contains the general search value
142+
'param_general_search_name' => 'query',
139143

140144
/*
141145
|--------------------------------------------------------------------------

src/Fields/HasFields.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ trait HasFields
1515
protected $fields = [];
1616
/** @var string[] */
1717
protected $fieldsAliases = [];
18-
protected $generalSearch = [];
18+
protected $generalSearch = ['fields' => [], 'operator' => null];
1919

2020
/**
2121
* Add a normal/relational field
@@ -85,6 +85,11 @@ public function addCustomField(string $alias, string $sqlRaw, $relation = null)
8585
return $field;
8686
}
8787

88+
public function addGeneralSearch(array $fields, string $operator = null)
89+
{
90+
$this->generalSearch = ['fields' => $fields, $operator => $operator];
91+
}
92+
8893
/**
8994
* Resolve factories fields and set fields aliases
9095
*

src/FilterRequest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class FilterRequest
1111
{
1212
private $filters = [];
1313
private $conjunction = 'and';
14+
private $generalSearch = null;
1415

1516
public function addFilter(string $fieldName, string $operator, $value = null)
1617
{
@@ -36,12 +37,29 @@ public function getConjunction()
3637
return $this->conjunction;
3738
}
3839

40+
/**
41+
* @return null
42+
*/
43+
public function getGeneralSearch()
44+
{
45+
return $this->generalSearch;
46+
}
47+
48+
/**
49+
* @param string|null $generalSearch
50+
*/
51+
public function setGeneralSearch(?string $generalSearch): void
52+
{
53+
$this->generalSearch = $generalSearch;
54+
}
55+
3956
public static function createFromRequest(Request $request = null)
4057
{
4158
$request = $request ?: request();
4259

4360
$filterRequest = QueryFormat::factory($request);
4461
$filterRequest->setConjunction($filterRequest->getConjunctionFromRequest($request));
62+
$filterRequest->setGeneralSearch($filterRequest->getGeneralSearchFromRequest($request));
4563

4664
return $filterRequest;
4765
}
@@ -55,4 +73,13 @@ private function getConjunctionFromRequest(Request $request = null)
5573
$request->input($paramConjunctionName, $defaultConjunction) :
5674
request($paramConjunctionName, $defaultConjunction);
5775
}
76+
77+
private function getGeneralSearchFromRequest(Request $request = null)
78+
{
79+
$paramGeneralSearchName = config('advanced_filter.param_general_search_name', 'query');
80+
81+
return $request ?
82+
$request->input($paramGeneralSearchName) :
83+
request($paramGeneralSearchName);
84+
}
5885
}

src/HasFilter.php

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,26 @@ public abstract function setupFilter();
3434
*/
3535
public function scopeFilter(Builder $builder, Request $request = null, Filter $filter = null)
3636
{
37-
return $this->apply($builder, $request);
37+
$filterRequest = FilterRequest::createFromRequest($request);
38+
39+
$builder = $this->apply($builder, $filterRequest);
40+
41+
$builder = $this->applyGeneralSearch($builder, $filterRequest);
42+
43+
return $builder;
3844
}
3945

4046
/**
4147
* Filter fields from request
4248
*
4349
* @param Builder $builder
44-
* @param $request
50+
* @param FilterRequest $filterRequest
4551
*
4652
* @return Builder
4753
* @throws UnsupportedDriverException
4854
*/
49-
private function apply(Builder $builder, $request)
55+
private function apply(Builder $builder, FilterRequest $filterRequest)
5056
{
51-
$filterRequest = FilterRequest::createFromRequest($request);
5257
$conjunction = $filterRequest->getConjunction();
5358

5459
foreach ($filterRequest->getFilters() as $filter) {
@@ -62,48 +67,92 @@ private function apply(Builder $builder, $request)
6267
continue;
6368
}
6469

65-
// apply filter inside relation if the field from relation
66-
if ($field->isFromRelation()) {
67-
// apply on custom scope if the relation has scope
68-
if ($this->modelHasScope($builder, $field->getScopeRelationFunctionName())) {
69-
$builder = $builder->{$field->getScopeRelationFunctionName()}($field, $operator, $value, $conjunction);
70-
} else {
71-
if ($builder->getConnection()->getName() == 'mongodb') {
72-
throw new UnsupportedDriverException('MongoDB', 'relational');
73-
}
74-
75-
$builder = $builder->has($field->getRelation(), '>=', 1, $conjunction,
76-
function (Builder $builder) use ($field, $value, $operator) {
77-
return $this->filterField($builder, $field, $operator, $value);
78-
}
79-
);
80-
}
81-
} else {
82-
// apply on field
83-
$builder = $this->filterField($builder, $field, $operator, $value, $conjunction);
84-
}
70+
$builder = $this->filterField($builder, $field, $operator, $value, $conjunction);
8571
}
8672
}
8773

8874
return $builder;
8975
}
9076

9177
/**
92-
* Filter field
78+
* Filter general search from the request
79+
*
80+
* @param Builder $builder
81+
* @param FilterRequest $filterRequest
9382
*
94-
* check if the field has a custom scope and apply it
83+
* @return Builder
84+
* @throws UnsupportedDriverException
85+
*/
86+
private function applyGeneralSearch(Builder $builder, FilterRequest $filterRequest)
87+
{
88+
if (!empty($filterRequest->getGeneralSearch())) {
89+
$operator = $this->generalSearch['operator'] ?: config('advanced_filter.default_general_search_operator');
90+
91+
$builder->where(function (Builder $builder) use ($filterRequest, $operator) {
92+
foreach ($this->generalSearch['fields'] as $fieldName) {
93+
$field = new Field($builder->getModel(), $fieldName);
94+
95+
$this->filterField($builder, $field, $operator, $filterRequest->getGeneralSearch());
96+
}
97+
});
98+
}
99+
100+
return $builder;
101+
}
102+
103+
/**
104+
* Filter a field
95105
*
96106
* @param Builder $builder
97107
* @param Field $field
98108
* @param $operator
99109
* @param $value
100110
* @param string $conjunction
101111
*
102-
* @return mixed
112+
* @return Builder
113+
* @throws UnsupportedDriverException
103114
*/
104115
private function filterField(Builder $builder, Field $field, $operator, $value, $conjunction = 'and')
105116
{
106-
// apply on custom scope if the field has scope
117+
// apply the filter inside the relation if the field from relation
118+
if ($field->isFromRelation()) {
119+
// apply on custom scope if the relation has a scope
120+
if ($this->modelHasScope($builder, $field->getScopeRelationFunctionName())) {
121+
return $builder->{$field->getScopeRelationFunctionName()}($field, $operator, $value, $conjunction);
122+
} else {
123+
if ($builder->getConnection()->getName() == 'mongodb') {
124+
throw new UnsupportedDriverException('MongoDB', 'relational');
125+
}
126+
127+
return $builder->has($field->getRelation(), '>=', 1, $conjunction,
128+
function (Builder $builder) use ($field, $value, $operator) {
129+
// consider as a non relation field inside the relation
130+
return $this->filterNonRelationalField($builder, $field, $operator, $value);
131+
}
132+
);
133+
}
134+
} else {
135+
// a non relational field
136+
return $this->filterNonRelationalField($builder, $field, $operator, $value, $conjunction);
137+
}
138+
}
139+
140+
/**
141+
* Filter a non relational field
142+
*
143+
* it checks if the field has a custom scope
144+
*
145+
* @param Builder $builder
146+
* @param Field $field
147+
* @param $operator
148+
* @param $value
149+
* @param string $conjunction
150+
*
151+
* @return mixed
152+
*/
153+
private function filterNonRelationalField(Builder $builder, Field $field, $operator, $value, $conjunction = 'and')
154+
{
155+
// apply on custom scope if the field has a scope
107156
if ($this->modelHasScope($builder, $field->getScopeFunctionName())) {
108157
return $builder->{$field->getScopeFunctionName()}($field, $operator, $value, $conjunction);
109158
}

0 commit comments

Comments
 (0)