Skip to content

Commit

Permalink
Merge pull request #161 from gsteel/v3/digits-refactor
Browse files Browse the repository at this point in the history
Refactor `Digits` Filter
  • Loading branch information
gsteel authored Sep 3, 2024
2 parents e288198 + 59e9413 commit 7754a99
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 91 deletions.
2 changes: 1 addition & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@
</file>
<file src="test/DigitsTest.php">
<PossiblyUnusedMethod>
<code><![CDATA[returnUnfilteredDataProvider]]></code>
<code><![CDATA[basicDataProvider]]></code>
</PossiblyUnusedMethod>
</file>
<file src="test/DirTest.php">
Expand Down
27 changes: 9 additions & 18 deletions src/Digits.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,36 @@

namespace Laminas\Filter;

use Laminas\Stdlib\StringUtils;

use function is_float;
use function is_int;
use function is_string;
use function preg_replace;

/**
* @psalm-type Options = array{}
* @extends AbstractFilter<Options>
*/
final class Digits extends AbstractFilter
/** @implements FilterInterface<numeric-string|''> */
final class Digits implements FilterInterface
{
/**
* Defined by Laminas\Filter\FilterInterface
*
* Returns the string $value, removing all but digit characters
*
* If the value provided is not integer, float or string, the value will remain unfiltered
*
* @psalm-return ($value is int|float|string ? numeric-string : mixed)
* @inheritDoc
*/
public function filter(mixed $value): mixed
{
if (is_int($value)) {
return (string) $value;
}

if (! is_float($value) && ! is_string($value)) {
return $value;
}
$value = (string) $value;

if (! StringUtils::hasPcreUnicodeSupport()) {
// POSIX named classes are not supported, use alternative 0-9 match
$pattern = '/[^0-9]/';
} else {
$pattern = '/[^[:digit:]]/';
}
return preg_replace('/[^[:digit:]]/', '', (string) $value);
}

return preg_replace($pattern, '', $value);
public function __invoke(mixed $value): mixed
{
return $this->filter($value);
}
}
121 changes: 49 additions & 72 deletions test/DigitsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,92 +7,69 @@
use Laminas\Filter\Digits as DigitsFilter;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use stdClass;

use function preg_match;
use function get_debug_type;
use function sprintf;

class DigitsTest extends TestCase
{
/**
* Is PCRE is compiled with UTF-8 and Unicode support
**/
private bool $unicodeEnabled;
use const PHP_INT_MAX;

/**
* Creates a new Laminas_Filter_Digits object for each test method
*/
public function setUp(): void
final class DigitsTest extends TestCase
{
/** @return array<array-key, array{0: mixed, 1: mixed}> */
public static function basicDataProvider(): array
{
$this->unicodeEnabled = (bool) @preg_match('/\pL/u', 'a');
$object = (object) ['foo'];

return [
'Mixed Unicode Numerics' => ['192八3四8', '123'],
'Unicode String with Numbers' => ['C 4.5B 6', '456'],
'Unicode String with Numbers 2' => ['9壱8@7.6,5#4', '987654'],
'Numeric String' => ['789', '789'],
'ASCII Alnum 1' => ['abc123', '123'],
'ASCII Alnum 2' => ['abc 123', '123'],
'ASCII Alnum 3' => ['AZ@#4.3', '43'],
'No Numbers' => ['abcxyz', ''],
'Float String' => ['1.23', '123'],
'Hex String' => ['0x9f', '09'],
'Hex Int' => [0xff, '255'],
'Boolean' => [true, true],
'Null' => [null, null],
'Array' => [['foo'], ['foo']],
'Object' => [$object, $object],
'Small Integer' => [123, '123'],
'Big Integer' => [PHP_INT_MAX, (string) PHP_INT_MAX],
'Float' => [3.141592653, '3141592653'],
];
}

/**
* Ensures that the filter follows expected behavior
*/
public function testBasic(): void
#[DataProvider('basicDataProvider')]
public function testBasic(mixed $input, mixed $expect): void
{
$filter = new DigitsFilter();

if ($this->unicodeEnabled) {
// Filter for the value with mbstring
/**
* The first element of $valuesExpected contains multibyte digit characters.
* But , Laminas_Filter_Digits is expected to return only singlebyte digits.
*
* The second contains multibyte or singebyte space, and also alphabet.
* The third contains various multibyte characters.
* The last contains only singlebyte digits.
*/
$valuesExpected = [
'192八3四8' => '123',
'C 4.5B 6' => '456',
'9壱8@7.6,5#4' => '987654',
'789' => '789',
];
} else {
// POSIX named classes are not supported, use alternative 0-9 match
// Or filter for the value without mbstring
$valuesExpected = [
'abc123' => '123',
'abc 123' => '123',
'abcxyz' => '',
'AZ@#4.3' => '43',
'1.23' => '123',
'0x9f' => '09',
];
}
/** @psalm-var mixed $result */
$result = $filter->filter($input);

foreach ($valuesExpected as $input => $output) {
self::assertSame(
$output,
$result = $filter($input),
"Expected '$input' to filter to '$output', but received '$result' instead"
);
}
}

/** @return list<array{0: mixed}> */
public static function returnUnfilteredDataProvider(): array
{
return [
[null],
[new stdClass()],
[
[
'abc123',
'abc 123',
],
],
[true],
[false],
];
self::assertSame(
$expect,
$result,
sprintf(
'Expected "%s" to filter to "%s", but received "%s" instead',
get_debug_type($input),
get_debug_type($expect),
get_debug_type($result),
),
);
}

#[DataProvider('returnUnfilteredDataProvider')]
public function testReturnUnfiltered(mixed $input): void
#[DataProvider('basicDataProvider')]
public function testInvokeProxiesToFilter(mixed $input): void
{
$filter = new DigitsFilter();

self::assertSame($input, $filter($input));
self::assertSame(
$filter->filter($input),
$filter->__invoke($input),
);
}
}

0 comments on commit 7754a99

Please sign in to comment.