Skip to content

Commit 3f9ecb8

Browse files
committed
Add 'uses' filter option
1 parent de16cb0 commit 3f9ecb8

3 files changed

Lines changed: 117 additions & 7 deletions

File tree

src/FilterOptions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ final class FilterOptions
2323
* @var string
2424
*/
2525
const CONFLICTS_WITH = 'conflictsWith';
26+
27+
/**
28+
* @var string
29+
*/
30+
const USES = 'uses';
2631
}

src/Filterer.php

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,21 @@ public function __construct(array $specification, array $options = [], array $fi
118118
public function execute(array $input) : FilterResponse
119119
{
120120
$filterAliases = $this->getAliases();
121-
$inputToFilter = array_intersect_key($input, $this->specification);
122-
$leftOverSpec = array_diff_key($this->specification, $input);
123-
$leftOverInput = array_diff_key($input, $this->specification);
121+
$inputToFilter = [];
122+
$leftOverSpec = [];
124123

124+
foreach ($this->specification as $field => $specification) {
125+
if (array_key_exists($field, $input)) {
126+
$inputToFilter[$field] = $input[$field];
127+
continue;
128+
}
129+
130+
$leftOverSpec[$field] = $specification;
131+
}
132+
133+
$leftOverInput = array_diff_key($input, $inputToFilter);
134+
135+
$filteredInput = [];
125136
$errors = [];
126137
$conflicts = [];
127138
foreach ($inputToFilter as $field => $input) {
@@ -132,6 +143,9 @@ public function execute(array $input) : FilterResponse
132143
unset($filters[FilterOptions::DEFAULT_VALUE]);//doesn't matter if there is a default since we have a value
133144
$conflicts = self::extractConflicts($filters, $field, $conflicts);
134145

146+
$uses = $filters[FilterOptions::USES] ?? [];
147+
unset($filters[FilterOptions::USES]);
148+
135149
foreach ($filters as $filter) {
136150
self::assertFilterIsNotArray($filter, $field);
137151

@@ -146,31 +160,41 @@ public function execute(array $input) : FilterResponse
146160

147161
array_unshift($filter, $input);
148162
try {
163+
foreach ($uses as $usedField) {
164+
if (!array_key_exists($usedField, $filteredInput)) {
165+
throw new FilterException(
166+
"{$field} uses {$usedField} but {$usedField} was not given."
167+
);
168+
}
169+
170+
array_push($filter, $filteredInput[$usedField]);
171+
}
172+
149173
$input = call_user_func_array($function, $filter);
150174
} catch (Exception $exception) {
151175
$errors = self::handleCustomError($field, $input, $exception, $errors, $customError);
152176
continue 2;//next field
153177
}
154178
}
155179

156-
$inputToFilter[$field] = $input;
180+
$filteredInput[$field] = $input;
157181
}
158182

159183
foreach ($leftOverSpec as $field => $filters) {
160184
self::assertFiltersIsAnArray($filters, $field);
161185
$required = self::getRequired($filters, $this->defaultRequired, $field);
162186
if (array_key_exists(FilterOptions::DEFAULT_VALUE, $filters)) {
163-
$inputToFilter[$field] = $filters[FilterOptions::DEFAULT_VALUE];
187+
$filteredInput[$field] = $filters[FilterOptions::DEFAULT_VALUE];
164188
continue;
165189
}
166190

167191
$errors = self::handleRequiredFields($required, $field, $errors);
168192
}
169193

170194
$errors = self::handleAllowUnknowns($this->allowUnknowns, $leftOverInput, $errors);
171-
$errors = self::handleConflicts($inputToFilter, $conflicts, $errors);
195+
$errors = self::handleConflicts($filteredInput, $conflicts, $errors);
172196

173-
return new FilterResponse($inputToFilter, $errors, $leftOverInput);
197+
return new FilterResponse($filteredInput, $errors, $leftOverInput);
174198
}
175199

176200
/**

tests/FiltererTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,87 @@ public function provideValidFilterData() : array
296296
[],
297297
],
298298
],
299+
'uses' => [
300+
'spec' => [
301+
'fieldOne' => [['uint']],
302+
'fieldTwo' => [
303+
FilterOptions::USES => ['fieldOne'],
304+
['uint'],
305+
[
306+
function (int $input, int $fieldOneValue) : int {
307+
return $input * $fieldOneValue;
308+
},
309+
],
310+
],
311+
],
312+
'input' => [
313+
'fieldOne' => '5',
314+
'fieldTwo' => '2',
315+
],
316+
'options' => [],
317+
'result' => [
318+
true,
319+
[
320+
'fieldOne' => 5,
321+
'fieldTwo' => 10,
322+
],
323+
null,
324+
[],
325+
],
326+
],
327+
'input order does not matter for uses' => [
328+
'spec' => [
329+
'fieldOne' => [['uint']],
330+
'fieldTwo' => [
331+
FilterOptions::USES => ['fieldOne'],
332+
['uint'],
333+
[
334+
function (int $input, int $fieldOneValue) : int {
335+
return $input * $fieldOneValue;
336+
},
337+
],
338+
],
339+
],
340+
'input' => [
341+
'fieldTwo' => '2',
342+
'fieldOne' => '5',
343+
],
344+
'options' => [],
345+
'result' => [
346+
true,
347+
[
348+
'fieldOne' => 5,
349+
'fieldTwo' => 10,
350+
],
351+
null,
352+
[],
353+
],
354+
],
355+
'uses missing field' => [
356+
'spec' => [
357+
'fieldOne' => [['uint']],
358+
'fieldTwo' => [
359+
FilterOptions::USES => ['fieldOne'],
360+
['uint'],
361+
[
362+
function (int $input, int $fieldOneValue) : int {
363+
return $input * $fieldOneValue;
364+
},
365+
],
366+
],
367+
],
368+
'input' => [
369+
'fieldTwo' => '2',
370+
],
371+
'options' => [],
372+
'result' => [
373+
false,
374+
null,
375+
"Field 'fieldTwo' with value '2' failed filtering, message 'fieldTwo uses fieldOne but fieldOne was"
376+
. " not given.'",
377+
[],
378+
],
379+
],
299380
];
300381
}
301382

0 commit comments

Comments
 (0)