Skip to content

Commit

Permalink
Merge pull request #93 from chadicus/fea/return-on-null
Browse files Browse the repository at this point in the history
Add FilterOptions::RETURN_ON_NULL
  • Loading branch information
chadicus committed Jul 8, 2020
2 parents 047bc08 + a582745 commit 3590bf1
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 9 deletions.
76 changes: 76 additions & 0 deletions README.md
Expand Up @@ -369,6 +369,82 @@ $specification = [

The exponent filter spec will call the PHP function `pow()` with the value provided and the result of the filtered `base`

## throwOnError

#### Summary

If true the Filterer will throw any exception caught when filtering a value instead of returning the error in the filter response.

#### Types

* boolean

#### Default

The default value for this option is `false`

#### Constant

```php
TraderInteractive\FilterOptions::THROW_ON_ERROR
```

#### Example

```php
$idFilter = function ($id) : int {
if (!is_int($id)) {
throw new NotFoundException("id '{$id}' was not found");
}

return $id;
};
$specification = [
'id' => [
\TraderInteractive\FilterOptions::THROW_ON_ERROR => true,
[$idFilter],
],
];
```

If the `id` value given in the input is not an integer the Filterer::execute() will throw the `NotFoundException`

## returnOnNull

#### Summary

Flag to break the filter chain if a resulting value is `null` Useful for nullable fields which require additional filtering if the value is not null.

#### Types

* boolean

#### Default

The default value for this option is `false`

#### Constant

```php
TraderInteractive\FilterOptions::RETURN_ON_NULL
```

#### Example

```php
$validCodes = ['A', 'I', 'X'];
$specification = [
'code' => [
\TraderInteractive\FilterOptions::RETURN_ON_NULL => true,
['string', true],
['strtoupper'],
['in', $validCodes],
],
];
```

If the `code` value is `null` then the resulting filtered value will be null. Otherwise the value must be one of the `$validCode` values.

### Included Filters
Of course, any function can potentially be used as a filter, but we include some useful filters with aliases for common circumstances.

Expand Down
13 changes: 9 additions & 4 deletions src/FilterOptions.php
Expand Up @@ -7,7 +7,7 @@ final class FilterOptions
/**
* @var string
*/
const DEFAULT_VALUE = 'default';
const CONFLICTS_WITH = 'conflictsWith';

/**
* @var string
Expand All @@ -17,20 +17,25 @@ final class FilterOptions
/**
* @var string
*/
const IS_REQUIRED = 'required';
const DEFAULT_VALUE = 'default';

/**
* @var string
*/
const CONFLICTS_WITH = 'conflictsWith';
const IS_REQUIRED = 'required';

/**
* @var string
*/
const USES = 'uses';
const RETURN_ON_NULL = 'returnOnNull';

/**
* @var string
*/
const THROW_ON_ERROR = 'throwOnError';

/**
* @var string
*/
const USES = 'uses';
}
28 changes: 24 additions & 4 deletions src/Filterer.php
Expand Up @@ -64,9 +64,7 @@ final class Filterer implements FiltererInterface
/**
* @var string
*/
const INVALID_THROW_ON_ERROR_VALUE_ERROR_FORMAT = (
FilterOptions::THROW_ON_ERROR . " for field '%s' was not a boolean value"
);
const INVALID_BOOLEAN_FILTER_OPTION = "%s for field '%s' was not a boolean value";

/**
* @var array
Expand Down Expand Up @@ -147,6 +145,7 @@ public function execute(array $input) : FilterResponse
self::assertFiltersIsAnArray($filters, $field);
$customError = self::validateCustomError($filters, $field);
$throwOnError = self::validateThrowOnError($filters, $field);
$returnOnNull = self::validateReturnOnNull($filters, $field);
unset($filters[FilterOptions::IS_REQUIRED]);//doesn't matter if required since we have this one
unset($filters[FilterOptions::DEFAULT_VALUE]);//doesn't matter if there is a default since we have a value
$conflicts = self::extractConflicts($filters, $field, $conflicts);
Expand All @@ -169,6 +168,9 @@ public function execute(array $input) : FilterResponse
try {
$this->addUsedInputToFilter($uses, $filteredInput, $field, $filter);
$input = call_user_func_array($function, $filter);
if ($input === null && $returnOnNull) {
break;
}
} catch (Exception $exception) {
if ($throwOnError) {
throw $exception;
Expand Down Expand Up @@ -623,7 +625,7 @@ private static function validateThrowOnError(array &$filters, string $field) : b
$throwOnError = $filters[FilterOptions::THROW_ON_ERROR];
if ($throwOnError !== true && $throwOnError !== false) {
throw new InvalidArgumentException(
sprintf(self::INVALID_THROW_ON_ERROR_VALUE_ERROR_FORMAT, $field)
sprintf(self::INVALID_BOOLEAN_FILTER_OPTION, FilterOptions::THROW_ON_ERROR, $field)
);
}

Expand All @@ -632,6 +634,24 @@ private static function validateThrowOnError(array &$filters, string $field) : b
return $throwOnError;
}

private static function validateReturnOnNull(array &$filters, string $field) : bool
{
if (!array_key_exists(FilterOptions::RETURN_ON_NULL, $filters)) {
return false;
}

$returnOnNull = $filters[FilterOptions::RETURN_ON_NULL];
if ($returnOnNull !== true && $returnOnNull !== false) {
throw new InvalidArgumentException(
sprintf(self::INVALID_BOOLEAN_FILTER_OPTION, FilterOptions::RETURN_ON_NULL, $field)
);
}

unset($filters[FilterOptions::RETURN_ON_NULL]);

return $returnOnNull;
}

private static function validateCustomError(array &$filters, string $field)
{
$customError = null;
Expand Down
30 changes: 29 additions & 1 deletion tests/FiltererTest.php
Expand Up @@ -378,6 +378,12 @@ function (int $input, int $fieldOneValue) : int {
[],
],
],
'returnOnNull filter option' => [
'spec' => ['field' => [FilterOptions::RETURN_ON_NULL => true, ['string', true], ['string']]],
'input' => ['field' => null],
'options' => [],
'result' => [true, ['field' => null], null, []],
],
];
}

Expand Down Expand Up @@ -411,7 +417,9 @@ public function executeThrowsOnError()
public function executeValidatesThrowsOnError()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf(Filterer::INVALID_THROW_ON_ERROR_VALUE_ERROR_FORMAT, 'id'));
$this->expectExceptionMessage(
sprintf(Filterer::INVALID_BOOLEAN_FILTER_OPTION, FilterOptions::THROW_ON_ERROR, 'id')
);
$specification = [
'id' => [
FilterOptions::THROW_ON_ERROR => 'abc',
Expand All @@ -422,6 +430,26 @@ public function executeValidatesThrowsOnError()
$filterer->execute(['id' => 1]);
}

/**
* @test
* @covers ::execute
*/
public function executeValidatesReturnOnNull()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
sprintf(Filterer::INVALID_BOOLEAN_FILTER_OPTION, FilterOptions::RETURN_ON_NULL, 'id')
);
$specification = [
'id' => [
FilterOptions::RETURN_ON_NULL => 'abc',
['uint'],
],
];
$filterer = new Filterer($specification);
$filterer->execute(['id' => 1]);
}

/**
* @test
* @covers ::filter
Expand Down

0 comments on commit 3590bf1

Please sign in to comment.