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/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..1075384 --- /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 getUrlProcessor() { + + // If the instance is already loaded, don't bother trying to reload it, just + // return it. + if ($this->urlProcessorInstance instanceof UrlProcessorInterface) { + return $this->urlProcessorInstance; + } + + $manager = \Drupal::getContainer()->get('plugin.manager.facets.url_processor'); + $this->urlProcessorInstance = $manager->createInstance($this->urlProcessor); + + return $this->urlProcessorInstance; + } + + /** + * {@inheritdoc} + */ + public function getUrlProcessorName() { + return $this->urlProcessor; + } + } diff --git a/src/FacetSourceInterface.php b/src/FacetSourceInterface.php index 8395760..a02cac8 100644 --- a/src/FacetSourceInterface.php +++ b/src/FacetSourceInterface.php @@ -38,4 +38,28 @@ 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 an instance of the url processor. + * + * @return \Drupal\facets\UrlProcessor\UrlProcessorInterface + * The url processor to be used. + */ + public function getUrlProcessor(); + + /** + * 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/FacetSourceEditForm.php b/src/Form/FacetSourceEditForm.php index 067a39f..1eaba54 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 $etm */ + $etm = $container->get('entity_type.manager'); + + /** @var \Drupal\facets\UrlProcessor\UrlProcessorPluginManager $uppm */ + $uppm = $container->get('plugin.manager.facets.url_processor'); + + return new static($etm, $uppm); + } + + /** * 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,17 @@ class FacetSourceEditForm extends EntityForm { ), ]; + $url_processors = array(); + foreach ($this->urlProcessorPluginManager->getDefinitions() as $definition) { + $url_processors[$definition['id']] = $definition['label']; + } + $form['urlProcessor'] = [ + '#type' => 'select', + '#title' => $this->t('URL Processor'), + '#options' => $url_processors, + '#default_value' => $facet_source->getUrlProcessorName(), + ]; + // 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..aa653fd --- /dev/null +++ b/src/Plugin/facets/processor/UrlProcessorHandler.php @@ -0,0 +1,72 @@ +getFacetSourceConfig(); + + $this->processor = $fs->getUrlProcessor(); + } + + /** + * {@inheritdoc} + */ + public function build(FacetInterface $facet, array $results) { + $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..346b294 --- /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 . ':' . $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/UrlProcessor/UrlProcessorInterface.php b/src/UrlProcessor/UrlProcessorInterface.php new file mode 100644 index 0000000..e040db4 --- /dev/null +++ b/src/UrlProcessor/UrlProcessorInterface.php @@ -0,0 +1,37 @@ +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..d3f3dcf --- /dev/null +++ b/src/UrlProcessor/UrlProcessorPluginManager.php @@ -0,0 +1,36 @@ +setCacheBackend($cache_backend, 'facets_url_processors'); + } + +} 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/url_processor/QueryStringUrlProcessorTest.php b/tests/src/Unit/Plugin/url_processor/QueryStringUrlProcessorTest.php new file mode 100644 index 0000000..9698c84 --- /dev/null +++ b/tests/src/Unit/Plugin/url_processor/QueryStringUrlProcessorTest.php @@ -0,0 +1,246 @@ +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 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); + } + +}