Bagaimana cara mengganti bidang Tampilan PHP dan menyortir menurut penangan Tampilan kustom?

11

Untuk mengatasi beberapa masalah kinerja Tampilan dan menghormati praktik terbaik, saya ingin mengganti beberapa Tampilan PHP yang saya konfigurasi beberapa waktu lalu oleh penangan kustom saya sendiri .

Misalnya saya punya bidang Views PHP, dikecualikan dari tampilan , dengan pengaturan itu:

Kode nilai:

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;
  }
}

Kode output :

<?php print $value ; ?>`

Kemudian saya menggunakan bidang itu sebagai kriteria sortir pertama ( menaik ), dalam kriteria sorting PHP Global:

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

Saya akan sangat berterima kasih jika Anda bisa menempatkan saya di jalan yang benar: di mana fungsi (s) yang akan saya buat kode yang sama untuk berakhir dengan PHP di database?

Ringkasan:

Setelah pencarian dan kemajuan, ditambah bantuan @Renrahf, sebagian besar implementasinya tampak ok, dirinci di bawah. Tapi saya masih berjuang dengan satu poin : saya menambahkan pawang lapangan kustom untuk menghitung nilai, tetapi bagaimana saya bisa memesan oleh pawang itu?

Suntingan:

Apa yang saya lakukan sejauh ini:

file .info

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

File modul

/**
 * 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 mengajukan

/**
 * 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 mengajukan

/*
 * 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;
  }
}

Pertanyaan yang tersisa:

  • cara memesan oleh pawang bidang khusus? Saya mencoba menambahkan 'click sortable'=> TRUE,ATAU 'sort' => array('handler' => 'views_handler_sort',),ATAU $this->query->add_orderby('custom', 'count_depconf_field', 'DESC');ke dalam hand sort handler kustom. Tidak ada yang berfungsi selain mengembalikan kolom Tidak Dikenal di 'order clause'

  • DONE : Bagaimana saya bisa masuk $row->product_iddan $row->nidmasuk query()? Saya membutuhkannya untuk membangun subquery. : Menambahkan bidang penangan tampilan dan menemukan nilai baris dalam render ($ values) ...

  • DIBUAT : Bagian mana dari handler contoh yang harus saya edit? Hanya fungsi kueri? Apakah saya perlu menyimpan seluruh kode contoh atau hanya bagian khusus?

Terima kasih

Kojo
sumber

Jawaban:

7

Anda perlu menggunakan penangan sortir jenis tampilan: https://api.drupal.org/api/views/handlers!views_handler_sort.inc/group/views_sort_handlers/7.x-3.x

Anda tidak dapat menggunakan PHP untuk menyortir hasil Anda karena alasan kinerja. PHP hanya dapat digunakan untuk mengurutkan hasil jika Anda mengambil seluruh hasil tabel, dan itu bukan opsi yang paling sering.

Jadi, Anda perlu membuat handler sortir view Anda sendiri, konfigurasikan dalam view Anda dan kemudian gunakan fungsi views API untuk membuat gabungan yang tepat, di mana, bahkan mungkin subqueries untuk mencapai data yang Anda butuhkan untuk sortir Anda. Dalam kasus Anda, sejumlah entitas yang memiliki kondisi tanggal dan jenis tertentu.

Semua kode ini harus berada di metode "query ()" objek Anda. Anda perlu mencapai permintaan seperti ini:

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())

Dengan menggunakan fungsi https://api.drupal.org/api/views/plugins%21views_plugin_query_default.inc/function/views_plugin_query_default%3A%3Aadd_orderby/7.x-3.x dan sebuah subquery.

Subquery dapat dioptimalkan dalam 3 atau lebih sambungan dan beberapa kondisi di mana mungkin tapi saya tidak tahu tanpa seluruh permintaan.

EDIT

Anda memanjang dari objek "views_handler" tetapi Anda harus langsung memanjang dari "views_handler_sort" untuk dapat menggunakan maksimum kode default inti:

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

Seperti yang Anda lihat di atas, hanya metode "kueri" yang diperlukan dalam kasus Anda karena Anda tidak memerlukan konfigurasi khusus di UI dll.

Untuk mendapatkan product_id atau nid di dalam metode "kueri ()" Anda, Anda harus menggunakan bidang yang sudah ada yang ditambahkan ke kueri oleh penangan bidang tampilan (dan didefinisikan dalam UI tampilan Anda).

File ini adalah contoh sempurna dari apa yang ingin Anda capai (Anda dapat menemukannya di dokumentasi tampilan, ini sudah ada tapi saya tidak diizinkan untuk mengatur tautan karena reputasi saya terlalu rendah):

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

Lihat apakah Anda dapat menyesuaikan kode ini dengan kebutuhan Anda dan saya akan senang melihat hasil akhirnya :)

Renrhaf
sumber
Saya mengedit pertanyaan saya dengan kemajuan. Jika Anda ingin melengkapi jawaban Anda? Terima kasih banyak
Kojo
1
Selesai, tolong periksa dan beritahu saya jika Anda berhasil membuat jenis pekerjaan Anda :)
Renrhaf
Buruk saya, saya menyadari bahwa karena pandangan bergantung pada permintaan DB untuk mengurutkan, sepertinya saya tidak akan pernah mencapai jenis tampilan dengan bidang boneka seperti yang dibuat oleh penangan! Jadi saya pasti harus bekerja pada subquery!
Kojo
1
Maaf karena tidak bereaksi sebelumnya! Saya harap jawaban saya bermanfaat tetapi Anda melakukan semua pekerjaan sendiri, saya tidak tahu tentang hal alias subquery, terima kasih atas solusi terperinci Anda, ini akan membantu banyak orang.
Renrhaf
4

Saya membagikan di bawah implementasi lengkap tentang bagaimana saya melakukan penggantian sortasi Views PHP oleh handler Views kustom .

file .info

files[] = includes/views_handler_my_custom_sort.inc

File modul

/**
 * 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'),
  );
}

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

  }
}

Sedikit penjelasan: setelah memahami bagaimana menerapkan penangan Views, saya bingung dengan subquery:

  • petakan dengan kueri luar untuk mendapatkan hasil "baris oleh" dinamis: tabel dan kolom yang sama tetapi alias berbeda: WHERE nod.nid = node.nid
  • atur alias di add_orderby: $this->query->add_orderby(NULL, $sub_query, 'DESC', 'subquery');berfungsi, tetapi $this->query->add_orderby(NULL, $sub_query, 'DESC');tidak

Poin terakhir ini mengejutkan karena ketika 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 )bekerja dalam input langsung SQL, itu tidak melintasi pengaturan saat ini.

Anda perlu menentukan alias subquery dan kueri akhir akan seperti itu 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

Mencoba menghitung nilai untuk mengurutkan hasil dalam bidang penangan kustom, tidak berfungsi karena pengurutan tampilan dilakukan berdasarkan DB dan penangan bidang kustom adalah jenis bidang dummy ... setidaknya ini adalah kesimpulan saya.

Kojo
sumber