diff --git a/wcfsetup/install/files/lib/action/GridViewFilterAction.class.php b/wcfsetup/install/files/lib/action/GridViewFilterAction.class.php index 154fd7e8473..5ed3e8c1e43 100644 --- a/wcfsetup/install/files/lib/action/GridViewFilterAction.class.php +++ b/wcfsetup/install/files/lib/action/GridViewFilterAction.class.php @@ -65,9 +65,19 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $response; } - $data = $form->getData()['data']; + $rawData = $form->getData(); + $data = $rawData['data']; + + foreach ($view->getAvailableFilters() as $filter) { + if (!isset($rawData[$filter->getFormDataId()])) { + continue; + } + + $data[$filter->getId()] = $filter->serializeValue($rawData[$filter->getFormDataId()]); + } + foreach ($data as $key => $value) { - if ($value === '' || $value === null) { + if ($value === '' || $value === null || $value === 0) { unset($data[$key]); } } @@ -95,7 +105,8 @@ private function getForm(AbstractGridView $gridView, array $values): Psr15Dialog $formField = $filter->getFormField(); if (isset($values[$filter->getID()])) { - $formField->value($values[$filter->getID()]); + $value = $filter->unserializeValue($values[$filter->getID()]); + $formField->value($value); } $form->appendChild($formField); diff --git a/wcfsetup/install/files/lib/action/ListViewFilterAction.class.php b/wcfsetup/install/files/lib/action/ListViewFilterAction.class.php index 7aa0ee62d57..027c4f2613b 100644 --- a/wcfsetup/install/files/lib/action/ListViewFilterAction.class.php +++ b/wcfsetup/install/files/lib/action/ListViewFilterAction.class.php @@ -64,13 +64,16 @@ public function handle(ServerRequestInterface $request): ResponseInterface if ($response !== null) { return $response; } + $rawData = $form->getData(); $data = $rawData['data']; - // This code is required to bypass the strange behavior of the LabelFormField. - if (!empty($rawData['labelIDs'])) { - foreach ($rawData['labelIDs'] as $groupID => $value) { - $data['labelIDs' . $groupID] = $value; + + foreach ($view->getAvailableFilters() as $filter) { + if (!isset($rawData[$filter->getFormDataId()])) { + continue; } + + $data[$filter->getId()] = $filter->serializeValue($rawData[$filter->getFormDataId()]); } foreach ($data as $key => $value) { @@ -102,7 +105,8 @@ private function getForm(AbstractListView $listView, array $values): Psr15Dialog $formField = $filter->getFormField(); if (isset($values[$filter->getID()])) { - $formField->value($values[$filter->getID()]); + $value = $filter->unserializeValue($values[$filter->getID()]); + $formField->value($value); } $form->appendChild($formField); diff --git a/wcfsetup/install/files/lib/system/gridView/admin/ArticleGridView.class.php b/wcfsetup/install/files/lib/system/gridView/admin/ArticleGridView.class.php index cfc2fd4756d..17567a4cb0b 100644 --- a/wcfsetup/install/files/lib/system/gridView/admin/ArticleGridView.class.php +++ b/wcfsetup/install/files/lib/system/gridView/admin/ArticleGridView.class.php @@ -26,6 +26,7 @@ use wcf\system\interaction\EditInteraction; use wcf\system\view\filter\BooleanFilter; use wcf\system\view\filter\CategoryFilter; +use wcf\system\view\filter\MultipleSelectFilter; use wcf\system\view\filter\SelectFilter; use wcf\system\view\filter\TextFilter; use wcf\system\view\filter\TimeFilter; @@ -192,7 +193,7 @@ public function applyFilter(DatabaseObjectList $list, string $value): void ); } }, - new SelectFilter( + new MultipleSelectFilter( [ 0 => 'wcf.acp.article.publicationStatus.unpublished', 1 => 'wcf.acp.article.publicationStatus.published', @@ -201,7 +202,7 @@ public function applyFilter(DatabaseObjectList $list, string $value): void 'publicationStatus', 'wcf.acp.article.publicationStatus' ), - new BooleanFilter('isDeleted', 'wcf.acp.article.isDeleted') + new BooleanFilter('isDeleted', 'wcf.acp.article.isDeleted'), ]); $provider = new ArticleInteractions(); $provider->addInteractions([ diff --git a/wcfsetup/install/files/lib/system/view/filter/AbstractFilter.class.php b/wcfsetup/install/files/lib/system/view/filter/AbstractFilter.class.php index 74335698bb7..c2cb7ada9e7 100644 --- a/wcfsetup/install/files/lib/system/view/filter/AbstractFilter.class.php +++ b/wcfsetup/install/files/lib/system/view/filter/AbstractFilter.class.php @@ -47,4 +47,22 @@ protected function getDatabaseColumnName(DatabaseObjectList $list): string { return ($this->databaseColumn ?: $list->getDatabaseTableAlias() . '.' . $this->id); } + + #[\Override] + public function serializeValue(mixed $value): string + { + return (string)$value; + } + + #[\Override] + public function unserializeValue(string $value): mixed + { + return $value; + } + + #[\Override] + public function getFormDataId(): string + { + return $this->getId(); + } } diff --git a/wcfsetup/install/files/lib/system/view/filter/IViewFilter.class.php b/wcfsetup/install/files/lib/system/view/filter/IViewFilter.class.php index 42aafa73af6..e584c2559f7 100644 --- a/wcfsetup/install/files/lib/system/view/filter/IViewFilter.class.php +++ b/wcfsetup/install/files/lib/system/view/filter/IViewFilter.class.php @@ -42,4 +42,19 @@ public function getId(): string; * Returns the label of this filter. */ public function getLabel(): string; + + /** + * Serializes the given form field value to a string that can be passed in a URL. + */ + public function serializeValue(mixed $value): string; + + /** + * Unserializes the given string to a value that can be passed to the form field. + */ + public function unserializeValue(string $value): mixed; + + /** + * Returns the id of the form field used by this filter. + */ + public function getFormDataId(): string; } diff --git a/wcfsetup/install/files/lib/system/view/filter/LabelFilter.class.php b/wcfsetup/install/files/lib/system/view/filter/LabelFilter.class.php index b7451a2e90f..4624400f840 100644 --- a/wcfsetup/install/files/lib/system/view/filter/LabelFilter.class.php +++ b/wcfsetup/install/files/lib/system/view/filter/LabelFilter.class.php @@ -68,4 +68,21 @@ public function renderValue(string $value): string { return $this->labelGroup->getLabel((int)$value)->getTitle(); } + + #[\Override] + public function serializeValue(mixed $value): string + { + if (\is_array($value) && isset($value[$this->labelGroup->groupID])) { + return $value[$this->labelGroup->groupID]; + } + + return ''; + } + + #[\Override] + public function getFormDataId(): string + { + // `LabelFormField` stores form data values always under the key `labelIDs`. + return 'labelIDs'; + } } diff --git a/wcfsetup/install/files/lib/system/view/filter/MultipleSelectFilter.class.php b/wcfsetup/install/files/lib/system/view/filter/MultipleSelectFilter.class.php new file mode 100644 index 00000000000..8942411f423 --- /dev/null +++ b/wcfsetup/install/files/lib/system/view/filter/MultipleSelectFilter.class.php @@ -0,0 +1,85 @@ + + * @since 6.2 + */ +class MultipleSelectFilter extends AbstractFilter +{ + /** + * @param array $options + */ + public function __construct( + protected readonly array $options, + string $id, + string $languageItem, + string $databaseColumn = '', + protected readonly bool $labelLanguageItems = true + ) { + parent::__construct($id, $languageItem, $databaseColumn); + } + + #[\Override] + public function getFormField(): AbstractFormField + { + return MultipleSelectionFormField::create($this->id) + ->label($this->languageItem) + ->options($this->options, labelLanguageItems: $this->labelLanguageItems); + } + + #[\Override] + public function applyFilter(DatabaseObjectList $list, string $value): void + { + $filterValues = $this->unserializeValue($value); + foreach ($filterValues as $filterValue) { + if (!isset($this->options[$filterValue])) { + throw new InvalidFilterValue("Invalid value '{$filterValue}' for filter '{$this->id}' given."); + } + } + + $columnName = $this->getDatabaseColumnName($list); + + $list->getConditionBuilder()->add("{$columnName} IN (?)", [$filterValues]); + } + + #[\Override] + public function renderValue(string $value): string + { + $renderedValues = \array_map(function ($filterValue): string { + if ($this->labelLanguageItems) { + return WCF::getLanguage()->get($this->options[$filterValue]); + } else { + return $this->options[$filterValue]; + } + }, $this->unserializeValue($value)); + + return \implode(', ', $renderedValues); + } + + #[\Override] + public function serializeValue(mixed $value): string + { + return \implode(',', $value); + } + + /** + * @return array + */ + #[\Override] + public function unserializeValue(string $value): array + { + return \explode(',', $value); + } +}