Як замінити поле PHP Views і сортування за власним обробником Views?


11

Для того, щоб вирішити деякі проблеми з ефективністю перегляду та дотримуватися кращих практик, я хотів би замінити деякі PHP-файли Views, які я налаштував деякий час тому своїми власними власними обробниками .

Наприклад, у мене з'явилося поле PHP Views 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 ; ?>`

Тоді я використовую це поле як критерії першого сортування (за зростанням ) у критеріях сортування Global PHP:

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,АБО 'sort' => array('handler' => 'views_handler_sort',),АБО $this->query->add_orderby('custom', 'count_depconf_field', 'DESC');до спеціального обробника сортування. Ніхто не працює, але повертає невідомий стовпець у "порядку замовлення"

  • Зроблено : Як я можу потрапити $row->product_idі $row->nidвсередину query()? Мені це потрібно для створення підзапиту. : Додано поле обробника поглядів та знайдено значення рядків у візуалізації ($ значень) ...

  • ВНИМАНО : Яку частину обробника прикладу я повинен редагувати? Функція запиту лише? Чи потрібно зберігати весь прикладний код або лише спеціальні частини?

Дякую

Відповіді:


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 або більше з'єднаннях, а десь там, де можливо, але я не можу сказати без цілого запиту.

EDIT

Ви поширюєтесь з об’єкта "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']);
  }
}

Як ви бачите вище, у вашому випадку потрібен лише метод "запит", оскільки вам не потрібні конкретні конфігурації в інтерфейсі тощо.

Щоб отримати product_id або nid у вашому методі "query ()", ви повинні використовувати наявні поля, які були додані до запиту обробниками полів перегляду (і визначені у вашому інтерфейсі перегляду).

Цей файл є ідеальним прикладом того, чого ви хочете досягти (ви можете знайти його в документації щодо переглядів, він є вже існуючим, але мені не дозволяється встановлювати посилання, оскільки моя репутація занадто низька):

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

Подивіться, чи можете ви пристосувати цей код до ваших потреб, і я буду радий побачити кінцевий результат :)


Я редагував своє питання з прогресом. Якщо ви хочете доповнити свою відповідь? Велике спасибі
Коджо

1
Готово, будь ласка, перевірте це та скажіть, чи вам вдалося
налагодити

Погано, я зрозумів, що оскільки погляди покладаються на запит БД для сортування, схоже, я ніколи не досягну сортування поглядів з фіктивним полем, подібним до того, яке створив обробник! Тож я остаточно повинен працювати над підзапитом!
Коджо

1
Вибачте, що раніше не реагували! Я сподіваюся, що моя відповідь виявилася корисною, але ви всю роботу зробили самі, я не знав про предмет псевдоніму, також дякую за ваше детальне рішення, це допоможе багатьом людям.
Renrhaf

4

Нижче я поділяюся повною реалізацією того, як я замінив сортування PHP-оглядів на користувальницький обробник Views .

.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

Спроби обчислити значення для сортування результатів у користувальницькому полі обробника, не спрацювали, тому що сортування переглядів проводиться на базі БД, а користувацький обробник поля - це своєрідне фіктивне поле ... принаймні, це був мій висновок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.