Jak zastąpić pole Widoki PHP i sortowanie według niestandardowego modułu obsługi widoków?

11

Aby rozwiązać niektóre problemy z wydajnością widoków i przestrzegać najlepszych praktyk, chciałbym zastąpić niektóre widoki PHP skonfigurowane jakiś czas temu własnymi niestandardowymi programami obsługi .

Na przykład mam pole Widoki PHP, wykluczone z wyświetlania , z taką konfiguracją:

Kod wartości:

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

Kod wyjściowy :

<?php print $value ; ?>`

Następnie używam tego pola jako kryteriów pierwszego sortowania ( rosnąco ) w globalnych kryteriach sortowania PHP:

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

Byłbym naprawdę wdzięczny, gdybyś mógł postawić mnie we właściwy sposób: w jakiej funkcji mam zbudować ten sam kod, aby skończyć z PHP w bazie danych?

Podsumowanie :

Po wyszukiwaniu i postępach oraz pomocy @Renrahf większość implementacji wydaje się być w porządku, szczegółowo poniżej. Ale wciąż walczę z jednym punktem : dodałem niestandardowy moduł obsługi pola, aby obliczyć wartość, ale jak mogę go zamówić?

Edycje:

Co do tej pory zrobiłem:

plik .info

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

Plik modułu

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

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

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

Pozostałe pytanie:

  • jak zamówić przez niestandardowy moduł obsługi pola? Próbowałem dodać 'click sortable'=> TRUE,OR 'sort' => array('handler' => 'views_handler_sort',),LUB $this->query->add_orderby('custom', 'count_depconf_field', 'DESC');do niestandardowego modułu obsługi sortowania. Żadne nie działa, ale zwraca nieznaną kolumnę w „klauzuli zamówienia”

  • ZRÓB : Jak mogę dostać się $row->product_iddo $row->nidśrodka query()? Potrzebuję go do zbudowania podzapytania. : Dodano pole obsługi widoków i znaleziono wartości wierszy w renderowaniu (wartości $) ...

  • ZAKOŃCZONE : Którą część przykładowego modułu obsługi muszę edytować? Tylko funkcja zapytania? Czy muszę zachować cały przykładowy kod, czy tylko niestandardowe części?

Dziękuję Ci

Kojo
źródło

Odpowiedzi:

7

Musisz użyć procedury sortowania widoków: https://api.drupal.org/api/views/handlers!views_handler_sort.inc/group/views_sort_handlers/7.x-3.x

Nie możesz używać PHP do sortowania wyników ze względu na wydajność. PHP może być używane do sortowania wyników tylko wtedy, gdy pobierzesz wyniki z całej tabeli, i nie jest to zazwyczaj opcja.

Musisz więc stworzyć własną procedurę obsługi sortowania widoków, skonfigurować ją w swoim widoku, a następnie użyć funkcji API views, aby wykonać odpowiednie sprzężenia, w których być może nawet podzapytania w celu uzyskania danych potrzebnych do sortowania. W twoim przypadku wiele podmiotów ma określone warunki dotyczące daty i typu.

Cały ten kod musi znajdować się w metodzie „query ()” obiektu. Musisz wykonać takie zapytanie:

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

Korzystając z funkcji https://api.drupal.org/api/views/plugins%21views_plugin_query_default.inc/function/views_plugin_query_default%3A%3Aadd_orderby/7.x-3.x oraz podzapytania.

Podkwerenda może być zoptymalizowana w 3 lub więcej połączeniach i w niektórych przypadkach, gdzie warunki, ale nie mogę powiedzieć bez całego zapytania.

EDYTOWAĆ

Rozszerzasz z obiektu „views_handler”, ale powinieneś bezpośrednio rozciągać z „views_handler_sort”, aby móc użyć maksimum podstawowego kodu domyślnego:

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

Jak widać powyżej, w twoim przypadku potrzebna jest tylko metoda „zapytanie”, ponieważ nie potrzebujesz żadnych konkretnych konfiguracji w interfejsie użytkownika itp.

Aby uzyskać product_id lub NID wewnątrz „zapytania ()” metoda, trzeba użyć istniejących pól, które zostały dodane do zapytania przez koparki widoki polowych (i zdefiniowane w widokach UI).

Ten plik jest doskonałym przykładem tego, co chcesz osiągnąć (możesz go znaleźć w dokumentacji widoków, jest już istniejący, ale nie mogę ustawić linku, ponieważ moja reputacja jest zbyt niska):

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

Sprawdź, czy możesz dostosować ten kod do swoich potrzeb, a ja z przyjemnością zobaczę wynik końcowy :)

Renrhaf
źródło
Zredagowałem moje pytanie z postępem. Jeśli chcesz wypełnić swoją odpowiedź? Wielkie dzięki
Kojo,
1
Gotowe, sprawdź to i powiedz mi, czy udało ci się uruchomić swój rodzaj :)
Renrhaf
Moje zło, zdałem sobie sprawę, że ponieważ widoki opierają się na zapytaniu DB do sortowania, wygląda na to, że nigdy nie osiągnę sortowania widoków z polem sztucznym, takim jak to utworzone przez moduł obsługi! Więc zdecydowanie muszę popracować nad podzapytaniem!
Kojo
1
Przepraszam, że nie zareagowałem wcześniej! Mam nadzieję, że moja odpowiedź była przydatna, ale wykonałeś całą pracę sam, nie wiedziałem o aliasie podzapytania, dzięki za szczegółowe rozwiązanie, pomoże wielu ludziom.
Renrhaf
4

Udostępniam poniżej pełnej implementacji, w jaki sposób zastąpiłem sortowanie widoków PHP przez niestandardową procedurę obsługi widoków .

plik .info

files[] = includes/views_handler_my_custom_sort.inc

Plik modułu

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

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

  }
}

Trochę wyjaśnienia: po zrozumieniu, jak zaimplementować procedury obsługi widoków, pomyliłem się z podzapytaniem:

  • zamapuj go za pomocą zewnętrznego zapytania, aby uzyskać dynamiczny wynik „wiersz po”: ta sama tabela i kolumna, ale inny alias: WHERE nod.nid = node.nid
  • ustaw alias w add_orderby: $this->query->add_orderby(NULL, $sub_query, 'DESC', 'subquery');działa, ale $this->query->add_orderby(NULL, $sub_query, 'DESC');nie działa

Ten ostatni punkt był zaskakujący, ponieważ chociaż 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 )działa w trybie bezpośredniego wprowadzania SQL, nie działa w bieżącej konfiguracji.

Musisz podać alias podzapytania, a końcowe zapytanie będzie podobne 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

Próby obliczenia wartości w celu posortowania wyniku w niestandardowym polu obsługi nie zadziałały, ponieważ sortowanie widoków odbywa się na podstawie bazy danych, a niestandardowy moduł obsługi pól jest rodzajem pola zastępczego ... przynajmniej taki był mój wniosek.

Kojo
źródło