From 2e27a15cdf1c70397741bef4f4b29e69aeab40bf Mon Sep 17 00:00:00 2001 From: Michael Krecek Date: Tue, 18 Jun 2024 15:40:03 +0200 Subject: [PATCH] Add "smallint" and "bigint" support to FilterModel (#2211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Voříšek --- demos/collection/tablefilter.php | 3 ++ src/Table/Column/FilterModel.php | 6 +-- src/Table/Column/FilterModel/TypeBoolean.php | 9 +++-- src/Table/Column/FilterModel/TypeDate.php | 18 ++++----- src/Table/Column/FilterModel/TypeDatetime.php | 28 +++++++------- src/Table/Column/FilterModel/TypeEnum.php | 2 +- src/Table/Column/FilterModel/TypeNumber.php | 11 +++--- src/Table/Column/FilterModel/TypeString.php | 10 ++--- src/Table/Column/FilterModel/TypeTime.php | 8 ++-- tests-behat/filter.feature | 37 +++++++++++++------ 10 files changed, 74 insertions(+), 58 deletions(-) diff --git a/demos/collection/tablefilter.php b/demos/collection/tablefilter.php index 48d306377c..4c18086113 100644 --- a/demos/collection/tablefilter.php +++ b/demos/collection/tablefilter.php @@ -6,6 +6,7 @@ use Atk4\Ui\App; use Atk4\Ui\Grid; +use Atk4\Ui\Table\Column\FilterModel; use Atk4\Ui\View; /** @var App $app */ @@ -16,6 +17,8 @@ $grid = Grid::addTo($view, ['menu' => ['class' => ['atk-grid-menu']]]); // menu class added for Behat testing $model = new Country($app->db); +$model->getIdField()->system = false; +$model->getIdField()->ui['filterModel'] = FilterModel\TypeNumber::class; $model->addExpression('is_uk', [ 'expr' => $model->expr('case when [atk_fp_country__iso] = [country] THEN [t] ELSE [f] END', ['country' => 'GB', 't' => true, 'f' => false]), 'type' => 'boolean', diff --git a/src/Table/Column/FilterModel.php b/src/Table/Column/FilterModel.php index 19df9467c9..6df1af9b31 100644 --- a/src/Table/Column/FilterModel.php +++ b/src/Table/Column/FilterModel.php @@ -54,7 +54,9 @@ public static function factoryType(App $app, Field $field): self Types::TEXT => FilterModel\TypeString::class, Types::BOOLEAN => FilterModel\TypeBoolean::class, + Types::SMALLINT => FilterModel\TypeNumber::class, Types::INTEGER => FilterModel\TypeNumber::class, + Types::BIGINT => FilterModel\TypeNumber::class, Types::FLOAT => FilterModel\TypeNumber::class, CustomTypes::MONEY => FilterModel\TypeNumber::class, @@ -68,7 +70,7 @@ public static function factoryType(App $app, Field $field): self Types::JSON => FilterModel\TypeString::class, 'TODO we do not support enum type, any type can be enum' => FilterModel\TypeEnum::class, - ][$field->type]; + ][$field->type] ?? null; // you can set your own filter model class if (isset($field->ui['filterModel'])) { @@ -99,8 +101,6 @@ protected function init(): void public function afterInit(): void { - $this->addField('name', ['default' => $this->lookupField->shortName, 'system' => true]); - // create a name for our filter model to save as session data $this->name = 'filter_model_' . $this->lookupField->shortName; diff --git a/src/Table/Column/FilterModel/TypeBoolean.php b/src/Table/Column/FilterModel/TypeBoolean.php index 68ded0d5c1..b5e1fb5cc5 100644 --- a/src/Table/Column/FilterModel/TypeBoolean.php +++ b/src/Table/Column/FilterModel/TypeBoolean.php @@ -16,11 +16,12 @@ protected function init(): void { parent::init(); + $this->op->type = 'smallint'; $this->op->values = [ - 'true' => 'Is Yes', - 'false' => 'Is No', + 0 => 'Is No', + 1 => 'Is Yes', ]; - $this->op->default = 'true'; + $this->op->default = 1; } #[\Override] @@ -28,7 +29,7 @@ public function setConditionForModel(Model $model): void { $filter = $this->recallData(); if ($filter !== null) { - $model->addCondition($filter['name'], $filter['op'] === 'true'); + $model->addCondition($this->lookupField, $filter['op'] === 1); } } } diff --git a/src/Table/Column/FilterModel/TypeDate.php b/src/Table/Column/FilterModel/TypeDate.php index cbe322a390..99f1701df3 100644 --- a/src/Table/Column/FilterModel/TypeDate.php +++ b/src/Table/Column/FilterModel/TypeDate.php @@ -71,11 +71,11 @@ public function setConditionForModel(Model $model): void if ($filter !== null) { switch ($filter['op']) { case 'empty': - $model->addCondition($filter['name'], '=', null); + $model->addCondition($this->lookupField, '=', null); break; case 'not empty': - $model->addCondition($filter['name'], '!=', null); + $model->addCondition($this->lookupField, '!=', null); break; case 'within': @@ -85,14 +85,14 @@ public function setConditionForModel(Model $model): void [$d1, $d2] = [$d2, $d1]; } $model->addCondition($model->expr('[field] between [value] and [value2]', [ - 'field' => $model->getField($filter['name']), - 'value' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1), - 'value2' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2), + 'field' => $this->lookupField, + 'value' => $model->getPersistence()->typecastSaveField($this->lookupField, $d1), + 'value2' => $model->getPersistence()->typecastSaveField($this->lookupField, $d2), ])); break; default: - $model->addCondition($filter['name'], $filter['op'], $this->getDate($filter['value'])); + $model->addCondition($this->lookupField, $filter['op'], $this->getDate($filter['value'])); } } } @@ -102,10 +102,8 @@ public function setConditionForModel(Model $model): void * Will construct and return a date object base on constructor string. * * @param string $dateModifier the string to pass to generated a date from - * - * @return \DateTime */ - public function getDate($dateModifier) + public function getDate(string $dateModifier): ?\DateTime { switch ($dateModifier) { case 'exact': @@ -123,7 +121,7 @@ public function getDate($dateModifier) break; default: - $date = $dateModifier ? new \DateTime($dateModifier) : null; + $date = null; } return $date; diff --git a/src/Table/Column/FilterModel/TypeDatetime.php b/src/Table/Column/FilterModel/TypeDatetime.php index b0efb11ce0..934aeede66 100644 --- a/src/Table/Column/FilterModel/TypeDatetime.php +++ b/src/Table/Column/FilterModel/TypeDatetime.php @@ -71,11 +71,11 @@ public function setConditionForModel(Model $model): void if ($filter !== null) { switch ($filter['op']) { case 'empty': - $model->addCondition($filter['name'], '=', null); + $model->addCondition($this->lookupField, '=', null); break; case 'not empty': - $model->addCondition($filter['name'], '!=', null); + $model->addCondition($this->lookupField, '!=', null); break; case 'within': @@ -85,9 +85,9 @@ public function setConditionForModel(Model $model): void [$d1, $d2] = [$d2, $d1]; } $model->addCondition($model->expr('[field] between [value] and [value2]', [ - 'field' => $model->getField($filter['name']), - 'value' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1), - 'value2' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2), + 'field' => $this->lookupField, + 'value' => $model->getPersistence()->typecastSaveField($this->lookupField, $d1), + 'value2' => $model->getPersistence()->typecastSaveField($this->lookupField, $d2), ])); break; @@ -100,24 +100,24 @@ public function setConditionForModel(Model $model): void } $betweenOperator = $filter['op'] === '!=' ? 'not between' : 'between'; $model->addCondition($model->expr('[field] ' . $betweenOperator . ' [value] and [value2]', [ - 'field' => $model->getField($filter['name']), - 'value' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1), - 'value2' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2), + 'field' => $this->lookupField, + 'value' => $model->getPersistence()->typecastSaveField($this->lookupField, $d1), + 'value2' => $model->getPersistence()->typecastSaveField($this->lookupField, $d2), ])); break; case '>': case '<=': - $model->addCondition($filter['name'], $filter['op'], $this->getDatetime($filter['value'])->setTime(23, 59, 59, 999_999)); + $model->addCondition($this->lookupField, $filter['op'], $this->getDatetime($filter['value'])->setTime(23, 59, 59, 999_999)); break; case '<': case '>=': - $model->addCondition($filter['name'], $filter['op'], $this->getDatetime($filter['value'])->setTime(0, 0, 0)); + $model->addCondition($this->lookupField, $filter['op'], $this->getDatetime($filter['value'])->setTime(0, 0, 0)); break; default: - $model->addCondition($filter['name'], $filter['op'], $this->getDatetime($filter['value'])); + $model->addCondition($this->lookupField, $filter['op'], $this->getDatetime($filter['value'])); } } } @@ -127,10 +127,8 @@ public function setConditionForModel(Model $model): void * Will construct and return a date object base on constructor string. * * @param string $dateModifier the string to pass to generated a date from - * - * @return \DateTime */ - public function getDatetime($dateModifier) + public function getDatetime(string $dateModifier): ?\DateTime { switch ($dateModifier) { case 'exact': @@ -148,7 +146,7 @@ public function getDatetime($dateModifier) break; default: - $date = $dateModifier ? new \DateTime($dateModifier) : null; + $date = null; } return $date; diff --git a/src/Table/Column/FilterModel/TypeEnum.php b/src/Table/Column/FilterModel/TypeEnum.php index 3169ee641e..087e76926b 100644 --- a/src/Table/Column/FilterModel/TypeEnum.php +++ b/src/Table/Column/FilterModel/TypeEnum.php @@ -41,7 +41,7 @@ public function setConditionForModel(Model $model): void } } if ($values !== []) { - $model->addCondition($filter['name'], 'in', $values); + $model->addCondition($this->lookupField, 'in', $values); } } } diff --git a/src/Table/Column/FilterModel/TypeNumber.php b/src/Table/Column/FilterModel/TypeNumber.php index 05caf33b54..777c7d5617 100644 --- a/src/Table/Column/FilterModel/TypeNumber.php +++ b/src/Table/Column/FilterModel/TypeNumber.php @@ -26,6 +26,7 @@ protected function init(): void ]; $this->op->default = '='; + $this->value->type = $this->lookupField->type; $this->value->ui['form'] = [Form\Control\Line::class]; $this->addField('range', ['ui' => ['caption' => '', 'form' => [Form\Control\Line::class]]]); } @@ -38,16 +39,16 @@ public function setConditionForModel(Model $model): void switch ($filter['op']) { case 'between': $model->addCondition( - $model->expr('[field] between [value] and [range]', [ - 'field' => $model->getField($filter['name']), - 'value' => $filter['value'], - 'range' => $filter['range'], + $model->expr('[field] between [value] and [value2]', [ + 'field' => $this->lookupField, + 'value' => $model->getPersistence()->typecastSaveField($this->lookupField, $filter['value']), + 'value2' => $model->getPersistence()->typecastSaveField($this->lookupField, $filter['range']), ]) ); break; default: - $model->addCondition($filter['name'], $filter['op'], $filter['value']); + $model->addCondition($this->lookupField, $filter['op'], $filter['value']); } } } diff --git a/src/Table/Column/FilterModel/TypeString.php b/src/Table/Column/FilterModel/TypeString.php index c9fb223e72..9a3a78bb99 100644 --- a/src/Table/Column/FilterModel/TypeString.php +++ b/src/Table/Column/FilterModel/TypeString.php @@ -31,23 +31,23 @@ public function setConditionForModel(Model $model): void if ($filter !== null) { switch ($filter['op']) { case 'is': - $model->addCondition($filter['name'], $filter['value']); + $model->addCondition($this->lookupField, $filter['value']); break; case 'is not': - $model->addCondition($filter['name'], '!=', $filter['value']); + $model->addCondition($this->lookupField, '!=', $filter['value']); break; case 'contains': - $model->addCondition($filter['name'], 'like', '%' . $filter['value'] . '%'); + $model->addCondition($this->lookupField, 'like', '%' . $filter['value'] . '%'); break; case 'start': - $model->addCondition($filter['name'], 'like', $filter['value'] . '%'); + $model->addCondition($this->lookupField, 'like', $filter['value'] . '%'); break; case 'end': - $model->addCondition($filter['name'], 'like', '%' . $filter['value']); + $model->addCondition($this->lookupField, 'like', '%' . $filter['value']); break; } diff --git a/src/Table/Column/FilterModel/TypeTime.php b/src/Table/Column/FilterModel/TypeTime.php index e6dee2108b..d00052e373 100644 --- a/src/Table/Column/FilterModel/TypeTime.php +++ b/src/Table/Column/FilterModel/TypeTime.php @@ -42,14 +42,14 @@ public function setConditionForModel(Model $model): void [$d1, $d2] = [$d2, $d1]; } $model->addCondition($model->expr('[field] between [value] and [value2]', [ - 'field' => $model->getField($filter['name']), - 'value' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1), - 'value2' => $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2), + 'field' => $this->lookupField, + 'value' => $model->getPersistence()->typecastSaveField($this->lookupField, $d1), + 'value2' => $model->getPersistence()->typecastSaveField($this->lookupField, $d2), ])); break; default: - $model->addCondition($filter['name'], $filter['op'], $filter['value']); + $model->addCondition($this->lookupField, $filter['op'], $filter['value']); } } } diff --git a/tests-behat/filter.feature b/tests-behat/filter.feature index 65ed0c3fa3..17e021426f 100644 --- a/tests-behat/filter.feature +++ b/tests-behat/filter.feature @@ -4,31 +4,46 @@ Feature: Table Filter Given I am on "collection/tablefilter.php" Then I should see "Australia" Then I click filter column name "atk_fp_country__name" - When I fill in "value" with "united kingdom" - Then I press button "Set" + When I fill field using "//div.popup[2]//input[@name='value']" with "united kingdom" + When I click using selector "//div.popup[2]//div[text()='Set']" Then I should not see "Australia" Then I should see "United Kingdom" Then I click filter column name "atk_fp_country__phonecode" - When I fill field using "//div.popup[5]//input[@name='value']" with "44" - When I click using selector "//div.popup[5]//div[text()='Set']" + When I fill field using "//div.popup[6]//input[@name='value']" with "44" + When I click using selector "//div.popup[6]//div[text()='Set']" Then I should see "United Kingdom" Then I click filter column name "atk_fp_country__phonecode" - When I fill field using "//div.popup[5]//input[@name='value']" with "4" - When I click using selector "//div.popup[5]//div[text()='Set']" + When I fill field using "//div.popup[6]//input[@name='value']" with "4" + When I click using selector "//div.popup[6]//div[text()='Set']" Then I should not see "United Kingdom" Then I should see "No records" Then I click filter column name "atk_fp_country__phonecode" - When I click using selector "//div.popup[5]//div[text()='Clear']" + When I click using selector "//div.popup[6]//div[text()='Clear']" Then I should not see "No records" Then I should see "United Kingdom" Then I click filter column name "is_uk" - Then I select value "Is No" in lookup "//div.popup[6]//input[@name='op']" - When I click using selector "//div.popup[6]//div[text()='Set']" + Then I select value "Is No" in lookup "//div.popup[7]//input[@name='op']" + When I click using selector "//div.popup[7]//div[text()='Set']" Then I should see "No records" Then I click filter column name "is_uk" - Then I select value "Is Yes" in lookup "//div.popup[6]//input[@name='op']" - When I click using selector "//div.popup[6]//div[text()='Set']" + Then I select value "Is Yes" in lookup "//div.popup[7]//input[@name='op']" + When I click using selector "//div.popup[7]//div[text()='Set']" Then I should see "United Kingdom" Then I press button "Clear Filters" Then I should not see "United Kingdom" Then I should see "Australia" + Then I should see "Argentina" + Then I should see "Austria" + Then I click filter column name "atk_fp_country__id" + When I select value "=" in lookup "//div.popup[1]//input[@name='op']" + When I fill field using "//div.popup[1]//input[@name='value']" with "13" + When I click using selector "//div.popup[1]//div[text()='Set']" + Then I should see "Australia" + Then I should not see "Argentina" + Then I should not see "Austria" + Then I click filter column name "atk_fp_country__id" + When I select value "< or equal" in lookup "//div.popup[1]//input[@name='op']" + When I click using selector "//div.popup[1]//div[text()='Set']" + Then I should see "Australia" + Then I should see "Argentina" + Then I should not see "Austria"