Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 288daa7

Browse files
committed
feat: add PipeFilters for quick apply filters for value
1 parent 3ff4fa5 commit 288daa7

File tree

4 files changed

+336
-1
lines changed

4 files changed

+336
-1
lines changed

‎README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ $userList = ListStream::of($userModels)
183183
vdump($userList);
184184
```
185185

186+
### PipeFilters
187+
188+
```php
189+
$pf = PipeFilters::newWithDefaultFilters();
190+
191+
$val = $pf->applyString('inhere', 'upper'); // 'INHERE'
192+
$val = $pf->applyString('inhere', 'upper|substr:0,3'); // 'INH'
193+
```
194+
186195
## License
187196

188197
[MIT](LICENSE)

‎src/Obj/Traits/NameAliasTrait.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
trait NameAliasTrait
1919
{
2020
/**
21-
* @var array
21+
* aliases string-map
22+
*
23+
* @var array<string, string>
2224
*/
2325
protected array $aliases = [];
2426

‎src/Std/PipeFilters.php

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Toolkit\Stdlib\Std;
4+
5+
use Toolkit\Stdlib\Helper\Assert;
6+
use Toolkit\Stdlib\Obj\AbstractObj;
7+
use Toolkit\Stdlib\Obj\Traits\NameAliasTrait;
8+
use Toolkit\Stdlib\Str;
9+
use function array_shift;
10+
use function is_array;
11+
use function is_string;
12+
use function str_contains;
13+
use function strlen;
14+
15+
/**
16+
* class PipeFilters
17+
*
18+
* @author inhere
19+
* @date 2023年1月14日
20+
*/
21+
class PipeFilters extends AbstractObj
22+
{
23+
use NameAliasTrait;
24+
25+
/**
26+
* @var bool
27+
*/
28+
public bool $allowPhpFunc = true;
29+
30+
/**
31+
* @var bool
32+
*/
33+
public bool $stopOnEmpty = true;
34+
35+
/**
36+
* @var bool
37+
*/
38+
public bool $trimForRule = true;
39+
40+
/**
41+
* sep char for split filter name and args
42+
*
43+
* @var string
44+
*/
45+
protected string $nameSep = ':';
46+
47+
/**
48+
* sep char for split args on filter rules
49+
*
50+
* @var string
51+
*/
52+
protected string $argsSep = ',';
53+
54+
/**
55+
* custom filters
56+
*
57+
* @var array<string, callable>
58+
*/
59+
protected array $filters = [];
60+
61+
/**
62+
* @return static
63+
*/
64+
public static function newWithDefaultFilters(): self
65+
{
66+
return self::new()->loadDefaultFilters();
67+
}
68+
69+
/**
70+
* @return array<string, callable>
71+
*/
72+
public static function getDefaultFilters(): array
73+
{
74+
return [
75+
'upper' => 'strtoupper',
76+
'lower' => 'strtolower',
77+
];
78+
}
79+
80+
/**
81+
* Alias for applyStringRules()
82+
*
83+
* ## Usage
84+
*
85+
* ```php
86+
* $pf = PipeFilters::newWithDefaultFilters();
87+
*
88+
* $val = $pf->applyString('inhere', 'upper'); // 'INHERE'
89+
* $val = $pf->applyString('inhere', 'upper | substr:0,3'); // 'INH'
90+
* ```
91+
*
92+
* @param mixed $value
93+
* @param string $rules
94+
* @param string $sep Sep char for multi filter rules
95+
*
96+
* @return mixed
97+
*/
98+
public function applyString(mixed $value, string $rules, string $sep = '|'): mixed
99+
{
100+
return $this->applyRules($value, Str::explode($rules, $sep));
101+
}
102+
103+
/**
104+
* @param mixed $value
105+
* @param string $rules
106+
* @param string $sep Sep char for multi filter rules
107+
*
108+
* @return mixed
109+
*/
110+
public function applyStringRules(mixed $value, string $rules, string $sep = '|'): mixed
111+
{
112+
return $this->applyRules($value, Str::explode($rules, $sep));
113+
}
114+
115+
/**
116+
* Alias for applyRules()
117+
*
118+
* @param mixed $value
119+
* @param array $filterRules
120+
*
121+
* @return mixed
122+
*/
123+
public function apply(mixed $value, array $filterRules): mixed
124+
{
125+
return $this->applyRules($value, $filterRules);
126+
}
127+
128+
/**
129+
* Apply filters for value
130+
*
131+
* ## Usage
132+
*
133+
* ```php
134+
* $pf = PipeFilters::newWithDefaultFilters();
135+
*
136+
* $val = $pf->apply('inhere', ['upper']); // 'INHERE'
137+
* $val = $pf->apply('inhere', ['upper', 'substr:0,3']); // 'INH'
138+
* ```
139+
*
140+
* @param mixed $value
141+
* @param array $filterRules filter names can be with args
142+
*
143+
* @return mixed
144+
*/
145+
public function applyRules(mixed $value, array $filterRules): mixed
146+
{
147+
foreach ($filterRules as $filter) {
148+
if ($this->stopOnEmpty && !$value) {
149+
break;
150+
}
151+
152+
$isStr = is_string($filter);
153+
$args = [];
154+
155+
// eg 'wrap:,'
156+
if ($isStr && str_contains($filter, $this->nameSep)) {
157+
[$filter, $argStr] = Str::toTrimmedArray($filter, $this->nameSep, 2);
158+
if (strlen($argStr) > 1 && str_contains($argStr, $this->argsSep)) {
159+
$args = Str::toTypedList($argStr, $this->argsSep);
160+
} else {
161+
$args = [Str::toTyped($argStr)];
162+
}
163+
}
164+
165+
$filterFn = $filter;
166+
if ($isStr) {
167+
$filter = $this->resolveAlias($filter);
168+
if (isset($this->filters[$filter] )) {
169+
$filterFn = $this->filters[$filter];
170+
}
171+
172+
// filter func and with args: ['my_func', arg1, arg2]
173+
} elseif (is_array($filter) && isset($filter[1])) {
174+
$filterFn = array_shift($filter);
175+
// remain as args
176+
$args = $filter;
177+
}
178+
179+
// call filter func
180+
if ($args) {
181+
$value = $filterFn($value, ...$args);
182+
} else {
183+
$value = $filterFn($value);
184+
}
185+
}
186+
187+
return $value;
188+
}
189+
190+
/**
191+
* @return $this
192+
*/
193+
public function loadDefaultFilters(): self
194+
{
195+
return $this->addFilters(self::getDefaultFilters());
196+
}
197+
198+
/**
199+
* @param array<string, callable> $filters
200+
*
201+
* @return $this
202+
*/
203+
public function addFilters(array $filters): self
204+
{
205+
foreach ($filters as $name => $filterFn) {
206+
$this->addFilter($name, $filterFn);
207+
}
208+
return $this;
209+
}
210+
211+
/**
212+
* @param string $name
213+
* @param callable $filterFn
214+
*
215+
* @return $this
216+
*/
217+
public function addFilter(string $name, callable $filterFn): self
218+
{
219+
Assert::notEmpty($name, 'filter name cannot be empty');
220+
$this->filters[$name] = $filterFn;
221+
return $this;
222+
}
223+
224+
/**
225+
* @return bool
226+
*/
227+
public function isAllowPhpFunc(): bool
228+
{
229+
return $this->allowPhpFunc;
230+
}
231+
232+
/**
233+
* @param bool $allowPhpFunc
234+
*/
235+
public function setAllowPhpFunc(bool $allowPhpFunc): void
236+
{
237+
$this->allowPhpFunc = $allowPhpFunc;
238+
}
239+
240+
/**
241+
* @return string
242+
*/
243+
public function getNameSep(): string
244+
{
245+
return $this->nameSep;
246+
}
247+
248+
/**
249+
* @param string $nameSep
250+
*/
251+
public function setNameSep(string $nameSep): void
252+
{
253+
if ($nameSep) {
254+
Assert::isTrue(strlen($nameSep) === 1, 'filter name args sep must be one char');
255+
$this->nameSep = $nameSep;
256+
}
257+
}
258+
259+
/**
260+
* @return string
261+
*/
262+
public function getArgsSep(): string
263+
{
264+
return $this->argsSep;
265+
}
266+
267+
/**
268+
* @param string $argsSep
269+
*/
270+
public function setArgsSep(string $argsSep): void
271+
{
272+
if ($argsSep) {
273+
Assert::isTrue(strlen($argsSep) === 1, 'filter name args sep must be one char');
274+
$this->argsSep = $argsSep;
275+
}
276+
}
277+
}

‎test/Std/PipeFiltersTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Toolkit\StdlibTest\Std;
4+
5+
use Toolkit\Stdlib\Std\PipeFilters;
6+
use Toolkit\StdlibTest\BaseLibTestCase;
7+
use function strtoupper;
8+
9+
/**
10+
* class PipeFiltersTest
11+
*
12+
* @author inhere
13+
* @date 2023年1月14日
14+
*/
15+
class PipeFiltersTest extends BaseLibTestCase
16+
{
17+
public function testApplyRules(): void
18+
{
19+
$pf = PipeFilters::new()->loadDefaultFilters();
20+
$pf->setAlias('upper', 'up');
21+
22+
$value = 'inhere';
23+
24+
$wanted = 'INHERE';
25+
$this->assertEquals($wanted, $pf->applyRules($value, ['up']));
26+
27+
$wanted = 'INH';
28+
$this->assertEquals($wanted, $pf->applyRules($value, ['upper', 'substr:0, 3']));
29+
30+
$this->assertEquals($wanted, $pf->applyRules($value, [function($val) {
31+
return strtoupper(substr($val, 0, 3));
32+
}]));
33+
}
34+
35+
public function testApplyStringRules(): void
36+
{
37+
$tests = [
38+
['INHERE', 'inhere', 'upper'],
39+
['INH', 'inhere', 'upper | substr:0,3'],
40+
];
41+
42+
$pf = PipeFilters::newWithDefaultFilters();
43+
foreach ($tests as [$wanted, $value, $rules]) {
44+
$this->assertEquals($wanted, $pf->applyStringRules($value, $rules));
45+
}
46+
}
47+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /