Skip to content

Commit

Permalink
Add casting for Finder. (#342)
Browse files Browse the repository at this point in the history
Add casting for Finder filter
  • Loading branch information
dereuromark committed Feb 26, 2024
1 parent 27c0686 commit c75326b
Show file tree
Hide file tree
Showing 20 changed files with 268 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .phive/phars.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpstan" version="1.10.14" installed="1.10.14" location="./tools/phpstan" copy="false"/>
<phar name="phpstan" version="1.10.59" installed="1.10.59" location="./tools/phpstan" copy="false"/>
<phar name="psalm" version="5.10.0" installed="5.10.0" location="./tools/psalm" copy="false"/>
</phive>
4 changes: 4 additions & 0 deletions docs/filters-and-examples.md
Expand Up @@ -238,6 +238,10 @@ The following options are supported by all filters except `Callback` and `Finder

- `options` (`array`, defaults to `[]`) Additional options to pass to the finder.

- `cast` (`array`, defaults to `[]`) Additional casts to be used on the (mapped
field values. You can use `'int'`, `'bool'`, `'float'`, etc as strings. You can also
use callable functions like `function ($value) { ... }` for more complex scenarios.

## Filtering by `belongsToMany` and `hasMany` associations

If you want to filter values related to a `belongsToMany` or `hasMany` association,
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
@@ -1,5 +1,5 @@
parameters:
level: 7
level: 8
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
paths:
Expand Down
6 changes: 3 additions & 3 deletions src/Model/Filter/Base.php
Expand Up @@ -20,7 +20,7 @@ abstract class Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [];

Expand Down Expand Up @@ -200,9 +200,9 @@ public function value(): mixed
}

/**
* @return array|string|null
* @return mixed
*/
protected function passedValue(): string|array|null
protected function passedValue(): mixed
{
if (!isset($this->_args[$this->name()])) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Boolean.php
Expand Up @@ -10,7 +10,7 @@ class Boolean extends Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'mode' => 'OR',
Expand Down
4 changes: 2 additions & 2 deletions src/Model/Filter/Compare.php
Expand Up @@ -10,7 +10,7 @@ class Compare extends Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'operator' => '>=',
Expand All @@ -20,7 +20,7 @@ class Compare extends Base
/**
* Allowed operators.
*
* @var array
* @var array<string>
*/
protected array $_operators = [
'>=', '<=', '<', '>',
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Escaper/DefaultEscaper.php
Expand Up @@ -12,7 +12,7 @@ class DefaultEscaper implements EscaperInterface
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'fromWildCardAny' => '%',
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Escaper/SqlserverEscaper.php
Expand Up @@ -8,7 +8,7 @@ class SqlserverEscaper extends DefaultEscaper
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'fromWildCardAny' => '%',
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Exists.php
Expand Up @@ -10,7 +10,7 @@ class Exists extends Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'mode' => 'OR',
Expand Down
20 changes: 19 additions & 1 deletion src/Model/Filter/Finder.php
Expand Up @@ -3,14 +3,17 @@

namespace Search\Model\Filter;

use Closure;

class Finder extends Base
{
/**
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'map' => [],
'options' => [],
'cast' => [],
];

/**
Expand All @@ -37,6 +40,21 @@ public function process(): bool
foreach ($map as $to => $from) {
$args[$to] = $args[$from] ?? null;
}
$casts = $this->getConfig('cast');
foreach ($casts as $field => $toType) {
$value = $args[$field] ?? null;
if ($value === null) {
continue;
}

if ($toType instanceof Closure) {
$value = $toType($value);
} else {
settype($value, $toType);
}

$args[$field] = $value;
}

$options = $this->getConfig('options');
$args += $options;
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Like.php
Expand Up @@ -22,7 +22,7 @@ class Like extends Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'before' => false,
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Filter/Value.php
Expand Up @@ -12,7 +12,7 @@ class Value extends Base
/**
* Default configuration.
*
* @var array
* @var array<string, mixed>
*/
protected array $_defaultConfig = [
'mode' => 'OR',
Expand Down
36 changes: 36 additions & 0 deletions tests/TestApp/Model/Table/FinderArticlesTable.php
Expand Up @@ -45,4 +45,40 @@ public function findSlugged(SelectQuery $query, string $slug): SelectQuery
{
return $query->where(['title' => $slug]);
}

/**
* Requires nullable slug key to be present in $options array.
*
* @param \Cake\ORM\Query\SelectQuery $query
* @param string|null $slug
* @return \Cake\ORM\Query\SelectQuery
*/
public function findSluggedNullable(SelectQuery $query, ?string $slug): SelectQuery
{
return $query->where(['title IS' => $slug]);
}

/**
* Requires uid key to be present in $options array.
*
* @param \Cake\ORM\Query\SelectQuery $query
* @param int $uid
* @return \Cake\ORM\Query\SelectQuery
*/
public function findUser(SelectQuery $query, int $uid): SelectQuery
{
return $query->where(['user_id' => $uid]);
}

/**
* Requires nullable uid key to be present in $options array.
*
* @param \Cake\ORM\Query\SelectQuery $query
* @param int|null $uid
* @return \Cake\ORM\Query\SelectQuery
*/
public function findUserNullable(SelectQuery $query, ?int $uid): SelectQuery
{
return $query->where(['user_id IS' => $uid]);
}
}
8 changes: 4 additions & 4 deletions tests/TestCase/Model/Filter/BaseTest.php
Expand Up @@ -105,7 +105,7 @@ public function testConstructNonEmptyNameArgument($nonEmptyValue)
$this->Manager,
['fields' => 'fields']
);
$this->assertEquals($filter->name(), $nonEmptyValue);
$this->assertSame($filter->name(), $nonEmptyValue);
}

/**
Expand Down Expand Up @@ -144,13 +144,13 @@ public function testValue()
);

$filter->setArgs(['fields' => 'value']);
$this->assertEquals('value', $filter->value());
$this->assertSame('value', $filter->value());

$filter->setArgs(['other_field' => 'value']);
$this->assertEquals('default', $filter->value());
$this->assertSame('default', $filter->value());

$filter->setArgs(['fields' => ['value1', 'value2']]);
$this->assertEquals('default', $filter->value());
$this->assertSame('default', $filter->value());
}

/**
Expand Down
26 changes: 13 additions & 13 deletions tests/TestCase/Model/Filter/BooleanTest.php
Expand Up @@ -31,7 +31,7 @@ public function testProcessWithFlagOn()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -53,7 +53,7 @@ public function testProcessWithFlagOff()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[false],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -75,7 +75,7 @@ public function testProcessWithStringFlagTrue()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -97,7 +97,7 @@ public function testProcessWithStringFlagFalse()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[false],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -119,7 +119,7 @@ public function testProcessWithBooleanFlagTrue()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -141,7 +141,7 @@ public function testProcessWithBooleanFlagFalse()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[false],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -163,7 +163,7 @@ public function testProcessWithStringFlag1()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -185,7 +185,7 @@ public function testProcessWithStringFlag0()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[false],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -207,7 +207,7 @@ public function testProcessWithIntegerFlag1()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -226,7 +226,7 @@ public function testProcessWithIntegerFlag0()
'/WHERE Articles\.is_active = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[false],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand Down Expand Up @@ -285,7 +285,7 @@ public function testProcessMultiField()
'/WHERE \(Articles\.is_active = :c0 OR Articles\.other = :c1\)$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true, true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -310,7 +310,7 @@ public function testProcessMultiFieldWithAndMode()
'/WHERE \(Articles\.is_active = :c0 AND Articles\.other = :c1\)$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true, true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -332,7 +332,7 @@ public function testProcessDefaultFallbackForDisallowedMultiValue()
'/WHERE Articles\.is_active = :c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[true],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand Down
2 changes: 1 addition & 1 deletion tests/TestCase/Model/Filter/CallbackTest.php
Expand Up @@ -36,7 +36,7 @@ public function testProcess()
'/WHERE title = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
['test'],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand Down
4 changes: 2 additions & 2 deletions tests/TestCase/Model/Filter/ExistsTest.php
Expand Up @@ -74,7 +74,7 @@ public function testProcessWithFlagOnNotNullable()
'/WHERE Articles\.number != \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[''],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand All @@ -100,7 +100,7 @@ public function testProcessWithFlagOffNotNullable()
'/WHERE Articles\.number = \:c0$/',
$filter->getQuery()->sql()
);
$this->assertEquals(
$this->assertSame(
[''],
Hash::extract($filter->getQuery()->getValueBinder()->bindings(), '{s}.value')
);
Expand Down

0 comments on commit c75326b

Please sign in to comment.