Skip to content

Commit

Permalink
EWPP-1613: Refactoring the contextual filters processing method.
Browse files Browse the repository at this point in the history
  • Loading branch information
upchuk committed Oct 27, 2021
1 parent b44dabb commit 4acc93c
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ services:
oe_list_pages_link_list_source.contextual_filters_field_mapper:
class: Drupal\oe_list_pages_link_list_source\ContextualFilterFieldMapper
arguments: ['@config.factory']
oe_list_pages_link_list_source.contextual_filters_values_processor:
class: Drupal\oe_list_pages_link_list_source\ContextualFilterValuesProcessor
arguments: ['@current_route_match', '@oe_list_pages.list_source.factory', '@oe_list_pages_link_list_source.contextual_filters_builder', '@entity_type.manager', '@oe_list_pages_link_list_source.contextual_filters_field_mapper', '@plugin.manager.multiselect_filter_field']
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
<?php

declare(strict_types = 1);

namespace Drupal\oe_list_pages_link_list_source;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\facets\FacetInterface;
use Drupal\oe_list_pages\FacetManipulationTrait;
use Drupal\oe_list_pages\ListPageConfiguration;
use Drupal\oe_list_pages\ListSourceFactoryInterface;
use Drupal\oe_list_pages\ListSourceInterface;
use Drupal\oe_list_pages\MultiselectFilterFieldPluginManager;
use Drupal\oe_list_pages_link_list_source\Exception\InapplicableContextualFilter;

