Skip to content

Commit 390c195

Browse files
committed
ENHANCE: refactor request filter for sylius resources, give more flexibility. move search filter in own class
1 parent 7b50d49 commit 390c195

File tree

9 files changed

+245
-27
lines changed

9 files changed

+245
-27
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"php-http/discovery": "^1.6",
3333
"php-http/message-factory": "^v1.0",
3434
"php-http/multipart-stream-builder": "^1.0",
35-
"php-http/client-implementation": "^1.0"
35+
"php-http/client-implementation": "^1.0",
36+
"symfony/expression-language": "^3.0|^4.0|^5.0"
3637
},
3738
"require-dev": {
3839
"friendsofphp/php-cs-fixer": "^2.14",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
/**
3+
* Diglin GmbH - Switzerland.
4+
*
5+
* @author Sylvain Rayé <support at diglin.com>
6+
* @category FWG - OroCRM
7+
* @copyright 2021 - Diglin (https://www.diglin.com)
8+
*/
9+
10+
namespace Diglin\Sylius\ApiClient\ExpressionLanguage;
11+
12+
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
13+
14+
final class BuildFilter extends ExpressionFunction
15+
{
16+
public function __construct($name)
17+
{
18+
parent::__construct(
19+
$name,
20+
\Closure::fromCallable([$this, 'compile'])->bindTo($this),
21+
\Closure::fromCallable([$this, 'evaluate'])->bindTo($this)
22+
);
23+
}
24+
25+
private function compile(string $input)
26+
{
27+
$function = <<<FUNC
28+
\$f = function(array \$input, \$firstLevel = true) use (&\$f) {
29+
\$output = '';
30+
foreach (\$input as \$key => \$value) {
31+
\$output .= sprintf('[%s]', \$key);
32+
if (is_array(\$value)) {
33+
\$output .= call_user_func(\$f, \$value, false);
34+
} else {
35+
\$output .= sprintf('=%s', \$value);
36+
}
37+
}
38+
39+
if (\$firstLevel) {
40+
return 'criteria' . \$output;
41+
}
42+
43+
return \$output;
44+
}
45+
FUNC;
46+
47+
return sprintf('(%s)($input)', $function);
48+
}
49+
50+
private function evaluate(array $context, array $input = [], $firstLevel = true)
51+
{
52+
$output = '';
53+
foreach ($input as $key => $value) {
54+
$output .= sprintf('[%s]', $key);
55+
if (is_array($value)) {
56+
$output .= $this->evaluate($context, $value, false);
57+
} else {
58+
$output .= sprintf('=%s', $value);
59+
}
60+
}
61+
62+
if ($firstLevel) {
63+
return 'criteria' . $output;
64+
}
65+
66+
return $output;
67+
}
68+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Diglin GmbH - Switzerland.
4+
*
5+
* @author Sylvain Rayé <support at diglin.com>
6+
* @category SyliusApiClient
7+
* @copyright 2020 - Diglin (https://www.diglin.com)
8+
*/
9+
10+
namespace Diglin\Sylius\ApiClient\ExpressionLanguage;
11+
12+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
13+
14+
class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
15+
{
16+
public function getFunctions()
17+
{
18+
return [
19+
new BuildFilter('build_filter_criteria')
20+
];
21+
}
22+
}

src/Filter/Filter.php

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,47 @@
33
* Diglin GmbH - Switzerland.
44
*
55
* @author Sylvain Rayé <support at diglin.com>
6-
*
76
* @category SyliusApiClient
8-
*
97
* @copyright 2020 - Diglin (https://www.diglin.com)
108
*/
119

10+
declare(strict_types=1);
11+
1212
namespace Diglin\Sylius\ApiClient\Filter;
1313

14+
use Diglin\Sylius\ApiClient\ExpressionLanguage\ExpressionLanguageProvider;
15+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
16+
1417
class Filter implements FilterInterface
1518
{
16-
/** @var string */
1719
private $nameOfCriterion;
18-
/** @var string */
19-
private $searchPhrase;
20-
/** @var string */
21-
private $searchOption;
20+
private $value;
2221

22+
/**
23+
* If $nameOfCriterion is an array, $value will be ignored
24+
*/
2325
public function __construct(
24-
string $nameOfCriterion = 'search',
25-
string $searchOption = SearchOptions::CONTAINS,
26-
string $searchPhrase = ''
27-
) {
26+
$nameOfCriterion,
27+
$value = ''
28+
)
29+
{
2830
$this->nameOfCriterion = $nameOfCriterion;
29-
$this->searchPhrase = $searchPhrase;
30-
$this->searchOption = $searchOption;
31+
$this->value = $value;
3132
}
3233

3334
public function getCriteria(): array
3435
{
36+
if (is_string($this->nameOfCriterion) && strpos($this->nameOfCriterion, 'criteria') === false) {
37+
$this->nameOfCriterion = sprintf('criteria[%s]', $this->nameOfCriterion);
38+
} else if (is_array($this->nameOfCriterion)) {
39+
$interpreter = new ExpressionLanguage(null, [new ExpressionLanguageProvider()]);
40+
$this->nameOfCriterion = $interpreter->evaluate('build_filter_criteria(input)', ['input' => $this->nameOfCriterion]);
41+
list($this->nameOfCriterion, $this->value) = explode('=', $this->nameOfCriterion );
42+
}
43+
3544
return [
36-
printf('criteria[%s][type]', $this->nameOfCriterion) => $this->searchOption,
37-
printf('criteria[%s][value]', $this->nameOfCriterion) => $this->searchPhrase,
45+
$this->nameOfCriterion => $this->value,
3846
];
3947
}
48+
4049
}

src/Filter/FilterBuilder.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
* Diglin GmbH - Switzerland.
44
*
55
* @author Sylvain Rayé <support at diglin.com>
6-
*
76
* @category SyliusApiClient
8-
*
97
* @copyright 2020 - Diglin (https://www.diglin.com)
108
*/
119

@@ -21,9 +19,6 @@ public function __construct(FilterInterface $filter)
2119
$this->filter = $filter;
2220
}
2321

24-
/**
25-
* API supports only one filter at the moment.
26-
*/
2722
public function __invoke(): array
2823
{
2924
return $this->filter->getCriteria() ?? [];

src/Filter/FilterInterface.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,5 @@
1616
*/
1717
interface FilterInterface
1818
{
19-
public function __construct(
20-
string $nameOfCriterion = 'search',
21-
string $searchOption = SearchOptions::CONTAINS,
22-
string $searchPhrase = ''
23-
);
24-
2519
public function getCriteria(): array;
2620
}

src/Filter/SearchFilter.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Diglin GmbH - Switzerland.
4+
*
5+
* @author Sylvain Rayé <support at diglin.com>
6+
* @category SyliusApiClient
7+
* @copyright 2020 - Diglin (https://www.diglin.com)
8+
*/
9+
10+
namespace Diglin\Sylius\ApiClient\Filter;
11+
12+
class SearchFilter implements FilterInterface
13+
{
14+
/** @var string */
15+
private $nameOfCriterion;
16+
/** @var string */
17+
private $searchPhrase;
18+
/** @var string */
19+
private $searchOption;
20+
21+
public function __construct(
22+
string $nameOfCriterion = 'search',
23+
string $searchOption = SearchOptions::CONTAINS,
24+
string $searchPhrase = ''
25+
) {
26+
$this->nameOfCriterion = $nameOfCriterion;
27+
$this->searchPhrase = $searchPhrase;
28+
$this->searchOption = $searchOption;
29+
}
30+
31+
public function getCriteria(): array
32+
{
33+
return [
34+
printf('criteria[%s][type]', $this->nameOfCriterion) => $this->searchOption,
35+
printf('criteria[%s][value]', $this->nameOfCriterion) => $this->searchPhrase,
36+
];
37+
}
38+
}

test/ExpressionLanguageTest.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/**
3+
* Diglin GmbH - Switzerland.
4+
*
5+
* @author Sylvain Rayé <support at diglin.com>
6+
* @category SyliusApiClient
7+
* @copyright 2020 - Diglin (https://www.diglin.com)
8+
*/
9+
10+
namespace Diglin\Sylius\ApiClient\Test;
11+
12+
use Diglin\Sylius\ApiClient\ExpressionLanguage\ExpressionLanguageProvider;
13+
use PHPUnit\Framework\TestCase;
14+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
15+
16+
class ExpressionLanguageTest extends TestCase
17+
{
18+
public function dataProvider()
19+
{
20+
yield [
21+
'criteria[date][from][date]=2021-02-04',
22+
[
23+
'date' => [
24+
'from' => [
25+
'date' => '2021-02-04',
26+
],
27+
],
28+
],
29+
'build_filter_criteria(input)',
30+
];
31+
32+
yield [
33+
'criteria[date][to][date]=2021-02-05',
34+
[
35+
'date' => [
36+
'to' => [
37+
'date' => '2021-02-05',
38+
],
39+
],
40+
],
41+
'build_filter_criteria(input)',
42+
];
43+
}
44+
45+
/**
46+
* @dataProvider dataProvider
47+
*/
48+
public function testBuildFilter(string $expected, array $input, string $expression)
49+
{
50+
$interpreter = new ExpressionLanguage(null, [new ExpressionLanguageProvider()]);
51+
52+
$this->assertEquals($expected, $interpreter->evaluate($expression, ['input' => $input]));
53+
}
54+
55+
/**
56+
* @dataProvider dataProvider
57+
*/
58+
public function testCompiledFilter(string $expected, array $input, string $expression)
59+
{
60+
$interpreter = new ExpressionLanguage(null, [new ExpressionLanguageProvider()]);
61+
62+
$compiled = include 'data://application/x-php;base64,' . base64_encode($sources = '<?php return function(array $input) {return ' . ($interpreter->compile($expression, ['input'])) . ';};');
63+
64+
$this->assertEquals($expected, $compiled($input));
65+
}
66+
}

test/Filter.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
/**
3+
* Diglin GmbH - Switzerland.
4+
*
5+
* @author Sylvain Rayé <support at diglin.com>
6+
* @category SyliusApiClient
7+
* @copyright 2020 - Diglin (https://www.diglin.com)
8+
*/
9+
10+
namespace Diglin\Sylius\ApiClient\Test;
11+
12+
use PHPUnit\Framework\TestCase;
13+
14+
class Filter extends TestCase
15+
{
16+
public function testFilter()
17+
{
18+
$criteria = (new \Diglin\Sylius\ApiClient\Filter\Filter('channel', 1))->getCriteria();
19+
$this->assertArrayHasKey('criteria[channel]', $criteria);
20+
21+
$criteria = (new \Diglin\Sylius\ApiClient\Filter\Filter(['date'=> ['from' => ['date' => '2021-02-04']]]))->getCriteria();
22+
$this->assertArrayHasKey('criteria[date][from][date]', $criteria);
23+
$this->assertEquals('2021-02-04', $criteria['criteria[date][from][date]']);
24+
}
25+
}

0 commit comments

Comments
 (0)