Skip to content
......@@ -7,8 +7,9 @@
namespace Drupal\facets;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
*
* The facet entity.
*/
interface FacetInterface extends ConfigEntityInterface {
......@@ -16,8 +17,10 @@ interface FacetInterface extends ConfigEntityInterface {
* Sets the facet's widget plugin id.
*
* @param string $widget
* The widget plugin id.
*
* @return $this
* Returns self
*/
public function setWidget($widget);
......@@ -25,142 +28,161 @@ interface FacetInterface extends ConfigEntityInterface {
* Returns the facet's widget plugin id.
*
* @return string
* The widget plugin id.
*/
public function getWidget();
/**
* Get field identifier.
* Returns field identifier.
*
* @return string
* The field identifier of this facet.
*/
public function getFieldIdentifier();
/**
* Set field identifier.
* Sets field identifier.
*
* @return mixed
* @param string $field_identifier
* The field identifier of this facet.
*
* @return $this
* Returns self.
*/
public function setFieldIdentifier($field_identifier);
/**
* Get the field alias used to identify the facet in the url.
* Returns the field alias used to identify the facet in the url.
*
* @return mixed
* @return string
* The field alias for the facet.
*/
public function getFieldAlias();
/**
* Get the field name of the facet as used in the index.
* Returns the field name of the facet as used in the index.
*
* @TODO: Check if fieldIdentifier can be used as well!
*
* @return mixed
* @return string
* The name of the facet.
*/
public function getName();
/**
* Returns the name of the facet for use in the URL.
*
* @return string
* The name of the facet for use in the URL.
*/
public function getUrlAlias();
/**
* Sets the name of the facet for use in the URL.
*
* @param string $url_alias
* The name of the facet for use in the URL.
*/
public function setUrlAlias($url_alias);
/**
* Sets an item with value to active.
*
* @param $value
* @param string $value
* An item that is active.
*/
public function setActiveItem($value);
/**
* Get all the active items in the facet.
* Returns all the active items in the facet.
*
* @return mixed
* An array containing all active items.
*/
public function getActiveItems();
/**
* Check if a value is active.
* Checks if a value is active.
*
* @param string $value
* The value to be checked.
*
* @return bool
* Is an active value.
*/
public function isActiveValue($value);
/**
* Get the result for the facet.
* Returns the result for the facet.
*
* @return \Drupal\facets\Result\ResultInterface[] $results
* The results of the facet.
*/
public function getResults();
/**
* Sets the reuslts for the facet.
* Sets the results for the facet.
*
* @param \Drupal\facets\Result\ResultInterface[] $results
* The results of the facet.
*/
public function setResults(array $results);
/**
* Get the query type instance.
* Sets an array of unfiltered results.
*
* @return string
*/
public function getQueryType();
/**
* Get the plugin name for the url processor.
* These unfiltered results are used to set the correct count of the actual
* facet results when using the OR query operator. They are not results value
* objects like those in ::$results.
*
* @return mixed
* @param array $all_results
* Unfiltered results.
*/
public function getUrlProcessorName();
public function setUnfilteredResults(array $all_results = []);
/**
* Retrieves an option.
*
* @param string $name
* The name of an option.
* @param mixed $default
* The value return if the option wasn't set.
*
* @return mixed
* The value of the option.
* Returns an array of unfiltered results.
*
* @see getOptions()
* @return array
* Unfiltered results.
*/
public function getOption($name, $default = NULL);
public function getUnfilteredResults();
/**
* Retrieves an array of all options.
* Returns the query type instance.
*
* @return array
* An associative array of option values, keyed by the option name.
* @return string
* The query type plugin being used.
*/
public function getOptions();
public function getQueryType();
/**
* Sets an option.
*
* @param string $name
* The name of an option.
* @param mixed $option
* The new option.
* Returns the query operator.
*
* @return $this
* @return string
* The query operator being used.
*/
public function setOption($name, $option);
public function getQueryOperator();
/**
* Sets the index's options.
* Returns the value of the exclude boolean.
*
* @param array $options
* The new index options.
* This will return true when the current facet's value should be exclusive
* from the search rather than inclusive.
* When this returns TRUE, the operator will be "<>" instead of "=".
*
* @return $this
* @return bool
* A boolean flag indicating if search should exlude selected facets
*/
public function setOptions(array $options);
public function getExclude();
/**
* Gets the facet manager plugin id.
* Returns the plugin name for the url processor.
*
* @return string
* The id of the url processor.
*/
public function getManagerPluginId();
public function getUrlProcessorName();
/**
* Sets a string representation of the Facet source plugin.
......@@ -168,32 +190,61 @@ interface FacetInterface extends ConfigEntityInterface {
* This is usually the name of the Search-api view.
*
* @param string $facet_source_id
* The facet source id.
*
* @return $this
* Returns self.
*/
public function setFacetSourceId($facet_source_id);
/**
* Sets the query operator.
*
* @param string $operator
* The query operator being used.
*/
public function setQueryOperator($operator);
/**
* Sets the exclude.
*
* @param bool $exclude
* A boolean flag indicating if search should exclude selected facets
*/
public function setExclude($exclude);
/**
* Returns the Facet source id.
*
* @return string
* The id of the facet source.
*/
public function getFacetSourceId();
/**
* Returns the plugin instance of a facet source.
*
* @return \Drupal\facets\FacetSource\FacetSourceInterface
* @return \Drupal\facets\FacetSource\FacetSourcePluginInterface
* The plugin instance for the facet source.
*/
public function getFacetSource();
/**
* Load the facet sources for this facet.
* Returns the facet source configuration object.
*
* @return \Drupal\facets\FacetSourceInterface
* A facet source configuration object.
*/
public function getFacetSourceConfig();
/**
* Loads the facet sources for this facet.
*
* @param bool|TRUE $only_enabled
* Only return enabled facet sources.
*
* @return \Drupal\facets\FacetSource\FacetSourceInterface[]
* @return \Drupal\facets\FacetSource\FacetSourcePluginInterface[]
* An array of facet sources.
*/
public function getFacetSources($only_enabled = TRUE);
......@@ -201,8 +252,10 @@ interface FacetInterface extends ConfigEntityInterface {
* Returns an array of processors with their configuration.
*
* @param bool|TRUE $only_enabled
* Only return enabled processors.
*
* @return \Drupal\facets\Processor\ProcessorInterface[]
* An array of processors.
*/
public function getProcessors($only_enabled = TRUE);
......@@ -223,6 +276,14 @@ interface FacetInterface extends ConfigEntityInterface {
*/
public function getProcessorsByStage($stage, $only_enabled = TRUE);
/**
* Retrieves this facets's processor configs.
*
* @return array
* An array of processors and their configs.
*/
public function getProcessorConfigs();
/**
* Sets the "only visible when facet source is visible" boolean flag.
*
......@@ -231,14 +292,80 @@ interface FacetInterface extends ConfigEntityInterface {
* does not show the facet source.
*
* @return $this
* Returns self.
*/
public function setOnlyVisibleWhenFacetSourceIsVisible($only_visible_when_facet_source_is_visible);
/**
* Returns the "only visible when facet source is visible" boolean flag.
*
* @return boolean
* @return bool
* True when the facet is only shown on a page with the facet source.
*/
public function getOnlyVisibleWhenFacetSourceIsVisible();
/**
* Adds a processor for this facet.
*
* @param array $processor
* An array definition for a processor.
*/
public function addProcessor(array $processor);
/**
* Removes a processor for this facet.
*
* @param string $processor_id
* The plugin id of the processor.
*/
public function removeProcessor($processor_id);
/**
* Defines the no-results behavior.
*
* @param array $behavior
* The definition of the behavior.
*/
public function setEmptyBehavior(array $behavior);
/**
* Returns the defined no-results behavior or NULL if none defined.
*
* @return array|NULL
* The behavior definition or NULL.
*/
public function getEmptyBehavior();
/**
* Returns the configuration of the selected widget.
*
* @return array
* The configuration settings for the widget.
*/
public function getWidgetConfigs();
/**
* Sets the configuration for the widget of this facet.
*
* @param array $widget_config
* The configuration settings for the widget.
*/
public function setWidgetConfigs(array $widget_config);
/**
* Returns any additional configuration for this facet, not defined above.
*
* @return array
* An array of additional configuration for the facet.
*/
public function getFacetConfigs();
/**
* Defines any additional configuration for this facet not defined above.
*
* @param array $facet_config
* An array of additional configuration for the facet.
*/
public function setFacetConfigs(array $facet_config);
}
......@@ -10,7 +10,7 @@ namespace Drupal\facets;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\facets\FacetSource\FacetSourceInterface;
use Drupal\Core\Link;
/**
* Builds a listing of facet entities.
......@@ -102,10 +102,10 @@ class FacetListBuilder extends ConfigEntityListBuilder {
),
'title' => array(
'data' => array(
'#type' => 'link',
'#title' => $entity->getName(),
'#suffix' => '<div>' . $entity->getFieldAlias() . ' - ' . $entity->getWidget() . '</div>',
) + $entity->urlInfo('edit-form')->toRenderArray(),
'#type' => 'link',
'#title' => $entity->getName(),
'#suffix' => '<div>' . $entity->getFieldAlias() . ' - ' . $entity->getWidget() . '</div>',
) + $entity->urlInfo('edit-form')->toRenderArray(),
'class' => array('search-api-title'),
),
'status' => array(
......@@ -120,7 +120,7 @@ class FacetListBuilder extends ConfigEntityListBuilder {
}
/**
* {@inheritdoc}
* Builds an array of facet sources for display in the overview.
*/
public function buildFacetSourceRow(array $facet_source = []) {
return array(
......@@ -135,7 +135,13 @@ class FacetListBuilder extends ConfigEntityListBuilder {
'status' => array(
'data' => '',
),
'operations' => array(),
'operations' => array(
'data' => Link::createFromRoute(
$this->t('Configure'),
'entity.facets_facet_source.edit_form',
['source_id' => $facet_source['id']]
)->toRenderable(),
),
),
'class' => array('facet-source'),
);
......@@ -154,8 +160,8 @@ class FacetListBuilder extends ConfigEntityListBuilder {
'#markup' => $this->t(
'You currently have no facet sources defined. You should start by adding a facet source before creating facets.<br />
An example of a facet source is a view based on Search API or a Search API page.
Other modules can also implement a facet source by providing a plugin that implements the FacetSourceInterface.'
)
Other modules can also implement a facet source by providing a plugin that implements the FacetSourcePluginInterface.'
),
];
}
......@@ -169,7 +175,9 @@ class FacetListBuilder extends ConfigEntityListBuilder {
'#rows' => array(),
'#empty' => $groups['lone_facets'] ? '' : $this->t('There are no facet sources or facets defined.'),
'#attributes' => array(
'id' => 'facets-groups-list',
'class' => array(
'facets-groups-list',
),
),
);
......@@ -216,7 +224,7 @@ class FacetListBuilder extends ConfigEntityListBuilder {
foreach ($facet_sources as $facet_source) {
$facet_source_groups[$facet_source['id']] = [
'facet_source' => $facet_source,
'facets' => []
'facets' => [],
];
foreach ($facets as $facet) {
......
......@@ -33,22 +33,32 @@ class DefaultFacetManager {
/**
* The query type plugin manager.
*
* @var \Drupal\facets\QueryType\QueryTypePluginManager
* The query type plugin manager.
*/
protected $query_type_plugin_manager;
protected $queryTypePluginManager;
/**
* The facet source plugin manager.
*
* @var FacetSourcePluginManager
* @var \Drupal\facets\FacetSource\FacetSourcePluginManager
*/
protected $facet_source_manager;
protected $facetSourcePluginManager;
/**
* The processor plugin manager.
*
* @var \Drupal\facets\Processor\ProcessorPluginManager
*/
protected $processor_plugin_manager;
protected $processorPluginManager;
/**
* The widget plugin manager.
*
* @var \Drupal\facets\Widget\WidgetPluginManager
*/
protected $widgetPluginManager;
/**
* An array of facets that are being rendered.
......@@ -92,42 +102,53 @@ class DefaultFacetManager {
* The id of the facet source.
*
* @var string
* @see \Drupal\facets\FacetSource\FacetSourceInterface
*
* @see \Drupal\facets\FacetSource\FacetSourcePluginInterface
*/
protected $facetsource_id;
protected $facetSourceId;
/**
* Set the search id.
* The entity storage for facets.
*
* @param string
* The id of the facet source.
* @var \Drupal\Core\Entity\EntityStorageInterface|object
*/
public function setFacetSourceId($facetsource_id) {
$this->facetsource_id = $facetsource_id;
}
protected $facetStorage;
/**
* Constructs a new instance of the DefaultFacetManager.
*
* @param \Drupal\facets\QueryType\QueryTypePluginManager $query_type_plugin_manager
* The query type plugin manager.
* @param \Drupal\facets\Widget\WidgetPluginManager $widget_plugin_manager
* The widget plugin manager.
* @param \Drupal\facets\FacetSource\FacetSourcePluginManager $facet_source_manager
* The facet source plugin manager.
* @param \Drupal\facets\Processor\ProcessorPluginManager $processor_plugin_manager
* The processor plugin manager.
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
* The entity type plugin manager.
*/
public function __construct(QueryTypePluginManager $query_type_plugin_manager, WidgetPluginManager $widget_plugin_manager, FacetSourcePluginManager $facet_source_manager, ProcessorPluginManager $processor_plugin_manager, EntityTypeManager $entity_type_manager) {
$this->query_type_plugin_manager = $query_type_plugin_manager;
$this->widget_plugin_manager = $widget_plugin_manager;
$this->facet_source_manager = $facet_source_manager;
$this->processor_plugin_manager = $processor_plugin_manager;
$this->facet_storage = $entity_type_manager->getStorage('facets_facet');
$this->queryTypePluginManager = $query_type_plugin_manager;
$this->widgetPluginManager = $widget_plugin_manager;
$this->facetSourcePluginManager = $facet_source_manager;
$this->processorPluginManager = $processor_plugin_manager;
$this->facetStorage = $entity_type_manager->getStorage('facets_facet');
// Immediately initialize the facets. This can be done directly because the
// only thing needed is the url.
$this->initFacets();
}
/**
* Sets the search id.
*
* @param string $facet_source_id
* The id of the facet source.
*/
public function setFacetSourceId($facet_source_id) {
$this->facetSourceId = $facet_source_id;
}
/**
* Allows the backend to add facet queries to its native query object.
*
......@@ -142,10 +163,16 @@ class DefaultFacetManager {
foreach ($this->facets as $facet) {
// Make sure we don't alter queries for facets with a different source.
if ($facet->getFacetSourceId() == $this->facetsource_id) {
if ($facet->getFacetSourceId() == $this->facetSourceId) {
/** @var \Drupal\facets\QueryType\QueryTypeInterface $query_type_plugin */
$query_type_plugin = $this->query_type_plugin_manager->createInstance($facet->getQueryType(), ['query' => $query, 'facet' => $facet]);
$query_type_plugin->execute();
$query_type_plugin = $this->queryTypePluginManager
->createInstance($facet->getQueryType(), ['query' => $query, 'facet' => $facet]);
$unfiltered_results = $query_type_plugin->execute();
// Save unfiltered results in facet.
if (!is_null($unfiltered_results)) {
$facet->setUnfilteredResults($unfiltered_results);
}
}
}
}
......@@ -157,16 +184,17 @@ class DefaultFacetManager {
* An array of enabled facets.
*/
public function getEnabledFacets() {
return $this->facet_storage->loadMultiple();
return $this->facetStorage->loadMultiple();
}
/**
* Get the ID of the facet source.
* Returns the ID of the facet source.
*
* @return string
* The id of the facet source.
*/
public function getFacetsourceId() {
return $this->facetsource_id;
public function getFacetSourceId() {
return $this->facetSourceId;
}
/**
......@@ -187,7 +215,7 @@ class DefaultFacetManager {
}
/**
* Initialize enabled facets.
* Initializes enabled facets.
*
* In this method all pre-query processors get called and their contents are
* executed.
......@@ -197,23 +225,20 @@ class DefaultFacetManager {
$this->facets = $this->getEnabledFacets();
foreach ($this->facets as $facet) {
foreach ($facet->getProcessors() as $processor) {
$processor_definition = $processor->getPluginDefinition();
if (is_array($processor_definition['stages']) && array_key_exists(ProcessorInterface::STAGE_PRE_QUERY, $processor_definition['stages'])) {
/** @var PreQueryProcessorInterface $pre_query_processor */
$pre_query_processor = $this->processor_plugin_manager->createInstance($processor->getPluginDefinition()['id']);
if (!$pre_query_processor instanceof PreQueryProcessorInterface) {
throw new InvalidProcessorException(new FormattableMarkup("The processor @processor has a pre_query definition but doesn't implement the required PreQueryProcessorInterface interface", ['@processor' => $processor_configuration['processor_id']]));
}
$pre_query_processor->preQuery($facet);
foreach ($facet->getProcessorsByStage(ProcessorInterface::STAGE_PRE_QUERY) as $processor) {
/** @var PreQueryProcessorInterface $pre_query_processor */
$pre_query_processor = $this->processorPluginManager->createInstance($processor->getPluginDefinition()['id'], ['facet' => $facet]);
if (!$pre_query_processor instanceof PreQueryProcessorInterface) {
throw new InvalidProcessorException(new FormattableMarkup("The processor @processor has a pre_query definition but doesn't implement the required PreQueryProcessorInterface interface", ['@processor' => $processor_configuration['processor_id']]));
}
$pre_query_processor->preQuery($facet);
}
}
}
}
/**
* Build a facet and returns it's render array.
* Builds a facet and returns it as a renderable array.
*
* This method delegates to the relevant plugins to render a facet, it calls
* out to a widget plugin to do the actual rendering when results are found.
......@@ -224,6 +249,7 @@ class DefaultFacetManager {
* BuildProcessorInterface enabled on this facet will run.
*
* @param \Drupal\facets\FacetInterface $facet
* The facet we should build.
*
* @return array
* Facet render arrays.
......@@ -236,7 +262,7 @@ class DefaultFacetManager {
$facet = $this->facets[$facet->id()];
// @TODO: inject the searcher id on create of the FacetManager.
$this->facetsource_id = $facet->getFacetSourceId();
$this->facetSourceId = $facet->getFacetSourceId();
if ($facet->getOnlyVisibleWhenFacetSourceIsVisible()) {
// Block rendering and processing should be stopped when the facet source
......@@ -260,33 +286,31 @@ class DefaultFacetManager {
// @see \Drupal\facets\Processor\WidgetOrderProcessorInterface.
$results = $facet->getResults();
foreach ($facet->getProcessors() as $processor) {
$processor_definition = $this->processor_plugin_manager->getDefinition($processor->getPluginDefinition()['id']);
if (is_array($processor_definition['stages']) && array_key_exists(ProcessorInterface::STAGE_BUILD, $processor_definition['stages'])) {
/** @var BuildProcessorInterface $build_processor */
$build_processor = $this->processor_plugin_manager->createInstance($processor->getPluginDefinition()['id']);
if (!$build_processor instanceof BuildProcessorInterface) {
throw new InvalidProcessorException(new FormattableMarkup("The processor @processor has a build definition but doesn't implement the required BuildProcessorInterface interface", ['@processor' => $processor['processor_id']]));
}
$results = $build_processor->build($facet, $results);
foreach ($facet->getProcessorsByStage(ProcessorInterface::STAGE_BUILD) as $processor) {
/** @var BuildProcessorInterface $build_processor */
$build_processor = $this->processorPluginManager->createInstance($processor->getPluginDefinition()['id'], ['facet' => $facet]);
if (!$build_processor instanceof BuildProcessorInterface) {
throw new InvalidProcessorException(new FormattableMarkup("The processor @processor has a build definition but doesn't implement the required BuildProcessorInterface interface", ['@processor' => $processor['processor_id']]));
}
$results = $build_processor->build($facet, $results);
}
$facet->setResults($results);
// No results behavior handling. Return a custom text or false depending on
// settings.
if (empty($facet->getResults())) {
$empty_behavior = $facet->getOption('empty_behavior');
if($empty_behavior['behavior'] == 'text'){
$empty_behavior = $facet->getEmptyBehavior();
if ($empty_behavior['behavior'] == 'text') {
return ['#markup' => $empty_behavior['text']];
}else{
}
else {
return;
}
}
// Let the widget plugin render the facet.
/** @var \Drupal\facets\Widget\WidgetInterface $widget */
$widget = $this->widget_plugin_manager->createInstance($facet->getWidget());
$widget = $this->widgetPluginManager->createInstance($facet->getWidget());
return $widget->build($facet);
}
......@@ -296,10 +320,29 @@ class DefaultFacetManager {
*/
public function updateResults() {
// Get an instance of the facet source.
/** @var \drupal\facets\FacetSource\FacetSourceInterface $facet_source_plugin */
$facet_source_plugin = $this->facet_source_manager->createInstance($this->facetsource_id);
/** @var \drupal\facets\FacetSource\FacetSourcePluginInterface $facet_source_plugin */
$facet_source_plugin = $this->facetSourcePluginManager->createInstance($this->facetSourceId);
$facet_source_plugin->fillFacetsWithResults($this->facets);
}
/**
* Returns one of the processed facets.
*
* Returns one of the processed facets, this is a facet with filled results.
* Keep in mind that if you want to have the facet's build processor executed,
* there needs to be an extra call to the FacetManager::build with the facet
* returned here as argument.
*
* @param string $facet_id
* The id of the facet.
*
* @return \Drupal\facets\FacetInterface|NULL
* The updated facet if it exists, NULL otherwise.
*/
public function returnProcessedFacet($facet_id) {
$this->processFacets();
return $this->facets[$facet_id];
}
}
......@@ -12,8 +12,9 @@ use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
*
* A base class for facet source derivers.
*/
abstract class FacetSourceDeriverBase implements ContainerDeriverInterface {
......@@ -81,7 +82,6 @@ abstract class FacetSourceDeriverBase implements ContainerDeriverInterface {
return isset($derivatives[$derivative_id]) ? $derivatives[$derivative_id] : NULL;
}
/**
* Compares two plugin definitions according to their labels.
*
......
<?php
/**+
/**
* @file
* Contains \Drupal\facets\FacetSource\FacetSourcePluginBase.
*/
......@@ -11,6 +11,8 @@ use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Facets\FacetInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Defines a base class from which other facet sources may extend.
......@@ -23,10 +25,10 @@ use Drupal\Facets\FacetInterface;
*
* @see \Drupal\facets\Annotation\FacetsFacetSource
* @see \Drupal\facets\FacetSource\FacetSourcePluginManager
* @see \Drupal\facets\FacetSource\FacetSourceInterface
* @see \Drupal\facets\FacetSource\FacetSourcePluginInterface
* @see plugin_api
*/
abstract class FacetSourcePluginBase extends PluginBase implements FacetSourceInterface, ContainerFactoryPluginInterface {
abstract class FacetSourcePluginBase extends PluginBase implements FacetSourcePluginInterface, ContainerFactoryPluginInterface {
/**
* The plugin manager.
......@@ -42,17 +44,23 @@ abstract class FacetSourcePluginBase extends PluginBase implements FacetSourceIn
*/
protected $keys;
/**
* The facet we're editing for.
*
* @var \Drupal\facets\FacetInterface
*/
protected $facet;
/**
* {@inheritdoc}
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
$query_type_plugin_manager
) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, $query_type_plugin_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->queryTypePluginManager = $query_type_plugin_manager;
if (isset($configuration['facet'])) {
$this->facet = $configuration['facet'];
}
}
/**
......@@ -101,4 +109,21 @@ abstract class FacetSourcePluginBase extends PluginBase implements FacetSourceIn
public function getSearchKeys() {
return $this->keys;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$facet_source_id = $this->facet->getFacetSourceId();
$field_identifier = $form_state->getValue('facet_source_configs')[$facet_source_id]['field_identifier'];
$this->facet->setFieldIdentifier($field_identifier);
}
}
......@@ -2,12 +2,12 @@
/**
* @file
* Contains \Drupal\facets\FacetSource\FacetSourceInterface.
* Contains \Drupal\facets\FacetSource\FacetSourcePluginInterface.
*/
namespace Drupal\facets\FacetSource;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\facets\FacetInterface;
/**
......@@ -15,49 +15,42 @@ use Drupal\facets\FacetInterface;
*
* A facet source is used to abstract the data source where facets can be added
* to. A good example of this is a search api view. There are other possible
* facet data sources, these all implement the FacetSourceInterface.
* facet data sources, these all implement the FacetSourcePluginInterface.
*
* @see plugin_api
*/
interface FacetSourceInterface {
interface FacetSourcePluginInterface extends PluginFormInterface {
/**
* Adds a configuration form for this facet source.
* Fills the facet entities with results from the facet source.
*
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
* @param \Drupal\facets\FacetInterface $facet
* @param \Drupal\facets\FacetSource\FacetSourceInterface $facet_source
* @param \Drupal\facets\FacetInterface[] $facets
* The configured facets.
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet, FacetSourceInterface $facet_source);
public function fillFacetsWithResults($facets);
/**
* Fill in facet data in to the configured facets.
* Returns the allowed query types for a given facet for the facet source.
*
* @param \Drupal\facets\FacetInterface[] $facets
* @param \Drupal\facets\FacetInterface $facet
* The facet we should get query types for.
*
* @return mixed
* @return string[]
* array of allowed query types
*
* @throws \Drupal\facets\Exception\Exception
* An error when no query types are found.
*/
public function fillFacetsWithResults($facets);
public function getQueryTypesForFacet(FacetInterface $facet);
/**
* Returns the path where a facet should link to.
*
* @return string
* The path of the facet.
*/
public function getPath();
/**
* Get the allowed query types for a given facet for the facet source.
*
* @param \Drupal\facets\FacetInterface $facet
*
* @return array of allowed query types
*
* @throws \Drupal\facets\Exception\Exception
*/
public function getQueryTypesForFacet(FacetInterface $facet);
/**
* Returns true if the Facet source is being rendered in the current request.
*
......@@ -65,7 +58,8 @@ interface FacetSourceInterface {
* when facet source visibility: "being rendered" is configured in the facet
* visibility settings.
*
* @return boolean
* @return bool
* True when the facet is rendered on the same page.
*/
public function isRenderedInCurrentRequest();
......@@ -76,6 +70,7 @@ interface FacetSourceInterface {
* is keyed by the field's machine name and has values of the field's label.
*
* @return array
* An array of available fields.
*/
public function getFields();
......@@ -91,7 +86,7 @@ interface FacetSourceInterface {
public function setSearchKeys($keys);
/**
* Gets the search keys, or query text, submitted by the user.
* Returns the search keys, or query text, submitted by the user.
*
* @return string
* The search keys, or query text, submitted by the user.
......
......@@ -21,18 +21,10 @@ use Drupal\Core\Plugin\DefaultPluginManager;
class FacetSourcePluginManager extends DefaultPluginManager {
/**
* Constructs a FacetSourcePluginManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* {@inheritdoc}
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct('Plugin/facets/facet_source', $namespaces, $module_handler, 'Drupal\facets\FacetSource\FacetSourceInterface', 'Drupal\facets\Annotation\FacetsFacetSource');
parent::__construct('Plugin/facets/facet_source', $namespaces, $module_handler, 'Drupal\facets\FacetSource\FacetSourcePluginInterface', 'Drupal\facets\Annotation\FacetsFacetSource');
}
}
<?php
/**
* @file
* Contains Drupal\facets\FacetSourceInterface.
*/
namespace Drupal\facets;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* The facet source entity.
*/
interface FacetSourceInterface extends ConfigEntityInterface {
/**
* Returns the label of the facet source.
*
* @return string
* The facet name.
*/
public function getName();
/**
* Returns the filter key for this facet source.
*
* @return string
* The filter key.
*/
public function getFilterKey();
/**
* Sets the filter key for this facet source.
*
* @param string $filter_key
* The filter key.
*/
public function setFilterKey($filter_key);
/**
* Sets 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();
}
......@@ -7,7 +7,6 @@
namespace Drupal\facets\Form;
use Drupal\block\Entity\Block;
use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
......@@ -42,17 +41,6 @@ class FacetDeleteConfirmForm extends EntityConfirmFormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$is_facet_used_by_block = $this->isFacetUsedBlock();
// The facet is currently used by a block so it can't be deleted.
if ($is_facet_used_by_block) {
$caption = '<p>' . $this->t("The facet is currently used in a block and thus can't be removed. Remove the block first.");
$form['#title'] = $this->getQuestion();
$form['description'] = array('#markup' => $caption);
return $form;
}
return parent::buildForm($form, $form_state);
}
......@@ -65,40 +53,4 @@ class FacetDeleteConfirmForm extends EntityConfirmFormBase {
$form_state->setRedirect('facets.overview');
}
/**
* Returns a boolean flag if deletion is safe according to the block module.
*
* If the block module is enabled and this facet is being used by a block,
* deletion is not safe. So to make sure that this facet can safely be
* deleted, we're first checking if the block module is enabled. If it isn't
* then deletion is safe. If it is, we're checking if the facet is in use by
* a block.
*
* @return bool
*/
protected function isFacetUsedBlock() {
// If the block module is not installed, we should automatically return
// false and go ahead with deletion.
if (!\Drupal::moduleHandler()->moduleExists('block')) {
return FALSE;
}
$is_facet_used_by_block = FALSE;
// Check if any blocks are currently using this facet.
$blocks = Block::loadMultiple();
foreach ($blocks as $block) {
if ($block->getPlugin() instanceof \Drupal\facets\Plugin\Block\FacetBlock) {
$facet_context_mapping = $block->getPlugin()->getConfiguration()['context_mapping']['facet'];
list(, $block_facet_uuid) = explode(':', $facet_context_mapping);
if ($this->entity->uuid() === $block_facet_uuid) {
$is_facet_used_by_block = TRUE;
}
}
}
return $is_facet_used_by_block;
}
}
......@@ -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;
......@@ -58,13 +59,13 @@ class FacetDisplayForm extends EntityForm {
* The entity manager.
* @param \Drupal\facets\Processor\ProcessorPluginManager $processor_plugin_manager
* The processor plugin manager.
* @param \Drupal\facets\Widget\WidgetPluginManager $widgetPluginManager
* @param \Drupal\facets\Widget\WidgetPluginManager $widget_plugin_manager
* The plugin manager for widgets.
*/
public function __construct(EntityTypeManager $entity_type_manager, ProcessorPluginManager $processor_plugin_manager, WidgetPluginManager $widgetPluginManager) {
public function __construct(EntityTypeManager $entity_type_manager, ProcessorPluginManager $processor_plugin_manager, WidgetPluginManager $widget_plugin_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->processorPluginManager = $processor_plugin_manager;
$this->widgetPluginManager = $widgetPluginManager;
$this->widgetPluginManager = $widget_plugin_manager;
}
/**
......@@ -86,7 +87,7 @@ class FacetDisplayForm extends EntityForm {
/**
* {@inheritdoc}
*/
public function getBaseFormID() {
public function getBaseFormId() {
return NULL;
}
......@@ -157,7 +158,7 @@ class FacetDisplayForm extends EntityForm {
'#ajax' => [
'trigger_as' => ['name' => 'widget_configure'],
'callback' => '::buildAjaxWidgetConfigForm',
'wrapper' => 'facet-api-widget-config-form',
'wrapper' => 'facets-widget-config-form',
'method' => 'replace',
'effect' => 'fade',
],
......@@ -165,7 +166,7 @@ class FacetDisplayForm extends EntityForm {
$form['widget_configs'] = [
'#type' => 'container',
'#attributes' => [
'id' => 'facet-api-widget-config-form',
'id' => 'facets-widget-config-form',
],
'#tree' => TRUE,
];
......@@ -177,7 +178,7 @@ class FacetDisplayForm extends EntityForm {
'#submit' => ['::submitAjaxWidgetConfigForm'],
'#ajax' => [
'callback' => '::buildAjaxWidgetConfigForm',
'wrapper' => 'facet-api-widget-config-form',
'wrapper' => 'facets-widget-config-form',
],
'#attributes' => ['class' => ['js-hide']],
];
......@@ -194,6 +195,7 @@ class FacetDisplayForm extends EntityForm {
else {
$all_processors = $form_state->get('processors');
}
$enabled_processors = $facet->getProcessors(TRUE);
$stages = $this->processorPluginManager->getProcessingStages();
$processors_by_stage = array();
......@@ -201,27 +203,28 @@ class FacetDisplayForm extends EntityForm {
$processors_by_stage[$stage] = $facet->getProcessorsByStage($stage, FALSE);
}
$processor_settings = $facet->getOption('processors');
$form['#tree'] = TRUE;
$form['#attached']['library'][] = 'search_api/drupal.search_api.index-active-formatters';
$form['#attached']['library'][] = 'facets/drupal.facets.index-active-formatters';
$form['#title'] = $this->t('Manage processors for facet %label', array('%label' => $facet->label()));
// Add the list of all other processors with checkboxes to enable/disable them.
// Add the list of all other processors with checkboxes to enable/disable
// them.
$form['facet_settings'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Facet settings'),
'#attributes' => array('class' => array(
'search-api-status-wrapper',
)),
'#attributes' => array(
'class' => array(
'search-api-status-wrapper',
),
),
);
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',
'#title' => (string) $processor->getPluginDefinition()['label'],
'#default_value' => $processor->isLocked() || !empty($processor_settings[$processor_id]),
'#default_value' => $processor->isLocked() || !empty($enabled_processors[$processor_id]),
'#description' => $processor->getDescription(),
'#attributes' => array(
'class' => array(
......@@ -233,18 +236,23 @@ class FacetDisplayForm extends EntityForm {
'#access' => !$processor->isHidden(),
);
$processor_form_state = new SubFormState($form_state, array('facet_settings', $processor_id, 'settings'));
$processor_form_state = new SubFormState(
$form_state,
['facet_settings', $processor_id, 'settings']
);
$processor_form = $processor->buildConfigurationForm($form, $processor_form_state, $facet);
if ($processor_form) {
$form['facet_settings'][$processor_id]['settings'] = array(
'#type' => 'details',
'#title' => $this->t('%processor settings', ['%processor' => (string) $processor->getPluginDefinition()['label']]),
'#open' => true,
'#attributes' => array('class' => array(
'facets-processor-settings-' . Html::cleanCssIdentifier($processor_id),
'facets-processor-settings-facet',
'facets-processor-settings'
),),
'#open' => TRUE,
'#attributes' => array(
'class' => array(
'facets-processor-settings-' . Html::cleanCssIdentifier($processor_id),
'facets-processor-settings-facet',
'facets-processor-settings',
),
),
'#states' => array(
'visible' => array(
':input[name="facet_settings[' . $processor_id . '][status]"]' => array('checked' => TRUE),
......@@ -255,21 +263,24 @@ class FacetDisplayForm extends EntityForm {
}
}
}
// Add the list of widget sort processors with checkboxes to enable/disable them.
// Add the list of widget sort processors with checkboxes to enable/disable
// them.
$form['facet_sorting'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Facet sorting'),
'#attributes' => array('class' => array(
'search-api-status-wrapper',
)),
'#attributes' => array(
'class' => array(
'search-api-status-wrapper',
),
),
);
foreach ($all_processors as $processor_id => $processor) {
if($processor instanceof WidgetOrderProcessorInterface){
if ($processor instanceof WidgetOrderProcessorInterface) {
$clean_css_id = Html::cleanCssIdentifier($processor_id);
$form['facet_sorting'][$processor_id]['status'] = array(
'#type' => 'checkbox',
'#title' => (string) $processor->getPluginDefinition()['label'],
'#default_value' => $processor->isLocked() || !empty($processor_settings[$processor_id]),
'#default_value' => $processor->isLocked() || !empty($enabled_processors[$processor_id]),
'#description' => $processor->getDescription(),
'#attributes' => array(
'class' => array(
......@@ -281,18 +292,22 @@ class FacetDisplayForm extends EntityForm {
'#access' => !$processor->isHidden(),
);
$processor_form_state = new SubFormState($form_state, array('facet_sorting', $processor_id, 'settings'));
$processor_form_state = new SubFormState(
$form_state,
array('facet_sorting', $processor_id, 'settings')
);
$processor_form = $processor->buildConfigurationForm($form, $processor_form_state, $facet);
if ($processor_form) {
$form['facet_sorting'][$processor_id]['settings'] = array(
'#type' => 'container',
// '#title' => $this->t('%processor settings', ['%processor' => (string) $processor->getPluginDefinition()['label']]),
'#open' => true,
'#attributes' => array('class' => array(
'facets-processor-settings-' . Html::cleanCssIdentifier($processor_id),
'facets-processor-settings-sorting',
'facets-processor-settings'
),),
'#open' => TRUE,
'#attributes' => array(
'class' => array(
'facets-processor-settings-' . Html::cleanCssIdentifier($processor_id),
'facets-processor-settings-sorting',
'facets-processor-settings',
),
),
'#states' => array(
'visible' => array(
':input[name="facet_sorting[' . $processor_id . '][status]"]' => array('checked' => TRUE),
......@@ -311,8 +326,7 @@ class FacetDisplayForm extends EntityForm {
'#default_value' => $facet->getOnlyVisibleWhenFacetSourceIsVisible(),
];
// Behavior for empty facets.
$empty_behavior_config = $facet->getOption('empty_behavior');
$empty_behavior_config = $facet->getEmptyBehavior();
$form['facet_settings']['empty_behavior'] = [
'#type' => 'radios',
'#title' => t('Empty facet behavior'),
......@@ -321,18 +335,36 @@ class FacetDisplayForm extends EntityForm {
'#description' => $this->t('The action to take when a facet has no items.'),
'#required' => TRUE,
];
$form['facet_settings']['empty_behavior_text'] = [
'#type' => 'text_format',
'#title' => $this->t('Empty text'),
'#format' => isset($empty_behavior_config['text_format']) ? $empty_behavior_config['text_format'] : 'plain_text',
'#editor' => true,
'#default_value' => isset($empty_behavior_config['text_format']) ? $empty_behavior_config['text'] : '',
$form['facet_settings']['empty_behavior_container'] = [
'#type' => 'container',
'#states' => array(
'visible' => array(
':input[name="facet_settings[empty_behavior]"]' => array('value' => 'text'),
),
),
];
$form['facet_settings']['empty_behavior_container']['empty_behavior_text'] = [
'#type' => 'text_format',
'#title' => $this->t('Empty text'),
'#format' => isset($empty_behavior_config['text_format']) ? $empty_behavior_config['text_format'] : 'plain_text',
'#editor' => TRUE,
'#default_value' => isset($empty_behavior_config['text_format']) ? $empty_behavior_config['text'] : '',
];
$form['facet_settings']['query_operator'] = [
'#type' => 'radios',
'#title' => $this->t('Operator'),
'#options' => ['OR' => $this->t('OR'), 'AND' => $this->t('AND')],
'#description' => $this->t('AND filters are exclusive and narrow the result set. OR filters are inclusive and widen the result set.'),
'#default_value' => $facet->getQueryOperator(),
];
$form['facet_settings']['exclude'] = [
'#type' => 'checkbox',
'#title' => $this->t('Exclude'),
'#description' => $this->t('Make the search exclude selected facets, instead of restricting it to them.'),
'#default_value' => $facet->getExclude(),
];
$form['weights'] = array(
'#type' => 'details',
......@@ -346,13 +378,15 @@ class FacetDisplayForm extends EntityForm {
// Order enabled processors per stage, create all the containers for the
// different stages.
foreach ($stages as $stage => $description) {
$form['weights'][$stage] = array (
$form['weights'][$stage] = array(
'#type' => 'fieldset',
'#title' => $description['label'],
'#attributes' => array('class' => array(
'search-api-stage-wrapper',
'search-api-stage-wrapper-' . Html::cleanCssIdentifier($stage),
)),
'#attributes' => array(
'class' => array(
'search-api-stage-wrapper',
'search-api-stage-wrapper-' . Html::cleanCssIdentifier($stage),
),
),
);
$form['weights'][$stage]['order'] = array(
'#type' => 'table',
......@@ -364,6 +398,8 @@ class FacetDisplayForm extends EntityForm {
);
}
$processor_settings = $facet->getProcessorConfigs();
// Fill in the containers previously created with the processors that are
// enabled on the facet.
foreach ($processors_by_stage as $stage => $processors) {
......@@ -389,9 +425,11 @@ class FacetDisplayForm extends EntityForm {
'#title_display' => 'invisible',
'#default_value' => $weight,
'#parents' => array('processors', $processor_id, 'weights', $stage),
'#attributes' => array('class' => array(
'search-api-processor-weight-' . Html::cleanCssIdentifier($stage),
)),
'#attributes' => array(
'class' => array(
'search-api-processor-weight-' . Html::cleanCssIdentifier($stage),
),
),
);
}
}
......@@ -422,16 +460,22 @@ class FacetDisplayForm extends EntityForm {
// Iterate over all processors that have a form and are enabled.
foreach ($form['facet_settings'] as $processor_id => $processor_form) {
if (!empty($values['status'][$processor_id])) {
$processor_form_state = new SubFormState($form_state, array('facet_settings', $processor_id, 'settings'));
$processors[$processor_id]->validateConfigurationForm($form['facet_settings'][$processor_id], $processor_form_state);
if (!empty($values['processors'][$processor_id])) {
$processor_form_state = new SubFormState(
$form_state,
array('facet_settings', $processor_id, 'settings')
);
$processors[$processor_id]->validateConfigurationForm($form['facet_settings'][$processor_id], $processor_form_state, $facet);
}
}
// Iterate over all sorting processors that have a form and are enabled.
foreach ($form['facet_sorting'] as $processor_id => $processor_form) {
if (!empty($values['status'][$processor_id])) {
$processor_form_state = new SubFormState($form_state, array('facet_sorting', $processor_id, 'settings'));
$processors[$processor_id]->validateConfigurationForm($form['facet_sorting'][$processor_id], $processor_form_state);
if (!empty($values['processors'][$processor_id])) {
$processor_form_state = new SubFormState(
$form_state,
array('facet_sorting', $processor_id, 'settings')
);
$processors[$processor_id]->validateConfigurationForm($form['facet_sorting'][$processor_id], $processor_form_state, $facet);
}
}
}
......@@ -441,12 +485,10 @@ class FacetDisplayForm extends EntityForm {
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValues();
$new_settings = array();
// Store processor settings.
// @todo Go through all available processors, enable/disable with method on
// processor plugin to allow reaction.
/** @var \Drupal\facets\FacetInterface $facet */
$facet = $this->entity;
......@@ -455,47 +497,61 @@ class FacetDisplayForm extends EntityForm {
foreach ($processors as $processor_id => $processor) {
$form_container_key = $processor instanceof WidgetOrderProcessorInterface ? 'facet_sorting' : 'facet_settings';
if (empty($values[$form_container_key][$processor_id]['status'])) {
$facet->removeProcessor($processor_id);
continue;
}
$new_settings[$processor_id] = array(
$new_settings = array(
'processor_id' => $processor_id,
'weights' => array(),
'settings' => array(),
);
$processor_values = $values[$form_container_key][$processor_id];
if (!empty($processor_values['weights'])) {
$new_settings[$processor_id]['weights'] = $processor_values['weights'];
if (!empty($values['processors'][$processor_id]['weights'])) {
$new_settings['weights'] = $values['processors'][$processor_id]['weights'];
}
if (isset($form[$form_container_key][$processor_id]['settings'])) {
$processor_form_state = new SubFormState($form_state, array($form_container_key, $processor_id, 'settings'));
$processor_form_state = new SubFormState(
$form_state,
array($form_container_key, $processor_id, 'settings')
);
$processor->submitConfigurationForm($form[$form_container_key][$processor_id]['settings'], $processor_form_state, $facet);
$new_settings[$processor_id]['settings'] = $processor->getConfiguration();
$new_settings['settings'] = $processor->getConfiguration();
}
$facet->addProcessor($new_settings);
}
// Sort the processors so we won't have unnecessary changes.
ksort($new_settings);
$facet->setOption('processors', $new_settings);
$facet->setWidget($form_state->getValue('widget'));
$facet->set('widget_configs', $form_state->getValue('widget_configs'));
$facet->set('only_visible_when_facet_source_is_visible', $form_state->getValue(['facet_settings','only_visible_when_facet_source_is_visible']));
$facet->setWidgetConfigs($form_state->getValue('widget_configs'));
$facet->setOnlyVisibleWhenFacetSourceIsVisible($form_state->getValue(['facet_settings', 'only_visible_when_facet_source_is_visible']));
$empty_behavior_config = [];
$empty_behavior = $form_state->getValue(['facet_settings', 'empty_behavior']);
$empty_behavior_config['behavior'] = $empty_behavior;
if($empty_behavior == 'text'){
$empty_behavior_config['text_format'] = $form_state->getValue(['facet_settings', 'empty_behavior_text', 'format']);
$empty_behavior_config['text'] = $form_state->getValue(['facet_settings', 'empty_behavior_text', 'value']);
if ($empty_behavior == 'text') {
$empty_behavior_config['text_format'] = $form_state->getValue([
'facet_settings',
'empty_behavior_container',
'empty_behavior_text',
'format',
]);
$empty_behavior_config['text'] = $form_state->getValue([
'facet_settings',
'empty_behavior_container',
'empty_behavior_text',
'value',
]);
}
$facet->setOption('empty_behavior', $empty_behavior_config);
$facet->setEmptyBehavior($empty_behavior_config);
$facet->setQueryOperator($form_state->getValue(['facet_settings', 'query_operator']));
$facet->setExclude($form_state->getValue(['facet_settings', 'exclude']));
$facet->save();
drupal_set_message(t('Facet %name has been updated.', ['%name' => $facet->getName()]));
}
/**
* Form submission handler for the widget subform.
* Handles form submissions for the widget subform.
*/
public function submitAjaxWidgetConfigForm($form, FormStateInterface $form_state) {
$form_state->setRebuild();
......
......@@ -10,7 +10,6 @@ namespace Drupal\facets\Form;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\facets\Exception\Exception;
use Drupal\facets\FacetInterface;
use Drupal\facets\FacetSource\FacetSourcePluginManager;
use Drupal\facets\Processor\ProcessorPluginManager;
......@@ -23,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
class FacetForm extends EntityForm {
/**
* The facet storage controller.
* The facet storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
......@@ -48,15 +47,15 @@ class FacetForm extends EntityForm {
*
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
* The entity manager.
* @param \Drupal\facets\FacetSource\FacetSourcePluginManager $facetSourcePluginManager
* @param \Drupal\facets\FacetSource\FacetSourcePluginManager $facet_source_plugin_manager
* The plugin manager for facet sources.
* @param \Drupal\facets\Processor\ProcessorPluginManager $processorPluginManager
* @param \Drupal\facets\Processor\ProcessorPluginManager $processor_plugin_manager
* The plugin manager for processors.
*/
public function __construct(EntityTypeManager $entity_type_manager, FacetSourcePluginManager $facetSourcePluginManager, ProcessorPluginManager $processorPluginManager) {
public function __construct(EntityTypeManager $entity_type_manager, FacetSourcePluginManager $facet_source_plugin_manager, ProcessorPluginManager $processor_plugin_manager) {
$this->facetStorage = $entity_type_manager->getStorage('facets_facet');
$this->facetSourcePluginManager = $facetSourcePluginManager;
$this->processorPluginManager = $processorPluginManager;
$this->facetSourcePluginManager = $facet_source_plugin_manager;
$this->processorPluginManager = $processor_plugin_manager;
}
/**
......@@ -75,22 +74,6 @@ class FacetForm extends EntityForm {
return new static($entity_type_manager, $facet_source_plugin_manager, $processor_plugin_manager);
}
/**
* Gets the form entity.
*
* The form entity which has been used for populating form element defaults.
* This method is defined on the \Drupal\Core\Entity\EntityFormInterface and
* has the same contents there, we only extend to add the correct return type,
* this makes IDE's smarter about the other places where we use
* $this->getEntity().
*
* @return \Drupal\facets\FacetInterface
* The current form facet entity.
*/
public function getEntity() {
return $this->entity;
}
/**
* Retrieves the facet storage controller.
*
......@@ -174,6 +157,18 @@ class FacetForm extends EntityForm {
],
];
$form['url_alias'] = [
'#type' => 'machine_name',
'#title' => $this->t('The name of the facet for usage in URLs'),
'#default_value' => $facet->getUrlAlias(),
'#maxlength' => 50,
'#required' => TRUE,
'#machine_name' => [
'exists' => [$this->getFacetStorage(), 'load'],
'source' => ['name'],
],
];
$facet_sources = [];
foreach ($this->getFacetSourcePluginManager()->getDefinitions() as $facet_source_id => $definition) {
$facet_sources[$definition['id']] = !empty($definition['label']) ? $definition['label'] : $facet_source_id;
......@@ -214,8 +209,6 @@ class FacetForm extends EntityForm {
];
$this->buildFacetSourceConfigForm($form, $form_state);
$form['status'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enabled'),
......@@ -225,9 +218,10 @@ class FacetForm extends EntityForm {
}
/**
* Form submission handler for the facet source subform.
* Handles form submissions for the facet source subform.
*/
public function submitAjaxFacetSourceConfigForm($form, FormStateInterface $form_state) {
$form_state->setValue('id', NULL);
$form_state->setRebuild();
}
......@@ -250,10 +244,10 @@ class FacetForm extends EntityForm {
$facet_source_id = $this->getEntity()->getFacetSourceId();
if (!is_null($facet_source_id) && $facet_source_id !== '') {
/** @var \Drupal\facets\FacetSource\FacetSourceInterface $facet_source */
$facet_source = $this->getFacetSourcePluginManager()->createInstance($facet_source_id);
/** @var \Drupal\facets\FacetSource\FacetSourcePluginInterface $facet_source */
$facet_source = $this->getFacetSourcePluginManager()->createInstance($facet_source_id, ['facet' => $this->getEntity()]);
if ($config_form = $facet_source->buildConfigurationForm([], $form_state, $this->getEntity(), $facet_source)) {
if ($config_form = $facet_source->buildConfigurationForm([], $form_state)) {
$form['facet_source_configs'][$facet_source_id]['#type'] = 'container';
$form['facet_source_configs'][$facet_source_id]['#title'] = $this->t('%plugin settings', ['%plugin' => $facet_source->getPluginDefinition()['label']]);
$form['facet_source_configs'][$facet_source_id] += $config_form;
......@@ -266,6 +260,13 @@ class FacetForm extends EntityForm {
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
$facet_source_id = $form_state->getValue('facet_source_id');
if (!is_null($facet_source_id) && $facet_source_id !== '') {
/** @var \Drupal\facets\FacetSource\FacetSourcePluginInterface $facet_source */
$facet_source = $this->getFacetSourcePluginManager()->createInstance($facet_source_id, ['facet' => $this->getEntity()]);
$facet_source->validateConfigurationForm($form, $form_state);
}
}
/**
......@@ -280,51 +281,49 @@ class FacetForm extends EntityForm {
if ($is_new) {
// On facet creation, enable all locked processors by default, using their
// default settings.
$initial_settings = [];
$stages = $this->getProcessorPluginManager()->getProcessingStages();
$processors_definitions = $this->getProcessorPluginManager()->getDefinitions();
foreach ($processors_definitions as $processor_id => $processor) {
if (isset($processor['locked']) && $processor['locked'] == TRUE) {
$weights = [];
foreach($stages as $stage_id => $stage) {
if(isset($processor['stages'][$stage_id])) {
foreach ($stages as $stage_id => $stage) {
if (isset($processor['stages'][$stage_id])) {
$weights[$stage_id] = $processor['stages'][$stage_id];
}
}
$initial_settings[$processor_id] = array(
$facet->addProcessor([
'processor_id' => $processor_id,
'weights' => $weights,
'settings' => [],
);
]);
}
}
$facet->setOption('processors', $initial_settings);
// Set a default widget for new facets.
$facet->setWidget('links');
// Set default empty behaviour
$facet->setOption('empty_behavior', ['behavior' => 'none']);
// Set default empty behaviour.
$facet->setEmptyBehavior(['behavior' => 'none']);
$facet->setOnlyVisibleWhenFacetSourceIsVisible(TRUE);
}
// Make sure the field identifier is copied from within the facet source
// config to the facet object and saved there.
$facet_source = $form_state->getValue('facet_source_id');
$field_identifier = $form_state->getValue('facet_source_configs')[$facet_source]['field_identifier'];
$facet->setFieldIdentifier($field_identifier);
$facet_source_id = $form_state->getValue('facet_source_id');
if (!is_null($facet_source_id) && $facet_source_id !== '') {
/** @var \Drupal\facets\FacetSource\FacetSourcePluginInterface $facet_source */
$facet_source = $this->getFacetSourcePluginManager()->createInstance($facet_source_id, ['facet' => $this->getEntity()]);
$facet_source->submitConfigurationForm($form, $form_state);
}
$facet->save();
// Ensure that the caching of the view display is disabled, so the search
// correctly returns the facets. This is a temporary fix, until the cache
// metadata is correctly stored on the facet block. Only apply this when the
// facet source type is actually something this is related to views.
list($type,) = explode(':', $facet_source);
list($type,) = explode(':', $facet_source_id);
if ($type === 'search_api_views') {
list(, $view_id, $display) = explode(':', $facet_source);
list(, $view_id, $display) = explode(':', $facet_source_id);
}
if (isset($view_id)) {
......@@ -337,12 +336,14 @@ class FacetForm extends EntityForm {
if ($is_new) {
if (\Drupal::moduleHandler()->moduleExists('block')) {
$message = $this->t('Facet %name has been created. Go to the <a href=":block_overview">Block overview page</a> and add a new "Facet block". If this is your first and only facet, just adding that block make it link to this facet, if you have addded more facets already, please make sure to select the correct Facet to render.', ['%name' => $facet->getName(), ':block_overview' => \Drupal::urlGenerator()->generateFromRoute('block.admin_display')]);
$message = $this->t('Facet %name has been created. Go to the <a href=":block_overview">Block overview page</a> to place the new block in the desired region.', ['%name' => $facet->getName(), ':block_overview' => \Drupal::urlGenerator()->generateFromRoute('block.admin_display')]);
drupal_set_message($message);
$form_state->setRedirect('entity.facets_facet.display_form', ['facets_facet' => $facet->id()]);
}
}else{
}
else {
drupal_set_message(t('Facet %name has been updated.', ['%name' => $facet->getName()]));
$form_state->setRedirect('entity.facets_facet.edit_form', ['facets_facet' => $facet->id()]);
}
return $facet;
......
<?php
/**
* @file
* Contains \Drupal\facets\Form\FacetSourceEditForm.
*/
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.
*
* Configuration saved trough this form is specific for a facet source and can
* be used by all facets on this facet source.
*/
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.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\facets\UrlProcessor\UrlProcessorPluginManager $url_processor_plugin_manager
* The url processor plugin manager.
*/
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.
$source_id = $this->getRequest()->get('source_id');
$source_id = str_replace(':', '__', $source_id);
$facet_source = $facet_source_storage->load($source_id);
if ($facet_source instanceof FacetSource) {
$this->setEntity($facet_source);
}
else {
// We didn't have a facet source config entity yet for this facet source
// plugin, so we create it on the fly.
$facet_source = new FacetSource(
[
'id' => $source_id,
'name' => $this->getRequest()->get('source_id'),
],
'facets_facet_source'
);
$facet_source->save();
$this->setEntity($facet_source);
}
$this->setModuleHandler(\Drupal::moduleHandler());
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'facet_source_edit_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
/** @var \Drupal\facets\FacetSourceInterface $facet_source */
$facet_source = $this->getEntity();
$form['filter_key'] = [
'#type' => 'textfield',
'#title' => $this->t('Filter key'),
'#size' => 20,
'#maxlength' => 255,
'#default_value' => $facet_source->getFilterKey(),
'#description' => $this->t(
'The key used in the url to identify the facet source.
When using multiple facet sources you should make sure each facet source has a different filter key.'
),
];
$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['url_processor'] = [
'#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.') . '<br />- ' . implode('<br>- ', $url_processors_description),
];
// The parent's form build method will add a save button.
return parent::buildForm($form, $form_state);
}
}
......@@ -515,8 +515,9 @@ class SubFormState implements FormStateInterface {
/**
* {@inheritdoc}
*
* @todo What are groups? Is this the way to handle them in a sub-form?
*/
// @todo What are groups? Is this the way to handle them in a sub-form?
public function setGroups(array $groups) {
$this->mainFormState->setGroups($groups);
return $this;
......
......@@ -3,40 +3,43 @@
/**
* @file
* Contains Drupal\facets\Plugin\Block\FacetBlock.
*
* NOTE: There should be a facetblock or settings for the facets later.
*/
namespace Drupal\facets\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\facets\FacetManager\DefaultFacetManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a 'FacetBlock' block.
* Exposes a facet rendered as a block.
*
* @Block(
* id = "facet_block",
* admin_label = @Translation("Facet block"),
* context = {
* "facet" = @ContextDefinition("entity:facets_facet", label=@Translation("Facet"))
* }
* id = "facet_block",
* deriver = "Drupal\facets\Plugin\Block\FacetBlockDeriver"
* )
*
*/
class FacetBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The facet_manager plugin manager.
* The facet manager.
*
* @var \Drupal\facets\FacetManager\DefaultFacetManager
*/
protected $facetManager;
/**
* Construct.
* The entity storage used for facets.
*
* @var \Drupal\Core\Entity\EntityStorageInterface $facetStorage
*/
protected $facetStorage;
/**
* Construct a FacetBlock instance.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
......@@ -44,10 +47,14 @@ class FacetBlock extends BlockBase implements ContainerFactoryPluginInterface {
* The plugin_id for the plugin instance.
* @param string $plugin_definition
* The plugin implementation definition.
* @param \Drupal\facets\FacetManager\DefaultFacetManager $facetManager
* @param \Drupal\facets\FacetManager\DefaultFacetManager $facet_manager
* The facet manager.
* @param \Drupal\Core\Entity\EntityStorageInterface $facet_storage
* The entity storage used for facets.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, \Drupal\facets\FacetManager\DefaultFacetManager $facetManager) {
$this->facetManager = $facetManager;
public function __construct(array $configuration, $plugin_id, $plugin_definition, DefaultFacetManager $facet_manager, EntityStorageInterface $facet_storage) {
$this->facetManager = $facet_manager;
$this->facetStorage = $facet_storage;
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
......@@ -55,15 +62,17 @@ class FacetBlock extends BlockBase implements ContainerFactoryPluginInterface {
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
/** @var \Drupal\facets\FacetManager\DefaultFacetManager $facetManager */
$facetManager = $container->get('facets.manager');
/** @var \Drupal\facets\FacetManager\DefaultFacetManager $facet_manager */
$facet_manager = $container->get('facets.manager');
/** @var \Drupal\Core\Entity\EntityStorageInterface $facet_storage */
$facet_storage = $container->get('entity_type.manager')->getStorage('facets_facet');
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$facetManager
$facet_manager,
$facet_storage
);
}
......@@ -71,17 +80,22 @@ class FacetBlock extends BlockBase implements ContainerFactoryPluginInterface {
* {@inheritdoc}
*/
public function build() {
/** @var Facet $facet */
$facet = $this->getContextValue('facet');
// The id saved in the configuration is in the format of
// base_plugin:facet_id. We're splitting that to get to the facet id.
$facet_mapping = $this->configuration['id'];
$facet_id = explode(PluginBase::DERIVATIVE_SEPARATOR, $facet_mapping)[1];
/** @var \Drupal\facets\FacetInterface $facet */
$facet = $this->facetStorage->load($facet_id);
// Let the facet_manager build the facets.
$build = $this->facetManager->build($facet);
// Add contextual links only when we have results.
if (!empty($build)) {
$build['#contextual_links']['facets_facet'] = array(
'route_parameters' => array('facets_facet' => $facet->id()),
);
$build['#contextual_links']['facets_facet'] = [
'route_parameters' => ['facets_facet' => $facet->id()],
];
}
return $build;
......@@ -90,18 +104,49 @@ class FacetBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
parent::blockSubmit($form, $form_state);
$this->configuration['facet_identifier'] = $form_state->getValue('facet_identifier');
public function getCacheMaxAge() {
// A facet block cannot be cached, because it must always match the current
// search results, and Search API gets those search results from a data
// source that can be external to Drupal. Therefore it is impossible to
// guarantee that the search results are in sync with the data managed by
// Drupal. Consequently, it is not possible to cache the search results at
// all. If the search results cannot be cached, then neither can the facets,
// because they must always match.
// Fortunately, facet blocks are rendered using a lazy builder (like all
// blocks in Drupal), which means their rendering can be deferred (unlike
// the search results, which are the main content of the page, and deferring
// their rendering would mean sending an empty page to the user). This means
// that facet blocks can be rendered and sent *after* the initial page was
// loaded, by installing the BigPipe (big_pipe) module.
//
// When BigPipe is enabled, the search results will appear first, and then
// each facet block will appear one-by-one, in DOM order.
// See https://www.drupal.org/project/big_pipe.
//
// In a future version of Facet API, this could be refined, but due to the
// reliance on external data sources, it will be very difficult if not
// impossible to improve this significantly.
//
// Note: when using Drupal core's Search module instead of the contributed
// Search API module, the above limitations do not apply, but for now it is
// not considered worth the effort to optimize this just for Drupal core's
// Search.
return 0;
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
// Makes sure a facet block is never cached.
// @TODO Make blocks cacheable, see: https://www.drupal.org/node/2581629
return 0;
public function calculateDependencies() {
// The ID saved in the configuration is of the format
// 'base_plugin:facet_id'. We're splitting that to get to the facet ID.
$facet_mapping = $this->configuration['id'];
$facet_id = explode(PluginBase::DERIVATIVE_SEPARATOR, $facet_mapping)[1];
/** @var \Drupal\facets\FacetInterface $facet */
$facet = $this->facetStorage->load($facet_id);
return ['config' => [$facet->getConfigDependencyName()]];
}
}
<?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();
}
}
......@@ -11,12 +11,11 @@ use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\facets\Exception\InvalidQueryTypeException;
use Drupal\facets\FacetInterface;
use Drupal\search_api\Backend\BackendInterface;
use Drupal\facets\FacetSource\FacetSourceInterface;
use Drupal\facets\FacetSource\FacetSourcePluginBase;
use Drupal\search_api\FacetsQueryTypeMappingInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
*
* A base class for Search API facet sources.
*/
abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
......@@ -65,7 +64,7 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet, FacetSourceInterface $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()]));
}
......@@ -121,7 +121,6 @@ abstract class SearchApiBaseFacetSource extends FacetSourcePluginBase {
*
* @param \Drupal\search_api\Backend\BackendInterface $backend
* The backend that we want to get the query types for.
*
* @param string $data_type_plugin_id
* The identifier of the data type.
*
......
......@@ -75,9 +75,7 @@ class SearchApiViewsPage extends SearchApiBaseFacetSource {
public function getPath() {
$view = Views::getView($this->pluginDefinition['view_id']);
$view->setDisplay($this->pluginDefinition['view_display']);
$view->execute();
return $view->getDisplay()->getOption('path');
return $view->getDisplay()->getPath();
}
/**
......
......@@ -35,15 +35,15 @@ class SearchApiViewsPageDeriver extends FacetSourceDeriverBase {
if (strpos($view->get('base_table'), 'search_api_index') !== FALSE) {
$displays = $view->get('display');
foreach ($displays as $name => $display_info) {
if($display_info['display_plugin'] == "page"){
if ($display_info['display_plugin'] == "page") {
$machine_name = $view->id() . PluginBase::DERIVATIVE_SEPARATOR . $name;
$plugin_derivatives[$machine_name] = [
'id' => $base_plugin_id . PluginBase::DERIVATIVE_SEPARATOR . $machine_name,
'label' => $this->t('Search api view: %view_name, display: %display_title', ['%view_name' => $view->label(), '%display_title' => $display_info['display_title']]),
'description' => $this->t('Provides a facet source.'),
'view_id' => $view->id(),
'view_display' => $name,
'id' => $base_plugin_id . PluginBase::DERIVATIVE_SEPARATOR . $machine_name,
'label' => $this->t('Search api view: %view_name, display: %display_title', ['%view_name' => $view->label(), '%display_title' => $display_info['display_title']]),
'description' => $this->t('Provides a facet source.'),
'view_id' => $view->id(),
'view_display' => $name,
] + $base_plugin_definition;
$sources[] = $this->t('Search api view: ' . $view->label() . ' display: ' . $display_info['display_title']);
......