diff --git a/config/schema/facets.facet.schema.yml b/config/schema/facets.facet.schema.yml index 5dbd43f..43c0bd8 100644 --- a/config/schema/facets.facet.schema.yml +++ b/config/schema/facets.facet.schema.yml @@ -28,7 +28,20 @@ facets.facet.*: label: 'Query Type Name' widget: type: string - label: 'Field identifier' + label: 'Widget identifier' + empty_behavior: + type: mapping + label: 'Empty behavior' + mapping: + behavior: + type: string + label: 'The empty behavior identifier' + text_format: + type: string + label: 'Text format' + text: + type: string + label: 'Text' widget_configs: type: sequence label: 'Widget plugin configurations' @@ -56,3 +69,9 @@ facets.facet.*: label: 'The processor''s weight for this stage' settings: type: plugin.plugin_configuration.facets_processor.[%parent.processor_id] + facet_configs: + type: sequence + label: 'Facet plugin-specific options' + sequence: + type: plugin.plugin_configuration.facets_facet_options.[%key] + label: 'Facet plugin options' diff --git a/src/Entity/Facet.php b/src/Entity/Facet.php index a6495fb..6e3de73 100644 --- a/src/Entity/Facet.php +++ b/src/Entity/Facet.php @@ -45,6 +45,9 @@ use Drupal\facets\FacetInterface; * "widget_configs", * "options", * "only_visible_when_facet_source_is_visible", + * "processor_configs", + * "empty_behavior", + * "facet_configs", * }, * links = { * "canonical" = "/admin/config/search/facets", @@ -178,6 +181,20 @@ class Facet extends ConfigEntityBase implements FacetInterface { protected $processors; /** + * Configuration for the processors. This is an array of arrays. + * + * @var array + */ + protected $processor_configs; + + /** + * Additional facet configurations. + * + * @var array + */ + protected $facet_configs; + + /** * Is the facet only visible when the facet source is only visible. * * A boolean that defines whether or not the facet is only visible when the @@ -188,6 +205,13 @@ class Facet extends ConfigEntityBase implements FacetInterface { protected $only_visible_when_facet_source_is_visible; /** + * The no-result configuration. + * + * @var string[]; + */ + protected $empty_behavior; + + /** * The widget plugin manager. * * @var object @@ -444,20 +468,19 @@ class Facet extends ConfigEntityBase implements FacetInterface { if (!isset($this->processors)) { /* @var $processor_plugin_manager \Drupal\facets\Processor\ProcessorPluginManager */ $processor_plugin_manager = \Drupal::service('plugin.manager.facets.processor'); - $processor_settings = $this->getOption('processors', []); - foreach ($processor_plugin_manager->getDefinitions() as $name => $processor_definition) { - if (class_exists($processor_definition['class']) && empty($this->processors[$name])) { - // Create our settings for this processor. - $settings = empty($processor_settings[$name]['settings']) ? [] : $processor_settings[$name]['settings']; + foreach ($processor_plugin_manager->getDefinitions() as $processor_id => $processor_definition) { + if (class_exists($processor_definition['class']) && empty($this->processors[$processor_id])) { + $settings = empty($this->processor_configs[$processor_id]['settings']) ? [] : $this->processor_configs[$processor_id]['settings']; + $settings['enabled'] = empty($this->processor_configs[$processor_id]) ? FALSE : TRUE; $settings['facet'] = $this; /* @var $processor \Drupal\facets\Processor\ProcessorInterface */ - $processor = $processor_plugin_manager->createInstance($name, $settings); - $this->processors[$name] = $processor; + $processor = $processor_plugin_manager->createInstance($processor_id, $settings); + $this->processors[$processor_id] = $processor; } elseif (!class_exists($processor_definition['class'])) { - \Drupal::logger('facets')->warning('Processor @id specifies a non-existing @class.', array('@id' => $name, '@class' => $processor_definition['class'])); + \Drupal::logger('facets')->warning('Processor @id specifies a non-existing @class.', array('@id' => $processor_id, '@class' => $processor_definition['class'])); } } } @@ -549,7 +572,7 @@ class Facet extends ConfigEntityBase implements FacetInterface { // Filter processors by status if required. Enabled processors are those // which have settings in the "processors" option. if ($only_enabled) { - $processors_settings = $this->getOption('processors', array()); + $processors_settings = !empty($this->processor_configs) ? $this->processor_configs : []; $processors = array_intersect_key($processors, $processors_settings); } @@ -561,7 +584,7 @@ class Facet extends ConfigEntityBase implements FacetInterface { */ public function getProcessorsByStage($stage, $only_enabled = TRUE) { $processors = $this->loadProcessors(); - $processor_settings = $this->getOption('processors', array()); + $processor_settings = $this->processor_configs; $processor_weights = array(); // Get a list of all processors meeting the criteria (stage and, optionally, @@ -602,4 +625,68 @@ class Facet extends ConfigEntityBase implements FacetInterface { return $this->only_visible_when_facet_source_is_visible; } + /** + * {@inheritdoc} + */ + public function addProcessor(array $processor) { + $this->processor_configs[$processor['processor_id']] = [ + 'processor_id' => $processor['processor_id'], + 'weights' => $processor['weights'], + 'settings' => $processor['settings'], + ]; + // Sort the processors so we won't have unnecessary changes. + ksort($this->processor_configs); + } + + /** + * {@inheritdoc} + */ + public function removeProcessor($processor_id) { + unset($this->processor_configs[$processor_id]); + } + + /** + * {@inheritdoc} + */ + public function getEmptyBehavior() { + return $this->empty_behavior; + } + + /** + * {@inheritdoc} + */ + public function setEmptyBehavior($empty_behavior) { + $this->empty_behavior = $empty_behavior; + } + + /** + * {@inheritdoc} + */ + public function setWidgetConfigs(array $widget_configs) { + $this->widget_configs = $widget_configs; + } + + /** + * {@inheritdoc} + */ + public function getWidgetConfigs() { + return $this->widget_configs; + } + + /** + * {@inheritdoc} + */ + public function setFacetConfigs(array $facet_configs) { + $this->facet_configs = $facet_configs; + } + + /** + * {@inheritdoc} + */ + public function getFacetConfigs() { + return $this->facet_configs; + } + + + } diff --git a/src/FacetInterface.php b/src/FacetInterface.php index d6f1b48..0f13cbe 100644 --- a/src/FacetInterface.php +++ b/src/FacetInterface.php @@ -286,4 +286,61 @@ interface FacetInterface extends ConfigEntityInterface { */ public function getOnlyVisibleWhenFacetSourceIsVisible(); + /** + * Enabled a processor for this facet. + * + * @param array $processor + */ + public function addProcessor(array $processor); + + /** + * Disable a processor for this facet. + * + * @param string $processor_id + */ + public function removeProcessor($processor_id); + + /** + * Define the no-results behavior. + * + * @param array $behavior + */ + public function setEmptyBehavior($behavior); + + /** + * Return the defined no-results behavior or NULL if none defined. + * + * @return array|NULL + */ + public function getEmptyBehavior(); + + /** + * Return the configuration of the selected widget. + * + * @return array + */ + public function getWidgetConfigs(); + + /** + * Set the configuration for the widget of this facet. + * + * @param array $widget_config + */ + public function setWidgetConfigs(array $widget_config); + + /** + * Get any additional configuration for this facet, no defined above. + * + * @return array + */ + public function getFacetConfigs(); + + /** + * Define any additional configuration for this facet not defined above. + * + * @param array $facet_config + */ + public function setFacetConfigs(array $facet_config); + + } diff --git a/src/FacetManager/DefaultFacetManager.php b/src/FacetManager/DefaultFacetManager.php index da1bb5a..7f3493c 100644 --- a/src/FacetManager/DefaultFacetManager.php +++ b/src/FacetManager/DefaultFacetManager.php @@ -294,7 +294,7 @@ class DefaultFacetManager { // No results behavior handling. Return a custom text or false depending on // settings. if (empty($facet->getResults())) { - $empty_behavior = $facet->getOption('empty_behavior'); + $empty_behavior = $facet->getEmptyBehavior(); if ($empty_behavior['behavior'] == 'text') { return ['#markup' => $empty_behavior['text']]; } diff --git a/src/FacetSource/FacetSourcePluginBase.php b/src/FacetSource/FacetSourcePluginBase.php index 53dba89..104ad21 100644 --- a/src/FacetSource/FacetSourcePluginBase.php +++ b/src/FacetSource/FacetSourcePluginBase.php @@ -11,6 +11,8 @@ use Drupal\Component\Plugin\PluginBase; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Facets\FacetInterface; +use Drupal\Core\Form\FormStateInterface; + /** * Defines a base class from which other facet sources may extend. @@ -102,4 +104,13 @@ abstract class FacetSourcePluginBase extends PluginBase implements FacetSourcePl return $this->keys; } + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(FormStateInterface $form_state, FacetInterface &$facet) { + $facet_source_id = $facet->getFacetSourceId(); + $field_identifier = $form_state->getValue('facet_source_configs')[$facet_source_id]['field_identifier']; + $facet->setFieldIdentifier($field_identifier); + } + } diff --git a/src/FacetSource/FacetSourcePluginInterface.php b/src/FacetSource/FacetSourcePluginInterface.php index 93c114e..976f3dd 100644 --- a/src/FacetSource/FacetSourcePluginInterface.php +++ b/src/FacetSource/FacetSourcePluginInterface.php @@ -36,6 +36,14 @@ interface FacetSourcePluginInterface { public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet, FacetSourcePluginInterface $facet_source); /** + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current form state. + * @param \Drupal\facets\FacetInterface $facet + * The facet being edited. + */ + public function submitConfigurationForm(FormStateInterface $form_state, FacetInterface &$facet); + + /** * Fill in facet data in to the configured facets. * * @param \Drupal\facets\FacetInterface[] $facets diff --git a/src/Form/FacetDisplayForm.php b/src/Form/FacetDisplayForm.php index e096de0..56b5cda 100644 --- a/src/Form/FacetDisplayForm.php +++ b/src/Form/FacetDisplayForm.php @@ -195,6 +195,7 @@ class FacetDisplayForm extends EntityForm { else { $all_processors = $form_state->get('processors'); } + $enabled_processors = $facet->getProcessors(TRUE); $stages = $this->processorPluginManager->getProcessingStages(); $processors_by_stage = array(); @@ -202,8 +203,6 @@ class FacetDisplayForm extends EntityForm { $processors_by_stage[$stage] = $facet->getProcessorsByStage($stage, FALSE); } - $processor_settings = $facet->getOption('processors'); - $form['#tree'] = TRUE; $form['#attached']['library'][] = 'search_api/drupal.search_api.index-active-formatters'; $form['#title'] = $this->t('Manage processors for facet %label', array('%label' => $facet->label())); @@ -225,7 +224,7 @@ class FacetDisplayForm extends EntityForm { $form['facet_settings'][$processor_id]['status'] = array( '#type' => 'checkbox', '#title' => (string) $processor->getPluginDefinition()['label'], - '#default_value' => $processor->isLocked() || !empty($processor_settings[$processor_id]), + '#default_value' => $processor->isLocked() || !empty($processor->configuration['enabled']), '#description' => $processor->getDescription(), '#attributes' => array( 'class' => array( @@ -281,7 +280,7 @@ class FacetDisplayForm extends EntityForm { $form['facet_sorting'][$processor_id]['status'] = array( '#type' => 'checkbox', '#title' => (string) $processor->getPluginDefinition()['label'], - '#default_value' => $processor->isLocked() || !empty($processor_settings[$processor_id]), + '#default_value' => $processor->isLocked() || !empty($enabled_processors[$processor_id]), '#description' => $processor->getDescription(), '#attributes' => array( 'class' => array( @@ -328,7 +327,7 @@ class FacetDisplayForm extends EntityForm { ]; // Behavior for empty facets. - $empty_behavior_config = $facet->getOption('empty_behavior'); + $empty_behavior_config = $facet->getEmptyBehavior(); $form['facet_settings']['empty_behavior'] = [ '#type' => 'radios', '#title' => t('Empty facet behavior'), @@ -470,7 +469,6 @@ class FacetDisplayForm extends EntityForm { */ public function submitForm(array &$form, FormStateInterface $form_state) { $values = $form_state->getValues(); - $new_settings = array(); // Store processor settings. // @todo Go through all available processors, enable/disable with method on @@ -483,16 +481,17 @@ class FacetDisplayForm extends EntityForm { foreach ($processors as $processor_id => $processor) { $form_container_key = $processor instanceof WidgetOrderProcessorInterface ? 'facet_sorting' : 'facet_settings'; if (empty($values[$form_container_key][$processor_id]['status'])) { + $facet->removeProcessor($processor_id); continue; } - $new_settings[$processor_id] = array( + $new_settings = array( 'processor_id' => $processor_id, 'weights' => array(), 'settings' => array(), ); $processor_values = $values[$form_container_key][$processor_id]; if (!empty($processor_values['weights'])) { - $new_settings[$processor_id]['weights'] = $processor_values['weights']; + $new_settings['weights'] = $processor_values['weights']; } if (isset($form[$form_container_key][$processor_id]['settings'])) { $processor_form_state = new SubFormState( @@ -500,16 +499,14 @@ class FacetDisplayForm extends EntityForm { array($form_container_key, $processor_id, 'settings') ); $processor->submitConfigurationForm($form[$form_container_key][$processor_id]['settings'], $processor_form_state, $facet); - $new_settings[$processor_id]['settings'] = $processor->getConfiguration(); + $new_settings['settings'] = $processor->getConfiguration(); } + $facet->addProcessor($new_settings); } - // Sort the processors so we won't have unnecessary changes. - ksort($new_settings); - $facet->setOption('processors', $new_settings); $facet->setWidget($form_state->getValue('widget')); - $facet->set('widget_configs', $form_state->getValue('widget_configs')); - $facet->set('only_visible_when_facet_source_is_visible', $form_state->getValue(['facet_settings', 'only_visible_when_facet_source_is_visible'])); + $facet->setWidgetConfigs($form_state->getValue('widget_configs')); + $facet->setOnlyVisibleWhenFacetSourceIsVisible($form_state->getValue(['facet_settings', 'only_visible_when_facet_source_is_visible'])); $empty_behavior_config = []; $empty_behavior = $form_state->getValue(['facet_settings', 'empty_behavior']); @@ -528,7 +525,7 @@ class FacetDisplayForm extends EntityForm { 'value', ]); } - $facet->setOption('empty_behavior', $empty_behavior_config); + $facet->setEmptyBehavior($empty_behavior_config); $facet->save(); drupal_set_message(t('Facet %name has been updated.', ['%name' => $facet->getName()])); diff --git a/src/Form/FacetForm.php b/src/Form/FacetForm.php index c1b96c1..872c520 100644 --- a/src/Form/FacetForm.php +++ b/src/Form/FacetForm.php @@ -285,7 +285,6 @@ class FacetForm extends EntityForm { if ($is_new) { // On facet creation, enable all locked processors by default, using their // default settings. - $initial_settings = []; $stages = $this->getProcessorPluginManager()->getProcessingStages(); $processors_definitions = $this->getProcessorPluginManager()->getDefinitions(); @@ -297,39 +296,38 @@ class FacetForm extends EntityForm { $weights[$stage_id] = $processor['stages'][$stage_id]; } } - $initial_settings[$processor_id] = array( + $facet->addProcessor([ 'processor_id' => $processor_id, 'weights' => $weights, 'settings' => [], - ); + ]); } } - $facet->setOption('processors', $initial_settings); // Set a default widget for new facets. $facet->setWidget('links'); // Set default empty behaviour. - $facet->setOption('empty_behavior', ['behavior' => 'none']); + $facet->setEmptyBehavior(['behavior' => 'none']); $facet->setOnlyVisibleWhenFacetSourceIsVisible(TRUE); } - // Make sure the field identifier is copied from within the facet source - // config to the facet object and saved there. - $facet_source = $form_state->getValue('facet_source_id'); - $field_identifier = $form_state->getValue('facet_source_configs')[$facet_source]['field_identifier']; - - $facet->setFieldIdentifier($field_identifier); + $facet_source_id = $form_state->getValue('facet_source_id'); + if (!is_null($facet_source_id) && $facet_source_id !== '') { + /** @var \Drupal\facets\FacetSource\FacetSourcePluginInterface $facet_source */ + $facet_source = $this->getFacetSourcePluginManager()->createInstance($facet_source_id); + $facet_source->submitConfigurationForm($form_state, $facet); + } $facet->save(); // Ensure that the caching of the view display is disabled, so the search // correctly returns the facets. This is a temporary fix, until the cache // metadata is correctly stored on the facet block. Only apply this when the // facet source type is actually something this is related to views. - list($type,) = explode(':', $facet_source); + list($type,) = explode(':', $facet_source_id); if ($type === 'search_api_views') { - list(, $view_id, $display) = explode(':', $facet_source); + list(, $view_id, $display) = explode(':', $facet_source_id); } if (isset($view_id)) { diff --git a/src/Plugin/facets/widget/CheckboxWidget.php b/src/Plugin/facets/widget/CheckboxWidget.php index 6d8bf49..685ffea 100644 --- a/src/Plugin/facets/widget/CheckboxWidget.php +++ b/src/Plugin/facets/widget/CheckboxWidget.php @@ -48,7 +48,7 @@ class CheckboxWidget implements WidgetInterface { $results = $facet->getResults(); $items = []; - $configuration = $facet->get('widget_configs'); + $configuration = $facet->getWidgetConfigs(); $show_numbers = (bool) $configuration['show_numbers']; foreach ($results as $result) { diff --git a/src/Plugin/facets/widget/LinksWidget.php b/src/Plugin/facets/widget/LinksWidget.php index 196cd5e..2b25bd5 100644 --- a/src/Plugin/facets/widget/LinksWidget.php +++ b/src/Plugin/facets/widget/LinksWidget.php @@ -48,7 +48,7 @@ class LinksWidget implements WidgetInterface { $results = $facet->getResults(); $items = []; - $configuration = $facet->get('widget_configs'); + $configuration = $facet->getWidgetConfigs(); $show_numbers = (bool) $configuration['show_numbers']; foreach ($results as $result) { diff --git a/tests/src/Unit/Plugin/processor/CountLimitProcessorTest.php b/tests/src/Unit/Plugin/processor/CountLimitProcessorTest.php index 12b672b..4db2c91 100644 --- a/tests/src/Unit/Plugin/processor/CountLimitProcessorTest.php +++ b/tests/src/Unit/Plugin/processor/CountLimitProcessorTest.php @@ -78,10 +78,10 @@ class CountLimitProcessorTest extends UnitTestCase { public function testNoFilter() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->setOption('processors', [ - 'count_limit' => [ - 'settings' => ['minimum_items' => 4], - ], + $facet->addProcessor([ + 'processor_id' => 'count_limit', + 'weights' => [], + 'settings' => ['minimum_items' => 4], ]); $this->processor->setConfiguration(['minimum_items' => 4]); $sorted_results = $this->processor->build($facet, $this->originalResults); @@ -99,10 +99,10 @@ class CountLimitProcessorTest extends UnitTestCase { public function testMinEqualsValue() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->setOption('processors', [ - 'count_limit' => [ - 'settings' => ['minimum_items' => 5], - ], + $facet->addProcessor([ + 'processor_id' => 'count_limit', + 'weights' => [], + 'settings' => ['minimum_items' => 5], ]); $this->processor->setConfiguration(['minimum_items' => 5]); @@ -121,8 +121,10 @@ class CountLimitProcessorTest extends UnitTestCase { public function testBetweenMinAndMaxValue() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->setOption('processors', [ - 'count_limit' => [], + $facet->addProcessor([ + 'processor_id' => 'count_limit', + 'weights' => [], + 'settings' => [], ]); $this->processor->setConfiguration(['minimum_items' => 6, 'maximum_items' => 14]); @@ -145,8 +147,10 @@ class CountLimitProcessorTest extends UnitTestCase { public function testMaxValue() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->setOption('processors', [ - 'count_limit' => [], + $facet->addProcessor([ + 'processor_id' => 'count_limit', + 'weights' => [], + 'settings' => [], ]); $this->processor->setConfiguration(['maximum_items' => 14]); @@ -173,10 +177,10 @@ class CountLimitProcessorTest extends UnitTestCase { public function testFilterResults() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->setOption('processors', [ - 'count_limit' => [ - 'settings' => ['minimum_items' => 8], - ], + $facet->addProcessor([ + 'processor_id' => 'count_limit', + 'weights' => [], + 'settings' => ['minimum_items' => 8], ]); $this->processor->setConfiguration(['minimum_items' => 8]); diff --git a/tests/src/Unit/Plugin/processor/ExcludeSpecifiedItemsProcessorTest.php b/tests/src/Unit/Plugin/processor/ExcludeSpecifiedItemsProcessorTest.php index 5c37429..2031416 100644 --- a/tests/src/Unit/Plugin/processor/ExcludeSpecifiedItemsProcessorTest.php +++ b/tests/src/Unit/Plugin/processor/ExcludeSpecifiedItemsProcessorTest.php @@ -91,6 +91,14 @@ class ExcludeSpecifiedItemsProcessorTest extends UnitTestCase { ], ], ]); + $facet->addProcessor([ + 'processor_id' => 'exclude_specified_items', + 'weights' => [], + 'settings' => [ + 'exclude' => 'alpaca', + 'regex' => 0, + ], + ]); $this->processor->setConfiguration([ 'exclude' => 'alpaca', 'regex' => 0, diff --git a/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php b/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php index 7b3c6c1..f24ee45 100644 --- a/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php +++ b/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php @@ -96,7 +96,7 @@ class CheckboxWidgetTest extends UnitTestCase { public function testShowAmount() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->set('widget_configs', ['show_numbers' => 1]); + $facet->setWidgetConfigs(['show_numbers' => 1]); $output = $this->widget->build($facet); diff --git a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php index 2f26246..6d737ff 100644 --- a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php +++ b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php @@ -73,7 +73,7 @@ class LinksWidgetTest extends UnitTestCase { public function testNoFilterResults() { $facet = new Facet([], 'facet'); $facet->setResults($this->originalResults); - $facet->set('widget_configs', ['show_numbers' => 1]); + $facet->setWidgetConfigs(['show_numbers' => 1]); $output = $this->widget->build($facet); @@ -95,7 +95,7 @@ class LinksWidgetTest extends UnitTestCase { $facet = new Facet([], 'facet'); $facet->setResults($original_results); - $facet->set('widget_configs', ['show_numbers' => 1]); + $facet->setWidgetConfigs(['show_numbers' => 1]); $output = $this->widget->build($facet); @@ -118,7 +118,7 @@ class LinksWidgetTest extends UnitTestCase { $facet = new Facet([], 'facet'); $facet->setResults($original_results); - $facet->set('widget_configs', ['show_numbers' => 1]); + $facet->setWidgetConfigs(['show_numbers' => 1]); $output = $this->widget->build($facet); @@ -145,7 +145,7 @@ class LinksWidgetTest extends UnitTestCase { $facet = new Facet([], 'facet'); $facet->setResults($original_results); - $facet->set('widget_configs', ['show_numbers' => 0]); + $facet->setWidgetConfigs(['show_numbers' => 0]); $output = $this->widget->build($facet); @@ -159,7 +159,7 @@ class LinksWidgetTest extends UnitTestCase { // Enable the 'show_numbers' setting again to make sure that the switch // between those settings works. - $facet->set('widget_configs', ['show_numbers' => 1]); + $facet->setWidgetConfigs(['show_numbers' => 1]); $output = $this->widget->build($facet);