Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 2.0.0 under development

- New #237: Add `Stringable` type support to filter values (@vjik)
- New #150: Extract `withLimit()` from `ReadableDataInterface` into `LimitableDataInterface` (@vjik)
- Enh #150: `PaginatorInterface` now extends `ReadableDataInterface` (@vjik)
- Chg #151: Rename `isRequired()` method in `PaginatorInterface` to `isPaginationRequired()` (@vjik)
Expand Down
9 changes: 5 additions & 4 deletions src/Reader/Filter/Between.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Data\Reader\Filter;

use DateTimeInterface;
use Stringable;
use Yiisoft\Data\Reader\FilterInterface;

/**
Expand All @@ -15,13 +16,13 @@ final class Between implements FilterInterface
{
/**
* @param string $field Name of the field to compare.
* @param bool|DateTimeInterface|float|int|string $minValue Minimal field value.
* @param bool|DateTimeInterface|float|int|string $maxValue Maximal field value.
* @param bool|DateTimeInterface|float|int|string|Stringable $minValue Minimal field value.
* @param bool|DateTimeInterface|float|int|string|Stringable $maxValue Maximal field value.
*/
public function __construct(
public readonly string $field,
public readonly bool|DateTimeInterface|float|int|string $minValue,
public readonly bool|DateTimeInterface|float|int|string $maxValue
public readonly bool|DateTimeInterface|float|int|string|Stringable $minValue,
public readonly bool|DateTimeInterface|float|int|string|Stringable $maxValue
) {
}
}
9 changes: 5 additions & 4 deletions src/Reader/Filter/Compare.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Data\Reader\Filter;

use DateTimeInterface;
use Stringable;
use Yiisoft\Data\Reader\FilterInterface;

/**
Expand All @@ -14,18 +15,18 @@ abstract class Compare implements FilterInterface
{
/**
* @param string $field Name of the field to compare.
* @param bool|DateTimeInterface|float|int|string $value Value to compare to.
* @param bool|DateTimeInterface|float|int|string|Stringable $value Value to compare to.
*/
final public function __construct(
public readonly string $field,
public readonly bool|DateTimeInterface|float|int|string $value,
public readonly bool|DateTimeInterface|float|int|string|Stringable $value,
) {
}

/**
* @param bool|DateTimeInterface|float|int|string $value Value to compare to.
* @param bool|DateTimeInterface|float|int|string|Stringable $value Value to compare to.
*/
final public function withValue(bool|DateTimeInterface|float|int|string $value): static
final public function withValue(bool|DateTimeInterface|float|int|string|Stringable $value): static
{
return new static($this->field, $value);
}
Expand Down
9 changes: 5 additions & 4 deletions src/Reader/Filter/In.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Data\Reader\Filter;

use InvalidArgumentException;
use Stringable;
use Yiisoft\Data\Reader\FilterInterface;

