web-dev-qa-db-fra.com

Comment modifier la requête d'affichage après avoir changé le filtre exposé?

Nous avons une vue personnalisée, myview, qui a deux filtres exposés: country et category. Pour la valeur country, nous avons une valeur que nous voulons appliquer indépendamment de ce qui est sélectionné comme filtre exposé qui n'est pas All Countries.

Comment modifierions-nous la requête après avoir sélectionné une valeur afin que nous ajoutions toujours un or country = United States of America À la valeur sélectionnée pour la requête de la vue?

Objectif:

Une fois le filtre exposé appliqué, modifiez la requête de telle sorte qu'elle renvoie tout ce que l'utilisateur a sélectionné ET tous les autres nœuds où country = 'United States'.

Valeur du pays:

  1. Tous les pays
  2. À l'échelle mondiale
  3. Les États-Unis d'Amérique
  4. Royaume-Uni
  5. France
  6. Allemagne

Ce que nous pensions utiliser hook_views_query_alter , mais nous ne savons pas comment modifier la requête après la sélection d'une valeur.

mymodule.module

use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;

/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {

  if ($view->id() == 'myview') {
    $or_statement = new Condition('OR');
    $or_statement->condition('field_country', '12', '=');
    $query->addWhere(0, $or_statement);
  }

}

Filtres actuels:

  1. publié = oui
  2. type de contenu = article
  3. pays (filtre exposé, tout afficher, sélection unique)
  4. catégorie (filtre exposé, afficher tout, sélection unique)

Lorsque vous utilisez ksm() pour imprimer le $condition_group, Voici les résultats. Il ne montre même pas les deux filtres exposés. condition group

Clause Where actuelle

10 Est la valeur sélectionnée par l'utilisateur dans le filtre exposé et 12 Est celle que nous voulons ajouter.

WHERE (((node__field_country.field_country_target_id = '10')) AND (node__field_country.field_country_target_id = '12'))

Clause where souhaitée

WHERE (((node__field_country.field_country_target_id = '10')) OR (node__field_country.field_country_target_id = '12'))
2
usernameabc

En utilisant la suggestion d70rr3s et ce patch (requis) , je suis tombé sur cette solution qui fonctionnait.

use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;

/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
   if ($view->id() == 'myview'  && !empty($view->exposed_raw_input['field_country']) && $view->exposed_raw_input['field_country'] !== 'all') {
    // Traverse through the 'where' part of the query.
    foreach ($query->where as &$condition_group) {
      foreach ($condition_group['conditions'] as &$condition) {
        if ($condition['field'] == 'your_entity.field_country') {
          $field = 'node__field_country.field_country_target_id';
          $value = 'somevalue';
          $operator = '=';
          $query->addWhere(2, $field, $value, $operator);
        }
      }
    }
  }
}

Résultats:

WHERE (((node__field_country.field_country_target_id = '10')) OR (node__field_country.field_country_target_id = 'someValue')) AND (node_field_data.status=1) AND (node_field_data.type='article')

Critères de filtre où les points 1 et 2 de la capture d'écran devaient être appliqués:

filter criteria

2
usernameabc

Tiré de l'exemple du crochet. En supposant que le nom de votre filtre est field-country une solution possible pourrait être:

use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;

/**
 * Implements hook_views_query_alter().
 */
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
   if ($view->id() == 'myview'  && !empty($view->exposed_raw_input['field_country']) && $view->exposed_raw_input['field_country'] != 'all') {
    // Traverse through the 'where' part of the query.
    foreach ($query->where as &$condition_group) {
      foreach ($condition_group['conditions'] as &$condition) {
        if ($condition['field'] == 'your_entity.field_country') {
           $filter_value = $view->exposed_raw_input['field_country'];
           if (!is_array($filter_value)) {
             $filter_value = [$filter_value];
           }

           $condition = [
             'field' => 'your_entity.field_country',
             'value' => array_merge($filter_value, ['United States Of America']),
             'operator' => 'IN',
           ];
        }
      }
    }
  }
}

Je ne l'ai pas entièrement testé mais je dois travailler.

Vous pouvez également toujours implémenter votre propre plugin de filtre ad-hoc .

Mise à jour : Ajoutez une condition pour vérifier si le filtre est à plusieurs valeurs.

Mise à jour : Supprimez la comparaison stricte pour la valeur d'entrée du filtre car cela peut provoquer des effets secondaires.

1
d70rr3s