diff --git a/config/schema/facets.facetsource.schema.yml b/config/schema/facets.facetsource.schema.yml
index 962703e..8cf0e35 100644
--- a/config/schema/facets.facetsource.schema.yml
+++ b/config/schema/facets.facetsource.schema.yml
@@ -14,3 +14,6 @@ facets.facet_source.*:
filterKey:
type: string
label: 'Filter key'
+ url_processor:
+ type: string
+ label: 'Url processor'
diff --git a/core_search_facets/src/Plugin/facets/url_processor/DummyQuery.php b/core_search_facets/src/Plugin/facets/url_processor/DummyQuery.php
new file mode 100644
index 0000000..764e67c
--- /dev/null
+++ b/core_search_facets/src/Plugin/facets/url_processor/DummyQuery.php
@@ -0,0 +1,143 @@
+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;
+ }
+ }
+ }
+
+}
diff --git a/facets.plugin_type.yml b/facets.plugin_type.yml
index 1fd9cbf..8db8901 100644
--- a/facets.plugin_type.yml
+++ b/facets.plugin_type.yml
@@ -3,6 +3,11 @@ facets_processor:
plugin_manager_service_id: plugin.manager.facets.processor
plugin_definition_decorator_class: \Drupal\plugin\PluginDefinition\ArrayPluginDefinitionDecorator
+facets_url_processor:
+ label: Facets URL processor
+ plugin_manager_service_id: plugin.manager.facets.url_processor
+ plugin_definition_decorator_class: \Drupal\plugin\PluginDefinition\ArrayPluginDefinitionDecorator
+
facets_facet_source:
label: Facets source
plugin_manager_service_id: plugin.manager.facets.facet_source
diff --git a/facets.services.yml b/facets.services.yml
index c33a611..01d4ee8 100644
--- a/facets.services.yml
+++ b/facets.services.yml
@@ -11,6 +11,9 @@ services:
plugin.manager.facets.processor:
class: Drupal\facets\Processor\ProcessorPluginManager
arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@string_translation']
+ plugin.manager.facets.url_processor:
+ class: Drupal\facets\UrlProcessor\UrlProcessorPluginManager
+ parent: default_plugin_manager
facets.manager:
class: Drupal\facets\FacetManager\DefaultFacetManager
arguments:
diff --git a/src/Annotation/FacetsUrlProcessor.php b/src/Annotation/FacetsUrlProcessor.php
new file mode 100644
index 0000000..8547812
--- /dev/null
+++ b/src/Annotation/FacetsUrlProcessor.php
@@ -0,0 +1,48 @@
+filterKey;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function setUrlProcessor($processor_name) {
+ $this->urlProcessor = $processor_name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUrlProcessorName() {
+ return $this->urlProcessor;
+ }
+
}
diff --git a/src/FacetSourceInterface.php b/src/FacetSourceInterface.php
index 8395760..8c6e909 100644
--- a/src/FacetSourceInterface.php
+++ b/src/FacetSourceInterface.php
@@ -38,4 +38,20 @@ interface FacetSourceInterface extends ConfigEntityInterface {
*/
public function setFilterKey($filter_key);
+ /**
+ * Set the processor name to be used.
+ *
+ * @param string $processor_name
+ * Plugin name of the url processor.
+ */
+ public function setUrlProcessor($processor_name);
+
+ /**
+ * Returns a string version of the url processor.
+ *
+ * @return string
+ * The url processor to be used as a string.
+ */
+ public function getUrlProcessorName();
+
}
diff --git a/src/Form/FacetDisplayForm.php b/src/Form/FacetDisplayForm.php
index d55dfe1..e096de0 100644
--- a/src/Form/FacetDisplayForm.php
+++ b/src/Form/FacetDisplayForm.php
@@ -14,6 +14,7 @@ use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\facets\Processor\ProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginManager;
+use Drupal\facets\UrlProcessor\UrlProcessorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\facets\Widget\WidgetPluginManager;
use Drupal\facets\Processor\WidgetOrderProcessorInterface;
@@ -219,7 +220,7 @@ class FacetDisplayForm extends EntityForm {
),
);
foreach ($all_processors as $processor_id => $processor) {
- if (!($processor instanceof WidgetOrderProcessorInterface)) {
+ if (!($processor instanceof WidgetOrderProcessorInterface) && !($processor instanceof UrlProcessorInterface)) {
$clean_css_id = Html::cleanCssIdentifier($processor_id);
$form['facet_settings'][$processor_id]['status'] = array(
'#type' => 'checkbox',
diff --git a/src/Form/FacetSourceEditForm.php b/src/Form/FacetSourceEditForm.php
index 067a39f..b8680b5 100644
--- a/src/Form/FacetSourceEditForm.php
+++ b/src/Form/FacetSourceEditForm.php
@@ -8,8 +8,11 @@
namespace Drupal\facets\Form;
use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\facets\Entity\FacetSource;
+use Drupal\facets\UrlProcessor\UrlProcessorPluginManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a form for editing facet sources.
@@ -20,10 +23,32 @@ use Drupal\facets\Entity\FacetSource;
class FacetSourceEditForm extends EntityForm {
/**
+ * The plugin manager for URL Processors.
+ *
+ * @var \Drupal\facets\UrlProcessor\UrlProcessorPluginManager
+ */
+ protected $urlProcessorPluginManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
+ $entity_type_manager = $container->get('entity_type.manager');
+
+ /** @var \Drupal\facets\UrlProcessor\UrlProcessorPluginManager $url_processor_plugin_manager */
+ $url_processor_plugin_manager = $container->get('plugin.manager.facets.url_processor');
+
+ return new static($entity_type_manager, $url_processor_plugin_manager);
+ }
+
+ /**
* Constructs a FacetSourceEditForm.
*/
- public function __construct() {
- $facet_source_storage = \Drupal::entityTypeManager()->getStorage('facets_facet_source');
+ public function __construct(EntityTypeManagerInterface $entity_type_manager, UrlProcessorPluginManager $url_processor_plugin_manager) {
+ $facet_source_storage = $entity_type_manager->getStorage('facets_facet_source');
+
+ $this->urlProcessorPluginManager = $url_processor_plugin_manager;
// Make sure we remove colons from the source id, those are disallowed in
// the entity id.
@@ -81,6 +106,21 @@ class FacetSourceEditForm extends EntityForm {
),
];
+ $url_processors = array();
+ $url_processors_description = array();
+ foreach ($this->urlProcessorPluginManager->getDefinitions() as $definition) {
+ $url_processors[$definition['id']] = $definition['label'];
+ $url_processors_description[] = $definition['description'];
+ }
+ $form['urlProcessor'] = [
+ '#type' => 'radios',
+ '#title' => $this->t('URL Processor'),
+ '#options' => $url_processors,
+ '#default_value' => $facet_source->getUrlProcessorName(),
+ '#description' => $this->t(
+ 'The URL Processor defines the url structure used for this facet source.') . '
- ' . implode('
- ', $url_processors_description),
+ ];
+
// The parent's form build method will add a save button.
return parent::buildForm($form, $form_state);
}
diff --git a/src/Plugin/facets/processor/QueryStringUrlProcessor.php b/src/Plugin/facets/processor/QueryStringUrlProcessor.php
deleted file mode 100644
index 3c53a32..0000000
--- a/src/Plugin/facets/processor/QueryStringUrlProcessor.php
+++ /dev/null
@@ -1,148 +0,0 @@
-initializeActiveFilters();
- }
-
- /**
- * {@inheritdoc}
- */
- public function build(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 . ':' . $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 preQuery(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;
- }
- }
- }
-
-}
diff --git a/src/Plugin/facets/processor/UrlProcessorHandler.php b/src/Plugin/facets/processor/UrlProcessorHandler.php
new file mode 100644
index 0000000..5a78e00
--- /dev/null
+++ b/src/Plugin/facets/processor/UrlProcessorHandler.php
@@ -0,0 +1,75 @@
+getFacetSourceConfig();
+
+ $url_processor_name = $fs->getUrlProcessorName();
+
+ $manager = \Drupal::getContainer()->get('plugin.manager.facets.url_processor');
+ $this->processor= $manager->createInstance($url_processor_name, ['facet' => $facet]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function build(FacetInterface $facet, array $results) {
+ return $this->processor->buildUrls($facet, $results);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function preQuery(FacetInterface $facet) {
+ $this->processor->setActiveItems($facet);
+ }
+
+}
diff --git a/src/Plugin/facets/url_processor/QueryString.php b/src/Plugin/facets/url_processor/QueryString.php
new file mode 100644
index 0000000..9be51c0
--- /dev/null
+++ b/src/Plugin/facets/url_processor/QueryString.php
@@ -0,0 +1,143 @@
+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;
+ }
+ }
+ }
+
+}
diff --git a/src/Processor/UrlProcessorInterface.php b/src/Processor/UrlProcessorInterface.php
deleted file mode 100644
index 31aeb9c..0000000
--- a/src/Processor/UrlProcessorInterface.php
+++ /dev/null
@@ -1,31 +0,0 @@
-filterKey;
- }
-
- /**
- * Constructs a new instance of the class.
- *
- * @param array $configuration
- * A configuration array containing information about the plugin instance.
- * @param string $plugin_id
- * The plugin_id for the plugin instance.
- * @param mixed $plugin_definition
- * The plugin implementation definition.
- * @param \Symfony\Component\HttpFoundation\Request $request
- * A request object for the current request.
- */
- public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
- $this->request = $request;
-
- if (!isset($configuration['facet'])) {
- throw new InvalidProcessorException();
- }
-
- /** @var \Drupal\facets\FacetInterface $facet */
- $facet = $configuration['facet'];
-
- /** @var \Drupal\facets\FacetSourceInterface $facet_source_config */
- $facet_source_config = $facet->getFacetSourceConfig();
-
- $this->filterKey = $facet_source_config->getFilterKey() ?: 'f';
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
- /** @var Request $request */
- $request = $container->get('request_stack')->getCurrentRequest();
- return new static($configuration, $plugin_id, $plugin_definition, $request);
- }
-
-}
diff --git a/src/Tests/FacetSourceTest.php b/src/Tests/FacetSourceTest.php
index 3beef1d..92d179e 100644
--- a/src/Tests/FacetSourceTest.php
+++ b/src/Tests/FacetSourceTest.php
@@ -29,11 +29,17 @@ class FacetSourceTest extends FacetWebTestBase {
$this->clickLink($this->t('Configure'));
// Test the edit page.
+ $edit = array(
+ 'filterKey' => 'fq',
+ 'urlProcessor' => 'query_string',
+ );
$this->assertField('filterKey');
- $this->drupalPostForm(NULL, array('filterKey' => 'fq'), $this->t('Save'));
+ $this->assertField('urlProcessor');
+ $this->drupalPostForm(NULL, $edit, $this->t('Save'));
// Test that saving worked.
$this->assertField('filterKey');
+ $this->assertField('urlProcessor');
$this->assertRaw('fq');
}
diff --git a/src/Tests/UrlIntegrationTest.php b/src/Tests/UrlIntegrationTest.php
new file mode 100644
index 0000000..565392e
--- /dev/null
+++ b/src/Tests/UrlIntegrationTest.php
@@ -0,0 +1,101 @@
+drupalLogin($this->adminUser);
+
+ $this->insertExampleContent();
+ $this->assertEqual($this->indexItems($this->indexId), 5, '5 items were indexed.');
+ }
+
+ /**
+ * Tests various url integration things.
+ */
+ public function testUrlIntegration() {
+ $id = 'facet';
+ $name = '&^Facet@#1';
+ $facet_add_page = 'admin/config/search/facets/add-facet';
+
+ $this->drupalGet($facet_add_page);
+
+ $form_values = [
+ 'id' => $id,
+ 'status' => 1,
+ 'url_alias' => $id,
+ 'name' => $name,
+ 'facet_source_id' => 'search_api_views:search_api_test_views_fulltext:page_1',
+ 'facet_source_configs[search_api_views:search_api_test_views_fulltext:page_1][field_identifier]' => 'entity:entity_test/type',
+ ];
+ $this->drupalPostForm(NULL, ['facet_source_id' => 'search_api_views:search_api_test_views_fulltext:page_1'], $this->t('Configure facet source'));
+ $this->drupalPostForm(NULL, $form_values, $this->t('Save'));
+
+ // Go to the only enabled facet source's config.
+ $this->drupalGet('admin/config/search/facets');
+ $this->clickLink($this->t('Configure'));
+
+ $edit = [
+ 'filterKey' => 'y',
+ 'urlProcessor' => 'dummy_query',
+ ];
+ $this->drupalPostForm(NULL, $edit, $this->t('Save'));
+
+ /** @var \Drupal\facets\FacetInterface $facet */
+ $facet = \Drupal::service('entity_type.manager')->getStorage('facets_facet')->load($id);
+ $block_values = [
+ 'region' => 'footer',
+ 'id' => str_replace('_', '-', $id),
+ 'context_mapping' => [
+ 'facet' => '@facets.facet_context:' . $facet->uuid(),
+ ],
+ ];
+ $this->drupalPlaceBlock('facet_block', $block_values);
+
+ $this->drupalGet('search-api-test-fulltext');
+ $this->assertResponse(200);
+ $this->assertLink('item');
+ $this->assertLink('article');
+
+ $this->clickLink('item');
+
+ $this->assertResponse(200);
+ $this->assertLink('(-) item');
+ $this->assertNoLink('article');
+ $this->assertUrl('search-api-test-fulltext?y[0]=facet||item');
+ }
+
+}
diff --git a/src/UrlProcessor/UrlProcessorInterface.php b/src/UrlProcessor/UrlProcessorInterface.php
new file mode 100644
index 0000000..3bc51a1
--- /dev/null
+++ b/src/UrlProcessor/UrlProcessorInterface.php
@@ -0,0 +1,56 @@
+filterKey;
+ }
+
+ /**
+ * Constructs a new instance of the class.
+ *
+ * @param array $configuration
+ * A configuration array containing information about the plugin instance.
+ * @param string $plugin_id
+ * The plugin_id for the plugin instance.
+ * @param mixed $plugin_definition
+ * The plugin implementation definition.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * A request object for the current request.
+ */
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, Request $request) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition);
+ $this->request = $request;
+
+ if (!isset($configuration['facet'])) {
+ throw new InvalidProcessorException("The url processor doesn't have the required 'facet' in the configuration array.");
+ }
+
+ /** @var \Drupal\facets\FacetInterface $facet */
+ $facet = $configuration['facet'];
+
+ /** @var \Drupal\facets\FacetSourceInterface $facet_source_config */
+ $facet_source_config = $facet->getFacetSourceConfig();
+
+ $this->filterKey = $facet_source_config->getFilterKey() ?: 'f';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ /** @var Request $request */
+ $request = $container->get('request_stack')->getCurrentRequest();
+ return new static($configuration, $plugin_id, $plugin_definition, $request);
+ }
+
+}
diff --git a/src/UrlProcessor/UrlProcessorPluginManager.php b/src/UrlProcessor/UrlProcessorPluginManager.php
new file mode 100644
index 0000000..84008fd
--- /dev/null
+++ b/src/UrlProcessor/UrlProcessorPluginManager.php
@@ -0,0 +1,35 @@
+setCacheBackend($cache_backend, 'facets_url_processors');
+ }
+
+}
diff --git a/tests/facets_query_processor/facets_query_processor.info.yml b/tests/facets_query_processor/facets_query_processor.info.yml
new file mode 100644
index 0000000..8347423
--- /dev/null
+++ b/tests/facets_query_processor/facets_query_processor.info.yml
@@ -0,0 +1,6 @@
+name: 'Facets query processor'
+type: module
+description: 'Facets query processor'
+package: 'Search'
+core: 8.x
+hidden: true
diff --git a/tests/src/Unit/Plugin/processor/QueryStringUrlProcessorTest.php b/tests/src/Unit/Plugin/processor/QueryStringUrlProcessorTest.php
deleted file mode 100644
index 1b4c58f..0000000
--- a/tests/src/Unit/Plugin/processor/QueryStringUrlProcessorTest.php
+++ /dev/null
@@ -1,246 +0,0 @@
-originalResults = [
- new Result('llama', 'Llama', 15),
- new Result('badger', 'Badger', 5),
- new Result('mushroom', 'Mushroom', 5),
- new Result('duck', 'Duck', 15),
- new Result('alpaca', 'Alpaca', 25),
- ];
-
- $this->setContainer();
- }
-
- /**
- * Basic test with one active item.
- */
- public function testSetSingleActiveItem() {
- $facet = new Facet([], 'facet');
- $facet->setResults($this->originalResults);
- $facet->setUrlAlias('test');
- $facet->setFieldIdentifier('test');
-
- $request = new Request();
- $request->query->set('f', ['test:badger']);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $this->processor->preQuery($facet);
-
- $this->assertEquals(['badger'], $facet->getActiveItems());
- }
-
- /**
- * Basic test with multiple active items.
- */
- public function testSetMultipleActiveItems() {
- $facet = new Facet([], 'facet');
- $facet->setResults($this->originalResults);
- $facet->setUrlAlias('test');
- $facet->setFieldIdentifier('test');
-
- $request = new Request();
- $request->query->set('f', ['test:badger', 'test:mushroom', 'donkey:kong']);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $this->processor->preQuery($facet);
-
- $this->assertEquals(['badger', 'mushroom'], $facet->getActiveItems());
- }
-
- /**
- * Basic test with an empty build.
- */
- public function testEmptyBuild() {
- $facet = new Facet([], 'facet');
- $facet->setUrlAlias('test');
- $facet->setFacetSourceId('facet_source__dummy');
-
- $request = new Request();
- $request->query->set('f', []);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $results = $this->processor->build($facet, []);
- $this->assertEmpty($results);
- }
-
- /**
- * Test with default build.
- */
- public function testBuild() {
- $facet = new Facet([], 'facet');
- $facet->setFieldIdentifier('test');
- $facet->setUrlAlias('test');
- $facet->setFacetSourceId('facet_source__dummy');
-
- $request = new Request();
- $request->query->set('f', []);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $results = $this->processor->build($facet, $this->originalResults);
-
- /** @var \Drupal\facets\Result\ResultInterface $r */
- foreach ($results as $r) {
- $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
- $this->assertEquals('route:test?f[0]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
- }
- }
-
- /**
- * Test with an active item already from url.
- */
- public function testBuildWithActiveItem() {
- $facet = new Facet([], 'facet');
- $facet->setFieldIdentifier('test');
- $facet->setUrlAlias('test');
- $facet->setFacetSourceId('facet_source__dummy');
-
- $original_results = $this->originalResults;
- $original_results[2]->setActiveState(TRUE);
-
- $request = new Request();
- $request->query->set('f', ['king:kong']);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $results = $this->processor->build($facet, $original_results);
-
- /** @var \Drupal\facets\Result\ResultInterface $r */
- foreach ($results as $k => $r) {
- $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
- if ($k === 2) {
- $this->assertEquals('route:test?f[0]=king%3Akong', $r->getUrl()->toUriString());
- }
- else {
- $this->assertEquals('route:test?f[0]=king%3Akong&f[1]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
- }
- }
- }
-
- /**
- * Test that the facet source configuration filter key override works.
- */
- public function testFacetSourceFilterKeyOverride() {
- $facet_source = new FacetSource(['filterKey' => 'ab'], 'facets_facet_source');
-
- // Override the container with the new facet source.
- $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
- $storage->expects($this->once())
- ->method('load')
- ->willReturn($facet_source);
- $em = $this->getMockBuilder('\Drupal\Core\Entity\EntityTypeManagerInterface')
- ->disableOriginalConstructor()
- ->getMock();
- $em->expects($this->any())
- ->method('getStorage')
- ->willReturn($storage);
-
- $container = \Drupal::getContainer();
- $container->set('entity_type.manager', $em);
- \Drupal::setContainer($container);
-
- $facet = new Facet([], 'facet');
- $facet->setFieldIdentifier('test');
- $facet->setFacetSourceId('facet_source__dummy');
- $facet->setUrlAlias('test');
-
- $request = new Request();
- $request->query->set('ab', []);
-
- $this->processor = new QueryStringUrlProcessor(['facet' => $facet], 'query_string', [], $request);
- $results = $this->processor->build($facet, $this->originalResults);
-
- /** @var \Drupal\facets\Result\ResultInterface $r */
- foreach ($results as $r) {
- $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
- $this->assertEquals('route:test?ab[0]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
- }
-
- }
-
- /**
- * Set the container for use in unit tests.
- */
- protected function setContainer() {
- $router = $this->getMockBuilder('Drupal\Tests\Core\Routing\TestRouterInterface')
- ->disableOriginalConstructor()
- ->getMock();
- $router->expects($this->any())
- ->method('matchRequest')
- ->willReturn(
- [
- '_raw_variables' => new ParameterBag([]),
- '_route' => 'test',
- ]
- );
-
- $fsi = $this->getMockBuilder('\Drupal\facets\FacetSource\FacetSourcePluginInterface')
- ->disableOriginalConstructor()
- ->getMock();
- $fsi->method('getPath')
- ->willReturn('search/test');
-
- $manager = $this->getMockBuilder('\Drupal\facets\FacetSource\FacetSourcePluginManager')
- ->disableOriginalConstructor()
- ->getMock();
- $manager->method('createInstance')
- ->willReturn($fsi);
-
- $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
- $em = $this->getMockBuilder('\Drupal\Core\Entity\EntityTypeManagerInterface')
- ->disableOriginalConstructor()
- ->getMock();
- $em->expects($this->any())
- ->method('getStorage')
- ->willReturn($storage);
-
- $container = new ContainerBuilder();
- $container->set('router.no_access_checks', $router);
- $container->set('plugin.manager.facets.facet_source', $manager);
- $container->set('entity_type.manager', $em);
- $container->set('entity.manager', $em);
- \Drupal::setContainer($container);
- }
-
-}
diff --git a/tests/src/Unit/Plugin/processor/UrlProcessorHandlerTest.php b/tests/src/Unit/Plugin/processor/UrlProcessorHandlerTest.php
new file mode 100644
index 0000000..c411be8
--- /dev/null
+++ b/tests/src/Unit/Plugin/processor/UrlProcessorHandlerTest.php
@@ -0,0 +1,80 @@
+setExpectedException('\Drupal\facets\Exception\InvalidProcessorException', "The UrlProcessorHandler doesn't have the required 'facet' in the configuration array.");
+ new UrlProcessorHandler([], 'test', []);
+ }
+
+ /**
+ * Tests that the processor correctly throws an exception.
+ */
+ public function testInvalidProcessorConfiguration() {
+ $this->setExpectedException('\Drupal\facets\Exception\InvalidProcessorException', "The UrlProcessorHandler doesn't have the required 'facet' in the configuration array.");
+ new UrlProcessorHandler(['facet' => new \stdClass()], 'test', []);
+ }
+
+ /**
+ * Test that the build method is correctly called.
+ */
+ public function testBuild() {
+ $facet = new Facet(['id' => '_test'], 'facets_facet');
+ $this->createContainer();
+
+ $processor = new UrlProcessorHandler(['facet' => $facet], 'url_processor_handler', []);
+ // The actual results of this should be tested in the actual processor.
+ $processor->build($facet, []);
+ }
+
+ /**
+ * Helper function to create a correct container.
+ */
+ protected function createContainer() {
+ $url_processor = $this->getMockBuilder('\Drupal\facets\UrlProcessor\UrlProcessorInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $manager = $this->getMockBuilder('\Drupal\facets\FacetSource\FacetSourcePluginManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $manager->expects($this->exactly(1))
+ ->method('createInstance')
+ ->willReturn($url_processor);
+
+ $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+ $em = $this->getMockBuilder('\Drupal\Core\Entity\EntityTypeManagerInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $em->expects($this->exactly(2))
+ ->method('getStorage')
+ ->willReturn($storage);
+
+ $container = new ContainerBuilder();
+ $container->set('entity.manager', $em);
+ $container->set('entity_type.manager', $em);
+ $container->set('plugin.manager.facets.url_processor', $manager);
+ \Drupal::setContainer($container);
+ }
+
+}
diff --git a/tests/src/Unit/Plugin/url_processor/QueryStringTest.php b/tests/src/Unit/Plugin/url_processor/QueryStringTest.php
new file mode 100644
index 0000000..df418fb
--- /dev/null
+++ b/tests/src/Unit/Plugin/url_processor/QueryStringTest.php
@@ -0,0 +1,254 @@
+originalResults = [
+ new Result('llama', 'Llama', 15),
+ new Result('badger', 'Badger', 5),
+ new Result('mushroom', 'Mushroom', 5),
+ new Result('duck', 'Duck', 15),
+ new Result('alpaca', 'Alpaca', 25),
+ ];
+
+ $this->setContainer();
+ }
+
+ /**
+ * Tests that the processor correctly throws an exception.
+ */
+ public function testEmptyProcessorConfiguration() {
+ $this->setExpectedException('\Drupal\facets\Exception\InvalidProcessorException', "The url processor doesn't have the required 'facet' in the configuration array.");
+ new QueryString([], 'test', [], new Request());
+ }
+
+ /**
+ * Basic test with one active item.
+ */
+ public function testSetSingleActiveItem() {
+ $facet = new Facet([], 'facet');
+ $facet->setResults($this->originalResults);
+ $facet->setUrlAlias('test');
+ $facet->setFieldIdentifier('test');
+
+ $request = new Request();
+ $request->query->set('f', ['test:badger']);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $this->processor->setActiveItems($facet);
+
+ $this->assertEquals(['badger'], $facet->getActiveItems());
+ }
+
+ /**
+ * Basic test with multiple active items.
+ */
+ public function testSetMultipleActiveItems() {
+ $facet = new Facet([], 'facet');
+ $facet->setResults($this->originalResults);
+ $facet->setUrlAlias('test');
+ $facet->setFieldIdentifier('test');
+
+ $request = new Request();
+ $request->query->set('f', ['test:badger', 'test:mushroom', 'donkey:kong']);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $this->processor->setActiveItems($facet);
+
+ $this->assertEquals(['badger', 'mushroom'], $facet->getActiveItems());
+ }
+
+ /**
+ * Basic test with an empty build.
+ */
+ public function testEmptyBuild() {
+ $facet = new Facet([], 'facet');
+ $facet->setUrlAlias('test');
+ $facet->setFacetSourceId('facet_source__dummy');
+
+ $request = new Request();
+ $request->query->set('f', []);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $results = $this->processor->buildUrls($facet, []);
+ $this->assertEmpty($results);
+ }
+
+ /**
+ * Test with default build.
+ */
+ public function testBuild() {
+ $facet = new Facet([], 'facet');
+ $facet->setFieldIdentifier('test');
+ $facet->setUrlAlias('test');
+ $facet->setFacetSourceId('facet_source__dummy');
+
+ $request = new Request();
+ $request->query->set('f', []);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $results = $this->processor->buildUrls($facet, $this->originalResults);
+
+ /** @var \Drupal\facets\Result\ResultInterface $r */
+ foreach ($results as $r) {
+ $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
+ $this->assertEquals('route:test?f[0]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
+ }
+ }
+
+ /**
+ * Test with an active item already from url.
+ */
+ public function testBuildWithActiveItem() {
+ $facet = new Facet([], 'facet');
+ $facet->setFieldIdentifier('test');
+ $facet->setUrlAlias('test');
+ $facet->setFacetSourceId('facet_source__dummy');
+
+ $original_results = $this->originalResults;
+ $original_results[2]->setActiveState(TRUE);
+
+ $request = new Request();
+ $request->query->set('f', ['king:kong']);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $results = $this->processor->buildUrls($facet, $original_results);
+
+ /** @var \Drupal\facets\Result\ResultInterface $r */
+ foreach ($results as $k => $r) {
+ $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
+ if ($k === 2) {
+ $this->assertEquals('route:test?f[0]=king%3Akong', $r->getUrl()->toUriString());
+ }
+ else {
+ $this->assertEquals('route:test?f[0]=king%3Akong&f[1]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
+ }
+ }
+ }
+
+ /**
+ * Test that the facet source configuration filter key override works.
+ */
+ public function testFacetSourceFilterKeyOverride() {
+ $facet_source = new FacetSource(['filterKey' => 'ab'], 'facets_facet_source');
+
+ // Override the container with the new facet source.
+ $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+ $storage->expects($this->once())
+ ->method('load')
+ ->willReturn($facet_source);
+ $em = $this->getMockBuilder('\Drupal\Core\Entity\EntityTypeManagerInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $em->expects($this->any())
+ ->method('getStorage')
+ ->willReturn($storage);
+
+ $container = \Drupal::getContainer();
+ $container->set('entity_type.manager', $em);
+ \Drupal::setContainer($container);
+
+ $facet = new Facet([], 'facet');
+ $facet->setFieldIdentifier('test');
+ $facet->setFacetSourceId('facet_source__dummy');
+ $facet->setUrlAlias('test');
+
+ $request = new Request();
+ $request->query->set('ab', []);
+
+ $this->processor = new QueryString(['facet' => $facet], 'query_string', [], $request);
+ $results = $this->processor->buildUrls($facet, $this->originalResults);
+
+ /** @var \Drupal\facets\Result\ResultInterface $r */
+ foreach ($results as $r) {
+ $this->assertInstanceOf('\Drupal\facets\Result\ResultInterface', $r);
+ $this->assertEquals('route:test?ab[0]=test%3A' . $r->getRawValue(), $r->getUrl()->toUriString());
+ }
+
+ }
+
+ /**
+ * Set the container for use in unit tests.
+ */
+ protected function setContainer() {
+ $router = $this->getMockBuilder('Drupal\Tests\Core\Routing\TestRouterInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $router->expects($this->any())
+ ->method('matchRequest')
+ ->willReturn(
+ [
+ '_raw_variables' => new ParameterBag([]),
+ '_route' => 'test',
+ ]
+ );
+
+ $fsi = $this->getMockBuilder('\Drupal\facets\FacetSource\FacetSourcePluginInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $fsi->method('getPath')
+ ->willReturn('search/test');
+
+ $manager = $this->getMockBuilder('\Drupal\facets\FacetSource\FacetSourcePluginManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $manager->method('createInstance')
+ ->willReturn($fsi);
+
+ $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+ $em = $this->getMockBuilder('\Drupal\Core\Entity\EntityTypeManagerInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $em->expects($this->any())
+ ->method('getStorage')
+ ->willReturn($storage);
+
+ $container = new ContainerBuilder();
+ $container->set('router.no_access_checks', $router);
+ $container->set('plugin.manager.facets.facet_source', $manager);
+ $container->set('entity_type.manager', $em);
+ $container->set('entity.manager', $em);
+ \Drupal::setContainer($container);
+ }
+
+}