Skip to content
Commits on Source (20)
......@@ -4,9 +4,7 @@ CONTENTS OF THIS FILE
* Requirements
* Installation
* Configuration
* Troubleshooting
* FAQ
* Maintainers
INTRODUCTION
------------
......@@ -14,8 +12,9 @@ Todo
REQUIREMENTS
------------
No other modules required, though the module is useless without an implementing
module like search api.
No other modules required, we're supporting drupal core as a source for creating
facets. Though we recommend using Search API, as that integration is better
tested.
INSTALLATION
------------
......@@ -25,17 +24,14 @@ INSTALLATION
CONFIGURATION
-------------
Todo
Before adding a facet, there should be a facet source. Facet sources can be:
- Drupal core's search.
- A view based on a Search API index with a page display.
- A page from the search_api_page module.
TROUBLESHOOTING
---------------
Todo
After adding one of those, you can add a facet on the facets configuration page:
/admin/config/search/facets
FAQ
---
Todo
MAINTAINERS
-----------
Current maintainers:
* Todo
......@@ -26,6 +26,12 @@ facets.facet.*:
query_type_name:
type: string
label: 'Query Type Name'
query_operator:
type: string
label: 'Query Operator'
exclude:
type: boolean
label: 'Exclude'
widget:
type: string
label: 'Widget identifier'
......@@ -75,3 +81,11 @@ facets.facet.*:
sequence:
type: plugin.plugin_configuration.facets_facet_options.[%key]
label: 'Facet plugin options'
condition.plugin.other_facet:
type: condition.plugin
mapping:
facet_value:
type: string
facets:
type: string
......@@ -11,7 +11,7 @@ facets.facet_source.*:
name:
type: label
label: Name'
filterKey:
filter_key:
type: string
label: 'Filter key'
url_processor:
......
......@@ -40,3 +40,9 @@ plugin.plugin_configuration.facets_processor.count_limit:
maximum_items:
type: integer
label: 'Maximum amount of items to show.'
plugin.plugin_configuration.facets_processor.url_processor_handler:
type: config_object
plugin.plugin_configuration.facets_processor.hide_non_narrowing_result_processor:
type: config_object
......@@ -80,8 +80,8 @@ class FacetsQuery extends SearchQuery {
// For complex search queries, add the LIKE conditions.
/*if (!$this->simple) {
$this->join('search_dataset', 'd', 'i.sid = d.sid AND i.type = d.type');
$this->condition($this->conditions);
$this->join('search_dataset', 'd', 'i.sid = d.sid AND i.type = d.type');
$this->condition($this->conditions);
}*/
// Add conditions to query.
......
......@@ -9,15 +9,17 @@ namespace Drupal\core_search_facets\Plugin\Search;
use Drupal\Core\Config\Config;
use Drupal\Core\Database\Driver\mysql\Connection;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\facets\FacetSource\FacetSourcePluginManager;
use Drupal\node\Plugin\Search\NodeSearch;
use Drupal\Core\Render\RendererInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Handles searching for node entities using the Search module index.
......@@ -34,13 +36,13 @@ class NodeSearchFacets extends NodeSearch {
$plugin_id,
$plugin_definition,
Connection $database,
EntityManagerInterface $entity_manager,
EntityTypeManagerInterface $entity_manager,
ModuleHandlerInterface $module_handler,
Config $search_settings,
LanguageManagerInterface $language_manager,
RendererInterface $renderer,
$facet_source_plugin_manager,
$request_stack,
FacetSourcePluginManager $facet_source_plugin_manager,
RequestStack $request_stack,
AccountInterface $account = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $database, $entity_manager, $module_handler, $search_settings, $language_manager, $renderer, $account);
......@@ -60,7 +62,7 @@ class NodeSearchFacets extends NodeSearch {
$plugin_id,
$plugin_definition,
$container->get('database'),
$container->get('entity.manager'),
$container->get('entity_type.manager'),
$container->get('module_handler'),
$container->get('config.factory')->get('search.settings'),
$container->get('language_manager'),
......@@ -96,6 +98,7 @@ class NodeSearchFacets extends NodeSearch {
'#access' => $this->account && $this->account->hasPermission('use advanced search'),
'#open' => $used_advanced,
);
$form['advanced']['keywords-fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Keywords'),
......
......@@ -13,10 +13,11 @@ use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\core_search_facets\Plugin\CoreSearchFacetSourceInterface;
use Drupal\facets\FacetInterface;
use Drupal\facets\FacetSource\FacetSourcePluginBase;
use Drupal\facets\FacetSource\FacetSourcePluginInterface;
use Drupal\facets\QueryType\QueryTypePluginManager;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\search\SearchPageInterface;
use Drupal\search\SearchPluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
......@@ -54,6 +55,11 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
*/
protected $configFactory;
/**
* The plugin manager for core search plugins.
*
* @var \Drupal\search\SearchPluginManager
*/
protected $searchManager;
/**
......@@ -64,7 +70,7 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, $query_type_plugin_manager, $search_manager, RequestStack $request_stack) {
public function __construct(array $configuration, $plugin_id, array $plugin_definition, QueryTypePluginManager $query_type_plugin_manager, SearchPluginManager $search_manager, RequestStack $request_stack) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $query_type_plugin_manager);
$this->searchManager = $search_manager;
$this->setSearchKeys($request_stack->getMasterRequest()->query->get('keys'));
......@@ -112,7 +118,6 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
// Get the Facet Specific Query Type so we can process the results
// using the build() function of the query type.
/** @var \Drupal\facets\Entity\Facet $facet **/
$query_type = $this->queryTypePluginManager->createInstance($facet->getQueryType(), $configuration);
$query_type->build();
}
......@@ -143,7 +148,7 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
* @return array
* An array of query types.
*/
public function getQueryTypesForFieldType($field_type) {
protected function getQueryTypesForFieldType($field_type) {
$query_types = [];
switch ($field_type) {
case 'type':
......@@ -178,7 +183,7 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet, FacetSourcePluginInterface $facet_source) {
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['field_identifier'] = [
'#type' => 'select',
......@@ -186,7 +191,7 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
'#title' => $this->t('Facet field'),
'#description' => $this->t('Choose the indexed field.'),
'#required' => TRUE,
'#default_value' => $facet->getFieldIdentifier(),
'#default_value' => $this->facet->getFieldIdentifier(),
];
return $form;
......@@ -204,10 +209,13 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
// Get the current field instances and detect if the field type is allowed.
$fields = FieldConfig::loadMultiple();
/** @var \Drupal\Field\FieldConfigInterface $field */
foreach ($fields as $field) {
// Verify if the target type is allowed for entity reference fields,
// otherwise verify the field type(i.e. integer, float...).
if (in_array($field->getFieldStorageDefinition()->getSetting('target_type'), $allowed_field_types) || in_array($field->getFieldStorageDefinition()->getType(), $allowed_field_types)) {
$target_is_allowed = in_array($field->getFieldStorageDefinition()->getSetting('target_type'), $allowed_field_types);
$field_is_allowed = in_array($field->getFieldStorageDefinition()->getType(), $allowed_field_types);
if ($target_is_allowed || $field_is_allowed) {
/** @var \Drupal\field\Entity\FieldConfig $field */
if (!array_key_exists($field->getName(), $facet_fields)) {
$facet_fields[$field->getName()] = $this->t('@label', ['@label' => $field->getLabel()]);
......@@ -222,6 +230,7 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
* Getter for default node fields.
*
* @return array
* An array containing the default fields enabled on a node.
*/
protected function getDefaultFields() {
return [
......@@ -235,14 +244,14 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
* {@inheritdoc}
*/
public function getFacetQueryExtender() {
if (!$this->facetQueryExtender) {
$this->facetQueryExtender = db_select('search_index', 'i', array('target' => 'replica'))->extend('Drupal\core_search_facets\FacetsQuery');
$this->facetQueryExtender->join('node_field_data', 'n', 'n.nid = i.sid');
$this->facetQueryExtender
if (!$this->facetQueryExtender) {
$this->facetQueryExtender = db_select('search_index', 'i', array('target' => 'replica'))->extend('Drupal\core_search_facets\FacetsQuery');
$this->facetQueryExtender->join('node_field_data', 'n', 'n.nid = i.sid');
$this->facetQueryExtender
// ->condition('n.status', 1).
->addTag('node_access')
->searchExpression($this->keys, 'node_search');
}
}
return $this->facetQueryExtender;
}
......@@ -254,10 +263,10 @@ class CoreNodeSearchFacetSource extends FacetSourcePluginBase implements CoreSea
$field_name = $facet->getFieldIdentifier();
$default_fields = $this->getDefaultFields();
if (array_key_exists($facet->getFieldIdentifier(), $default_fields)) {
// We add the language code of the indexed item to the result of the query.
// So in this case we need to use the search_index table alias (i) for the
// langcode field. Otherwise we will have same nid for multiple languages
// as result. For more details see NodeSearch::findResults().
// We add the language code of the indexed item to the result of the
// query. So in this case we need to use the search_index table alias (i)
// for the langcode field. Otherwise we will have same nid for multiple
// languages as result. For more details see NodeSearch::findResults().
// @TODO review if I can refactor this.
$table_alias = $facet->getFieldIdentifier() == 'langcode' ? 'i' : 'n';
$query_info = [
......
......@@ -8,7 +8,9 @@
namespace Drupal\core_search_facets\Plugin\facets\facet_source;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\facets\FacetSource\FacetSourceDeriverBase;
use Drupal\search\SearchPluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -18,12 +20,24 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class CoreNodeSearchFacetSourceDeriver extends FacetSourceDeriverBase {
/**
* The plugin manager for core search plugins.
*
* @var \Drupal\search\SearchPluginManager
*/
protected $searchManager;
/**
* Create an instance of the deriver.
* Creates an instance of the deriver.
*
* @param string $base_plugin_id
* The plugin ID.
* @param \Drupal\search\SearchPluginManager $search_manager
* The plugin manager for core search plugins.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity manager.
*/
public function __construct(ContainerInterface $container, $base_plugin_id, $search_manager, $entity_type_manager) {
public function __construct($base_plugin_id, SearchPluginManager $search_manager, EntityTypeManagerInterface $entity_type_manager) {
$this->searchManager = $search_manager;
$this->entityTypeManager = $entity_type_manager;
}
......@@ -33,11 +47,10 @@ class CoreNodeSearchFacetSourceDeriver extends FacetSourceDeriverBase {
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container,
$base_plugin_id,
$container->get('plugin.manager.search'),
$container->get('entity_type.manager')
);
);
}
/**
......
......@@ -21,7 +21,7 @@ use Drupal\facets\Result\Result;
class CoreNodeSearchString extends QueryTypePluginBase {
/**
* Holds the backend's native query object.
* The backend's native query object.
*
* @var \Drupal\search_api\Query\QueryInterface
*/
......@@ -31,7 +31,6 @@ class CoreNodeSearchString extends QueryTypePluginBase {
* {@inheritdoc}
*/
public function execute() {
/** @var \Drupal\core_search_facets\Plugin\CoreSearchFacetSourceInterface $facet_source */
$facet_source = $this->facet->getFacetSource();
$query_info = $facet_source->getQueryInfo($this->facet);
......
<?php
/**
* @file
* Contains Drupal\facets_query_processor\Plugin\facets\url_processor\DummyQuery.
*/
namespace Drupal\facets_query_processor\Plugin\facets\url_processor;
use Drupal\Core\Url;
use Drupal\facets\FacetInterface;
use Drupal\facets\UrlProcessor\UrlProcessorPluginBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Query string URL processor.
*
* @FacetsUrlProcessor(
* id = "dummy_query",
* label = @Translation("Dummy query"),
* description = @Translation("Dummy for testing.")
* )
*/
class DummyQuery extends UrlProcessorPluginBase {
/**
* A string that separates the filters in the query string.
*/
const SEPARATOR = '||';
/**
* A string of how to represent the facet in the url.
*
* @var string
*/
protected $url_alias;
/**
* An array of active filters.
*
* @var string[]
* An array containing the active filters
*/
protected $activeFilters = [];
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $request);
$this->initializeActiveFilters();
}
/**
* {@inheritdoc}
*/
public function buildUrls(FacetInterface $facet, array $results) {
// Create links for all the values.
// First get the current list of get parameters.
$get_params = $this->request->query;
// Set the url alias from the the facet object.
$this->url_alias = $facet->getUrlAlias();
// No results are found for this facet, so don't try to create urls.
if (empty($results)) {
return [];
}
/** @var \Drupal\facets\Result\ResultInterface $result */
foreach ($results as &$result) {
$filter_string = $this->url_alias . self::SEPARATOR . $result->getRawValue();
$result_get_params = clone $get_params;
$filter_params = $result_get_params->get($this->filterKey, [], TRUE);
// If the value is active, remove the filter string from the parameters.
if ($result->isActive()) {
foreach ($filter_params as $key => $filter_param) {
if ($filter_param == $filter_string) {
unset($filter_params[$key]);
}
}
}
// If the value is not active, add the filter string.
else {
$filter_params[] = $filter_string;
}
$result_get_params->set($this->filterKey, $filter_params);
$request = $this->request;
if ($facet->getFacetSource()->getPath()) {
$request = Request::create('/' . $facet->getFacetSource()->getPath());
}
$url = Url::createFromRequest($request);
$url->setOption('query', $result_get_params->all());
$result->setUrl($url);
}
return $results;
}
/**
* {@inheritdoc}
*/
public function setActiveItems(FacetInterface $facet) {
// Set the url alias from the the facet object.
$this->url_alias = $facet->getUrlAlias();
// Get the filter key of the facet.
if (isset($this->activeFilters[$this->url_alias])) {
foreach ($this->activeFilters[$this->url_alias] as $value) {
$facet->setActiveItem(trim($value, '"'));
}
}
}
/**
* Initialize the active filters.
*
* Get all the filters that are active. This method only get's all the
* filters but doesn't assign them to facets. In the processFacet method the
* active values for a specific facet are added to the facet.
*/
protected function initializeActiveFilters() {
$url_parameters = $this->request->query;
// Get the active facet parameters.
$active_params = $url_parameters->get($this->filterKey, array(), TRUE);
// Explode the active params on the separator.
foreach ($active_params as $param) {
list($key, $value) = explode(self::SEPARATOR, $param);
if (!isset($this->activeFilters[$key])) {
$this->activeFilters[$key] = [$value];
}
else {
$this->activeFilters[$key][] = $value;
}
}
}
}
......@@ -9,7 +9,6 @@ namespace Drupal\core_search_facets\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field_ui\Tests\FieldUiTestTrait;
/**
* Tests integration of hooks.
......@@ -25,7 +24,7 @@ class HooksTest extends WebTestBase {
'node',
'search',
'core_search_facets_test_hooks',
'field'
'field',
];
/**
......@@ -34,8 +33,6 @@ class HooksTest extends WebTestBase {
public function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page']);
// Create a field of type float.
FieldStorageConfig::create(
[
......@@ -51,7 +48,7 @@ class HooksTest extends WebTestBase {
'field_name' => 'float',
'entity_type' => 'node',
'bundle' => 'page',
'label' => 'Float Field Label'
'label' => 'Float Field Label',
]
)->save();
......@@ -64,7 +61,6 @@ class HooksTest extends WebTestBase {
*/
public function testHooks() {
// Verify that hook_facets_core_allowed_field_types was triggered.
$facet_add_page = 'admin/config/search/facets/add-facet';
$this->drupalGet($facet_add_page);
$this->assertResponse(200);
......
<?php
/**
* @file
* Contains \Drupal\core_search_facets\Tests\IntegrationTest.
*/
namespace Drupal\core_search_facets\Tests;
use Drupal\core_search_facets\Tests\WebTestBase as CoreSearchFacetsWebTestBase;
/**
* Tests the admin UI with the core search facet source.
*
* @group core_search_facets
*/
class IntegrationTest extends CoreSearchFacetsWebTestBase {
/**
* The block entities used by this test.
*
* @var \Drupal\block\BlockInterface[]
*/
protected $blocks;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->drupalLogin($this->adminUser);
// Index the content.
\Drupal::service('plugin.manager.search')->createInstance('node_search')->updateIndex();
search_update_totals();
// Make absolutely sure the ::$blocks variable doesn't pass information
// along between tests.
$this->blocks = NULL;
}
/**
* Tests various operations via the Facets' admin UI.
*/
public function testFramework() {
$facet_name = "Test Facet name";
$facet_id = 'test_facet_name';
// Check if the overview is empty.
$this->checkEmptyOverview();
// Add a new facet and edit it.
$this->addFacet($facet_name);
$this->editFacet($facet_name);
// Create and place a block for "Test Facet name" facet.
$this->createFacetBlock($facet_id);
// Verify that the facet results are correct.
$this->drupalGet('search/node', ['query' => ['keys' => 'test']]);
$this->assertLink('page');
$this->assertLink('article');
// Verify that facet blocks appear as expected.
$this->assertFacetBlocksAppear();
$this->setShowAmountOfResults($facet_name, TRUE);
// Verify that the number of results per item.
$this->drupalGet('search/node', ['query' => ['keys' => 'test']]);
$this->assertLink('page (10)');
$this->assertLink('article (10)');
// Do not show the block on empty behaviors.
// Truncate the search_index table because, for the moment, we don't have
// the possibility to clear the index from the API.
// See https://www.drupal.org/node/326062
\Drupal::database()->truncate('search_index')->execute();
// Verify that no facet blocks appear. Empty behavior "None" is selected by
// default.
$this->drupalGet('search/node', ['query' => ['keys' => 'test']]);
$this->assertNoFacetBlocksAppear();
// Verify that the "empty_text" appears as expected.
$this->setEmptyBehaviorFacetText($facet_name);
$this->drupalGet('search/node', ['query' => ['keys' => 'test']]);
$this->assertRaw('block-test-facet-name');
$this->assertRaw('No results found for this block!');
// Delete the block.
$this->deleteBlock($facet_id);
// Delete the facet and make sure the overview is empty again.
$this->deleteUnusedFacet($facet_name);
$this->checkEmptyOverview();
}
/**
* Configures the possibility to show the amount of results for facet blocks.
*
* @param string $facet_name
* The name of the facet.
* @param bool|TRUE $show
* Boolean to determine if we want to show the amount of results.
*/
protected function setShowAmountOfResults($facet_name, $show = TRUE) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_display_page = '/admin/config/search/facets/' . $facet_id . '/display';
// Go to the facet edit page and make sure "edit facet %facet" is present.
$this->drupalGet($facet_display_page);
$this->assertResponse(200);
// Configure the text for empty results behavior.
$edit = [
'widget_configs[show_numbers]' => $show,
];
$this->drupalPostForm(NULL, $edit, $this->t('Save'));
}
/**
* Deletes a facet block by id.
*
* @param string $id
* The id of the block.
*/
protected function deleteBlock($id) {
$this->drupalGet('admin/structure/block/manage/' . $this->blocks[$id]->id(), array('query' => array('destination' => 'admin')));
$this->clickLink(t('Delete'));
$this->drupalPostForm(NULL, array(), t('Delete'));
$this->assertRaw(t('The block %name has been deleted.', array('%name' => $this->blocks[$id]->label())));
}
/**
* Asserts that a facet block does not appear.
*/
protected function assertNoFacetBlocksAppear() {
foreach ($this->blocks as $block) {
$this->assertNoBlockAppears($block);
}
}
/**
* Asserts that a facet block appears.
*/
protected function assertFacetBlocksAppear() {
foreach ($this->blocks as $block) {
$this->assertBlockAppears($block);
}
}
/**
* Creates a facet block by id.
*
* @param string $id
* The id of the block.
*/
protected function createFacetBlock($id) {
$block = [
'plugin_id' => 'facet_block:' . $id,
'settings' => [
'region' => 'footer',
'id' => str_replace('_', '-', $id),
],
];
$this->blocks[$id] = $this->drupalPlaceBlock($block['plugin_id'], $block['settings']);
}
/**
* Configures empty behavior option to show a text on empty results.
*
* @param string $facet_name
* The name of the facet.
*/
protected function setEmptyBehaviorFacetText($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_display_page = '/admin/config/search/facets/' . $facet_id . '/display';
// Go to the facet edit page and make sure "edit facet %facet" is present.
$this->drupalGet($facet_display_page);
$this->assertResponse(200);
// Configure the text for empty results behavior.
$edit = [
'facet_settings[empty_behavior]' => 'text',
'facet_settings[empty_behavior_container][empty_behavior_text][value]' => 'No results found for this block!',
];
$this->drupalPostForm(NULL, $edit, $this->t('Save'));
}
/**
* Configures a facet to only be visible when accessing to the facet source.
*
* @param string $facet_name
* The name of the facet.
*/
protected function setOptionShowOnlyWhenFacetSourceVisible($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_display_page = '/admin/config/search/facets/' . $facet_id . '/display';
$this->drupalGet($facet_display_page);
$this->assertResponse(200);
$edit = [
'facet_settings[only_visible_when_facet_source_is_visible]' => TRUE,
'widget' => 'links',
'widget_configs[show_numbers]' => '0',
];
$this->drupalPostForm(NULL, $edit, $this->t('Save'));
}
/**
* Get the facet overview page and make sure the overview is empty.
*/
protected function checkEmptyOverview() {
$facet_overview = '/admin/config/search/facets';
$this->drupalGet($facet_overview);
$this->assertResponse(200);
// The list overview has Field: field_name as description. This tests on the
// absence of that.
$this->assertNoText('Field:');
}
/**
* Tests adding a facet trough the interface.
*
* @param string $facet_name
* The name of the facet.
*/
protected function addFacet($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
// Go to the Add facet page and make sure that returns a 200.
$facet_add_page = '/admin/config/search/facets/add-facet';
$this->drupalGet($facet_add_page);
$this->assertResponse(200);
$form_values = [
'name' => '',
'id' => $facet_id,
'status' => 1,
'url_alias' => $facet_id,
];
// Try filling out the form, but without having filled in a name for the
// facet to test for form errors.
$this->drupalPostForm($facet_add_page, $form_values, $this->t('Save'));
$this->assertText($this->t('Facet name field is required.'));
$this->assertText($this->t('Facet source field is required.'));
// Make sure that when filling out the name, the form error disappears.
$form_values['name'] = $facet_name;
$this->drupalPostForm(NULL, $form_values, $this->t('Save'));
$this->assertNoText($this->t('Facet name field is required.'));
// Configure the facet source by selecting one of the search api views.
$this->drupalGet($facet_add_page);
$this->drupalPostForm(NULL, ['facet_source_id' => 'core_node_search:node_search'], $this->t('Configure facet source'));
// The facet field is still required.
$this->drupalPostForm(NULL, $form_values, $this->t('Save'));
$this->assertText($this->t('Facet field field is required.'));
// Fill in all fields and make sure the 'field is required' message is no
// longer shown.
$facet_source_form = [
'facet_source_configs[core_node_search:node_search][field_identifier]' => 'type',
];
$this->drupalPostForm(NULL, $form_values + $facet_source_form, $this->t('Save'));
$this->assertNoText('field is required.');
// Make sure that the redirection to the display page is correct.
$this->assertRaw(t('Facet %name has been created.', ['%name' => $facet_name]));
$this->assertUrl('admin/config/search/facets/' . $facet_id . '/display');
$this->drupalGet('admin/config/search/facets');
}
/**
* Tests editing of a facet through the UI.
*
* @param string $facet_name
* The name of the facet.
*/
public function editFacet($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_edit_page = '/admin/config/search/facets/' . $facet_id . '/edit';
// Go to the facet edit page and make sure "edit facet %facet" is present.
$this->drupalGet($facet_edit_page);
$this->assertResponse(200);
$this->assertRaw($this->t('Edit facet @facet', ['@facet' => $facet_name]));
// Change the facet name to add in "-2" to test editing of a facet works.
$form_values = ['name' => $facet_name . ' - 2'];
$this->drupalPostForm($facet_edit_page, $form_values, $this->t('Save'));
// Make sure that the redirection back to the overview was successful and
// the edited facet is shown on the overview page.
$this->assertRaw(t('Facet %name has been updated.', ['%name' => $facet_name . ' - 2']));
// Make sure the "-2" suffix is still on the facet when editing a facet.
$this->drupalGet($facet_edit_page);
$this->assertRaw($this->t('Edit facet @facet', ['@facet' => $facet_name . ' - 2']));
// Edit the form and change the facet's name back to the initial name.
$form_values = ['name' => $facet_name];
$this->drupalPostForm($facet_edit_page, $form_values, $this->t('Save'));
// Make sure that the redirection back to the overview was successful and
// the edited facet is shown on the overview page.
$this->assertRaw(t('Facet %name has been updated.', ['%name' => $facet_name]));
}
/**
* This deletes an unused facet through the UI.
*
* @param string $facet_name
* The name of the facet.
*/
protected function deleteUsedFacet($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_delete_page = '/admin/config/search/facets/' . $facet_id . '/delete';
// Go to the facet delete page and make the warning is shown.
$this->drupalGet($facet_delete_page);
$this->assertResponse(200);
// Check that the facet by testing for the message and the absence of the
// facet name on the overview.
$this->assertRaw($this->t('The facet is currently used in a block and thus can\'t be removed. Remove the block first.'));
}
/**
* This deletes a facet through the UI.
*
* @param string $facet_name
* The name of the facet.
*/
protected function deleteUnusedFacet($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_delete_page = '/admin/config/search/facets/' . $facet_id . '/delete';
// Go to the facet delete page and make the warning is shown.
$this->drupalGet($facet_delete_page);
$this->assertResponse(200);
$this->assertText($this->t('This action cannot be undone'));
// Actually submit the confirmation form.
$this->drupalPostForm(NULL, [], $this->t('Delete'));
// Check that the facet by testing for the message and the absence of the
// facet name on the overview.
$this->assertRaw($this->t('The facet %facet has been deleted.', ['%facet' => $facet_name]));
// Refresh the page because on the previous page the $facet_name is still
// visible (in the message).
$facet_overview = '/admin/config/search/facets';
$this->drupalGet($facet_overview);
$this->assertResponse(200);
$this->assertNoText($facet_name);
}
/**
* Convert facet name to machine name.
*
* @param string $facet_name
* The name of the facet.
*
* @return string
* The facet name changed to a machine name.
*/
protected function convertNameToMachineName($facet_name) {
return preg_replace('@[^a-zA-Z0-9_]+@', '_', strtolower($facet_name));
}
/**
* Go to the Delete Facet Page using the facet name.
*
* @param string $facet_name
* The name of the facet.
*/
protected function goToDeleteFacetPage($facet_name) {
$facet_id = $this->convertNameToMachineName($facet_name);
$facet_delete_page = '/admin/config/search/facets/' . $facet_id . '/delete';
// Go to the facet delete page and make the warning is shown.
$this->drupalGet($facet_delete_page);
$this->assertResponse(200);
}
}
......@@ -17,21 +17,15 @@ abstract class WebTestBase extends SimpletestWebTestBase {
use StringTranslationTrait;
/**
* Exempt from strict schema checking.
*
* @see \Drupal\Core\Config\Testing\ConfigSchemaChecker
*
* @var bool
*/
protected $strictConfigSchema = FALSE;
/**
* Modules to enable for this test.
*
* @var string[]
*/
public static $modules = [
'field',
'search',
'entity_test',
'views',
'node',
'facets',
......@@ -60,19 +54,34 @@ abstract class WebTestBase extends SimpletestWebTestBase {
*/
protected $anonymousUser;
/**
* A search index ID.
*
* @var string
*/
protected $indexId = 'database_search_index';
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Create content types.
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateContentType(['type' => 'article']);
// Adding 10 pages.
for ($i = 0; $i < 10; $i++) {
$this->drupalCreateNode(array(
'title' => 'foo bar' . $i,
'body' => 'test page' . $i,
'type' => 'page',
));
}
// Adding 10 articles.
for ($i = 0; $i < 10; $i++) {
$this->drupalCreateNode(array(
'title' => 'foo baz' . $i,
'body' => 'test article' . $i,
'type' => 'article',
));
}
// Create the users used for the tests.
$this->adminUser = $this->drupalCreateUser([
'administer search',
......@@ -84,10 +93,6 @@ abstract class WebTestBase extends SimpletestWebTestBase {
'administer blocks',
'search content',
]);
$this->unauthorizedUser = $this->drupalCreateUser(['access administration pages']);
$this->anonymousUser = $this->drupalCreateUser();
}
}
......@@ -4,3 +4,6 @@ description: 'Faceted search interfaces that can be used on Search API searchers
core: 8.x
package: Search
configure: facets.overview
test_dependencies:
- search_api:search_api
- drupal:views
......@@ -7,12 +7,10 @@
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\search_api\Query\QueryInterface;
use Drupal\facets\FacetInterface;
/**
* Implements hook_help().
*/
function facets_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the facets module.
......
......@@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\facets\Annotation\FacetsFacet.
* Contains \Drupal\facets\Annotation\FacetsFacetSource.
*/
namespace Drupal\facets\Annotation;
......@@ -29,7 +29,7 @@ class FacetsFacetSource extends Plugin {
public $id;
/**
* The human-readable name of the facet soruce plugin.
* The human-readable name of the facet source plugin.
*
* @ingroup plugin_translatable
*
......
......@@ -43,7 +43,8 @@ use Drupal\facets\FacetInterface;
* "facet_source_id",
* "widget",
* "widget_configs",
* "options",
* "query_operator",
* "exclude",
* "only_visible_when_facet_source_is_visible",
* "processor_configs",
* "empty_behavior",
......@@ -98,18 +99,23 @@ class Facet extends ConfigEntityBase implements FacetInterface {
/**
* Configuration for the widget. This is a key-value stored array.
*
* @var string
* @var array
*/
protected $widget_configs;
protected $widget_configs = [];
/**
* An array of options configuring this facet.
* The operator to hand over to the query, currently AND | OR.
*
* @var array
* @var string
*/
protected $query_operator;
/**
* A boolean flag indicating if search should exclude selected facets.
*
* @see getOptions()
* @var bool
*/
protected $options = array();
protected $exclude;
/**
* The field identifier.
......@@ -162,6 +168,18 @@ class Facet extends ConfigEntityBase implements FacetInterface {
*/
protected $results = [];
/**
* The results.
*
* @var \Drupal\facets\Result\ResultInterface[]
*/
protected $unfiltered_results = [];
/**
* An array of active values.
*
* @var string[]
*/
protected $active_values = [];
/**
......@@ -185,14 +203,14 @@ class Facet extends ConfigEntityBase implements FacetInterface {
*
* @var array
*/
protected $processor_configs;
protected $processor_configs = [];
/**
* Additional facet configurations.
*
* @var array
*/
protected $facet_configs;
protected $facet_configs = [];
/**
* Is the facet only visible when the facet source is only visible.
......@@ -234,7 +252,7 @@ class Facet extends ConfigEntityBase implements FacetInterface {
}
/**
* Gets the widget plugin manager.
* Returns the widget plugin manager.
*
* @return \Drupal\facets\Widget\WidgetPluginManager
* The widget plugin manager.
......@@ -248,8 +266,9 @@ class Facet extends ConfigEntityBase implements FacetInterface {
/**
* {@inheritdoc}
*/
public function id() {
return $this->id;
protected function urlRouteParameters($rel) {
$parameters = parent::urlRouteParameters($rel);
return $parameters;
}
/**
......@@ -267,6 +286,13 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this;
}
/**
* {@inheritdoc}
*/
public function getQueryTypes() {
return $this->query_type_name;
}
/**
* {@inheritdoc}
*/
......@@ -274,6 +300,48 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this->widget;
}
/**
* Retrieves all processors supported by this facet.
*
* @return \Drupal\facets\Processor\ProcessorInterface[]
* The loaded processors, keyed by processor ID.
*/
protected function loadProcessors() {
if (!isset($this->processors)) {
/* @var $processor_plugin_manager \Drupal\facets\Processor\ProcessorPluginManager */
$processor_plugin_manager = \Drupal::service('plugin.manager.facets.processor');
$processor_settings = $this->getProcessorConfigs();
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'];
$settings['facet'] = $this;
/* @var $processor \Drupal\facets\Processor\ProcessorInterface */
$processor = $processor_plugin_manager->createInstance($name, $settings);
$this->processors[$name] = $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'],
));
}
}
}
return $this->processors;
}
/**
* {@inheritdoc}
*/
public function getProcessorConfigs() {
return !empty($this->processor_configs) ? $this->processor_configs : [];
}
/**
* {@inheritdoc}
*/
......@@ -292,56 +360,54 @@ class Facet extends ConfigEntityBase implements FacetInterface {
/**
* {@inheritdoc}
*/
public function getFieldAlias() {
// For now, create the field alias based on the field identifier.
$field_alias = preg_replace('/[:\/]+/', '_', $this->field_identifier);
return $field_alias;
public function setQueryOperator($operator = '') {
return $this->query_operator = $operator;
}
/**
* {@inheritdoc}
*/
public function setActiveItem($value) {
if (!in_array($value, $this->active_values)) {
$this->active_values[] = $value;
}
public function getQueryOperator() {
return $this->query_operator ?: 'OR';
}
/**
* {@inheritdoc}
*/
public function getActiveItems() {
return $this->active_values;
public function setExclude($exclude) {
return $this->exclude = $exclude;
}
/**
* {@inheritdoc}
*/
public function getOption($name, $default = NULL) {
return isset($this->options[$name]) ? $this->options[$name] : $default;
public function getExclude() {
return $this->exclude;
}
/**
* {@inheritdoc}
*/
public function getOptions() {
return $this->options;
public function getFieldAlias() {
// For now, create the field alias based on the field identifier.
$field_alias = preg_replace('/[:\/]+/', '_', $this->field_identifier);
return $field_alias;
}
/**
* {@inheritdoc}
*/
public function setOption($name, $option) {
$this->options[$name] = $option;
return $this;
public function setActiveItem($value) {
if (!in_array($value, $this->active_values)) {
$this->active_values[] = $value;
}
}
/**
* {@inheritdoc}
*/
public function setOptions(array $options) {
$this->options = $options;
return $this;
public function getActiveItems() {
return $this->active_values;
}
/**
......@@ -359,13 +425,6 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this;
}
/**
* {@inheritdoc}
*/
public function getQueryTypes() {
return $this->query_type_name;
}
/**
* {@inheritdoc}
*/
......@@ -411,7 +470,7 @@ class Facet extends ConfigEntityBase implements FacetInterface {
if (!$this->facet_source_instance && $this->facet_source_id) {
/* @var $facet_source_plugin_manager \Drupal\facets\FacetSource\FacetSourcePluginManager */
$facet_source_plugin_manager = \Drupal::service('plugin.manager.facets.facet_source');
$this->facet_source_instance = $facet_source_plugin_manager->createInstance($this->facet_source_id);
$this->facet_source_instance = $facet_source_plugin_manager->createInstance($this->facet_source_id, ['facet' => $this]);
}
return $this->facet_source_instance;
......@@ -458,44 +517,6 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this->facetSourceConfig;
}
/**
* Retrieves all processors supported by this facet.
*
* @return \Drupal\facets\Processor\ProcessorInterface[]
* The loaded processors, keyed by processor ID.
*/
protected function loadProcessors() {
if (!isset($this->processors)) {
/* @var $processor_plugin_manager \Drupal\facets\Processor\ProcessorPluginManager */
$processor_plugin_manager = \Drupal::service('plugin.manager.facets.processor');
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($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' => $processor_id, '@class' => $processor_definition['class']));
}
}
}
return $this->processors;
}
/**
* {@inheritdoc}
*/
protected function urlRouteParameters($rel) {
$parameters = parent::urlRouteParameters($rel);
return $parameters;
}
/**
* {@inheritdoc}
*/
......@@ -519,6 +540,20 @@ class Facet extends ConfigEntityBase implements FacetInterface {
}
}
/**
* {@inheritdoc}
*/
public function setUnfilteredResults(array $all_results = []) {
$this->unfiltered_results = $all_results;
}
/**
* {@inheritdoc}
*/
public function getUnfilteredResults() {
return $this->unfiltered_results;
}
/**
* {@inheritdoc}
*/
......@@ -550,7 +585,11 @@ class Facet extends ConfigEntityBase implements FacetInterface {
$this->facetSourcePlugins[$name] = $facet_source;
}
elseif (!class_exists($facet_source_definition['class'])) {
\Drupal::logger('facets')->warning('Facet Source @id specifies a non-existing @class.', ['@id' => $name, '@class' => $facet_source_definition['class']]);
\Drupal::logger('facets')
->warning('Facet Source @id specifies a non-existing @class.', [
'@id' => $name,
'@class' => $facet_source_definition['class'],
]);
}
}
}
......@@ -570,9 +609,9 @@ class Facet extends ConfigEntityBase implements FacetInterface {
$processors = $this->loadProcessors();
// Filter processors by status if required. Enabled processors are those
// which have settings in the "processors" option.
// which have settings in the processor_configs.
if ($only_enabled) {
$processors_settings = !empty($this->processor_configs) ? $this->processor_configs : [];
$processors_settings = $this->getProcessorConfigs();
$processors = array_intersect_key($processors, $processors_settings);
}
......@@ -584,7 +623,7 @@ class Facet extends ConfigEntityBase implements FacetInterface {
*/
public function getProcessorsByStage($stage, $only_enabled = TRUE) {
$processors = $this->loadProcessors();
$processor_settings = $this->processor_configs;
$processor_settings = $this->getProcessorConfigs();
$processor_weights = array();
// Get a list of all processors meeting the criteria (stage and, optionally,
......@@ -655,7 +694,7 @@ class Facet extends ConfigEntityBase implements FacetInterface {
/**
* {@inheritdoc}
*/
public function setEmptyBehavior($empty_behavior) {
public function setEmptyBehavior(array $empty_behavior) {
$this->empty_behavior = $empty_behavior;
}
......@@ -687,6 +726,4 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this->facet_configs;
}
}
......@@ -9,7 +9,6 @@ namespace Drupal\facets\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\facets\FacetSourceInterface;
use Drupal\facets\UrlProcessor\UrlProcessorInterface;
/**
* Defines the facet source configuration entity.
......@@ -37,8 +36,8 @@ use Drupal\facets\UrlProcessor\UrlProcessorInterface;
* config_export = {
* "id",
* "name",
* "filterKey",
* "urlProcessor"
* "filter_key",
* "url_processor"
* },
* links = {
* "canonical" = "/admin/config/search/facets/facet-sources/",
......@@ -67,21 +66,14 @@ class FacetSource extends ConfigEntityBase implements FacetSourceInterface {
*
* @var string
*/
protected $filterKey;
protected $filter_key;
/**
* The url processor name.
*
* @var string
*/
protected $urlProcessor = 'query_string';
/**
* {@inheritdoc}
*/
public function id() {
return $this->id;
}
protected $url_processor = 'query_string';
/**
* {@inheritdoc}
......@@ -94,28 +86,28 @@ class FacetSource extends ConfigEntityBase implements FacetSourceInterface {
* {@inheritdoc}
*/
public function setFilterKey($filter_key) {
$this->filterKey = $filter_key;
$this->filter_key = $filter_key;
}
/**
* {@inheritdoc}
*/
public function getFilterKey() {
return $this->filterKey;
return $this->filter_key;
}
/**
* {@inheritdoc}
*/
public function setUrlProcessor($processor_name) {
$this->urlProcessor = $processor_name;
$this->url_processor = $processor_name;
}
/**
* {@inheritdoc}
*/
public function getUrlProcessorName() {
return $this->urlProcessor;
return $this->url_processor;
}
}
......@@ -33,7 +33,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function getWidget();
/**
* Get field identifier.
* Returns field identifier.
*
* @return string
* The field identifier of this facet.
......@@ -41,7 +41,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function getFieldIdentifier();
/**
* Set field identifier.
* Sets field identifier.
*
* @param string $field_identifier
* The field identifier of this facet.
......@@ -52,7 +52,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function setFieldIdentifier($field_identifier);
/**
* Get the field alias used to identify the facet in the url.
* Returns the field alias used to identify the facet in the url.
*
* @return string
* The field alias for the facet.
......@@ -60,7 +60,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function getFieldAlias();
/**
* Get the field name of the facet as used in the index.
* Returns the field name of the facet as used in the index.
*
* @TODO: Check if fieldIdentifier can be used as well!
*
......@@ -70,9 +70,10 @@ interface FacetInterface extends ConfigEntityInterface {
public function getName();
/**
* Gets the name of the facet for use in the URL.
* Returns the name of the facet for use in the URL.
*
* @return string
* The name of the facet for use in the URL.
*/
public function getUrlAlias();
......@@ -80,6 +81,7 @@ interface FacetInterface extends ConfigEntityInterface {
* Sets the name of the facet for use in the URL.
*
* @param string $url_alias
* The name of the facet for use in the URL.
*/
public function setUrlAlias($url_alias);
......@@ -92,7 +94,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function setActiveItem($value);
/**
* Get all the active items in the facet.
* Returns all the active items in the facet.
*
* @return mixed
* An array containing all active items.
......@@ -111,7 +113,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function isActiveValue($value);
/**
* Get the result for the facet.
* Returns the result for the facet.
*
* @return \Drupal\facets\Result\ResultInterface[] $results
* The results of the facet.
......@@ -126,69 +128,61 @@ interface FacetInterface extends ConfigEntityInterface {
*/
public function setResults(array $results);
/**
* Get the query type instance.
* Sets an array of unfiltered results.
*
* @return string
* The query type plugin being used.
* These unfiltered results are used to set the correct count of the actual
* facet results when using the OR query operator. They are not results value
* objects like those in ::$results.
*
* @param array $all_results
* Unfiltered results.
*/
public function getQueryType();
public function setUnfilteredResults(array $all_results = []);
/**
* Get the plugin name for the url processor.
* Returns an array of unfiltered results.
*
* @return string
* The id of the url processor.
* @return array
* Unfiltered results.
*/
public function getUrlProcessorName();
public function getUnfilteredResults();
/**
* Retrieves an option.
*
* @param string $name
* The name of an option.
* @param mixed $default
* The value return if the option wasn't set.
* Returns the query type instance.
*
* @return mixed
* The value of the option.
*
* @see getOptions()
* @return string
* The query type plugin being used.
*/
public function getOption($name, $default = NULL);
public function getQueryType();
/**
* Retrieves an array of all options.
* Returns the query operator.
*
* @return array
* An associative array of option values, keyed by the option name.
* @return string
* The query operator being used.
*/
public function getOptions();
public function getQueryOperator();
/**
* Sets an option.
* Returns the value of the exclude boolean.
*
* @param string $name
* The name of an option.
* @param mixed $option
* The new option.
* This will return true when the current facet's value should be exclusive
* from the search rather than inclusive.
* When this returns TRUE, the operator will be "<>" instead of "=".
*
* @return $this
* Returns self.
* @return bool
* A boolean flag indicating if search should exlude selected facets
*/
public function setOption($name, $option);
public function getExclude();
/**
* Sets the index's options.
* Returns the plugin name for the url processor.
*
* @param array $options
* The new index options.
*
* @return $this
* Returns self.
* @return string
* The id of the url processor.
*/
public function setOptions(array $options);
public function getUrlProcessorName();
/**
* Sets a string representation of the Facet source plugin.
......@@ -203,6 +197,22 @@ interface FacetInterface extends ConfigEntityInterface {
*/
public function setFacetSourceId($facet_source_id);
/**
* Sets the query operator.
*
* @param string $operator
* The query operator being used.
*/
public function setQueryOperator($operator);
/**
* Sets the exclude.
*
* @param bool $exclude
* A boolean flag indicating if search should exclude selected facets
*/
public function setExclude($exclude);
/**
* Returns the Facet source id.
*
......@@ -228,7 +238,7 @@ interface FacetInterface extends ConfigEntityInterface {
public function getFacetSourceConfig();
/**
* Load the facet sources for this facet.
* Loads the facet sources for this facet.
*
* @param bool|TRUE $only_enabled
* Only return enabled facet sources.
......@@ -266,6 +276,14 @@ interface FacetInterface extends ConfigEntityInterface {
*/
public function getProcessorsByStage($stage, $only_enabled = TRUE);
/**
* Retrieves this facets's processor configs.
*
* @return array
* An array of processors and their configs.
*/
public function getProcessorConfigs();
/**
* Sets the "only visible when facet source is visible" boolean flag.
*
......@@ -287,60 +305,67 @@ interface FacetInterface extends ConfigEntityInterface {
public function getOnlyVisibleWhenFacetSourceIsVisible();
/**
* Enabled a processor for this facet.
* Adds a processor for this facet.
*
* @param array $processor
* An array definition for a processor.
*/
public function addProcessor(array $processor);
/**
* Disable a processor for this facet.
* Removes a processor for this facet.
*
* @param string $processor_id
* The plugin id of the processor.
*/
public function removeProcessor($processor_id);
/**
* Define the no-results behavior.
* Defines the no-results behavior.
*
* @param array $behavior
* The definition of the behavior.
*/
public function setEmptyBehavior($behavior);
public function setEmptyBehavior(array $behavior);
/**
* Return the defined no-results behavior or NULL if none defined.
* Returns the defined no-results behavior or NULL if none defined.
*
* @return array|NULL
* The behavior definition or NULL.
*/
public function getEmptyBehavior();
/**
* Return the configuration of the selected widget.
* Returns the configuration of the selected widget.
*
* @return array
* The configuration settings for the widget.
*/
public function getWidgetConfigs();
/**
* Set the configuration for the widget of this facet.
* Sets the configuration for the widget of this facet.
*
* @param array $widget_config
* The configuration settings for the widget.
*/
public function setWidgetConfigs(array $widget_config);
/**
* Get any additional configuration for this facet, no defined above.
* Returns any additional configuration for this facet, not defined above.
*
* @return array
* An array of additional configuration for the facet.
*/
public function getFacetConfigs();
/**
* Define any additional configuration for this facet not defined above.
* Defines any additional configuration for this facet not defined above.
*
* @param array $facet_config
* An array of additional configuration for the facet.
*/
public function setFacetConfigs(array $facet_config);
}
......@@ -120,7 +120,7 @@ class FacetListBuilder extends ConfigEntityListBuilder {
}
/**
* {@inheritdoc}
* Builds an array of facet sources for display in the overview.
*/
public function buildFacetSourceRow(array $facet_source = []) {
return array(
......