Skip to content
facets.module 7.23 KiB
Newer Older
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\facets\Entity\FacetSource;
Nick Veenhof's avatar
Nick Veenhof committed
use Drupal\search_api\Query\QueryInterface;
use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;

/**
 * Implements hook_help().
 */
function facets_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the facets module.
    case 'help.page.facets':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Facets test') . '</p>';
      return $output;
      return t('Below is a list of facets grouped by facetsources they are associated with. A facetsource is the instance where the facet does the actual filtering, for example a View on a Search API index.');
/**
 * Implements hook_theme().
 */
function facets_theme($existing, $type, $theme, $path) {
  return [
    'facets_result_item' => [
      'variables' => [
        'value' => '',
        'show_count' => FALSE,
        'count' => NULL,
        'is_active' => FALSE,
      ],
    ],
    'facets_item_list' => [
      'variables' => [
        'items' => [],
        'title' => '',
        'list_type' => 'ul',
        'wrapper_attributes' => [],
        'attributes' => [],
        'empty' => NULL,
        'context' => [],
      ],
    ],
Nick Veenhof's avatar
Nick Veenhof committed
/**
 * Implements hook_search_api_query_alter().
Nick Veenhof's avatar
Nick Veenhof committed
 *
 * @param \Drupal\search_api\Query\QueryInterface $query
function facets_search_api_query_alter(QueryInterface &$query) {
  if ($query->getIndex()->getServerInstance()->supportsFeature('search_api_facets')) {
    /** @var \Drupal\facets\FacetManager\DefaultFacetManager $facet_manager */
    $facet_manager = \Drupal::service('facets.manager');
    // It's safe to hardcode this to the search api scheme because this is in a
    // search_api_query_alter method. If this generated source is not correct,
    // implementing the same alter and directly calling
    // $manager->alterQuery($query, $your_facetsource_id); will fix that.
    $facet_source = 'search_api:' . str_replace(':', '__', $query->getSearchId());
    $facet_manager->alterQuery($query, $facet_source);

/**
 * Implements hook_entity_presave().
 *
 * We implement this to make sure that a facet gets removed on view updates, so
 * we don't get broken facet blocks.
 */
function facets_entity_presave(EntityInterface $entity) {
  // Make sure that we only react on view entities with changed displays.
  if ($entity instanceof View && !empty($entity->original)) {
    if ($entity->original->get('display') != $entity->get('display')) {

      /** @var \Drupal\facets\FacetSource\FacetSourcePluginManager $facet_source_plugin_manager */
      $facet_source_plugin_manager = \Drupal::getContainer()
        ->get('plugin.manager.facets.facet_source');
      $definitions = $facet_source_plugin_manager->getDefinitions();

      // Setup an array of sources that are deleted.
      $sources = [];
      foreach ($entity->original->get('display') as $k => $display) {
        // Check if the current display is also a facet source plugin and that
        // is removed from the view. We use the double underscore here to make
        // sure that we use core convention of "plugin:derived_plugin".
        $facets_source_plugin_id = 'search_api:views_' . $display['display_plugin'] . '__' . $entity->id() . '__' . $display['id'];
        if (array_key_exists($facets_source_plugin_id, $definitions) && !array_key_exists($k, $entity->get('display'))) {
          $entity_id = str_replace(':', '__', $facets_source_plugin_id);
          $source_entity = FacetSource::load($entity_id);
          if (!is_null($source_entity)) {
            $source_entity->delete();
          }
        }
      }

      // Loop over all deleted sources and delete the facets that were linked to
      // that source.
      if (count($sources) > 0) {
        /** @var \Drupal\facets\FacetManager\DefaultFacetManager $fm */
        $fm = \Drupal::getContainer()->get('facets.manager');
        foreach ($sources as $source) {
          $facets = $fm->getFacetsByFacetSourceId($source);
          foreach ($facets as $facet) {
            $facet->delete();
          }
        }
      }
      $facet_source_plugin_manager->clearCachedDefinitions();
    }
  }

}

/**
 * Implements hook_preprocess_block().
 *
 * Adds a class for the widget to the facet block to allow for more specific
 * styling.
 */
function facets_preprocess_block(&$variables) {
  if ($variables['configuration']['provider'] == 'facets') {
    if (!empty($variables['derivative_plugin_id'])) {
      $facet = Facet::load($variables['derivative_plugin_id']);
      $variables['attributes']['class'][] = 'block-facet--' . Html::cleanCssIdentifier($facet->getWidget()['type']);
    }

/**
 * Implements hook_entity_predelete().
 *
 * We implement this hook to make sure that facet source plugins are cleared
 * when a view is deleted. It also deletes facets that are created on those
 * plugins.
 */
function facets_entity_predelete(EntityInterface $entity) {
  if ($entity instanceof View) {
    $facet_source_plugin_manager = \Drupal::getContainer()
      ->get('plugin.manager.facets.facet_source');

    $definitions = $facet_source_plugin_manager->getDefinitions();
    foreach ($definitions as $plugin_id => $definition) {
      if (strpos($plugin_id, 'search_api:' . $entity->id() . '__') !== FALSE) {
        try {
          $facetManager = \Drupal::getContainer()->get('facets.manager');
        }
        catch (ServiceNotFoundException $e) {
          \Drupal::logger('facets')->log(RfcLogLevel::DEBUG, 'Facet manager not found on trying to delete a view.');
        $facets = $facetManager->getFacetsByFacetSourceId($plugin_id);
        foreach ($facets as $facet) {
          $facet->delete();
        }
      }
    }

    // Clear cached plugin definitions for facet source to make sure we don't
    // show stale data.
    $facet_source_plugin_manager->clearCachedDefinitions();
  }
}

/**
 * Prepares variables for facets item list templates.
 *
 * Default template: facets-item-list.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - items: An array of items to be displayed in the list. Each item can be
 *     either a string or a render array. If #type, #theme, or #markup
 *     properties are not specified for child render arrays, they will be
 *     inherited from the parent list, allowing callers to specify larger
 *     nested lists without having to explicitly specify and repeat the
 *     render properties for all nested child lists.
 *   - title: A title to be prepended to the list.
 *   - list_type: The type of list to return (e.g. "ul", "ol").
 *   - wrapper_attributes: HTML attributes to be applied to the list wrapper.
 *
 * @see https://www.drupal.org/node/1842756
 */
function facets_preprocess_facets_item_list(&$variables) {
  template_preprocess_item_list($variables);
}