diff --git a/config/schema/project_browser.schema.yml b/config/schema/project_browser.schema.yml index df95b93e76445d9c586016f6dd43c9982d37a508..59c876d40674ad16e9a2434b0f2e072ed2b96e4d 100644 --- a/config/schema/project_browser.schema.yml +++ b/config/schema/project_browser.schema.yml @@ -48,3 +48,8 @@ block.settings.project_browser_block:*: nullable: true constraints: NotBlank: [] + filters: + type: sequence + label: 'Filter options' + sequence: + type: string diff --git a/src/Element/ProjectBrowser.php b/src/Element/ProjectBrowser.php index 9a261629e1514d016e56efc9805e1a473019b090..e009bb785738b0a253fc84d945a4592bb779809a 100644 --- a/src/Element/ProjectBrowser.php +++ b/src/Element/ProjectBrowser.php @@ -36,6 +36,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * choose how many projects to display on each page, if pagination is enabled. * Must be an array of numbers that are greater than zero. Does not need to be * in any particular order. Defaults to 12, 24, 36, and 48. + * - #filters: (optional) Associative array of filters where keys are filter + * machine names, and values are their default values. If provided, only + * these filters will be displayed, and their default values will be + * set accordingly. * * Usage example: * @@ -49,6 +53,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * '#sort_by' => 'a_z', * '#paginate' => FALSE, * '#page_sizes' => [5, 10, 25], + * '#filters' => [ + * 'development_status' => TRUE, + * 'categories' => [123, 456], + * ], * ]; * @endcode */ @@ -146,6 +154,37 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn // This sort will re-key the array. sort($page_sizes); + $available_filters = $source->getFilterDefinitions(); + // If the element specifies filters, ensure that they are all defined + // by the source plugin. + if (isset($element['#filters'])) { + if (!is_array($element['#filters'])) { + throw new \InvalidArgumentException('#filters must be an associative array where keys are valid filter names.'); + } + + $invalid_filters = array_diff_key($element['#filters'], $available_filters); + if (!empty($invalid_filters)) { + throw new \InvalidArgumentException( + sprintf( + "Invalid filters provided: %s. Allowed filters: %s", + implode(', ', array_keys($invalid_filters)), + implode(', ', array_keys($available_filters)) + ) + ); + } + + $filtered_filters = array_intersect_key($available_filters, $element['#filters']); + if (!empty($filtered_filters)) { + $available_filters = $filtered_filters; + // Set default values for the filters. + foreach ($element['#filters'] as $filter_name => $default_value) { + if (isset($available_filters[$filter_name])) { + // @todo Need to validate and set the default value. + } + } + } + } + $global_settings = $this->configFactory->get('project_browser.admin_settings'); $element['#attached']['drupalSettings']['project_browser'] = [ @@ -158,7 +197,7 @@ final class ProjectBrowser implements ElementInterface, ContainerFactoryPluginIn $element['#id'] => [ 'source' => $source->getPluginId(), 'name' => $source->getPluginDefinition()['label'], - 'filters' => (object) $source->getFilterDefinitions(), + 'filters' => (object) $available_filters, 'sorts' => (object) $sort_options, 'sortBy' => $sort_by, 'paginate' => $element['#paginate'] ?? TRUE, diff --git a/src/Plugin/Block/ProjectBrowserBlock.php b/src/Plugin/Block/ProjectBrowserBlock.php index 25ed3bbc2235ddf4df0d87b24df07413ae8006f3..5a43085819ebb83ee70decf51ad69c8bfa2a6d4f 100644 --- a/src/Plugin/Block/ProjectBrowserBlock.php +++ b/src/Plugin/Block/ProjectBrowserBlock.php @@ -69,6 +69,8 @@ final class ProjectBrowserBlock extends BlockBase implements ContainerFactoryPlu 'page_sizes' => implode(', ', $this->elementInfo->getInfoProperty('project_browser', '#page_sizes')), // Use the default sort criterion chosen by the render element. 'default_sort' => NULL, + // Allow all filters defined by the source plugin. + 'filters' => NULL, ]; } @@ -106,6 +108,23 @@ final class ProjectBrowserBlock extends BlockBase implements ContainerFactoryPlu '#default_value' => $configuration['default_sort'] ?? array_key_first($sort_options), '#options' => $sort_options, ]; + + $filter_definitions = $this->source->getFilterDefinitions(); + $filter_options = array_combine( + array_keys($filter_definitions), + array_column($filter_definitions, 'name'), + ); + $default_values = !empty($configuration['filters']) + ? $configuration['filters'] + : array_combine(array_keys($filter_options), array_keys($filter_options)); + + $form['filters'] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Filter options'), + '#options' => $filter_options, + '#default_value' => $default_values, + '#description' => $this->t('Only selected filters will be available to users.'), + ]; return $form; } @@ -134,6 +153,7 @@ final class ProjectBrowserBlock extends BlockBase implements ContainerFactoryPlu $this->configuration['paginate'] = (bool) $form_state->getValue('paginate'); $this->configuration['page_sizes'] = trim($form_state->getValue('page_sizes')); $this->configuration['default_sort'] = $form_state->getValue('default_sort'); + $this->configuration['filters'] = array_values(array_filter($form_state->getValue('filters'))); } /** @@ -171,6 +191,7 @@ final class ProjectBrowserBlock extends BlockBase implements ContainerFactoryPlu '#paginate' => $configuration['paginate'], '#page_sizes' => static::pageSizesToArray($configuration['page_sizes']), '#sort_by' => $configuration['default_sort'], + '#filters' => array_combine($configuration['filters'], $configuration['filters']), ]; }