Drupal 8:在视图中创建子查询


本文向大家介绍Drupal 8:在视图中创建子查询,包括了Drupal 8:在视图中创建子查询的使用技巧和注意事项,需要的朋友参考一下

您以前可能去过那里。您正在使用的Drupal View看起来很棒,并且具有您需要的所有数据和字段,但是当您仔细查看结果时,您会发现有些问题。查看生成的SQL查询后,您会发现其中一个联接存在问题,这会导致计数减少。最终,您需要删除此联接,但实际上您需要包含在结果中的数据。

创建子查询可以使您从特定字段中提取数据,而无需添加另一个导致结果不正确的联接。

前几天我在一个视图中遇到了这个问题,该视图合并了“下载计数”模块中的数据。此模块记录用户在您的站点上下载文件的操作。尽管确实提供了一些Views集成,但我添加了其他一些关系,这些关系导致下载计数不正确。经过一番调查后,我知道我需要创建一个子查询以将下载计数的值注入到View的输出中。

做到这一点的最佳方法是创建一个View字段处理程序,该处理程序将在字段设置中创建一个子查询。要创建字段处理程序插件,您需要在my_module / src / Plugin / views / field位置创建一个类。以下是一个名为FileDownloadCount的类,该类扩展了默认的NumericField Views字段。这是在类级别的注释,它使Views可以了解此字段,因此这一点非常重要。我的插件的完整文件路径为my_module / src / Plugin / views / field / FileDownloadCount.php。

<?php
 
namespace Drupal\my_module\Plugin\views\field;
 
use Drupal\views\Plugin\views\field\NumericField;
use Drupal\views\ResultRow;
 
/**
 * Field handler for search score.
 *
 * @ingroup views_field_handlers
 *
 * @ViewsField("file_download_count")
 */
class FileDownloadCount extends NumericField {
 
}

Views会自动拾取它,但是直到我们添加一些其他方法后它才做任何事情。

我们需要添加的第一件事是一种query()方法,以便Views知道子查询并将其添加到显示输出中。通过创建数据库查询的新实例,然后将其作为联接添加到主查询中来创建子查询,就好像它是真实表一样。此处的子查询(由于我要获取的数据)取决于file_managed表,因此这构成了我们创建的联接的基础。

这是完整的方法,带有注释以帮助分解发生的情况。

/**
 * {@inheritdoc}
 */
public function query() {
  // 将子查询添加到查询中,以找到下载计数。
  $subQuery = \Drupal::database()->select('download_count', 'download_count');
  $subQuery->addField('download_count', 'fid');
  $subQuery->addExpression("COUNT(fid)", 'file_download_count');
  $subQuery->groupBy("download_count.fid");
 
  // 将子查询添加为联接的组件。
  $joinDefinition = [
    'table formula' => $subQuery,
    'field' => 'fid',
    'left_table' => 'file_managed',
    'left_field' => 'fid',
    'adjust' => TRUE,
  ];
 
  // 创建一个连接对象,并在主查询和子查询之间创建一个关系。
  $join = \Drupal::service('plugin.manager.views.join')->createInstance('standard', $joinDefinition);
  $this->query->addRelationship('download_data', $join, 'file_managed');
 
  // 将字段添加到“视图”界面。
  $this->query->addField(NULL, 'file_download_count', 'file_download_count');
}

现在,我们已经有了子查询,并且在主查询中添加了字段,因此我们现在需要的数据将通过。最重要的是,查询的输出为null时的默认值。如果从未下载过文件,则将返回此值,因此在项目开始时会非常定期地进行,并且此功能也很难通过以前的测试。为了解决这个问题,我们只需要检测该值是否为null并使用render()方法将其重置为0 。

/**
 * {@inheritdoc}
 */
public function render(ResultRow $values) {
  if (is_null($values->file_download_count)) {
    // 确保将空值打印为0。
    $values->file_download_count = 0;
  }
  return parent::render($values);
}

当渲染输出时,Views会自动调用该渲染。

最后,最好还让您的新字段具有单击排序功能,这在创建表时尤为重要,因为允许对列进行排序是一个非常好的功能。为此,您需要创建一个名为的方法clickSort(),该addOderBy()方法在查询中调用该方法。当需要按字段对视图进行排序时,视图将自动调用此方法。

/**
 * {@inheritdoc}
 */
public function clickSort($order) {
  if (isset($this->field_alias)) {
    $params = $this->options['group_type'] != 'group' ? ['function' => $this->options['group_type']] : [];
    $this->query->addOrderBy(NULL, 'file_download_count', $order, $this->field_alias, $params);
  }
}

一切就绪后,我们只需要像普通字段一样将此字段添加到视图中即可。您还需要在“视图”表输出中配置排序,以使排序也能正常工作。

我在互联网上看到了几篇文章,展示了如何在Views中创建子查询,但是它们往往会遗漏将数据也添加到View输出中的关键项。上面的解决方案将添加子查询并将数据添加到您的视图中,以便您可以执行一些操作。