Skip to content

Commit 03813b0

Browse files
authored
Merge pull request #34 from kettasoft/feat/save-applied-filters
Add Applied Filters Tracking to Filterable Engine
2 parents 3c7d022 + a4b427c commit 03813b0

File tree

10 files changed

+124
-5
lines changed

10 files changed

+124
-5
lines changed

docs/api/filterable.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ Return the strict flag (`true`/`false`) or `null` when not explicitly set.
269269

270270
---
271271

272+
### States & Clauses
273+
274+
#### `applied($key): mixed`
275+
276+
Get applied claueses.
277+
278+
---
279+
272280
### Flow Control
273281

274282
#### `when(bool $condition, callable $callback): static`

src/Contracts/Commitable.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Kettasoft\Filterable\Contracts;
4+
5+
use Kettasoft\Filterable\Engines\Foundation\Clause;
6+
7+
/**
8+
* Contract for commitable filters.
9+
*
10+
* @package Kettasoft\Filterable\Contracts
11+
*/
12+
interface Commitable
13+
{
14+
/**
15+
* Commit applied clauses.
16+
* @param string $key
17+
* @param Clause $clause
18+
* @return bool
19+
*/
20+
public function commit(string $key, Clause $clause): bool;
21+
}

src/Engines/Expression.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public function execute(Builder $builder)
4949
continue; // skip disallowed field
5050
}
5151

52+
$this->commit($field, $clause);
53+
5254
return Applier::apply(new ClauseApplier($clause), $builder);
5355
}
5456

src/Engines/Foundation/Clause.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Clause implements Arrayable, Jsonable
4242
*
4343
* @param Payload $payload
4444
*/
45-
public function __construct(protected Payload $payload)
45+
public function __construct(Payload $payload)
4646
{
4747
$this->field = $payload->field;
4848
$this->operator = $payload->operator;

src/Engines/Foundation/Engine.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,15 @@ final protected function sanitizeValue($filed, $value)
110110

111111
return $sanitizer->handle($filed, $value);
112112
}
113+
114+
/**
115+
* Commit applied clauses.
116+
* @param string $key
117+
* @param Clause $clause
118+
* @return bool
119+
*/
120+
final protected function commit(string $key, Clause $clause): bool
121+
{
122+
return $this->context->commit($key, $clause);
123+
}
113124
}

src/Engines/Invokable.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ public function execute(Builder $builder): Builder
6262
throw new \RuntimeException(sprintf("Filter method [%s] conflicts with core Filterable method.", [$method]));
6363
}
6464

65-
$this->initializeFilters($filter, $method, $clause->getPayload());
65+
$this->initializeFilters($filter, $method, $payload);
66+
67+
$this->commit($method, $clause);
6668
}
6769

6870
return $this->builder;

src/Engines/Ruleset.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public function execute(Builder $builder): Builder
4343
if (! $clause->validated) continue;
4444

4545
Applier::apply(new ClauseApplier($clause), $builder);
46+
47+
$this->commit($field, $clause);
4648
}
4749

4850
return $builder;

src/Engines/Tree.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ private function applyNode(Builder $builder, TreeNode $node)
6868
} else {
6969
Applier::apply(new ClauseApplier($clause), $builder);
7070
}
71+
72+
$this->commit($node->field, $clause);
7173
}
7274

7375
return $builder;

