Skip to content

Commit

Permalink
add select2 support for selects.
Browse files Browse the repository at this point in the history
implements data convertion on search for Date fields.
  • Loading branch information
skie committed Oct 9, 2024
1 parent 9b40088 commit 7702f4a
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 37 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"test": "phpunit --stderr",
"coverage-test": "phpunit --stderr --coverage-clover=clover.xml",
"stan": "phpstan.phar analyse --memory-limit=-1 src/",
"stan-local": "php vendor/bin/phpstan.phar analyse --memory-limit=-1 src/",
"stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:0.12.94 psalm/phar:~4.9.2 && mv composer.backup composer.json",
"psalm": "psalm.phar --show-info=false",
"stan-rebuild-baseline": "phpstan.phar analyse ./src/ --generate-baseline",
Expand Down
8 changes: 8 additions & 0 deletions docs/Filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@ use CakeDC\SearchFilter\Filter\SelectFilter;
use CakeDC\SearchFilter\Model\Filter\Criterion\InCriterion;
use CakeDC\SearchFilter\Model\Filter\Criterion\StringCriterion;

$selectFilter = (new SelectFilter())
->setCriterion($manager->criterion()->numeric('status_id'))
->setLabel('Status')
->setOptions($this->Statuses->find('list')->toArray())
->setEmpty('All Statuses');

// or

$selectFilter = (new SelectFilter())
->setCriterion(new InCriterion('status', $statusesTable, new StringCriterion('name')))
->setLabel('Status')
Expand Down
1 change: 1 addition & 0 deletions src/Filter/AbstractFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public function setConditions(array|object $conditions): self
public function excludeIn(): self
{
unset($this->conditions[AbstractFilter::COND_IN]);
unset($this->conditions[AbstractFilter::COND_NOT_IN]);

return $this;
}
Expand Down
34 changes: 30 additions & 4 deletions src/Model/Filter/Criterion/DateCriterion.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ class DateCriterion extends BaseCriterion
*/
protected FunctionsBuilder $func;

/**
* Database type
*
* @var string
*/
protected string $dbType = 'date';

