You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drupal视图Alter钩子获取总行数及去重后计数异常解决

解决Drupal视图去重后的计数异常问题&获取总行数方法

我来帮你搞定这个视图去重后的计数问题,顺便说下怎么在Alter钩子里获取总行数。

首先说你的问题根源:你当前的代码在pre_render阶段直接把$view->total_rows设为当前页去重后的结果数,但分页开启时,$view->result已经是当前页的数据集了,所以总计数自然不对。而且你注释掉了$view->pager->total_items的设置,这也是分页控件显示异常的核心原因。

修正后的pre_render钩子代码

下面是调整后的代码,能正确显示去重后的总结果数,同时修复分页计数问题:

function search_helper_views_pre_render(\Drupal\views\ViewExecutable $view) {
  $target_views = ["all_news", "all_publications", "all_events", "global_search"];
  if (!in_array($view->id(), $target_views)) {
    return;
  }

  // 第一步:获取所有符合查询条件的nid,计算去重后的总数量
  $base_query = $view->query->query();
  // 只查询nid,减少数据传输开销
  $base_query->addField('node_field_data', 'nid');
  $all_raw_nids = $base_query->execute()->fetchCol();
  $unique_total_count = count(array_unique($all_raw_nids));

  // 第二步:处理当前页的结果去重
  $current_page_unique_nids = [];
  foreach ($view->result as $key => $result_item) {
    if (!in_array($result_item->nid, $current_page_unique_nids)) {
      $current_page_unique_nids[] = $result_item->nid;
    } else {
      unset($view->result[$key]);
    }
  }
  // 重置数组索引,避免视图渲染时出现索引断裂的问题
  $view->result = array_values($view->result);

  // 第三步:更新视图计数和分页信息
  $view->total_rows = $unique_total_count;
  if ($view->pager) {
    $view->pager->total_items = $unique_total_count;
    // 可选处理:如果当前页去重后为空,自动跳转到上一页
    if (empty($view->result) && $view->current_page > 0) {
      $view->current_page--;
      $view->pager->setCurrentPage($view->current_page);
      // 重新执行查询获取上一页数据
      $view->execute();
      // 再次对新结果去重
      $new_page_unique = [];
      foreach ($view->result as $k => $res) {
        if (!in_array($res->nid, $new_page_unique)) {
          $new_page_unique[] = $res->nid;
        } else {
          unset($view->result[$k]);
        }
      }
      $view->result = array_values($view->result);
    }
    $view->pager->updatePageInfo();
  }
}

代码关键点解释

  1. 获取总去重数量:通过视图的原始查询获取所有nid,再用array_unique去重后计数,这样得到的是全量去重后的总数,不是当前页的数量。
  2. 重置结果数组索引:删除重复项后数组会出现索引空缺,重置索引能避免视图渲染时出现报错或显示异常。
  3. 正确设置分页参数:把$view->pager->total_items设为总去重数量,分页控件就能显示正确的页数和总计数了。
  4. 空页面处理:可选逻辑,防止用户进入去重后为空的分页页面,提升体验。

关于在视图Alter钩子中获取总行数

根据不同的钩子阶段,获取方式略有不同:

1. 在hook_views_query_alter中(查询执行前)

这个阶段可以复制原始查询,执行计数操作,还能提前修改查询逻辑:

function search_helper_views_query_alter(\Drupal\views\ViewExecutable $view, \Drupal\views\Plugin\views\query\Sql $query) {
  $target_views = ["all_news", "all_publications", "all_events", "global_search"];
  if (!in_array($view->id(), $target_views)) {
    return;
  }

  // 复制查询,仅做计数(去重版)
  $count_query = clone $query->query();
  $count_query->addExpression('COUNT(DISTINCT node_field_data.nid)', 'total');
  $count_query->groupBy = []; // 移除分组保证计数准确
  $total_unique_rows = $count_query->execute()->fetchField();
  
  // 可以把结果存在视图临时属性里,供后续钩子使用
  $view->set('custom_total_unique', $total_unique_rows);
}

2. 在hook_views_pre_render/hook_views_post_render中

  • 如果要获取原始查询的总行数(未去重),直接用$view->total_rows即可。
  • 如果要获取去重后的总行数,就用上面解决方案里的查询方式,或者从query_alter阶段存储的临时属性里读取。

更优的去重方式(推荐)

如果你的重复结果是因为视图关联了其他表导致的,直接在数据库层面去重更高效:

function search_helper_views_query_alter(\Drupal\views\ViewExecutable $view, \Drupal\views\Plugin\views\query\Sql $query) {
  $target_views = ["all_news", "all_publications", "all_events", "global_search"];
  if (in_array($view->id(), $target_views)) {
    // 添加DISTINCT关键字,让数据库直接返回唯一结果
    $query->distinct();
  }
}

这种方式不需要在PHP层面处理去重,计数也会自动正确,性能更好。

内容的提问来源于stack exchange,提问作者Arunkumar T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:55:16