src/Filterable.php

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
use Illuminate\Support\Traits\Macroable;
1010
use Illuminate\Database\Eloquent\Builder;
1111
use Kettasoft\Filterable\Foundation\Invoker;
12+
use Kettasoft\Filterable\Contracts\Commitable;
1213
use Kettasoft\Filterable\Foundation\Resources;
1314
use Kettasoft\Filterable\Contracts\Validatable;
1415
use Kettasoft\Filterable\Contracts\Authorizable;
1516
use Kettasoft\Filterable\Sanitization\Sanitizer;
17+
use Kettasoft\Filterable\Engines\Foundation\Clause;
1618
use Kettasoft\Filterable\Engines\Foundation\Engine;
1719
use Kettasoft\Filterable\Foundation\Sorting\Sorter;
1820
use Kettasoft\Filterable\Contracts\FilterableContext;
@@ -21,15 +23,15 @@
2123
use Kettasoft\Filterable\Foundation\FilterableSettings;
2224
use Kettasoft\Filterable\Exceptions\MissingBuilderException;
2325
use Kettasoft\Filterable\Engines\Foundation\Executors\Executer;
26+
use Kettasoft\Filterable\Foundation\Contracts\FilterableProfile;
2427
use Kettasoft\Filterable\Foundation\Contracts\Sorting\Invokable;
28+
use Kettasoft\Filterable\Foundation\Events\Contracts\EventManager;
2529
use Kettasoft\Filterable\Foundation\Events\FilterableEventManager;
2630
use Kettasoft\Filterable\HttpIntegration\HeaderDrivenEngineSelector;
2731
use Kettasoft\Filterable\Foundation\Contracts\ShouldReturnQueryBuilder;
2832
use Kettasoft\Filterable\Exceptions\RequestSourceIsNotSupportedException;
29-
use Kettasoft\Filterable\Foundation\Contracts\FilterableProfile;
30-
use Kettasoft\Filterable\Foundation\Events\Contracts\EventManager;
3133

32-
class Filterable implements FilterableContext, Authorizable, Validatable
34+
class Filterable implements FilterableContext, Authorizable, Validatable, Commitable
3335
{
3436
use Traits\InteractsWithFilterKey,
3537
Traits\InteractsWithMethodMentoring,
@@ -154,6 +156,12 @@ class Filterable implements FilterableContext, Authorizable, Validatable
154156
*/
155157
protected static EventManager $eventManager;
156158

159+
/**
160+
* Applied clauses.
161+
* @var array
162+
*/
163+
protected $applied = [];
164+
157165
/**
158166
* Create a new Filterable instance.
159167
* @param Request|null $request
@@ -257,6 +265,34 @@ public function useProfile(FilterableProfile|callable|string $profile): static
257265
return $this;
258266
}
259267

268+
/**
269+
* Commit clause.
270+
*
271+
* @param string $key
272+
* @param Clause $clause
273+
* @return bool
274+
*/
275+
public function commit(string $key, Clause $clause): bool
276+
{
277+
$this->applied[$key] = $clause;
278+
return true;
279+
}
280+
281+
/**
282+
* Get applied clauses.
283+
*
284+
* @param string $key
285+
* @return array|Clause|null
286+
*/
287+
public function applied($key = null)
288+
{
289+
if (!$key) {
290+
return $this->applied;
291+
}
292+
293+
return $this->applied[$key] ?? null;
294+
}
295+
260296
/**
261297
* Register the event manager instance.
262298
* @param array $options
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Kettasoft\Filterable\Tests\Feature\Filterable;
4+
5+
use Kettasoft\Filterable\Filterable;
6+
use Kettasoft\Filterable\Tests\Models\Post;
7+
use Kettasoft\Filterable\Tests\TestCase;
8+
9+
class FilterableCommitingFilterTest extends TestCase
10+
{
11+
public function test_it_saving_applied_filters()
12+
{
13+
request()->merge([
14+
'status' => 'active',
15+
'category' => 'news',
16+
]);
17+
18+
$filterable = new class extends Filterable {
19+
protected $filters = ['status', 'category'];
20+
public function status($payload)
21+
{
22+
return $this->builder->where('status', $payload->value);
23+
}
24+
public function category($payload)
25+
{
26+
return $this->builder->where('category', $payload->value);
27+
}
28+
};
29+
30+
$filterable->apply(Post::query());
31+
32+
$this->assertCount(2, $filterable->applied());
33+
$this->assertEquals('status', $filterable->applied('status')->field);
34+
}
35+
}

0 commit comments

Comments
 (0)