Skip to content
<?php
/**
* @file
* Contains Drupal\facets\Plugin\Block\FacetBlockDeriver.
*/
namespace Drupal\facets\Plugin\Block;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* This deriver creates a block for every facet that has been created.
*/
class FacetBlockDeriver implements ContainerDeriverInterface {
use StringTranslationTrait;
/**
* List of derivative definitions.
*
* @var array
*/
protected $derivatives = [];
/**
* The entity storage used for facets.
*
* @var \Drupal\Core\Entity\EntityStorageInterface $facetStorage
*/
protected $facetStorage;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
$deriver = new static($container, $base_plugin_id);
$deriver->facetStorage = $container->get('entity_type.manager')->getStorage('facets_facet');
return $deriver;
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
$derivatives = $this->getDerivativeDefinitions($base_plugin_definition);
return isset($derivatives[$derivative_id]) ? $derivatives[$derivative_id] : NULL;
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$base_plugin_id = $base_plugin_definition['id'];
if (!isset($this->derivatives[$base_plugin_id])) {
$plugin_derivatives = [];
/** @var \Drupal\facets\FacetInterface[] $all_facets */
$all_facets = $this->facetStorage->loadMultiple();
foreach ($all_facets as $facet) {
$machine_name = $facet->id();
$plugin_derivatives[$machine_name] = [
'id' => $base_plugin_id . PluginBase::DERIVATIVE_SEPARATOR . $machine_name,
'label' => $this->t('Facet: :facet', [':facet' => $facet->getName()]),
'admin_label' => $facet->getName(),
'description' => $this->t('Facet'),
] + $base_plugin_definition;
$sources[] = $this->t('Facet: :facet', [':facet' => $facet->getName()]);
}
$this->derivatives[$base_plugin_id] = $plugin_derivatives;
}
return $this->derivatives[$base_plugin_id];
}
}
<?php
/**
* @file
* Contains \Drupal\facets\Plugin\Condition\OtherFacet.
*/
namespace Drupal\facets\Plugin\Condition;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Block\BlockManager;
use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\facets\FacetManager\DefaultFacetManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides an 'other facet' condition.
*
* This adds a condition plugin to make sure that facets can depend on other
* facet's or their values. The facet value is a freeform textfield and works on
* both raw and display values of the results.
*
* @Condition(
* id = "other_facet",
* label = @Translation("Other facet"),
* )
*/
class OtherFacet extends ConditionPluginBase implements ContainerFactoryPluginInterface {
/**
* The facet entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $facetStorage;
/**
* The block plugin manager.
*
* @var \Drupal\Core\Block\BlockManager
*/
protected $blockManager;
/**
* The user that's currently logged in.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* The facet manager service.
*
* @var \Drupal\facets\FacetManager\DefaultFacetManager
*/
protected $facetManager;
/**
* Creates a new instance of the condition.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
* The entity storage.
* @param \Drupal\Core\Block\BlockManager $block_manager
* The block plugin manager.
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
* The currently logged in user.
* @param \Drupal\facets\FacetManager\DefaultFacetManager $facet_manager
* The default facet manager class.
* @param array $configuration
* The plugin configuration, i.e. an array with configuration values keyed
* by configuration option name. The special key 'context' may be used to
* initialize the defined contexts by setting it to an array of context
* values keyed by context names.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
*/
public function __construct(EntityStorageInterface $entity_storage, BlockManager $block_manager, AccountProxyInterface $current_user, DefaultFacetManager $facet_manager, array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->facetStorage = $entity_storage;
$this->blockManager = $block_manager;
$this->currentUser = $current_user;
$this->facetManager = $facet_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('entity_type.manager')->getStorage('facets_facet'),
$container->get('plugin.manager.block'),
$container->get('current_user'),
$container->get('facets.manager'),
$configuration,
$plugin_id,
$plugin_definition
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$options = [];
// Loop over all defined blocks and filter them by provider, this builds an
// array of blocks that are provided by the facets module.
foreach ($this->blockManager->getDefinitions() as $definition) {
if ($definition['provider'] == 'facets') {
$options[$definition['id']] = $definition['label'];
}
}
$form['facets'] = [
'#title' => $this->t('Other facet blocks'),
'#type' => 'radios',
'#options' => $options,
'#default_value' => $this->configuration['facets'],
];
$form['facet_value'] = [
'#title' => $this->t('Facet value'),
'#description' => $this->t('Only applies when a facet is already selected.'),
'#type' => 'textfield',
'#default_value' => $this->configuration['facet_value'],
];
return parent::buildConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['facets'] = $form_state->getValue('facets');
$this->configuration['facet_value'] = $form_state->getValue('facet_value');
parent::submitConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function summary() {
return $this->t(
'The facet is @facet also rendered on the same page.',
['@facet' => $this->configuration['facets']]
);
}
/**
* {@inheritdoc}
*/
public function evaluate() {
$allowed_facet_value = $this->configuration['facet_value'];
$allowed_facets = $this->configuration['facets'];
// Return as early as possible when there are no settings for allowed
// facets.
if (empty($allowed_facets)) {
return TRUE;
}
/** @var \Drupal\facets\Plugin\Block\FacetBlock $block_plugin */
$block_plugin = $this->blockManager->createInstance($allowed_facets);
// Allowed facet value is not set, so we only have to check if the block is
// shown here by running the access method on the block plugin with the
// currently logged in user.
if (empty($allowed_facet_value)) {
return $block_plugin->access($this->currentUser);
}
// The block plugin id is saved in the schema: BasePluginID:FacetID. This
// means we can explode the ID on ':' and the facet id is in the last part
// of that result.
$block_plugin_id = $block_plugin->getPluginId();
$facet_id = explode(PluginBase::DERIVATIVE_SEPARATOR, $block_plugin_id)[1];
/** @var \Drupal\facets\FacetInterface $facet */
$facet = $this->facetStorage->load($facet_id);
$this->facetManager->setFacetSourceId($facet->getFacetSourceId());
$facet = $this->facetManager->returnProcessedFacet($facet_id);
foreach ($facet->getResults() as $result) {
$is_value = $result->getRawValue() == $allowed_facet_value || $result->getDisplayValue() == $allowed_facet_value;
if ($is_value && $result->isActive()) {
return TRUE;
}
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
$config = ['facets' => FALSE, 'facet_value' => FALSE];
return $config + parent::defaultConfiguration();
}
}
......@@ -10,7 +10,6 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\facets\Exception\InvalidQueryTypeException;
use Drupal\facets\FacetInterface;
use Drupal\facets\FacetSource\FacetSourcePluginInterface;
use Drupal\search_api\Backend\BackendInterface;
use Drupal\facets\FacetSource\FacetSourcePluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -65,7 +64,7 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
/**
* {@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',
......@@ -73,7 +72,7 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
'#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;
......@@ -84,7 +83,7 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
*/
public function getFields() {
$indexed_fields = [];
$fields = $this->index->getFields(TRUE);
$fields = $this->index->getFields();
foreach ($fields as $field) {
$indexed_fields[$field->getFieldIdentifier()] = $field->getLabel();
}
......@@ -99,16 +98,17 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
// identifier.
$field_id = $facet->getFieldIdentifier();
// Get the Search API Server.
$server = $this->index->getServer();
$server = $this->index->getServerInstance();
// Get the Search API Backend.
$backend = $server->getBackend();
$fields = $this->index->getFields(TRUE);
$fields = $this->index->getFields();
foreach ($fields as $field) {
if ($field->getFieldIdentifier() == $field_id) {
return $this->getQueryTypesForDataType($backend, $field->getType());
}
}
throw new InvalidQueryTypeException($this->t("No available query types were found for facet @facet", ['@facet' => $facet->getName()]));
}
......
......@@ -75,7 +75,7 @@ class SearchApiViewsPage extends SearchApiBaseFacetSource {
public function getPath() {
$view = Views::getView($this->pluginDefinition['view_id']);
$view->setDisplay($this->pluginDefinition['view_display']);
return $view->getDisplay()->getOption('path');
return $view->getDisplay()->getPath();
}
/**
......
<?php
/**
* @file
* Contains Drupal\facets\Plugin\facets\processor\UrlProcessorHandler.
*/
namespace Drupal\facets\Plugin\facets\processor;
use Drupal\facets\Exception\InvalidProcessorException;
use Drupal\facets\FacetInterface;
use Drupal\facets\Processor\BuildProcessorInterface;
use Drupal\facets\Processor\PreQueryProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginBase;
/**
* The URL processor handler triggers the actual url processor.
*
* The URL processor handler allows managing the weight of the actual URL
* processor per Facet. This handler will trigger the actual.
*
* @FacetsUrlProcessor, which can be configured on the Facet source.
*
* @FacetsProcessor(
* id = "url_processor_handler",
* label = @Translation("URL handler"),
* description = @Translation("Triggers the URL processor, which is set in the Facet source configuration."),
* stages = {
* "pre_query" = 50,
* "build" = 15,
* },
* locked = true
* )
*/
class UrlProcessorHandler extends ProcessorPluginBase implements BuildProcessorInterface, PreQueryProcessorInterface {
/**
* The actual url processor used for handing urls.
*
* @var \Drupal\facets\UrlProcessor\UrlProcessorInterface
*/
protected $processor;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
if (!isset($configuration['facet']) || !$configuration['facet'] instanceof FacetInterface) {
throw new InvalidProcessorException("The UrlProcessorHandler doesn't have the required 'facet' in the configuration array.");
}
/** @var \Drupal\facets\FacetInterface $facet */
$facet = $configuration['facet'];
/** @var \Drupal\facets\FacetSourceInterface $fs */
$fs = $facet->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);
}
}
......@@ -29,7 +29,7 @@ use Drupal\facets\Result\Result;
class SearchApiString extends QueryTypePluginBase {
/**
* Holds the backend's native query object.
* The backend's native query object.
*
* @var \Drupal\search_api\Query\QueryInterface
*/
......@@ -41,11 +41,33 @@ class SearchApiString extends QueryTypePluginBase {
public function execute() {
$query = $this->query;
// Alter the query here.
if (!empty($query)) {
$options = &$query->getOptions();
$unfiltered_results = [];
// Only alter the query when there's an actual query object to alter.
if (!empty($query)) {
$operator = $this->facet->getQueryOperator();
$field_identifier = $this->facet->getFieldIdentifier();
$exclude = $this->facet->getExclude();
// Copy the query object so we can do an unfiltered query. We need to have
// this unfiltered results to make sure that the count of a facet is
// correct. The unfiltered results get returned to the facet manager, the
// facet manager will save it on facet::unfiltered_results.
$unfiltered_query = $query;
$unfiltered_options = &$unfiltered_query->getOptions();
$unfiltered_options['search_api_facets'][$field_identifier] = array(
'field' => $field_identifier,
'limit' => 50,
'operator' => 'and',
'min_count' => 0,
'missing' => FALSE,
);
$unfiltered_results = $unfiltered_query
->execute()
->getExtraData('search_api_facets');
// Set the options for the actual query.
$options = &$query->getOptions();
$options['search_api_facets'][$field_identifier] = array(
'field' => $field_identifier,
'limit' => 50,
......@@ -56,25 +78,36 @@ class SearchApiString extends QueryTypePluginBase {
// Add the filter to the query if there are active values.
$active_items = $this->facet->getActiveItems();
if (count($active_items)) {
$filter = $query->createConditionGroup($operator);
foreach ($active_items as $value) {
$filter = $query->createConditionGroup();
$filter->addCondition($this->facet->getFieldIdentifier(), $value);
$query->addConditionGroup($filter);
$filter->addCondition($this->facet->getFieldIdentifier(), $value, $exclude ? '<>' : '=');
}
$query->addConditionGroup($filter);
}
}
return $unfiltered_results;
}
/**
* {@inheritdoc}
*/
public function build() {
$query_operator = $this->facet->getQueryOperator();
if (!empty($this->results)) {
$facet_results = array();
foreach ($this->results as $result) {
if ($result['count']) {
$facet_results[] = new Result(trim($result['filter'], '"'), trim($result['filter'], '"'), $result['count']);
foreach ($this->results as $key => $result) {
if ($result['count'] || $query_operator == 'OR') {
$count = $result['count'];
if ($query_operator === 'OR') {
$count = $this->facet->getUnfilteredResults()[$this->facet->getFieldIdentifier()][$key]['count'];
}
$result = new Result(trim($result['filter'], '"'), trim($result['filter'], '"'), $count);
$facet_results[] = $result;
}
}
$this->facet->setResults($facet_results);
......
......@@ -2,31 +2,26 @@
/**
* @file
* Contains Drupal\facets\Plugin\facets\url_processor\UrlProcessorQueryString.
* Contains Drupal\facets\Plugin\facets\url_processor\QueryString.
*/
namespace Drupal\facets\Plugin\facets\processor;
namespace Drupal\facets\Plugin\facets\url_processor;
use Drupal\Core\Url;
use Drupal\facets\FacetInterface;
use Drupal\facets\Processor\UrlProcessorPluginBase;
use Drupal\facets\UrlProcessor\UrlProcessorPluginBase;
use Symfony\Component\HttpFoundation\Request;
/**
* The basic url processor, uses query strings.
* Query string URL processor.
*
* @FacetsProcessor(
* @FacetsUrlProcessor(
* id = "query_string",
* label = @Translation("Query string url processor"),
* description = @Translation("Most simple url processor which uses the query sting."),
* stages = {
* "pre_query" = 50,
* "build" = 15,
* },
* locked = true
* label = @Translation("Query string"),
* description = @Translation("Query string is the default Facets URL processor, and uses GET parameters, e.g. ?f[0]=brand:drupal&f[1]=color:blue")
* )
*/
class QueryStringUrlProcessor extends UrlProcessorPluginBase {
class QueryString extends UrlProcessorPluginBase {
/**
* A string that separates the filters in the query string.
......@@ -38,7 +33,7 @@ class QueryStringUrlProcessor extends UrlProcessorPluginBase {
*
* @var string
*/
protected $url_alias;
protected $urlAlias;
/**
* An array of active filters.
......@@ -59,22 +54,21 @@ class QueryStringUrlProcessor extends UrlProcessorPluginBase {
/**
* {@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();
public function buildUrls(FacetInterface $facet, array $results) {
// No results are found for this facet, so don't try to create urls.
if (empty($results)) {
return [];
}
// First get the current list of get parameters.
$get_params = $this->request->query;
// Set the url alias from the the facet object.
$this->urlAlias = $facet->getUrlAlias();
/** @var \Drupal\facets\Result\ResultInterface $result */
foreach ($results as &$result) {
$filter_string = $this->url_alias . ':' . $result->getRawValue();
$filter_string = $this->urlAlias . self::SEPARATOR . $result->getRawValue();
$result_get_params = clone $get_params;
$filter_params = $result_get_params->get($this->filterKey, [], TRUE);
......@@ -108,20 +102,20 @@ class QueryStringUrlProcessor extends UrlProcessorPluginBase {
/**
* {@inheritdoc}
*/
public function preQuery(FacetInterface $facet) {
public function setActiveItems(FacetInterface $facet) {
// Set the url alias from the the facet object.
$this->url_alias = $facet->getUrlAlias();
$this->urlAlias = $facet->getUrlAlias();
// Get the filter key of the facet.
if (isset($this->activeFilters[$this->url_alias])) {
foreach ($this->activeFilters[$this->url_alias] as $value) {
if (isset($this->activeFilters[$this->urlAlias])) {
foreach ($this->activeFilters[$this->urlAlias] as $value) {
$facet->setActiveItem(trim($value, '"'));
}
}
}
/**
* Initialize the active filters.
* Initializes 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
......
......@@ -7,10 +7,13 @@
namespace Drupal\facets\Plugin\facets\widget;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\facets\FacetInterface;
use Drupal\facets\Widget\WidgetInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* The checkbox / radios widget.
......@@ -21,18 +24,10 @@ use Drupal\facets\Widget\WidgetInterface;
* description = @Translation("A configurable widget that shows a list of checkboxes"),
* )
*/
class CheckboxWidget implements WidgetInterface {
class CheckboxWidget implements WidgetInterface, FormInterface {
use StringTranslationTrait;
/**
* The link generator.
*
* @var \Drupal\Core\Utility\LinkGeneratorInterface $linkGenerator
* The link generator.
*/
protected $linkGenerator;
/**
* {@inheritdoc}
*/
......@@ -44,33 +39,14 @@ class CheckboxWidget implements WidgetInterface {
* {@inheritdoc}
*/
public function build(FacetInterface $facet) {
/** @var \Drupal\facets\Result\Result[] $results */
$results = $facet->getResults();
$items = [];
$configuration = $facet->get('widget_configs');
$show_numbers = (bool) $configuration['show_numbers'];
$form_builder = \Drupal::getContainer()->get('form_builder');
foreach ($results as $result) {
if ($result->getCount()) {
// Get the link.
$text = $result->getDisplayValue();
if ($show_numbers) {
$text .= ' (' . $result->getCount() . ')';
}
if ($result->isActive()) {
$text = '(-) ' . $text;
}
$link = $this->linkGenerator()->generate($text, $result->getUrl());
$items[] = $link;
}
}
$build = [
'#theme' => 'item_list',
'#items' => $items,
];
// The form builder's getForm method accepts 1 argument in the interface,
// the form ID. Extra arguments get passed into the form states addBuildInfo
// method. This way we can pass the facet to the ::buildForm method, it uses
// FormState::getBuildInfo to get the facet out.
$build = $form_builder->getForm(static::class, $facet);
$build['#prefix'] = $this->t('Checkboxes');
return $build;
}
......@@ -102,16 +78,102 @@ class CheckboxWidget implements WidgetInterface {
}
/**
* Gets the link generator.
*
* @return \Drupal\Core\Utility\LinkGeneratorInterface
* The link generator.
* {@inheritdoc}
*/
protected function linkGenerator() {
if (!isset($this->linkGenerator)) {
$this->linkGenerator = \Drupal::linkGenerator();
public function getFormId() {
return 'facets_checkbox_widget';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
/** @var \Drupal\facets\FacetInterface $facet */
// Get the facet form the build info, see the remark in ::build to know
// where this comes from.
$build_info = $form_state->getBuildInfo();
$facet = $build_info['args'][0];
/** @var \Drupal\facets\Result\Result[] $results */
$results = $facet->getResults();
$configuration = $facet->getWidgetConfigs();
$show_numbers = (bool) (isset($configuration['show_numbers']) ? $configuration['show_numbers'] : FALSE);
$form[$facet->getFieldAlias()] = [
'#type' => 'checkboxes',
'#title' => $facet->getName(),
];
$options = array();
foreach ($results as $result) {
$text = $result->getDisplayValue();
if ($show_numbers) {
$text .= ' (' . $result->getCount() . ')';
}
$options[$result->getRawValue()] = $text;
if ($result->isActive()) {
$form[$facet->getFieldAlias()]['#default_value'][] = $result->getRawValue();
}
}
$form[$facet->getFieldAlias()]['#options'] = $options;
$form[$facet->id() . '_submit'] = [
'#type' => 'submit',
'#value' => 'submit',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValues();
/** @var \Drupal\facets\FacetInterface $facet */
$build_info = $form_state->getBuildInfo();
$facet = $build_info['args'][0];
$result_link = FALSE;
$active_items = [];
foreach ($values[$facet->getFieldAlias()] as $key => $value) {
if ($value !== 0) {
$active_items[] = $value;
}
}
return $this->linkGenerator;
foreach ($facet->getResults() as $result) {
if (in_array($result->getRawValue(), $active_items)) {
$result_link = $result->getUrl();
}
}
// We have an active item, so we redirect to the page that has that facet
// selected. This should be an absolute link because RedirectResponse is a
// symfony class that requires a full URL.
if ($result_link instanceof Url) {
$result_link->setAbsolute();
$form_state->setResponse(new RedirectResponse($result_link->toString()));
return;
}
// The form was submitted but nothing was active in the form, we should
// still redirect, but the url for the new page can't come from a result.
// So we're redirecting to the facet source's page.
$link = Url::fromUri($facet->getFacetSource()->getPath());
$link->setAbsolute();
$form_state->setResponse(new RedirectResponse($link->toString()));
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\facets\Plugin\facets\widget;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\facets\FacetInterface;
use Drupal\facets\Widget\WidgetInterface;
......@@ -25,14 +26,6 @@ class LinksWidget implements WidgetInterface {
use StringTranslationTrait;
/**
* The link generator.
*
* @var \Drupal\Core\Utility\LinkGeneratorInterface $linkGenerator
* The link generator.
*/
protected $linkGenerator;
/**
* {@inheritdoc}
*/
......@@ -48,32 +41,36 @@ class LinksWidget implements WidgetInterface {
$results = $facet->getResults();
$items = [];
$configuration = $facet->get('widget_configs');
$show_numbers = (bool) $configuration['show_numbers'];
$configuration = $facet->getWidgetConfigs();
$show_numbers = empty($configuration['show_numbers']) ? FALSE : (bool) $configuration['show_numbers'];
foreach ($results as $result) {
if ($result->getCount()) {
// Get the link.
$text = $result->getDisplayValue();
if ($show_numbers) {
$text .= ' (' . $result->getCount() . ')';
}
if ($result->isActive()) {
$text = '(-) ' . $text;
}
if (is_null($result->getUrl())) {
$items[] = $text;
}
else {
$items[] = $this->linkGenerator()->generate($text, $result->getUrl());
}
// Get the link.
$text = $result->getDisplayValue();
if ($show_numbers) {
$text .= ' (' . $result->getCount() . ')';
}
if ($result->isActive()) {
$text = '(-) ' . $text;
}
if (is_null($result->getUrl())) {
$items[] = $text;
}
else {
$items[] = new Link($text, $result->getUrl());
}
}
$build = [
'#theme' => 'item_list',
'#items' => $items,
'#cache' => [
'contexts' => [
'url.path',
'url.query_args',
],
],
];
return $build;
}
......@@ -107,17 +104,4 @@ class LinksWidget implements WidgetInterface {
return $query_types['string'];
}
/**
* Gets the link generator.
*
* @return \Drupal\Core\Utility\LinkGeneratorInterface
* The link generator.
*/
protected function linkGenerator() {
if (!isset($this->linkGenerator)) {
$this->linkGenerator = \Drupal::linkGenerator();
}
return $this->linkGenerator;
}
}
......@@ -16,7 +16,7 @@ use Drupal\facets\FacetInterface;
interface BuildProcessorInterface extends ProcessorInterface {
/**
* Processor runs before the renderable array is created.
* Runs before the renderable array is created.
*
* @param \Drupal\facets\FacetInterface $facet
* The facet being changed.
......
......@@ -14,7 +14,7 @@ namespace Drupal\facets\Processor;
interface PostQueryProcessorInterface extends ProcessorInterface {
/**
* Processor runs after the query was executed.
* Runs after the query was executed.
*
* Uses the query results and can alter those results, for example a
* ValueCallbackProcessor.
......
......@@ -15,7 +15,7 @@ use Drupal\facets\FacetInterface;
interface PreQueryProcessorInterface extends ProcessorInterface {
/**
* Processor runs before the query is executed.
* Runs before the query is executed.
*
* Uses the queryType and the facetSource implementation to make sure the
* alteration to the query was added before the query is executed in the
......
......@@ -28,8 +28,7 @@ class ProcessorPluginBase extends PluginBase implements ProcessorInterface {
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet) {
}
public function validateConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet) {}
/**
* {@inheritdoc}
......
......@@ -11,7 +11,7 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\facets\FacetInterface;
/**
* A base class for plugins that implements most of the boilerplate.
* A base class for plugins that implements some boilerplate for a widget order.
*/
abstract class WidgetOrderPluginBase extends ProcessorPluginBase implements WidgetOrderProcessorInterface {
......
......@@ -13,7 +13,7 @@ namespace Drupal\facets\Processor;
interface WidgetOrderProcessorInterface extends BuildProcessorInterface {
/**
* Order results and return the new order of results.
* Orders results and return the new order of results.
*
* @param \Drupal\facets\Result\Result[] $results
* An array containing results.
......
......@@ -12,12 +12,15 @@ namespace Drupal\facets\QueryType;
interface QueryTypeInterface {
/**
* Add facet info to the query using the backend native query object.
* Adds facet info to the query using the backend native query object.
*
* @return array
* Returns an array of unfiltered results
*/
public function execute();
/**
* Build the facet information, so it can be rendered.
* Builds the facet information, so it can be rendered.
*/
public function build();
......
......@@ -28,7 +28,7 @@ abstract class QueryTypePluginBase extends PluginBase implements QueryTypeInterf
}
/**
* Holds the backend native query object.
* The backend native query object.
*
* @var \Drupal\search_api\Query\Query $query
*/
......@@ -42,7 +42,7 @@ abstract class QueryTypePluginBase extends PluginBase implements QueryTypeInterf
protected $facet;
/**
* Holds the results for the facet.
* The results for the facet.
*
* @var \Drupal\facets\Result\ResultInterface[]
*/
......
......@@ -45,7 +45,7 @@ class Result implements ResultInterface {
protected $active = FALSE;
/**
* Construct a new instance of the value object.
* Constructs a new result value object.
*
* @param mixed $raw_value
* The raw value.
......
......@@ -15,7 +15,7 @@ use Drupal\Core\Url;
interface ResultInterface {
/**
* Get the raw value as present in the index.
* Returns the raw value as present in the index.
*
* @return string
* The raw value of the result.
......@@ -23,7 +23,7 @@ interface ResultInterface {
public function getRawValue();
/**
* Get the display value as present in the index.
* Returns the display value as present in the index.
*
* @return string
* The formatted value of the result.
......@@ -31,7 +31,7 @@ interface ResultInterface {
public function getDisplayValue();
/**
* Get the count for the result.
* Returns the count for the result.
*
* @return mixed
* The amount of items for the result.
......@@ -39,7 +39,7 @@ interface ResultInterface {
public function getCount();
/**
* Get the url.
* Returns the url.
*
* @return \Drupal\Core\Url
* The url of the search page with the facet url appended.
......@@ -47,7 +47,7 @@ interface ResultInterface {
public function getUrl();
/**
* Set the url.
* Sets the url.
*
* @param \Drupal\Core\Url $url
* The url of the search page with the facet url appended.
......@@ -55,7 +55,7 @@ interface ResultInterface {
public function setUrl(Url $url);
/**
* Indicate that the value is active (selected).
* Indicates that the value is active (selected).
*
* @param bool $active
* A boolean indicating the active state.
......@@ -71,7 +71,7 @@ interface ResultInterface {
public function isActive();
/**
* Override the display value of a result.
* Overrides the display value of a result.
*
* @param string $display_value
* Override display value.
......
......@@ -8,7 +8,6 @@
namespace Drupal\facets\Tests;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\Utility;
/**
* Contains helpers to create data that can be used by tests.
......@@ -36,44 +35,45 @@ trait ExampleContentTrait {
protected function insertExampleContent() {
$count = \Drupal::entityQuery('entity_test')->count()->execute();
$entity_test_storage = \Drupal::entityManager()->getStorage('entity_test');
$entity_test_storage = \Drupal::entityTypeManager()
->getStorage('entity_test');
$this->entities[1] = $entity_test_storage->create(array(
'name' => 'foo bar baz',
'body' => 'test test',
'type' => 'item',
'keywords' => array('orange'),
'category' => 'item_category'
));
'name' => 'foo bar baz',
'body' => 'test test',
'type' => 'item',
'keywords' => array('orange'),
'category' => 'item_category',
));
$this->entities[1]->save();
$this->entities[2] = $entity_test_storage->create(array(
'name' => 'foo test',
'body' => 'bar test',
'type' => 'item',
'keywords' => array('orange', 'apple', 'grape'),
'category' => 'item_category'
));
'name' => 'foo test',
'body' => 'bar test',
'type' => 'item',
'keywords' => array('orange', 'apple', 'grape'),
'category' => 'item_category',
));
$this->entities[2]->save();
$this->entities[3] = $entity_test_storage->create(array(
'name' => 'bar',
'body' => 'test foobar',
'type' => 'item',
));
'name' => 'bar',
'body' => 'test foobar',
'type' => 'item',
));
$this->entities[3]->save();
$this->entities[4] = $entity_test_storage->create(array(
'name' => 'foo baz',
'body' => 'test test test',
'type' => 'article',
'keywords' => array('apple', 'strawberry', 'grape'),
'category' => 'article_category'
));
'name' => 'foo baz',
'body' => 'test test test',
'type' => 'article',
'keywords' => array('apple', 'strawberry', 'grape'),
'category' => 'article_category',
));
$this->entities[4]->save();
$this->entities[5] = $entity_test_storage->create(array(
'name' => 'bar baz',
'body' => 'foo',
'type' => 'article',
'keywords' => array('orange', 'strawberry', 'grape', 'banana'),
'category' => 'article_category'
));
'name' => 'bar baz',
'body' => 'foo',
'type' => 'article',
'keywords' => array('orange', 'strawberry', 'grape', 'banana'),
'category' => 'article_category',
));
$this->entities[5]->save();
$count = \Drupal::entityQuery('entity_test')->count()->execute() - $count;
$this->assertEqual($count, 5, "$count items inserted.");
......@@ -89,37 +89,9 @@ trait ExampleContentTrait {
* The number of successfully indexed items.
*/
protected function indexItems($index_id) {
/** @var \Drupal\search_api\IndexInterface $index */
$index = Index::load($index_id);
return $index->indexItems();
}
/**
* Returns the internal field ID for the given entity field name.
*
* @param string $field_name
* The field name.
*
* @return string
* The internal field ID.
*/
protected function getFieldId($field_name) {
return Utility::createCombinedId('entity:entity_test', $field_name);
}
/**
* Returns the item IDs for the given entity IDs.
*
* @param array $entity_ids
* An array of entity IDs.
*
* @return string[]
* An array of item IDs.
*/
protected function getItemIds(array $entity_ids) {
$translate_ids = function ($entity_id) {
return Utility::createCombinedId('entity:entity_test', $entity_id . ':en');
};
return array_map($translate_ids, $entity_ids);
}
}