use function is_scalar;
Expand All @@ -17,11 +18,11 @@ final class In implements FilterInterface
{
/**
* @param string $field Name of the field to compare.
* @param bool[]|float[]|int[]|string[] $values Values to check against.
* @param bool[]|float[]|int[]|string[]|Stringable[] $values Values to check against.
*/
public function __construct(
public readonly string $field,
/** @var bool[]|float[]|int[]|string[] Values to check against. */
/** @var bool[]|float[]|int[]|string[]|Stringable[] Values to check against. */
public readonly array $values
) {
$this->assertValues($values);
Expand All @@ -30,10 +31,10 @@ public function __construct(
private function assertValues(array $values): void
{
foreach ($values as $value) {
if (!is_scalar($value)) {
if (!is_scalar($value) && !$value instanceof Stringable) {
throw new InvalidArgumentException(
sprintf(
'The value should be scalar. "%s" is received.',
'The value should be scalar or Stringable. "%s" is received.',
get_debug_type($value),
)
);
Expand Down
5 changes: 3 additions & 2 deletions src/Reader/Filter/Like.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Data\Reader\Filter;

use Stringable;
use Yiisoft\Data\Reader\FilterInterface;

/**
Expand All @@ -13,7 +14,7 @@ final class Like implements FilterInterface
{
/**
* @param string $field Name of the field to compare.
* @param string $value Value to like-compare with.
* @param string|Stringable $value Value to like-compare with.
* @param bool|null $caseSensitive Whether search must be case-sensitive:
*
* - `null` - depends on implementation;
Expand All @@ -23,7 +24,7 @@ final class Like implements FilterInterface
*/
public function __construct(
public readonly string $field,
public readonly string $value,
public readonly string|Stringable $value,
public readonly ?bool $caseSensitive = null,
public readonly LikeMode $mode = LikeMode::Contains,
) {
Expand Down
9 changes: 5 additions & 4 deletions src/Reader/Iterable/FilterHandler/LikeHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ public function match(object|array $item, FilterInterface $filter, Context $cont
return false;
}

if ($filter->value === '') {
$searchValue = (string) $filter->value;
if ($searchValue === '') {
return true;
}

return match ($filter->mode) {
LikeMode::Contains => $this->matchContains($itemValue, $filter->value, $filter->caseSensitive),
LikeMode::StartsWith => $this->matchStartsWith($itemValue, $filter->value, $filter->caseSensitive),
LikeMode::EndsWith => $this->matchEndsWith($itemValue, $filter->value, $filter->caseSensitive),
LikeMode::Contains => $this->matchContains($itemValue, $searchValue, $filter->caseSensitive),
LikeMode::StartsWith => $this->matchStartsWith($itemValue, $searchValue, $filter->caseSensitive),
LikeMode::EndsWith => $this->matchEndsWith($itemValue, $searchValue, $filter->caseSensitive),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
use PHPUnit\Framework\Attributes\DataProvider;
use Yiisoft\Data\Reader\Filter\Between;
use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase;
use Yiisoft\Data\Tests\Support\StringableValue;

abstract class BaseReaderWithBetweenTestCase extends BaseReaderTestCase
{
public static function dataWithReader(): iterable
{
yield 'stringable' => [new Between('email', new StringableValue('ta'), new StringableValue('tz')), [4, 5]];
yield 'float' => [new Between('balance', 10.25, 100.0), [1, 3, 5]];
yield 'datetime' => [new Between('born_at', new DateTimeImmutable('1989-01-01'), new DateTimeImmutable('1991-01-01')), [5]];
yield 'datetime 2' => [new Between('born_at', new DateTimeImmutable('1990-01-02'), new DateTimeImmutable('1990-01-03')), []];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPUnit\Framework\Attributes\DataProvider;
use Yiisoft\Data\Reader\Filter\Equals;
use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase;
use Yiisoft\Data\Tests\Support\StringableValue;

abstract class BaseReaderWithEqualsTestCase extends BaseReaderTestCase
{
Expand All @@ -16,6 +17,7 @@ public static function dataWithReader(): iterable
yield 'integer' => [new Equals('number', 2), [2]];
yield 'float' => [new Equals('balance', 10.25), [1]];
yield 'string' => [new Equals('email', 'the@best'), [4]];
yield 'stringable' => [new Equals('email', new StringableValue('the@best')), [4]];
yield 'datetime' => [new Equals('born_at', new DateTimeImmutable('1990-01-01')), [5]];
}

Expand Down
18 changes: 15 additions & 3 deletions tests/Common/Reader/ReaderWithFilter/BaseReaderWithInTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@

namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter;

use PHPUnit\Framework\Attributes\DataProvider;
use Yiisoft\Data\Reader\Filter\In;
use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase;
use Yiisoft\Data\Tests\Support\StringableValue;

abstract class BaseReaderWithInTestCase extends BaseReaderTestCase
{
public function testWithReader(): void
public static function dataWithReader(): iterable
{
$reader = $this->getReader()->withFilter(new In('number', [2, 3]));
$this->assertFixtures([1, 2], $reader->read());
yield 'int' => [new In('number', [2, 3]), [1, 2]];
yield 'stringable' => [
new In('email', [new StringableValue('seed@beat'), new StringableValue('the@best')]),
[2, 3],
];
}

#[DataProvider('dataWithReader')]
public function testWithReader(In $filter, array $expected): void
{
$reader = $this->getReader()->withFilter($filter);
$this->assertFixtures($expected, $reader->read());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Yiisoft\Data\Reader\Filter\Like;
use Yiisoft\Data\Reader\Filter\LikeMode;
use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase;
use Yiisoft\Data\Tests\Support\StringableValue;

abstract class BaseReaderWithLikeTestCase extends BaseReaderTestCase
{
Expand All @@ -24,13 +25,14 @@ public static function dataWithReader(): array
'wildcard is not supported, %' => ['email', '%st', null, []],
'wildcard is not supported, _' => ['email', '____@___t', null, []],
'search: contains backslash' => ['email', 'foo@bar\\baz', null, [0]],
'stringable' => ['email', new StringableValue('seed@'), null, [2]],
];
}

#[DataProvider('dataWithReader')]
public function testWithReader(
string $field,
string $value,
mixed $value,
bool|null $caseSensitive,
array $expectedFixtureIndexes,
): void {
Expand Down
2 changes: 1 addition & 1 deletion tests/Reader/Filter/InTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class InTest extends TestCase
public function testNotScalarValues(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The value should be scalar. "' . stdClass::class . '" is received.');
$this->expectExceptionMessage('The value should be scalar or Stringable. "' . stdClass::class . '" is received.');
new In('test', [new stdClass()]);
}
}
20 changes: 20 additions & 0 deletions tests/Support/StringableValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Data\Tests\Support;

use Stringable;

final class StringableValue implements Stringable
{
public function __construct(
private readonly string $value,
) {
}

public function __toString(): string
{
return $this->value;
}
}
Loading