ビューのPHPフィールドを置き換え、カスタムビューハンドラーで並べ替える方法


11

ビューのパフォーマンスの問題に対処し、ベストプラクティスを尊重するために、少し前に設定したビューのPHPを、独自のカスタムハンドラーに置き換えたいと思います

たとえば、私はその設定で、表示から除外されたビューPHPフィールドを持っています:

値コード:

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 ; ?>`

次に、そのフィールドを最初のソート基準(昇順)として、グローバルPHPソート基準で使用します。

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

あなたが正しい方法で私を置くことができれば本当に感謝します:どの関数で同じコードを構築してPHPでデータベースに入れるか?

まとめ:

検索と進捗状況に加えて、@ Renrahfのヘルプを参照すると、ほとんどの実装は問題ないようです。しかし、私はまだ1つの点で戦っています。値を計算するためにカスタムフィールドハンドラーを追加しましたが、そのハンドラーでどのように注文できますか?

編集:

これまでに行ったこと:

.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句'で不明な列を返します

  • 完了:どのように$row->product_idして$row->nid内部に入ることができquery()ますか?サブクエリを作成するために必要です。:ビューハンドラーフィールドを追加し、render($ values)で行の値を見つけました...

  • 完了:サンプルハンドラのどの部分を編集する必要がありますか?クエリ機能のみ?サンプルコード全体を保持する必要がありますか、それともカスタムパーツのみを保持する必要がありますか?

ありがとうございました

回答:


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_idまたはnidを取得するには、ビューフィールドハンドラーによってクエリに追加された(およびビュー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

私の悪いことに、ビューは並べ替えをDBクエリに依存しているため、ハンドラーによって作成されたようなダミーフィールドでビューの並べ替えを実行することはできないようです。だから私は間違いなくサブクエリに取り組む必要があります!
Kojo

1
以前に反応しないために申し訳ありません!私の回答がお役に立てば幸いですが、あなたは自分ですべての仕事をしました。サブクエリのエイリアスについては知りませんでした。詳細な解決策のおかげで、多くの人に役立ちます。
Renrhaf

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');

  }
}

少し説明:ビューハンドラーの実装方法を理解した後、サブクエリと混同しました:

  • 動的な「行」の結果を取得するために、それを外部クエリにマップします。テーブルと列は同じですが、エイリアスは異なります。 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

ビューの並べ替えはDBベースで行われ、カスタムフィールドハンドラーは一種のダミーフィールドであるため、カスタムハンドラーフィールドで結果を並べ替えるための値を計算しようとしてが機能しませんでした...少なくともこれは私の結論でした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.