diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index dd8b22b3..ad5daa78 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -32,48 +32,6 @@
-
-
-
-
-
-
-
-
-
- ]]>
-
-
- options['translations'][$message]]]>
-
-
-
-
-
-
-
-
-
- options['casting']]]>
- options['type']]]>
-
-
-
-
-
- options['casting']]]>
- options['type']]]>
-
-
-
-
-
-
-
-
-
-
-
options['callback'], $params)]]>
@@ -838,37 +796,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Boolean.php b/src/Boolean.php
index 3ba81160..7fa66639 100644
--- a/src/Boolean.php
+++ b/src/Boolean.php
@@ -4,29 +4,34 @@
namespace Laminas\Filter;
-use Laminas\Stdlib\ArrayUtils;
-use Traversable;
-
+use function array_merge;
use function array_search;
-use function get_debug_type;
+use function assert;
use function gettype;
+use function in_array;
use function is_array;
use function is_bool;
-use function is_float;
use function is_int;
use function is_string;
use function sprintf;
use function strtolower;
/**
- * @psalm-type Options = array{
- * type?: int-mask-of,
+ * @psalm-immutable
+ * phpcs:disable Generic.Files.LineLength
+ * @psalm-type TypeOption = int-mask-of|list|list>|value-of
+ * @psalm-type OptionsArgument = array{
+ * type?: TypeOption,
* casting?: bool,
- * translations?: array,
+ * translations?: array,
+ * }
+ * @psalm-type Options = array{
+ * type: int-mask-of,
+ * casting: bool,
+ * translations: array,
* }
- * @extends AbstractFilter
*/
-final class Boolean extends AbstractFilter
+final class Boolean implements FilterInterface
{
public const TYPE_BOOLEAN = 1;
public const TYPE_INTEGER = 2;
@@ -55,161 +60,82 @@ final class Boolean extends AbstractFilter
];
/** @var Options */
- protected $options = [
- 'type' => self::TYPE_PHP,
- 'casting' => true,
- 'translations' => [],
- ];
+ private readonly array $options;
/**
- * phpcs:ignore Generic.Files.LineLength.TooLong
- * @param self::TYPE_*|value-of|list|int-mask-of|Options|iterable|null $typeOrOptions
- * @param bool $casting
- * @param array $translations
+ * @param OptionsArgument $options
*/
- public function __construct($typeOrOptions = null, $casting = true, $translations = [])
+ public function __construct(array $options = [])
{
- if ($typeOrOptions instanceof Traversable) {
- $typeOrOptions = ArrayUtils::iteratorToArray($typeOrOptions);
- }
-
- if (
- is_array($typeOrOptions) && (
- isset($typeOrOptions['type'])
- || isset($typeOrOptions['casting'])
- || isset($typeOrOptions['translations'])
- )
- ) {
- $this->setOptions($typeOrOptions);
-
- return;
- }
-
- if (is_array($typeOrOptions) || is_int($typeOrOptions) || is_string($typeOrOptions)) {
- $this->setType($typeOrOptions);
- }
-
- $this->setCasting($casting);
- $this->setTranslations($translations);
+ $defaults = [
+ 'type' => self::TYPE_PHP,
+ 'casting' => true,
+ 'translations' => [],
+ ];
+
+ $options = array_merge($defaults, $options);
+ $options['type'] = $this->resolveType($options['type']);
+ $this->options = $options;
}
/**
- * Set boolean types
+ * Resolve int-mask type from various options
*
- * @param self::TYPE_*|int-mask-of|value-of|list|null $type
+ * @param int-mask-of|list|list>|value-of $type
+ * @return int-mask-of
* @throws Exception\InvalidArgumentException
- * @return self
*/
- public function setType($type = null)
+ private function resolveType(array|int|string $type): int
{
+ if (is_int($type) && ($type & self::TYPE_ALL) !== 0) {
+ return $type;
+ }
+
+ if (is_string($type) && in_array($type, self::CONSTANTS, true)) {
+ $type = array_search($type, self::CONSTANTS, true);
+ assert(is_int($type));
+
+ return $type;
+ }
+
if (is_array($type)) {
$detected = 0;
foreach ($type as $value) {
if (is_int($value)) {
+ assert(($value & self::TYPE_ALL) !== 0);
$detected |= $value;
- } elseif (($found = array_search($value, self::CONSTANTS, true)) !== false) {
+ } else {
+ $found = array_search($value, self::CONSTANTS, true);
+ assert(is_int($found));
+
$detected |= $found;
}
}
- $type = $detected;
- } elseif (is_string($type) && ($found = array_search($type, self::CONSTANTS, true)) !== false) {
- $type = $found;
- }
-
- if (! is_int($type) || ($type < 0) || ($type > self::TYPE_ALL)) {
- throw new Exception\InvalidArgumentException(sprintf(
- 'Unknown type value "%s" (%s)',
- $type,
- gettype($type)
- ));
- }
-
- $this->options['type'] = $type;
- return $this;
- }
-
- /**
- * Returns defined boolean types
- *
- * @return int-mask-of
- */
- public function getType()
- {
- return $this->options['type'];
- }
-
- /**
- * Set the working mode
- *
- * @param bool $flag When true this filter works like cast
- * When false it recognises only true and false
- * and all other values are returned as is
- * @return self
- */
- public function setCasting($flag = true)
- {
- $this->options['casting'] = (bool) $flag;
- return $this;
- }
-
- /**
- * Returns the casting option
- *
- * @return bool
- */
- public function getCasting()
- {
- return $this->options['casting'];
- }
-
- /**
- * @param array|Traversable $translations
- * @throws Exception\InvalidArgumentException
- * @return self
- */
- public function setTranslations($translations)
- {
- if (! is_array($translations) && ! $translations instanceof Traversable) {
- throw new Exception\InvalidArgumentException(sprintf(
- '"%s" expects an array or Traversable; received "%s"',
- __METHOD__,
- get_debug_type($translations)
- ));
- }
-
- foreach ($translations as $message => $flag) {
- $this->options['translations'][$message] = (bool) $flag;
+ /** @psalm-var int-mask-of */
+ return $detected;
}
- return $this;
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Unknown type value "%s" (%s)',
+ $type,
+ gettype($type),
+ ));
}
/**
- * @return array
- */
- public function getTranslations()
- {
- return $this->options['translations'] ?? [];
- }
-
- /**
- * Defined by Laminas\Filter\FilterInterface
- *
* Returns a boolean representation of $value
- *
- * @param null|array|bool|float|int|string $value
*/
public function filter(mixed $value): mixed
{
- $type = $this->getType();
- $casting = $this->getCasting();
+ $type = $this->options['type'];
+ $casting = $this->options['casting'];
// LOCALIZED
if ($type & self::TYPE_LOCALIZED) {
if (is_string($value)) {
if (isset($this->options['translations'][$value])) {
- return (bool) $this->options['translations'][$value];
+ return $this->options['translations'][$value];
}
}
}
@@ -220,7 +146,7 @@ public function filter(mixed $value): mixed
return false;
}
- if (! $casting && is_string($value) && strtolower($value) === 'true') {
+ if (is_string($value) && strtolower($value) === 'true') {
return true;
}
}
@@ -234,47 +160,47 @@ public function filter(mixed $value): mixed
// EMPTY_ARRAY (array())
if ($type & self::TYPE_EMPTY_ARRAY) {
- if (is_array($value) && $value === []) {
+ if ($value === []) {
return false;
}
}
// ZERO_STRING ('0')
if ($type & self::TYPE_ZERO_STRING) {
- if (is_string($value) && $value === '0') {
+ if ($value === '0') {
return false;
}
- if (! $casting && is_string($value) && $value === '1') {
+ if (! $casting && $value === '1') {
return true;
}
}
// STRING ('')
if ($type & self::TYPE_STRING) {
- if (is_string($value) && $value === '') {
+ if ($value === '') {
return false;
}
}
// FLOAT (0.0)
if ($type & self::TYPE_FLOAT) {
- if (is_float($value) && $value === 0.0) {
+ if ($value === 0.0) {
return false;
}
- if (! $casting && is_float($value) && $value === 1.0) {
+ if (! $casting && $value === 1.0) {
return true;
}
}
// INTEGER (0)
if ($type & self::TYPE_INTEGER) {
- if (is_int($value) && $value === 0) {
+ if ($value === 0) {
return false;
}
- if (! $casting && is_int($value) && $value === 1) {
+ if (! $casting && $value === 1) {
return true;
}
}
@@ -292,4 +218,9 @@ public function filter(mixed $value): mixed
return $value;
}
+
+ public function __invoke(mixed $value): mixed
+ {
+ return $this->filter($value);
+ }
}
diff --git a/test/BooleanTest.php b/test/BooleanTest.php
index ed8f31be..03a640f9 100644
--- a/test/BooleanTest.php
+++ b/test/BooleanTest.php
@@ -4,7 +4,7 @@
namespace LaminasTest\Filter;
-use Laminas\Filter\Boolean as BooleanFilter;
+use Laminas\Filter\Boolean;
use Laminas\Filter\Exception;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
@@ -13,78 +13,247 @@
use function sprintf;
use function var_export;
+/**
+ * @psalm-import-type TypeOption from Boolean
+ * @psalm-import-type OptionsArgument from Boolean
+ */
class BooleanTest extends TestCase
{
- public function testConstructorOptions(): void
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function integerProvider(): array
{
- $filter = new BooleanFilter([
- 'type' => BooleanFilter::TYPE_INTEGER,
- 'casting' => false,
- ]);
+ return [
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => false], 1, true],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => false], 0, false],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => true], 1, true],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => true], 0, false],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => true], 99, true],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => false], 99, 99],
+ [['type' => Boolean::TYPE_INTEGER, 'casting' => false], null, null],
+ [['type' => [Boolean::TYPE_INTEGER], 'casting' => false], 1, true],
+ [['type' => 'integer', 'casting' => false], 1, true],
+ [['type' => ['integer'], 'casting' => false], 1, true],
+ ];
+ }
- self::assertSame(BooleanFilter::TYPE_INTEGER, $filter->getType());
- self::assertFalse($filter->getCasting());
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function floatProvider(): array
+ {
+ return [
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => false], 1.0, true],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => false], 0.0, false],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => true], 1.0, true],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => true], 0.0, false],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => true], 99.9, true],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => false], 99.9, 99.9],
+ [['type' => Boolean::TYPE_FLOAT, 'casting' => false], null, null],
+ [['type' => [Boolean::TYPE_FLOAT], 'casting' => false], 1.0, true],
+ [['type' => 'float', 'casting' => false], 1.0, true],
+ [['type' => ['float'], 'casting' => false], 1.0, true],
+ ];
}
- public function testConstructorParams(): void
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function booleanProvider(): array
{
- $filter = new BooleanFilter(BooleanFilter::TYPE_INTEGER, false);
+ return [
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], true, true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], false, false],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], 'foo', 'foo'],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], 'true', 'true'],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], 1, 1],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], 0, 0],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => false], [], []],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], true, true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], false, false],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], 'foo', true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], 'true', true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], 1, true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], 0, true],
+ [['type' => Boolean::TYPE_BOOLEAN, 'casting' => true], [], true],
+ [['type' => [Boolean::TYPE_BOOLEAN], 'casting' => false], true, true],
+ [['type' => ['boolean'], 'casting' => false], true, true],
+ [['type' => 'boolean', 'casting' => false], true, true],
+ ];
+ }
- self::assertSame(BooleanFilter::TYPE_INTEGER, $filter->getType());
- self::assertFalse($filter->getCasting());
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function stringProvider(): array
+ {
+ return [
+ [['type' => Boolean::TYPE_STRING, 'casting' => false], 'foo', 'foo'],
+ [['type' => Boolean::TYPE_STRING, 'casting' => false], '', false],
+ [['type' => Boolean::TYPE_STRING, 'casting' => true], 'foo', true],
+ [['type' => Boolean::TYPE_STRING, 'casting' => true], '', false],
+ [['type' => Boolean::TYPE_STRING, 'casting' => true], ' ', true],
+ [['type' => Boolean::TYPE_STRING, 'casting' => true], "\t", true],
+ [['type' => Boolean::TYPE_STRING, 'casting' => true], "\n", true],
+ [['type' => [Boolean::TYPE_STRING], 'casting' => false], 'foo', 'foo'],
+ [['type' => ['string'], 'casting' => false], 'foo', 'foo'],
+ [['type' => 'string', 'casting' => false], 'foo', 'foo'],
+ ];
}
- #[DataProvider('defaultTestProvider')]
- public function testDefault(mixed $value, bool $expected): void
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function falseStringProvider(): array
{
- $filter = new BooleanFilter();
- self::assertSame($expected, $filter->filter($value));
+ return [
+ [['type' => Boolean::TYPE_FALSE_STRING, 'casting' => false], 'true', true],
+ [['type' => Boolean::TYPE_FALSE_STRING, 'casting' => false], 'false', false],
+ [['type' => Boolean::TYPE_FALSE_STRING, 'casting' => true], 'true', true],
+ [['type' => Boolean::TYPE_FALSE_STRING, 'casting' => true], 'false', false],
+ [['type' => [Boolean::TYPE_FALSE_STRING], 'casting' => false], 'false', false],
+ [['type' => ['false'], 'casting' => false], 'false', false],
+ [['type' => 'false', 'casting' => false], 'false', false],
+ ];
+ }
+
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function nullProvider(): array
+ {
+ return [
+ [['type' => Boolean::TYPE_NULL, 'casting' => false], null, false],
+ [['type' => Boolean::TYPE_NULL, 'casting' => true], null, false],
+ [['type' => Boolean::TYPE_NULL, 'casting' => true], 'false', true],
+ [['type' => [Boolean::TYPE_NULL], 'casting' => false], 'false', 'false'],
+ [['type' => ['null'], 'casting' => false], null, false],
+ [['type' => 'null', 'casting' => false], null, false],
+ ];
+ }
+
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function zeroStringProvider(): array
+ {
+ return [
+ [['type' => Boolean::TYPE_ZERO_STRING, 'casting' => false], '0', false],
+ [['type' => Boolean::TYPE_ZERO_STRING, 'casting' => false], '1', true],
+ [['type' => Boolean::TYPE_ZERO_STRING, 'casting' => true], '0', false],
+ [['type' => Boolean::TYPE_ZERO_STRING, 'casting' => true], '1', true],
+ [['type' => [Boolean::TYPE_ZERO_STRING], 'casting' => false], '0', false],
+ [['type' => ['zero'], 'casting' => false], '0', false],
+ [['type' => 'zero', 'casting' => false], '0', false],
+ ];
+ }
+
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
+ public static function emptyArrayProvider(): array
+ {
+ return [
+ [['type' => Boolean::TYPE_EMPTY_ARRAY, 'casting' => false], [], false],
+ [['type' => Boolean::TYPE_EMPTY_ARRAY, 'casting' => false], ['foo'], ['foo']],
+ [['type' => Boolean::TYPE_EMPTY_ARRAY, 'casting' => true], [], false],
+ [['type' => Boolean::TYPE_EMPTY_ARRAY, 'casting' => true], ['foo'], true],
+ [['type' => [Boolean::TYPE_EMPTY_ARRAY], 'casting' => false], [], false],
+ [['type' => ['array'], 'casting' => false], [], false],
+ [['type' => 'array', 'casting' => false], [], false],
+ ];
+ }
+
+ /** @param OptionsArgument $options */
+ #[DataProvider('integerProvider')]
+ #[DataProvider('floatProvider')]
+ #[DataProvider('booleanProvider')]
+ #[DataProvider('stringProvider')]
+ #[DataProvider('falseStringProvider')]
+ #[DataProvider('nullProvider')]
+ #[DataProvider('zeroStringProvider')]
+ #[DataProvider('emptyArrayProvider')]
+ public function testIndividualTypes(array $options, mixed $input, mixed $expect): void
+ {
+ $filter = new Boolean($options);
+
+ /** @psalm-var mixed $result */
+ $result = $filter->filter($input);
+
+ $message = sprintf(
+ 'Expected (%s) %s to be filtered to (%s) %s',
+ gettype($input),
+ var_export($input, true),
+ gettype($expect),
+ var_export($expect, true),
+ );
+
+ self::assertSame($expect, $result, $message);
+ self::assertSame($expect, $filter->__invoke($input));
}
- #[DataProvider('noCastingTestProvider')]
- public function testNoCasting(mixed $value, mixed $expected): void
+ #[DataProvider('defaultTestProvider')]
+ public function testDefault(mixed $value, bool $expected): void
{
- $filter = new BooleanFilter('all', false);
+ $filter = new Boolean();
self::assertSame($expected, $filter->filter($value));
}
/**
- * @param array{0: mixed, 1: mixed} $testData
+ * @param int-mask-of $type
+ * @param list $testData
*/
#[DataProvider('typeTestProvider')]
public function testTypes(int $type, array $testData): void
{
- $filter = new BooleanFilter($type);
+ $filter = new Boolean(['type' => $type]);
foreach ($testData as $data) {
+ /**
+ * @var mixed $value
+ * @var mixed $expected
+ */
[$value, $expected] = $data;
$message = sprintf(
'%s (%s) is not filtered as %s; type = %s',
var_export($value, true),
gettype($value),
var_export($expected, true),
- $type
+ $type,
);
self::assertSame($expected, $filter->filter($value), $message);
}
}
/**
- * @param array $typeData
- * @param array $testData
+ * @param list $typeData
+ * @param list $testData
*/
#[DataProvider('combinedTypeTestProvider')]
- public function testCombinedTypes($typeData, $testData): void
+ public function testCombinedTypes(array $typeData, array $testData): void
{
foreach ($typeData as $type) {
- $filter = new BooleanFilter(['type' => $type]);
+ $filter = new Boolean(['type' => $type]);
foreach ($testData as $data) {
+ /**
+ * @psalm-var mixed $value
+ * @psalm-var mixed $expected
+ */
[$value, $expected] = $data;
$message = sprintf(
'%s (%s) is not filtered as %s; type = %s',
var_export($value, true),
gettype($value),
var_export($expected, true),
- var_export($type, true)
+ var_export($type, true),
);
self::assertSame($expected, $filter->filter($value), $message);
}
@@ -93,8 +262,8 @@ public function testCombinedTypes($typeData, $testData): void
public function testLocalized(): void
{
- $filter = new BooleanFilter([
- 'type' => BooleanFilter::TYPE_LOCALIZED,
+ $filter = new Boolean([
+ 'type' => Boolean::TYPE_LOCALIZED,
'translations' => [
'yes' => true,
'y' => true,
@@ -111,35 +280,19 @@ public function testLocalized(): void
self::assertFalse($filter->filter('nay'));
}
- public function testSettingFalseType(): void
+ public function testInvalidType(): void
{
- $filter = new BooleanFilter();
$this->expectException(Exception\InvalidArgumentException::class);
$this->expectExceptionMessage('Unknown type value');
- /** @psalm-suppress InvalidArgument */
- $filter->setType(true);
- }
- public function testGettingDefaultType(): void
- {
- $filter = new BooleanFilter();
- self::assertSame(127, $filter->getType());
+ /** @psalm-suppress InvalidArgument */
+ new Boolean(['type' => 'foo']);
}
/**
- * Ensures that if a type is specified more than once, we get the expected type, not something else.
- * https://github.com/zendframework/zend-filter/issues/48
- *
- * @param mixed $type Type to double initialize
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
*/
- #[DataProvider('duplicateProvider')]
- public function testDuplicateTypesWorkProperly(int|string $type, int $expected): void
- {
- $filter = new BooleanFilter([$type, $type]);
- self::assertSame($expected, $filter->getType());
- }
-
- /** @return list */
public static function defaultTestProvider(): array
{
return [
@@ -163,37 +316,15 @@ public static function defaultTestProvider(): array
];
}
- /** @return list */
- public static function noCastingTestProvider(): array
- {
- return [
- [false, false],
- [true, true],
- [0, false],
- [1, true],
- [2, 2],
- [0.0, false],
- [1.0, true],
- [0.5, 0.5],
- ['', false],
- ['abc', 'abc'],
- ['0', false],
- ['1', true],
- ['2', '2'],
- [[], false],
- [[0], [0]],
- [null, false],
- ['false', false],
- ['true', true],
- ];
- }
-
- /** @return list */
+ /**
+ * @return list, 1: list}>
+ * @psalm-suppress PossiblyUnusedMethod
+ */
public static function typeTestProvider(): array
{
return [
[
- BooleanFilter::TYPE_BOOLEAN,
+ Boolean::TYPE_BOOLEAN,
[
[false, false],
[true, true],
@@ -215,7 +346,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_INTEGER,
+ Boolean::TYPE_INTEGER,
[
[false, true],
[true, true],
@@ -237,7 +368,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_FLOAT,
+ Boolean::TYPE_FLOAT,
[
[false, true],
[true, true],
@@ -259,7 +390,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_STRING,
+ Boolean::TYPE_STRING,
[
[false, true],
[true, true],
@@ -281,7 +412,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_ZERO_STRING,
+ Boolean::TYPE_ZERO_STRING,
[
[false, true],
[true, true],
@@ -303,7 +434,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_EMPTY_ARRAY,
+ Boolean::TYPE_EMPTY_ARRAY,
[
[false, true],
[true, true],
@@ -325,7 +456,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_NULL,
+ Boolean::TYPE_NULL,
[
[false, true],
[true, true],
@@ -347,7 +478,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_PHP,
+ Boolean::TYPE_PHP,
[
[false, false],
[true, true],
@@ -369,7 +500,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_FALSE_STRING,
+ Boolean::TYPE_FALSE_STRING,
[
[false, true],
[true, true],
@@ -393,7 +524,7 @@ public static function typeTestProvider(): array
// default behaviour with no translations provided
// all values filtered as true
[
- BooleanFilter::TYPE_LOCALIZED,
+ Boolean::TYPE_LOCALIZED,
[
[false, true],
[true, true],
@@ -415,7 +546,7 @@ public static function typeTestProvider(): array
],
],
[
- BooleanFilter::TYPE_ALL,
+ Boolean::TYPE_ALL,
[
[false, false],
[true, true],
@@ -439,23 +570,27 @@ public static function typeTestProvider(): array
];
}
+ /**
+ * @return list, 1: list}>
+ * @psalm-suppress PossiblyUnusedMethod
+ */
public static function combinedTypeTestProvider(): array
{
return [
[
[
[
- BooleanFilter::TYPE_ZERO_STRING,
- BooleanFilter::TYPE_STRING,
- BooleanFilter::TYPE_BOOLEAN,
+ Boolean::TYPE_ZERO_STRING,
+ Boolean::TYPE_STRING,
+ Boolean::TYPE_BOOLEAN,
],
[
'zero',
'string',
'boolean',
],
- BooleanFilter::TYPE_ZERO_STRING | BooleanFilter::TYPE_STRING | BooleanFilter::TYPE_BOOLEAN,
- BooleanFilter::TYPE_ZERO_STRING + BooleanFilter::TYPE_STRING + BooleanFilter::TYPE_BOOLEAN,
+ Boolean::TYPE_ZERO_STRING | Boolean::TYPE_STRING | Boolean::TYPE_BOOLEAN,
+ Boolean::TYPE_ZERO_STRING + Boolean::TYPE_STRING + Boolean::TYPE_BOOLEAN,
],
[
[false, false],
@@ -480,32 +615,30 @@ public static function combinedTypeTestProvider(): array
];
}
- /** @return list */
+ /**
+ * @return list
+ * @psalm-suppress PossiblyUnusedMethod
+ */
public static function duplicateProvider(): array
{
return [
- [BooleanFilter::TYPE_BOOLEAN, BooleanFilter::TYPE_BOOLEAN],
- [BooleanFilter::TYPE_INTEGER, BooleanFilter::TYPE_INTEGER],
- [BooleanFilter::TYPE_FLOAT, BooleanFilter::TYPE_FLOAT],
- [BooleanFilter::TYPE_STRING, BooleanFilter::TYPE_STRING],
- [BooleanFilter::TYPE_ZERO_STRING, BooleanFilter::TYPE_ZERO_STRING],
- [BooleanFilter::TYPE_EMPTY_ARRAY, BooleanFilter::TYPE_EMPTY_ARRAY],
- [BooleanFilter::TYPE_NULL, BooleanFilter::TYPE_NULL],
- [BooleanFilter::TYPE_PHP, BooleanFilter::TYPE_PHP],
- [BooleanFilter::TYPE_FALSE_STRING, BooleanFilter::TYPE_FALSE_STRING],
- [BooleanFilter::TYPE_LOCALIZED, BooleanFilter::TYPE_LOCALIZED],
- [BooleanFilter::TYPE_ALL, BooleanFilter::TYPE_ALL],
- ['boolean', BooleanFilter::TYPE_BOOLEAN],
- ['integer', BooleanFilter::TYPE_INTEGER],
- ['float', BooleanFilter::TYPE_FLOAT],
- ['string', BooleanFilter::TYPE_STRING],
- ['zero', BooleanFilter::TYPE_ZERO_STRING],
- ['array', BooleanFilter::TYPE_EMPTY_ARRAY],
- ['null', BooleanFilter::TYPE_NULL],
- ['php', BooleanFilter::TYPE_PHP],
- ['false', BooleanFilter::TYPE_FALSE_STRING],
- ['localized', BooleanFilter::TYPE_LOCALIZED],
- ['all', BooleanFilter::TYPE_ALL],
+ [['type' => [Boolean::TYPE_BOOLEAN, Boolean::TYPE_BOOLEAN], 'casting' => false]],
+ [['type' => ['boolean', Boolean::TYPE_BOOLEAN], 'casting' => false]],
+ [['type' => ['boolean', 'boolean'], 'casting' => false]],
];
}
+
+ /**
+ * Ensures that if a type is specified more than once, we get the expected type, not something else.
+ * https://github.com/zendframework/zend-filter/issues/48
+ *
+ * @param OptionsArgument $options
+ */
+ #[DataProvider('duplicateProvider')]
+ public function testDuplicateTypesWorkProperly(array $options): void
+ {
+ $filter = new Boolean($options);
+ self::assertFalse($filter->filter(false));
+ self::assertTrue($filter->filter(true));
+ }
}
diff --git a/test/StaticAnalysis/BooleanFilterChecks.php b/test/StaticAnalysis/BooleanFilterChecks.php
index 92f6779a..fea10efd 100644
--- a/test/StaticAnalysis/BooleanFilterChecks.php
+++ b/test/StaticAnalysis/BooleanFilterChecks.php
@@ -11,25 +11,27 @@ final class BooleanFilterChecks
{
public function constructorAcceptsSingleTypeConstant(): Filter\Boolean
{
- return new Filter\Boolean(Filter\Boolean::TYPE_FLOAT);
+ return new Filter\Boolean(['type' => Filter\Boolean::TYPE_FLOAT]);
}
public function constructorAcceptsListOfConstants(): Filter\Boolean
{
return new Filter\Boolean([
- Filter\Boolean::TYPE_EMPTY_ARRAY,
- Filter\Boolean::TYPE_FALSE_STRING,
+ 'type' => [
+ Filter\Boolean::TYPE_EMPTY_ARRAY,
+ Filter\Boolean::TYPE_FALSE_STRING,
+ ],
]);
}
public function constructorAcceptsIntMaskOfConstants(): Filter\Boolean
{
- return new Filter\Boolean(Filter\Boolean::TYPE_ALL ^ Filter\Boolean::TYPE_FLOAT);
+ return new Filter\Boolean(['type' => Filter\Boolean::TYPE_ALL ^ Filter\Boolean::TYPE_FLOAT]);
}
public function constructorAcceptsNamedType(): Filter\Boolean
{
- return new Filter\Boolean('localized');
+ return new Filter\Boolean(['type' => 'localized']);
}
public function constructorAcceptsOptionsArray(): Filter\Boolean