1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Rs\XmlFilter\Filter; |
6
|
|
|
|
7
|
|
|
use Rs\XmlFilter\Document\Element; |
8
|
|
|
use Rs\XmlFilter\Exception\AmbigousValueException; |
9
|
|
|
use Rs\XmlFilter\Exception\NoValueException; |
10
|
|
|
use Symfony\Component\OptionsResolver\OptionsResolver; |
11
|
|
|
|
12
|
|
|
class ScalarFilter extends AbstractFilter implements Filter |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* {@inheritdoc} |
16
|
|
|
*/ |
17
|
36 |
|
public function find(Element $element, array $options) |
18
|
|
|
{ |
19
|
36 |
|
$nodes = $element->find($this->preparePath($options['path'], $options)); |
20
|
|
|
|
21
|
36 |
|
if (true === $options['multiple']) { |
22
|
8 |
|
return $this->findMultiple($element, $nodes, $options); |
23
|
|
|
} |
24
|
|
|
|
25
|
32 |
|
if (1 === count($nodes)) { |
26
|
27 |
|
return $this->findSingle($nodes, $options); |
27
|
|
|
} |
28
|
|
|
|
29
|
5 |
|
if (0 === count($nodes)) { |
30
|
4 |
|
if ($options['nullable']) { |
31
|
3 |
|
return; |
32
|
|
|
} |
33
|
|
|
|
34
|
1 |
|
throw new NoValueException(sprintf('no value detected! "%s"', $options['path']), $element, $options); |
35
|
|
|
} |
36
|
|
|
|
37
|
1 |
|
$error = sprintf('non unique filter result detected! "%s" has %d different values (%s).', $options['path'], count($nodes), implode(',', $nodes)); |
38
|
|
|
|
39
|
1 |
|
throw new AmbigousValueException($error, $element, $options, $nodes); |
40
|
|
|
} |
41
|
|
|
|
42
|
31 |
|
private function cast(Element $node, string $cast) |
43
|
|
|
{ |
44
|
31 |
|
$value = (string) $node; |
45
|
|
|
|
46
|
31 |
|
settype($value, $cast); |
47
|
|
|
|
48
|
31 |
|
return $value; |
49
|
|
|
} |
50
|
|
|
|
51
|
8 |
|
private function findMultiple(Element $element, array $nodes, array $options) : array |
52
|
|
|
{ |
53
|
8 |
|
$values = []; |
54
|
8 |
|
foreach ($nodes as $index => $node) { |
55
|
|
|
/* @var Element $node */ |
56
|
|
|
|
57
|
8 |
|
if (is_string($options['sort'])) { |
58
|
1 |
|
$index = $this->find($this->getSearchElement($element, $options), array_merge($options, [ |
59
|
1 |
|
'multiple' => false, |
60
|
1 |
|
'context' => $node, |
61
|
1 |
|
'path' => $this->preparePath($options['sort'], $options), |
62
|
|
|
])); |
63
|
|
|
} |
64
|
|
|
|
65
|
8 |
|
$value = $this->cast($node, $options['cast']); |
66
|
|
|
|
67
|
8 |
|
if (false === $this->checkCondition($index, $value, $options, $node)) { |
68
|
1 |
|
continue; |
69
|
|
|
} |
70
|
|
|
|
71
|
8 |
|
$values[$index] = $value; |
72
|
|
|
} |
73
|
|
|
|
74
|
8 |
|
$values = $this->sort($values, $options); |
75
|
|
|
|
76
|
8 |
|
return array_values($values); |
77
|
|
|
} |
78
|
|
|
|
79
|
27 |
|
private function findSingle(array $nodes, array $options) |
80
|
|
|
{ |
81
|
27 |
|
$node = reset($nodes); |
82
|
|
|
|
83
|
27 |
|
$value = $this->cast($node, $options['cast']); |
84
|
|
|
|
85
|
27 |
|
if ($this->checkCondition(null, $value, $options, $node)) { |
86
|
26 |
|
return $value; |
87
|
|
|
} |
88
|
1 |
|
} |
89
|
|
|
|
90
|
8 |
|
protected function sort(array $data, array $options): array |
91
|
|
|
{ |
92
|
8 |
|
if (true === $options['sort']) { |
93
|
6 |
|
sort($data); |
94
|
2 |
|
} elseif (is_string($options['sort'])) { |
95
|
1 |
|
ksort($data); |
96
|
|
|
} |
97
|
|
|
|
98
|
8 |
|
return $data; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* {@inheritdoc} |
103
|
|
|
*/ |
104
|
37 |
|
public function getOptions(OptionsResolver $resolver) |
105
|
|
|
{ |
106
|
37 |
|
$resolver->setRequired([ |
107
|
37 |
|
'path', |
108
|
|
|
|
109
|
|
|
]); |
110
|
|
|
|
111
|
37 |
|
$resolver->setDefaults([ |
112
|
37 |
|
'nullable' => true, |
113
|
|
|
'multiple' => false, |
114
|
|
|
'cast' => 'string', |
115
|
|
|
]); |
116
|
37 |
|
$resolver->remove('context'); |
117
|
37 |
|
$resolver->setAllowedTypes('path', 'string'); |
118
|
37 |
|
$resolver->setAllowedTypes('nullable', 'bool'); |
119
|
37 |
|
$resolver->setAllowedTypes('multiple', 'boolean'); |
120
|
37 |
|
$resolver->setAllowedValues('cast', ['string', 'int', 'float', 'bool']); |
121
|
|
|
|
122
|
37 |
|
parent::getOptions($resolver); |
123
|
37 |
|
} |
124
|
|
|
} |
125
|
|
|
|