/**
* Processes the contextual filter values from the current context.
*/
class ContextualFilterValuesProcessor {

use FacetManipulationTrait;

/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;

/**
* The list source factory.
*
* @var \Drupal\oe_list_pages\ListSourceFactoryInterface
*/
protected $listSourceFactory;

/**
* The contextual filters configuration builder.
*
* @var \Drupal\oe_list_pages_link_list_source\ContextualFiltersConfigurationBuilder
*/
protected $configurationBuilder;

/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* The contextual filters field mapper.
*
* @var \Drupal\oe_list_pages_link_list_source\ContextualFilterFieldMapper
*/
protected $contextualFilterFieldMapper;

/**
* The multiselect filter field plugin manager.
*
* @var \Drupal\oe_list_pages\MultiselectFilterFieldPluginInterface|\Drupal\oe_list_pages\MultiselectFilterFieldPluginManager
*/
protected $multiselectFilterFieldPluginManager;

/**
* ContextualFilterValuesProcessor constructor.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch
* The current route match.
* @param \Drupal\oe_list_pages\ListSourceFactoryInterface $listSourceFactory
* The list source factory.
* @param \Drupal\oe_list_pages_link_list_source\ContextualFiltersConfigurationBuilder $configurationBuilder
* The contextual filters configuration builder.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
* @param \Drupal\oe_list_pages_link_list_source\ContextualFilterFieldMapper $contextualFilterFieldMapper
* The contextual filters field mapper.
* @param \Drupal\oe_list_pages\MultiselectFilterFieldPluginManager $multiselectFilterFieldPluginManager
* The multiselect filter field plugin manager.
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(RouteMatchInterface $routeMatch, ListSourceFactoryInterface $listSourceFactory, ContextualFiltersConfigurationBuilder $configurationBuilder, EntityTypeManagerInterface $entityTypeManager, ContextualFilterFieldMapper $contextualFilterFieldMapper, MultiselectFilterFieldPluginManager $multiselectFilterFieldPluginManager) {
$this->routeMatch = $routeMatch;
$this->listSourceFactory = $listSourceFactory;
$this->configurationBuilder = $configurationBuilder;
$this->entityTypeManager = $entityTypeManager;
$this->contextualFilterFieldMapper = $contextualFilterFieldMapper;
$this->multiselectFilterFieldPluginManager = $multiselectFilterFieldPluginManager;
}

/**
* Processes the raw configuration into a configuration object.
*
* Looking at the current entity from context, it tries to transform values
* from it into preset filter values on the configuration.
*
* @param array $raw_configuration
* The raw configuration.
* @param \Drupal\Core\Cache\CacheableMetadata $cache
* The cache metadata.
*
* @return \Drupal\oe_list_pages\ListPageConfiguration
* The configuration object ready for the query execution.
*/
public function processConfiguration(array $raw_configuration, CacheableMetadata $cache): ListPageConfiguration {
$configuration = new ListPageConfiguration($raw_configuration);
$cache->addCacheContexts(['route']);

// Add the contextual filters.
$contextual_filters = $raw_configuration['contextual_filters'];
$entity = $this->getCurrentEntityFromRoute();

if (!$entity instanceof ContentEntityInterface) {
if (!empty($contextual_filters)) {
// If we have contextual filters but don't have an entity to check for
// the corresponding fields, we cannot have results.
throw new InapplicableContextualFilter();
}

// Otherwise, the configuration stays untouched.
return $configuration;
}

$cache->addCacheableDependency($entity);

$default_filter_values = $configuration->getDefaultFiltersValues();
$list_source = $this->listSourceFactory->get($configuration->getEntityType(), $configuration->getBundle());

foreach ($contextual_filters as $contextual_filter) {
$facet = $this->configurationBuilder->getFacetById($list_source, $contextual_filter->getFacetId());
$definition = $this->getFacetFieldDefinition($facet, $list_source);
if ($definition) {
$field_name = $definition->getName();
// Map the field correctly.
$field_name = $this->contextualFilterFieldMapper->getCorrespondingFieldName($field_name, $entity, $cache);
if (!$field_name) {
// If the field doesn't exist on the current entity, we need to not
// show any results.
throw new InapplicableContextualFilter();
}

$field = $entity->get($field_name);
$values = $this->extractValuesFromField($field, $facet, $list_source);
if (empty($values)) {
// If the contextual filter does not have a value, we again cannot
// show any results.
throw new InapplicableContextualFilter();
}

$contextual_filter->setValues($values);
}
else {
$processor = ContextualFiltersHelper::getContextualAwareSearchApiProcessor($list_source, $facet);
if (!$processor) {
throw new InapplicableContextualFilter();
}

$contextual_filter->setValues($processor->getContextualValues($entity));
}

$default_filter_values[ContextualFiltersConfigurationBuilder::generateFilterId($contextual_filter->getFacetId(), array_keys($default_filter_values))] = $contextual_filter;
}

$configuration->setDefaultFilterValues($default_filter_values);

return $configuration;
}

/**
* Get content entity from route.
*
* @return \Drupal\Core\Entity\ContentEntityInterface|null
* The content entity.
*/
protected function getCurrentEntityFromRoute() :?ContentEntityInterface {
$route_name = $this->routeMatch->getRouteName();
$parts = explode('.', $route_name);
if (count($parts) !== 3 || $parts[0] !== 'entity') {
return NULL;
}

$entity_type = $parts[1];
$entity = $this->routeMatch->getParameter($entity_type);

// In case the entity parameter is not resolved (e.g.: revisions route.
if (!$entity instanceof ContentEntityInterface) {
$entity = $this->entityTypeManager->getStorage($entity_type)->load($entity);
}
return $entity;
}

/**
* Extracts the field values.
*
* Determines what type of field we are dealing with and delegates to the
* correct multiselect filter field plugin to handle the value extraction.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The field items list.
* @param \Drupal\facets\FacetInterface $facet
* The facet.
* @param \Drupal\oe_list_pages\ListSourceInterface $list_source
* The list source.
*
* @return array
* The values.
*/
protected function extractValuesFromField(FieldItemListInterface $items, FacetInterface $facet, ListSourceInterface $list_source) {
$field_definition = $items->getFieldDefinition();
$id = $this->multiselectFilterFieldPluginManager->getPluginIdByFieldType($field_definition->getType());
if (!$id) {
return [];
}

$config = [
'facet' => $facet,
'preset_filter' => [],
'list_source' => $list_source,
];

/** @var \Drupal\oe_list_pages\MultiselectFilterFieldPluginInterface $plugin */
$plugin = $this->multiselectFilterFieldPluginManager->createInstance($id, $config);

return $plugin->getFieldValues($items);
}

}
Loading

0 comments on commit 4acc93c

Please sign in to comment.