如何通过自定义Views处理程序替换Views PHP字段并进行排序?


11

为了解决某些Views性能问题并尊重最佳实践,我想用自己的自定义处理程序替换我之前配置的一些Views PHP

例如,我有一个Views PHP字段,该显示设置除外,该字段从display排除

值码:

if( $row->sticky ==1 ) {
  return 100;
} else {

  if ( isset($row->product_id) && $row->product_id != ""  ){

    $query = "SELECT COUNT(statut.entity_id) FROM field_data_field_statut_depart statut"
    . " INNER JOIN  field_data_field_product product ON statut.entity_id= product.field_product_product_id"
    . " INNER JOIN  field_data_field_date_depart depart ON statut.entity_id = depart.entity_id"
    . " WHERE product.entity_id = ". $row->nid." AND field_statut_depart_value IN (2,3) AND field_date_depart_value > NOW(); ";

    $select = db_query($query);
    $count = $select->fetchField();

    return $count; 
  }
  else {
    return -1;
  }
}

输出代码

<?php print $value ; ?>`

然后,在Global PHP排序条件中,将该字段用作第一排序条件(ascending

if ($row1->php> $row2->php) return -1; else return 1;

如果您能采取正确的方法,我将不胜感激:我应该在哪个函数中构建相同的代码以在数据库中以PHP结尾?

总结:

经过搜索并取得进展,再加上@Renrahf帮助,大多数实现似乎还可以,下面详细介绍。但是我仍然在争论一点:我添加了一个自定义字段处理程序来计算值,但是如何按该处理程序排序?

编辑:

到目前为止,我做了什么:

.info文件

files[] = views_handler_vts_products_sort.inc
files[] = includes/views_handler_vts_count_depconf_field.inc

模块文件

/**
 * Implements hook_views_data().
 */
function vts_views_handler_views_data() {
  $data['custom']['table']['group'] = t('Custom');
  $data['custom']['table']['join'] = array(
    // #global is a special flag which let's a table appear all the time.
    '#global' => array(),
  );

  $data['custom']['custom_handler'] = array(
    'title' => t('Vts custom Sort Handler'),
    'help' => 'Sorts products by sticky first then by custom statut field',
    'sort' => array(
      'handler' => 'views_handler_vts_products_sort',
    ),
  );

  $data['custom']['count_depconf_field'] = array(
    'title' => t('Sum of products with status confirmed '),
    'help' => t('Calculate Sum of products with status confirmed, to order lists".'),
    'field' => array(
      'handler' => 'views_handler_vts_count_depconf_field',
      'click sortable'=> TRUE,
    ),
    /*'sort' => array(
      'handler' => 'views_handler_sort',
    ), */
  );  
  return $data;
}

function vts_views_handler_views_api() {
    return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'vts_views_handler'),
  );
}

views_handler_vts_products_sort 文件

/**
 * Base sort handler that has no options and performs a simple sort.
 *
 * @ingroup views_sort_handlers
 */
class views_handler_vts_products_sort extends views_handler_sort {

  function query() {
    $this->ensure_my_table();
    // Add the field.
    $this->query->add_orderby('node', 'sticky', 'DESC');
  }
}

views_handler_vts_count_depconf_field 文件

/*
 * A simple field to calculate the value I wish to order by.
 */
class views_handler_vts_count_depconf_field extends views_handler_field {

  function query() {
    //do nothing
  }

  function render($values) {
    $count = 0;

    $product_id = isset($values-> commerce_product_field_data_field_product_product_id)? $values-> commerce_product_field_data_field_product_product_id: NULL;
    if(!is_null($product_id)){

      $query = "SELECT COUNT(statut.entity_id) FROM field_data_field_statut_depart statut"
      . " INNER JOIN  field_data_field_product product ON statut.entity_id= product.field_product_product_id"
      . " INNER JOIN  field_data_field_date_depart depart ON statut.entity_id = depart.entity_id"
      . " WHERE product.entity_id = " . $values->nid . " AND field_statut_depart_value IN (2,3) AND field_date_depart_value > NOW(); ";

      $select = db_query($query);
      $count = $select->fetchField();
    }
    return $count;
  }
}

剩余的问题:

  • 如何通过自定义字段处理程序订购?我尝试将'click sortable'=> TRUE,OR 'sort' => array('handler' => 'views_handler_sort',),OR 添加$this->query->add_orderby('custom', 'count_depconf_field', 'DESC');到自定义排序处理程序中。没有任何工作,但在“ order子句”中返回Unknown列

  • DONE:我怎样才能$row->product_id$row->nid里面query()?我需要它来构建子查询。:添加了一个视图处理程序字段,并在render($ values)中找到了行值...

  • 完成:我必须对示例处理程序的哪一部分进行编辑?仅查询功能?我是否需要保留整个示例代码或仅保留定制部分?

谢谢

Answers:


7

您需要使用视图排序处理程序:https : //api.drupal.org/api/views/handlers!views_handler_sort.inc/group/views_sort_handlers/7.x-3.x

由于性能原因,您不能使用PHP对结果进行排序。仅当获取整个表的结果时,PHP才可用于对结果进行排序,而在大多数情况下,这不是一种选择。

因此,您需要创建自己的视图排序处理程序,在视图中对其进行配置,然后使用视图API函数进行适当的联接,甚至在其中可以通过子查询来获得进行排序所需的数据。在您的情况下,许多具有特定日期和类型条件的实体。

所有这些代码都必须驻留在对象的“ query()”方法中。您需要实现如下查询:

SELECT table_x.field_y, ...
FROM  ...
...
...
ORDER BY row.sticky, (SELECT COUNT(statut.entity_id) 
FROM field_data_field_statut_depart statut
INNER JOIN field_data_field_product product
INNER JOIN field_data_field_date_depart depart
WHERE product.entity_id = table_x.field_y
AND field_statut_depart_value IN (2,3) 
AND field_date_depart_value > NOW())

通过使用函数https://api.drupal.org/api/views/plugins%21views_plugin_query_default.inc/function/views_plugin_query_default%3A%3Aadd_orderby/7.x-3.x和一个子查询。

子查询可能会在3个或更多关节中进行优化,有些情况可能会满足条件,但如果没有整个查询我就无法判断。

编辑

您从“ views_handler”对象扩展而来,但应直接从“ views_handler_sort”对象扩展,以便能够使用最大的核心默认代码:

class views_handler_vts_products_sort extends views_handler_sort {
  /**
   * Called to add the sort to a query.
   */
  function query() {
    $this->ensure_my_table();
    // Add the field.
    $this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
  }
}

正如您在上面看到的,您的情况仅需要“查询”方法,因为您在UI等中不需要任何特定的配置。

要在您的“ query()”方法中获取product_idnid,您必须使用由视图字段处理程序添加到查询中的现有字段(并在您的视图UI中定义)。

该文件是您想要实现的完美示例(您可以在视图文档中找到它,它是现有文件,但是由于我的信誉太低,我不允许设置该链接):

class views_handler_sort_node_version_count extends views_handler_sort {
  function query() {
    $this->ensure_my_table();

    $this->query->add_orderby(NULL, '(SELECT COUNT(vid) FROM {node_revision} WHERE nid = {' . $this->table_alias . '}.nid)', $this->options['order'], 'sort_node_version_count');
  }
}

看看您是否可以根据需要调整此代码,我将很高兴看到最终结果:)


我用进度编辑了问题。如果您想完成答案?非常感谢
Kojo

1
做完了,请检查一下,并告诉我您是否设法使分类工作正常:)
Renrhaf

糟糕的是,我意识到,由于视图依赖于数据库查询来进行排序,因此看来我永远都不会像处理程序创建的虚拟字段那样实现对视图的排序!所以我绝对必须在子查询上工作!
Kojo

1
对不起,您未及早做出反应!希望我的回答有用,但是您自己做了所有工作,我不知道子查询别名,感谢您的详细解决方案,它将对很多人有所帮助。
Renrhaf '16

4

我在下面的完整实现中分享了如何通过自定义Views处理程序替换Views PHP排序

.info文件

files[] = includes/views_handler_my_custom_sort.inc

模块文件

/**
 * Implements hook_views_data().
 */
function MODULE_NAME_views_data() {
  $data['custom']['table']['group'] = t('Custom');
  $data['custom']['table']['join'] = array(
    '#global' => array(),
  );

  $data['custom']['custom_handler'] = array(
    'title' => t('My custom Sort Handler'),
    'help' => 'Sorts products by sticky first then by custom statut field',
    'sort' => array(
      'handler' => 'views_handler_vts_products_sort',
    ),
  );

  return $data;
}

function MODULE_NAME_views_api() {
    return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'MODULE_NAME'),
  );
}

views_handler_my_custom_sort.inc文件

/**
 * Base sort handler that has no options and performs a simple sort.
 *
 * @ingroup views_sort_handlers
 */
class views_handler_my_custom_sort extends views_handler_sort {

  function query() {
    $this->ensure_my_table();

    $sub_query = "(SELECT COUNT(p.field_product_product_id) "
      . "FROM field_data_field_product p "
      . "LEFT JOIN field_data_field_statut_depart statut ON statut.entity_id = p.field_product_product_id "
      . "LEFT JOIN field_data_field_date_depart depart ON depart.entity_id = p.field_product_product_id  "
      . "LEFT JOIN node nod ON nod.nid = p.entity_id "
      . "WHERE nod.nid = node.nid "//This is a the obligatory condition mapping the subquery with the outer query
      . "AND field_statut_depart_value IN (2,3) "
      . "AND field_date_depart_value > NOW())";

    /* I'm timeless to write the query with the object syntax, here was a beginning
    $sub_query = db_select('field_data_field_product', 'p');
    $sub_query->addField('p', 'field_product_product_id');
    $sub_query->leftJoin('node', 'nod', 'nod.nid = p.entity_id');
    $sub_query->where("nod.nid = node.nid");
    $sub_query->countQuery(); */  

    $this->query->add_orderby('node', 'sticky', 'DESC');
    $this->query->add_orderby(NULL, $sub_query, 'DESC', 'subquery');

  }
}

有点解释:了解了如何实现Views处理程序后,我对子查询感到困惑:

  • 使用外部查询将其映射以获取动态的“行依据”结果:相同的表和列,但别名不同: WHERE nod.nid = node.nid
  • add_orderby:中设置别名$this->query->add_orderby(NULL, $sub_query, 'DESC', 'subquery');有效,但$this->query->add_orderby(NULL, $sub_query, 'DESC');不适用

最后一点令人惊讶,因为虽然SELECT TITLE FROM node ORDER BY (SELECT COUNT(field_product_product_id) FROM field_data_field_product p LEFT JOIN node nod ON nod.nid = p.entity_id WHERE nod.nid = node.nid )可以在SQL直接输入中使用,但不适用于当前设置。

您需要指定子查询别名,最终查询将类似于 SELECT TITLE, (SELECT COUNT(field_product_product_id) FROM field_data_field_product p LEFT JOIN node nod ON nod.nid = p.entity_id WHERE nod.nid = node.nid ) as subquery FROM node ORDER BY subquery

尝试计算值以对自定义处理程序字段中的结果进行排序的尝试不起作用,因为视图排序是在数据库的基础上完成的,并且自定义字段处理程序是一种伪字段...至少这是我的结论。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.