web-dev-qa-db-fra.com

Comment ajouter un gestionnaire de filtre de vues personnalisé pour un champ spécifique?

Actuellement, j'ai un champ booléen field_private_content, Si ce champ est défini, le contenu ne doit être montré qu'aux utilisateurs authentifiés, les utilisateurs anonymes ne peuvent voir que le teaser et un formulaire de connexion. Jusqu'à présent, cela fonctionne bien, également avec des vues où j'ai ajouté le filtre sur ce champ. Le filtre est supprimé automatiquement par l'implémentation de hook_views_pre_view() dans un module personnalisé:

function custom_module_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  // Remove filter on field_private_content != TRUE for authenticated users.
  if ($view->getHandler($view->current_display, 'filter', 'field_private_content') && \Drupal::currentUser()->isAuthenticated()) {
    $view->removeHandler($view->current_display, 'filter', 'field_private_content');
  }
}

Bien que cela fonctionne très bien, le comportement n'est pas évident à partir des vues ui. Je préférerais avoir un doublon du filtre field_private_content qui devrait avoir le comportement mentionné par défaut et pourrait être étiqueté correctement - le filtre d'origine devrait garder son comportement d'origine.

Comment y parvenir?

Comment ajouter un gestionnaire de filtre de vues personnalisé pour un champ spécifique?

6
LarS

Cela nécessite un petit effort, je ne mettrai ici que les parties principales et une référence à un article que j'ai utilisé pour créer un filtre de vues personnalisé dans Drupal 8.

Vous devez d'abord déclarer le filtre à l'intérieur de l'implémentation hook_views_data_alter():

$data['node_field_data']['nodes_titles'] = array(
  'title' => t('Node titles'),
  'filter' => array(
    'title' => t('Node titles'),
    'help' => t('Specify a list of titles a node can have.'),
    'field' => 'title',
    'id' => 'd8views_node_titles'
  ),
)

Puisque nous filtrons sur la colonne de titre, nous nous étendons sur la table node_field_data mais avec la colonne de titre comme champ réel à utiliser. De plus, cette fois, nous créons un plugin pour gérer le filtrage identifié comme d8views_node_titles. Maintenant, il suit pour créer cette classe:

src/Plugin/views/filter/NodeTitles.php :

    /**
     * @file
     * Definition of Drupal\d8views\Plugin\views\filter\NodeTitles.
     */

    namespace Drupal\d8views\Plugin\views\filter;

    use Drupal\views\Plugin\views\display\DisplayPluginBase;
    use Drupal\views\Plugin\views\filter\InOperator;
    use Drupal\views\ViewExecutable;

    /**
     * Filters by given list of node title options.
     *
     * @ingroup views_filter_handlers
     *
     * @ViewsFilter("d8views_node_titles")
     */
    class NodeTitles extends InOperator {

      /**
       * {@inheritdoc}
       */
      public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
        parent::init($view, $display, $options);
        $this->valueTitle = t('Allowed node titles');
        $this->definition['options callback'] = array($this, 'generateOptions');
      }

      /**
       * Override the query so that no filtering takes place if the user doesn't
       * select any options.
       */
      public function query() {
        if (!empty($this->value)) {
          parent::query();
        }
      }

      /**
       * Skip validation if no options have been chosen so we can use it as a
       * non-filter.
       */
      public function validate() {
        if (!empty($this->value)) {
          parent::validate();
        }
      }

      /**
       * Helper function that generates the options.
       * @return array
       */
      public function generateOptions() {
        // Array keys are used to compare with the table field values.
        return array(
          'my title' => 'my title',
          'another title' => 'another title',
        );
      }

    }

À l'intérieur du plugin, vous devez remplacer trois méthodes, comme expliqué dans Création d'un filtre de vues personnalisé dans Drupal 8 . En voici une citation:

Dans init(), nous spécifions le titre de l'ensemble d'options de filtre et le rappel qui génère les valeurs des options. Ce rappel doit être un appelable et dans ce cas, nous avons opté pour la méthode generateOptions() sur cette classe. Ce dernier renvoie simplement un tableau d'options à présenter aux utilisateurs, dont les clés sont utilisées dans la modification de la requête. Alternativement, nous aurions pu également créer directement les options dans la méthode init() en remplissant la propriété $this->valueOptions Avec nos titres disponibles. L'utilisation d'un rappel est plus propre, car vous pouvez y exécuter diverses logiques chargées de fournir les titres de noeud nécessaires.

Le but de remplacer les méthodes query() et validate() était d'empêcher une requête et une validation de se produire au cas où l'utilisateur créerait le filtre sans sélectionner aucun titre. De cette façon, le filtre n'a aucun effet sur les résultats plutôt que de renvoyer 0 résultat. C'est une préférence simple destinée à illustrer comment vous pouvez remplacer diverses fonctionnalités pour adapter vos plugins à vos besoins.

12