From 060908c386182f48db714612531db686d672c49a Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 3 Apr 2024 17:06:47 +0300 Subject: [PATCH 1/4] Add option `queryField` to `DataColumn` --- src/BaseListView.php | 14 +++++++++- src/Column/Base/HeaderContext.php | 23 ++++++++++++---- src/Column/DataColumn.php | 9 +++++-- src/Column/DataColumnRenderer.php | 27 +++++++++++++------ .../OverrideOrderFieldsColumnInterface.php | 13 +++++++++ src/Column/QueryProperty.php | 19 +++++++++++++ src/GridView.php | 23 ++++++++++++++++ 7 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 src/Column/OverrideOrderFieldsColumnInterface.php create mode 100644 src/Column/QueryProperty.php diff --git a/src/BaseListView.php b/src/BaseListView.php index 2a520eb4e..ea0089b1b 100644 --- a/src/BaseListView.php +++ b/src/BaseListView.php @@ -18,6 +18,7 @@ use Yiisoft\Data\Reader\LimitableDataInterface; use Yiisoft\Data\Reader\OffsetableDataInterface; use Yiisoft\Data\Reader\ReadableDataInterface; +use Yiisoft\Data\Reader\Sort; use Yiisoft\Data\Reader\SortableDataInterface; use Yiisoft\Html\Html; use Yiisoft\Html\Tag\Div; @@ -30,12 +31,14 @@ use Yiisoft\Translator\TranslatorInterface; use Yiisoft\Validator\Result as ValidationResult; use Yiisoft\Widget\Widget; +use Yiisoft\Data\Reader\OrderHelper; use Yiisoft\Yii\DataView\Exception\DataReaderNotSetException; /** * @psalm-type UrlArguments = array * @psalm-type UrlCreator = callable(UrlArguments,array):string * @psalm-type PageNotFoundExceptionCallback = callable(PageNotFoundException):void + * @psalm-import-type TOrder from Sort */ abstract class BaseListView extends Widget { @@ -366,7 +369,9 @@ private function prepareDataReaderByParams( if ($dataReader->isSortable() && !empty($sort)) { $sortObject = $dataReader->getSort(); if ($sortObject !== null) { - $dataReader = $dataReader->withSort($sortObject->withOrderString($sort)); + $order = OrderHelper::stringToArray($sort); + $this->prepareOrder($order); + $dataReader = $dataReader->withSort($sortObject->withOrder($order)); } } @@ -377,6 +382,13 @@ private function prepareDataReaderByParams( return $dataReader; } + /** + * @psalm-param TOrder $order + */ + protected function prepareOrder(array &$order): void + { + } + /** * Return new instance with the header for the grid. * diff --git a/src/Column/Base/HeaderContext.php b/src/Column/Base/HeaderContext.php index 7f22a520e..73ceff345 100644 --- a/src/Column/Base/HeaderContext.php +++ b/src/Column/Base/HeaderContext.php @@ -5,12 +5,14 @@ namespace Yiisoft\Yii\DataView\Column\Base; use Stringable; +use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Paginator\PageToken; use Yiisoft\Data\Reader\Sort; use Yiisoft\Html\Html; use Yiisoft\Html\Tag\A; use Yiisoft\Translator\TranslatorInterface; use Yiisoft\Yii\DataView\BaseListView; +use Yiisoft\Data\Reader\OrderHelper; use Yiisoft\Yii\DataView\UrlConfig; use Yiisoft\Yii\DataView\UrlParametersFactory; @@ -22,11 +24,13 @@ final class HeaderContext /** * @internal * + * @psalm-param array $overrideOrderFields * @psalm-param UrlCreator|null $urlCreator */ public function __construct( private readonly ?Sort $originalSort, private readonly ?Sort $sort, + private readonly array $overrideOrderFields, private readonly ?string $sortableHeaderClass, private string|Stringable $sortableHeaderPrepend, private string|Stringable $sortableHeaderAppend, @@ -59,6 +63,8 @@ public function translate(string|Stringable $id): string */ public function prepareSortable(Cell $cell, string $property): array { + $originalProperty = $property; + $property = $this->overrideOrderFields[$property] ?? $property; if ($this->sort === null || $this->originalSort === null || !$this->sort->hasFieldInConfig($property)) { return [$cell, null, '', '']; } @@ -85,7 +91,7 @@ public function prepareSortable(Cell $cell, string $property): array UrlParametersFactory::create( $this->pageToken, $this->pageSize, - $this->getLinkSortValue($this->originalSort, $this->sort, $property), + $this->getLinkSortValue($this->originalSort, $this->sort, $property, $originalProperty), $this->urlConfig, ) ); @@ -98,7 +104,12 @@ public function prepareSortable(Cell $cell, string $property): array ]; } - private function getLinkSortValue(Sort $originalSort, Sort $sort, string $property): ?string + private function getLinkSortValue( + Sort $originalSort, + Sort $sort, + string $property, + string $originalProperty + ): ?string { $originalOrder = $originalSort->getOrder(); $order = $sort->getOrder(); @@ -141,12 +152,14 @@ private function getLinkSortValue(Sort $originalSort, Sort $sort, string $proper return null; } - $result = $sort->withOrder($order)->getOrderAsString(); - if (empty($result)) { + $resultOrder = $sort->withOrder($order)->getOrder(); + if (empty($resultOrder)) { return null; } - return $result; + return OrderHelper::arrayToString( + ArrayHelper::replaceKey($resultOrder, $property, $originalProperty) + ); } private function isEqualOrders(array $a, array $b): bool diff --git a/src/Column/DataColumn.php b/src/Column/DataColumn.php index 2f9c71ae4..d8412d428 100644 --- a/src/Column/DataColumn.php +++ b/src/Column/DataColumn.php @@ -24,7 +24,7 @@ */ final class DataColumn implements ColumnInterface { - public readonly ?string $queryProperty; + public readonly ?QueryProperty $queryProperty; /** * @var bool|callable|null @@ -40,6 +40,7 @@ final class DataColumn implements ColumnInterface public function __construct( public readonly ?string $property = null, ?string $queryProperty = null, + ?string $queryField = null, public readonly ?string $header = null, public readonly bool $encodeHeader = true, public readonly ?string $footer = null, @@ -55,7 +56,11 @@ public function __construct( bool|callable|null $filterEmpty = null, private readonly bool $visible = true, ) { - $this->queryProperty = $queryProperty ?? $this->property; + $queryProperty ??= $property; + $this->queryProperty = $queryProperty === null + ? null + : new QueryProperty($queryProperty, $queryField ?? $queryProperty); + $this->filterEmpty = $filterEmpty; } diff --git a/src/Column/DataColumnRenderer.php b/src/Column/DataColumnRenderer.php index 8d4bcef6f..84246ca33 100644 --- a/src/Column/DataColumnRenderer.php +++ b/src/Column/DataColumnRenderer.php @@ -29,7 +29,7 @@ /** * @psalm-import-type FilterEmptyCallable from DataColumn */ -final class DataColumnRenderer implements FilterableColumnRendererInterface +final class DataColumnRenderer implements FilterableColumnRendererInterface, OverrideOrderFieldsColumnInterface { /** * @var bool|callable @@ -76,7 +76,7 @@ public function renderHeader(ColumnInterface $column, Cell $cell, HeaderContext return $cell; } - [$cell, $link, $prepend, $append] = $context->prepareSortable($cell, $column->queryProperty); + [$cell, $link, $prepend, $append] = $context->prepareSortable($cell, $column->queryProperty->property); if ($link !== null) { $link = $link->content($label)->encode(false); } @@ -103,14 +103,14 @@ public function renderFilter(ColumnInterface $column, Cell $cell, FilterContext $content = [ $widget->withContext( new Context( - $column->queryProperty, - $context->getQueryValue($column->queryProperty), + $column->queryProperty->property, + $context->getQueryValue($column->queryProperty->property), $context->formId ) ), ]; - $errors = $context->validationResult->getAttributeErrorMessages($column->queryProperty); + $errors = $context->validationResult->getAttributeErrorMessages($column->queryProperty->property); if (!empty($errors)) { $cell = $cell->addClass($context->cellInvalidClass); $content[] = Html::div(attributes: $context->errorsContainerAttributes) @@ -127,7 +127,7 @@ public function makeFilter(ColumnInterface $column, MakeFilterContext $context): return null; } - $value = $context->getQueryValue($column->queryProperty); + $value = $context->getQueryValue($column->queryProperty->property); if ($value === null) { return null; } @@ -144,7 +144,7 @@ public function makeFilter(ColumnInterface $column, MakeFilterContext $context): $context->validationResult->addError( $error->getMessage(), $error->getParameters(), - [$column->queryProperty] + [$column->queryProperty->property] ); } return null; @@ -163,7 +163,7 @@ public function makeFilter(ColumnInterface $column, MakeFilterContext $context): $factory = $column->filterFactory; } - return $factory->create($column->queryProperty, $value); + return $factory->create($column->queryProperty->field, $value); } public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell @@ -244,4 +244,15 @@ private function checkColumn(ColumnInterface $column): void ); } } + + public function getOverrideOrderFields(ColumnInterface $column): array + { + $this->checkColumn($column); + + if ($column->queryProperty === null || $column->queryProperty->hasEqualField()) { + return []; + } + + return [$column->queryProperty->property => $column->queryProperty->field]; + } } diff --git a/src/Column/OverrideOrderFieldsColumnInterface.php b/src/Column/OverrideOrderFieldsColumnInterface.php new file mode 100644 index 000000000..70a21d8d3 --- /dev/null +++ b/src/Column/OverrideOrderFieldsColumnInterface.php @@ -0,0 +1,13 @@ + + */ + public function getOverrideOrderFields(ColumnInterface $column): array; +} diff --git a/src/Column/QueryProperty.php b/src/Column/QueryProperty.php new file mode 100644 index 000000000..2d7a9c366 --- /dev/null +++ b/src/Column/QueryProperty.php @@ -0,0 +1,19 @@ +property === $this->field; + } +} diff --git a/src/GridView.php b/src/GridView.php index 55a8f4aa6..d61b6b2c4 100644 --- a/src/GridView.php +++ b/src/GridView.php @@ -7,6 +7,7 @@ use Closure; use Psr\Container\ContainerInterface; use Stringable; +use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Data\Paginator\PaginatorInterface; use Yiisoft\Data\Reader\ReadableDataInterface; use Yiisoft\Data\Reader\Sort; @@ -25,6 +26,7 @@ use Yiisoft\Yii\DataView\Column\ColumnInterface; use Yiisoft\Yii\DataView\Column\ColumnRendererInterface; use Yiisoft\Yii\DataView\Column\FilterableColumnRendererInterface; +use Yiisoft\Yii\DataView\Column\OverrideOrderFieldsColumnInterface; use Yiisoft\Yii\DataView\Filter\Factory\IncorrectValueException; /** @@ -531,10 +533,18 @@ protected function renderItems(array $items, ValidationResult $filterValidationR $blocks[] = Html::colgroup()->columns(...$tags)->render(); } + $overrideOrderFields = []; + foreach ($columns as $i => $column) { + if ($renderers[$i] instanceof OverrideOrderFieldsColumnInterface) { + $overrideOrderFields = array_merge($overrideOrderFields, $renderers[$i]->getOverrideOrderFields($column)); + } + } + if ($this->headerTableEnabled) { $headerContext = new HeaderContext( $this->getSort($dataReader), $this->getSort($this->preparedDataReader), + $overrideOrderFields, $this->sortableHeaderClass, $this->sortableHeaderPrepend, $this->sortableHeaderAppend, @@ -665,6 +675,19 @@ protected function makeFilters(): array return [$filters, $validationResult]; } + protected function prepareOrder(array &$order): void + { + $columns = $this->getColumns(); + $renderers = $this->getColumnRenderers(); + foreach ($columns as $i => $column) { + if ($renderers[$i] instanceof OverrideOrderFieldsColumnInterface) { + foreach ($renderers[$i]->getOverrideOrderFields($column) as $from => $to) { + $order = ArrayHelper::replaceKey($order, $from, $to); + } + } + } + } + private function prepareBodyAttributes(array $attributes, DataContext $context): array { foreach ($attributes as $i => $attribute) { From bddf7656f5827bae2bdf9bbc4e8565ae9893a53b Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 3 Apr 2024 14:07:10 +0000 Subject: [PATCH 2/4] Apply fixes from StyleCI --- src/Column/Base/HeaderContext.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Column/Base/HeaderContext.php b/src/Column/Base/HeaderContext.php index 73ceff345..e777a8585 100644 --- a/src/Column/Base/HeaderContext.php +++ b/src/Column/Base/HeaderContext.php @@ -109,8 +109,7 @@ private function getLinkSortValue( Sort $sort, string $property, string $originalProperty - ): ?string - { + ): ?string { $originalOrder = $originalSort->getOrder(); $order = $sort->getOrder(); From 7184b82885bde7b9fd1a8e78f45287235059fdcc Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 3 Apr 2024 20:09:40 +0300 Subject: [PATCH 3/4] replace queryProperty to field --- src/Column/DataColumn.php | 10 +--------- src/Column/DataColumnRenderer.php | 27 +++++++++++++++------------ src/Column/QueryProperty.php | 19 ------------------- 3 files changed, 16 insertions(+), 40 deletions(-) delete mode 100644 src/Column/QueryProperty.php diff --git a/src/Column/DataColumn.php b/src/Column/DataColumn.php index d8412d428..d1a877676 100644 --- a/src/Column/DataColumn.php +++ b/src/Column/DataColumn.php @@ -24,8 +24,6 @@ */ final class DataColumn implements ColumnInterface { - public readonly ?QueryProperty $queryProperty; - /** * @var bool|callable|null * @psalm-var bool|FilterEmptyCallable|null @@ -39,8 +37,7 @@ final class DataColumn implements ColumnInterface */ public function __construct( public readonly ?string $property = null, - ?string $queryProperty = null, - ?string $queryField = null, + public readonly ?string $field = null, public readonly ?string $header = null, public readonly bool $encodeHeader = true, public readonly ?string $footer = null, @@ -56,11 +53,6 @@ public function __construct( bool|callable|null $filterEmpty = null, private readonly bool $visible = true, ) { - $queryProperty ??= $property; - $this->queryProperty = $queryProperty === null - ? null - : new QueryProperty($queryProperty, $queryField ?? $queryProperty); - $this->filterEmpty = $filterEmpty; } diff --git a/src/Column/DataColumnRenderer.php b/src/Column/DataColumnRenderer.php index 84246ca33..abc7ec09b 100644 --- a/src/Column/DataColumnRenderer.php +++ b/src/Column/DataColumnRenderer.php @@ -72,11 +72,11 @@ public function renderHeader(ColumnInterface $column, Cell $cell, HeaderContext } $cell = $cell->content($label); - if (!$column->withSorting || $column->queryProperty === null) { + if (!$column->withSorting || $column->property === null) { return $cell; } - [$cell, $link, $prepend, $append] = $context->prepareSortable($cell, $column->queryProperty->property); + [$cell, $link, $prepend, $append] = $context->prepareSortable($cell, $column->property); if ($link !== null) { $link = $link->content($label)->encode(false); } @@ -88,7 +88,7 @@ public function renderFilter(ColumnInterface $column, Cell $cell, FilterContext { $this->checkColumn($column); - if ($column->queryProperty === null || $column->filter === false) { + if ($column->property === null || $column->filter === false) { return null; } @@ -103,14 +103,14 @@ public function renderFilter(ColumnInterface $column, Cell $cell, FilterContext $content = [ $widget->withContext( new Context( - $column->queryProperty->property, - $context->getQueryValue($column->queryProperty->property), + $column->property, + $context->getQueryValue($column->property), $context->formId ) ), ]; - $errors = $context->validationResult->getAttributeErrorMessages($column->queryProperty->property); + $errors = $context->validationResult->getAttributeErrorMessages($column->property); if (!empty($errors)) { $cell = $cell->addClass($context->cellInvalidClass); $content[] = Html::div(attributes: $context->errorsContainerAttributes) @@ -123,11 +123,11 @@ public function renderFilter(ColumnInterface $column, Cell $cell, FilterContext public function makeFilter(ColumnInterface $column, MakeFilterContext $context): ?FilterInterface { $this->checkColumn($column); - if ($column->queryProperty === null) { + if ($column->property === null) { return null; } - $value = $context->getQueryValue($column->queryProperty->property); + $value = $context->getQueryValue($column->property); if ($value === null) { return null; } @@ -144,7 +144,7 @@ public function makeFilter(ColumnInterface $column, MakeFilterContext $context): $context->validationResult->addError( $error->getMessage(), $error->getParameters(), - [$column->queryProperty->property] + [$column->property] ); } return null; @@ -163,7 +163,7 @@ public function makeFilter(ColumnInterface $column, MakeFilterContext $context): $factory = $column->filterFactory; } - return $factory->create($column->queryProperty->field, $value); + return $factory->create($column->field ?? $column->property, $value); } public function renderBody(ColumnInterface $column, Cell $cell, DataContext $context): Cell @@ -249,10 +249,13 @@ public function getOverrideOrderFields(ColumnInterface $column): array { $this->checkColumn($column); - if ($column->queryProperty === null || $column->queryProperty->hasEqualField()) { + if ($column->property === null + || $column->field === null + || $column->property === $column->field + ) { return []; } - return [$column->queryProperty->property => $column->queryProperty->field]; + return [$column->property => $column->field]; } } diff --git a/src/Column/QueryProperty.php b/src/Column/QueryProperty.php deleted file mode 100644 index 2d7a9c366..000000000 --- a/src/Column/QueryProperty.php +++ /dev/null @@ -1,19 +0,0 @@ -property === $this->field; - } -} From 5f313372e94eb95f8dfd49764528eb979765bf02 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 4 Apr 2024 14:12:45 +0300 Subject: [PATCH 4/4] use new Yii Arrays --- composer.json | 2 +- src/Column/Base/HeaderContext.php | 2 +- src/GridView.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index f966e11dc..03a704cee 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "ext-json": "*", "ext-mbstring": "*", "psr/container": "^1.0|^2.0", - "yiisoft/arrays": "^2.0|^3.0", + "yiisoft/arrays": "^3.1", "yiisoft/data": "dev-master", "yiisoft/factory": "^1.0", "yiisoft/friendly-exception": "^1.0", diff --git a/src/Column/Base/HeaderContext.php b/src/Column/Base/HeaderContext.php index e777a8585..b59b625ba 100644 --- a/src/Column/Base/HeaderContext.php +++ b/src/Column/Base/HeaderContext.php @@ -157,7 +157,7 @@ private function getLinkSortValue( } return OrderHelper::arrayToString( - ArrayHelper::replaceKey($resultOrder, $property, $originalProperty) + ArrayHelper::renameKey($resultOrder, $property, $originalProperty) ); } diff --git a/src/GridView.php b/src/GridView.php index d61b6b2c4..8cbcd65e2 100644 --- a/src/GridView.php +++ b/src/GridView.php @@ -682,7 +682,7 @@ protected function prepareOrder(array &$order): void foreach ($columns as $i => $column) { if ($renderers[$i] instanceof OverrideOrderFieldsColumnInterface) { foreach ($renderers[$i]->getOverrideOrderFields($column) as $from => $to) { - $order = ArrayHelper::replaceKey($order, $from, $to); + $order = ArrayHelper::renameKey($order, $from, $to); } } }