/**
* DateCriterion constructor.
*
Expand Down Expand Up @@ -97,6 +104,10 @@ public function buildFilter(string $condition, array $values, array $criteria, a
*/
public function buildCondition(string|ExpressionInterface $fieldName, string $condition, array $values, array $options = []): ?callable
{
if ($this->dbType === 'date') {
$fieldName = $this->ensureFieldIsDate($fieldName);
}

if ($condition == AbstractFilter::COND_BETWEEN) {
$from = $this->getValues('date_from', $condition, $values);
$to = $this->getValues('date_to', $condition, $values);
Expand All @@ -106,15 +117,15 @@ public function buildCondition(string|ExpressionInterface $fieldName, string $co

if (!empty($from) && !empty($to)) {
return function (QueryExpression $exp) use ($fieldName, $from, $to): QueryExpression {
return $exp->between($fieldName, $from, $to, 'datetime');
return $exp->between($fieldName, $from, $to, $this->dbType);
};
} elseif (!empty($from)) {
return function (QueryExpression $exp) use ($fieldName, $from): QueryExpression {
return $exp->gte($fieldName, $from, 'datetime');
return $exp->gte($fieldName, $from, $this->dbType);
};
} elseif (!empty($to)) {
return function (QueryExpression $exp) use ($fieldName, $to): QueryExpression {
return $exp->lte($fieldName, $to, 'datetime');
return $exp->lte($fieldName, $to, $this->dbType);
};
}

Expand Down Expand Up @@ -149,7 +160,7 @@ public function buildCondition(string|ExpressionInterface $fieldName, string $co
$value = $this->prepareTime($value);
}

return $this->buildQueryByCondition($fieldName, $condition, $value);
return $this->buildQueryByCondition($fieldName, $condition, $value, ['type' => $this->dbType]);
}

/**
Expand Down Expand Up @@ -186,4 +197,19 @@ protected function prepareTime(string $dateStr): \DateTimeInterface
{
return FrozenDate::createFromFormat($this->format, $dateStr);
}

/**
* Ensure the field is converted to a date if it's a datetime
*
* @param string|\Cake\Database\ExpressionInterface $field
* @return \Cake\Database\ExpressionInterface
*/
protected function ensureFieldIsDate(string|ExpressionInterface $field): ExpressionInterface
{
if (is_string($field)) {
$field = new IdentifierExpression($field);
}

return new FunctionExpression('DATE', [$field], [], 'date');
}
}
7 changes: 7 additions & 0 deletions src/Model/Filter/Criterion/DateTimeCriterion.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@

class DateTimeCriterion extends DateCriterion
{
/**
* Database type
*
* @var string
*/
protected string $dbType = 'datetime';

/**
* DateCriterion constructor.
*
Expand Down
41 changes: 31 additions & 10 deletions templates/element/Search/v_templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,39 @@ class="form-control value"
/>
</span>
</script>

<script type="text/x-template" id="search-select2-template">
<div>
<select class="form-control" :id="id" :name="name" :disabled="disabled" :required="required"></select>
</div>
</script>

<script type="text/x-template" id="search-input-select-template">
<span>
<select
class="form-control value"
:name="'v[' + index + '][value][]'"
v-model="currentValue"
@change="setValue()"
>
<option value="">{{ empty || '[Select]' }}</option>
<option v-for="(field, key) in options" :value="key">{{ field }}</option>
</select>
<template v-if="mode === 'select2'">
<Select2
:id="'select-' + index"
:name="'v[' + index + '][value][]'"
v-model="currentValue"
:options="options"
:placeholder="empty"
@update:modelValue="setValue"
/>
</template>
<template v-else>
<select
class="form-control value"
:id="'select-' + index"
:name="'v[' + index + '][value][]'"
v-model="currentValue"
@change="setValue($event.target.value)"
>
<option value="">{{ empty }}</option>
<option v-for="(text, id) in options" :key="id" :value="id">
{{ text }}
</option>
</select>
</template>
</span>
</script>

Expand All @@ -204,7 +226,6 @@ class="form-control value"
</span>
</script>


<script type="text/x-template" id="search-input-date-template">
<span class="date-wrapper">
<input
Expand Down
22 changes: 11 additions & 11 deletions tests/TestCase/Model/Filter/Criterion/DateCriterionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function testBuildEqualFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date =', $sql);
$this->assertStringContainsString('(DATE(test_date)) =', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -122,7 +122,7 @@ public function testBuildNotEqualFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date !=', $sql);
$this->assertStringContainsString('(DATE(test_date)) !=', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -154,7 +154,7 @@ public function testBuildGreaterThanFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date >', $sql);
$this->assertStringContainsString('(DATE(test_date)) >', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -186,7 +186,7 @@ public function testBuildGreaterThanOrEqualFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date >=', $sql);
$this->assertStringContainsString('(DATE(test_date)) >=', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -218,7 +218,7 @@ public function testBuildLessThanFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date <', $sql);
$this->assertStringContainsString('(DATE(test_date)) <', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -250,7 +250,7 @@ public function testBuildLessThanOrEqualFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date <=', $sql);
$this->assertStringContainsString('(DATE(test_date)) <=', $sql);
$this->assertStringContainsString(':c0', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -282,7 +282,7 @@ public function testBuildBetweenFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date BETWEEN', $sql);
$this->assertStringContainsString('DATE(test_date) BETWEEN', $sql);
$this->assertStringContainsString(':c0 AND :c1', $sql);

$bindings = $valueBinder->bindings();
Expand Down Expand Up @@ -316,7 +316,7 @@ public function testBuildTodayFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date = (CURRENT_DATE())', $sql);
$this->assertStringContainsString('DATE(test_date) = (CURRENT_DATE())', $sql);
}

/**
Expand All @@ -343,7 +343,7 @@ public function testBuildYesterdayFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('test_date = (DATE_ADD(CURRENT_DATE, INTERVAL -1 DAY))', $sql);
$this->assertStringContainsString('DATE(test_date) = (DATE_ADD(CURRENT_DATE, INTERVAL -1 DAY))', $sql);
}

/**
Expand All @@ -370,7 +370,7 @@ public function testBuildThisWeekFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('CONCAT(CAST(EXTRACT(YEAR FROM test_date) AS varchar), CAST(EXTRACT(WEEK FROM test_date) AS varchar)) = (CONCAT(CAST(EXTRACT(YEAR FROM CURRENT_DATE) AS varchar), CAST(EXTRACT(WEEK FROM CURRENT_DATE) AS varchar)))', $sql);
$this->assertStringContainsString('CONCAT(CAST(EXTRACT(YEAR FROM DATE(test_date)) AS varchar), CAST(EXTRACT(WEEK FROM DATE(test_date)) AS varchar)) = (CONCAT(CAST(EXTRACT(YEAR FROM CURRENT_DATE) AS varchar), CAST(EXTRACT(WEEK FROM CURRENT_DATE) AS varchar)))', $sql);
}

/**
Expand All @@ -397,6 +397,6 @@ public function testBuildLastWeekFilter(): void
$valueBinder = new ValueBinder();
$sql = $modifiedExpression->sql($valueBinder);

$this->assertStringContainsString('CONCAT(CAST(EXTRACT(YEAR FROM test_date) AS varchar), CAST(EXTRACT(WEEK FROM test_date) AS varchar)) = (CONCAT(CAST(EXTRACT(YEAR FROM DATE_ADD(CURRENT_DATE, INTERVAL -7 DAY)) AS varchar), CAST(EXTRACT(WEEK FROM DATE_ADD(CURRENT_DATE, INTERVAL -7 DAY)) AS varchar)))', $sql);
$this->assertStringContainsString('CONCAT(CAST(EXTRACT(YEAR FROM DATE(test_date)) AS varchar), CAST(EXTRACT(WEEK FROM DATE(test_date)) AS varchar)) = (CONCAT(CAST(EXTRACT(YEAR FROM DATE_ADD(CURRENT_DATE, INTERVAL -7 DAY)) AS varchar), CAST(EXTRACT(WEEK FROM DATE_ADD(CURRENT_DATE, INTERVAL -7 DAY)) AS varchar)))', $sql);
}
}
Loading

0 comments on commit 7702f4a

Please sign in to comment.