Wie ersetze ich das PHP-Feld für Ansichten und sortiere es nach einem benutzerdefinierten Ansichten-Handler?

11

Um einige Leistungsprobleme von Views zu beheben und Best Practices zu respektieren, möchte ich einige Views PHP ersetzen, die ich vor einiger Zeit durch meine eigenen benutzerdefinierten Handler konfiguriert habe .

Zum Beispiel habe ich ein PHP-Feld für Ansichten, das von der Anzeige ausgeschlossen ist , mit diesem Setup:

Wertecode:

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

Ausgabecode :

<?php print $value ; ?>`

Dann verwende ich dieses Feld als erstes Sortierkriterium ( aufsteigend ) in einem globalen PHP-Sortierkriterium:

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

Ich wäre Ihnen sehr dankbar, wenn Sie mich auf den richtigen Weg bringen könnten: In welchen Funktionen soll ich denselben Code erstellen, um PHP in der Datenbank zu erhalten?

Zusammenfassung :

Nach der Suche und dem Fortschritt sowie der @ Renrahf-Hilfe scheint der größte Teil der Implementierung in Ordnung zu sein (siehe unten). Aber ich kämpfe immer noch mit einem Punkt : Ich habe einen benutzerdefinierten Feldhandler hinzugefügt, um einen Wert zu berechnen, aber wie kann ich nach diesem Handler bestellen?

Bearbeitungen:

Was ich bisher gemacht habe:

.info Datei

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

Moduldatei

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

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

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

Verbleibende Frage:

  • Wie bestelle ich mit dem benutzerdefinierten Feldhandler? Ich habe versucht, 'click sortable'=> TRUE,OR 'sort' => array('handler' => 'views_handler_sort',),OR $this->query->add_orderby('custom', 'count_depconf_field', 'DESC');in einen benutzerdefinierten Sortierhandler einzufügen. Keine funktioniert, aber unbekannte Spalte in 'order-Klausel' zurückgeben

  • FERTIG : Wie komme ich hinein $row->product_idund $row->nidhinein query()? Ich brauche es, um die Unterabfrage zu erstellen. : Ein Views-Handler-Feld wurde hinzugefügt und die Zeilenwerte in render ($ values) gefunden ...

  • FERTIG : Welchen Teil des Beispiel- Handlers muss ich bearbeiten? Nur die Abfragefunktion? Muss ich den gesamten Beispielcode oder nur die benutzerdefinierten Teile behalten?

Vielen Dank

Kojo
quelle

Antworten:

7

Sie müssen einen Views Sort Handler verwenden: https://api.drupal.org/api/views/handlers!views_handler_sort.inc/group/views_sort_handlers/7.x-3.x

Sie können PHP aus Leistungsgründen nicht zum Sortieren Ihrer Ergebnisse verwenden. PHP kann nur zum Sortieren von Ergebnissen verwendet werden, wenn Sie die gesamten Tabellenergebnisse abrufen. Dies ist meistens keine Option.

Sie müssen also Ihren eigenen Ansichts-Sortier-Handler erstellen, ihn in Ihrer Ansicht konfigurieren und dann die Ansichten-API-Funktionen verwenden, um die richtigen Verknüpfungen herzustellen, wobei möglicherweise sogar Unterabfragen die Daten enthalten, die Sie für Ihre Sortierung benötigen. In Ihrem Fall eine Reihe von Entitäten mit bestimmten Datums- und Typbedingungen.

Der gesamte Code muss sich in der Methode "query ()" Ihres Objekts befinden. Sie müssen eine Abfrage wie folgt durchführen:

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

Mithilfe der Funktion https://api.drupal.org/api/views/plugins%21views_plugin_query_default.inc/function/views_plugin_query_default%3A%3Aadd_orderby/7.x-3.x und einer Unterabfrage.

Die Unterabfrage kann in 3 oder mehr Gelenken und einigen Bedingungen optimiert werden, aber ich kann es nicht ohne die gesamte Abfrage sagen.

BEARBEITEN

Sie erstrecken sich vom Objekt "views_handler", sollten sich jedoch direkt vom Objekt "views_handler_sort" erstrecken, um das Maximum des Standard-Kerncodes verwenden zu können:

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

Wie Sie oben sehen können, wird in Ihrem Fall nur die "Abfragemethode" benötigt, da Sie keine spezifischen Konfigurationen in der Benutzeroberfläche usw. benötigen.

Um die product_id oder nid in Ihre "query ()" - Methode aufzunehmen, müssen Sie vorhandene Felder verwenden, die der Abfrage von Views-Feldhandlern hinzugefügt (und in Ihrer Views-Benutzeroberfläche definiert) wurden.

Diese Datei ist das perfekte Beispiel für das, was Sie erreichen möchten (Sie finden sie in der Ansichtsdokumentation, es ist eine vorhandene, aber ich darf den Link nicht festlegen, da mein Ruf zu niedrig ist):

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

Sehen Sie, ob Sie diesen Code an Ihre Bedürfnisse anpassen können, und ich freue mich über das Endergebnis :)

Renrhaf
quelle
Ich habe meine Frage mit Fortschritt bearbeitet. Wenn Sie Ihre Antwort vervollständigen möchten? Vielen Dank
Kojo
1
Fertig, bitte
schau es
Mein schlechtes, ich habe festgestellt, dass es so aussieht, als würde ich niemals eine Ansichtssortierung mit einem Dummy-Feld wie dem vom Handler erstellten erzielen, da die Ansichten zum Sortieren auf DB-Abfragen basieren! Also muss ich definitiv an der Unterabfrage arbeiten!
Kojo
1
Entschuldigung, dass Sie nicht früher reagiert haben! Ich hoffe, meine Antwort war nützlich, aber Sie haben die ganze Arbeit selbst erledigt. Ich wusste nichts über den Unterabfrage-Alias. Vielen Dank für Ihre detaillierte Lösung, sie wird vielen Menschen helfen.
Renrhaf
4

Im Folgenden wird die vollständige Implementierung erläutert, wie ich die PHP-Sortierung für Ansichten durch einen benutzerdefinierten Ansichtshandler ersetzt habe .

.info Datei

files[] = includes/views_handler_my_custom_sort.inc

Moduldatei

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

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

  }
}

Eine kleine Erklärung: Nachdem ich verstanden hatte, wie Views-Handler implementiert werden, wurde ich mit der Unterabfrage verwechselt:

  • Ordnen Sie es der äußeren Abfrage zu, um ein dynamisches "row by" -Ergebnis zu erhalten: gleiche Tabelle und Spalte, aber unterschiedlicher Alias: WHERE nod.nid = node.nid
  • Setzen Sie den Alias ​​in add_orderby: $this->query->add_orderby(NULL, $sub_query, 'DESC', 'subquery');funktioniert, funktioniert aber $this->query->add_orderby(NULL, $sub_query, 'DESC');nicht

Dieser letzte Punkt war überraschend, da er zwar 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 )in der direkten SQL-Eingabe funktioniert, jedoch nicht im aktuellen Setup.

Sie müssen den Unterabfrage-Alias ​​angeben, und die endgültige Abfrage lautet ungefähr so 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

Die Versuche, die Werte zum Sortieren des Ergebnisses in einem benutzerdefinierten Handlerfeld zu berechnen, haben nicht funktioniert, da die Sortierung der Ansichten auf DB-Basis erfolgt und der benutzerdefinierte Feldhandler eine Art Dummy-Feld ist ... zumindest war dies meine Schlussfolgerung.

Kojo
quelle