Как отсортировать результаты поиска программно?

Я пытаюсь взять результаты представления - используя функцию views_get_view_result() - и отсортировать массив так, как я не мог бы сделать из интерфейса Views. Все идет нормально. У меня есть переменная $rows со всеми необходимыми материалами.

Теперь... Как мне вернуть его?:) Прежде чем мне понадобился этот вид, я использовал views_embed_view(), но больше не могу этого делать.

Спасибо за любую помощь в этом, чувствую, что я так близок к ее взлому!

$important_var = important_function();
$result = views_get_view_result($view, $display, $args);
$result = sorting_function($result, $important_var);

//TODO: Put the result back into the view

Ответ 1

Модуль views предоставляет некоторые крючки для "внешних" манипуляций, как и ядро ​​Drupal.

Вы можете реализовать hook_views_pre_render(&$view) в настраиваемом модуле и управлять массивом результатов, доступным в $view->result:

/**
 * Implementation of hook_views_pre_render()
 *
 * @param view $view
 */
function YourModuleName_views_pre_render(&$view) {
  // Check if this is the view and display you want to manipulate
  // NOTE: Adjust/Remove the display check, if you want to manipulate some/all displays of the view
  if ('YourViewName' == $view->name && 'YourDisplayName' == $view->current_display) {
    // EXAMPLE: Just reverse result order
    // TODO: Replace with your desired (re)ordering logic
    $view->result = array_reverse($view->result);
  }
}

Крюк вызывается в середине процесса создания представления, после того, как все данные результата собраны, но до того, как фактический вывод будет обработан, поэтому изменения в массиве результатов будут отражены в окончательном выходе представлений.

EDIT:. Кроме того, вы можете обрабатывать представление "вручную", копируя поведение функции views_get_view_result(), но вместо того, чтобы возвращать результат, вы управляете им и продолжаете отображать представление

function yourModule_get_custom_sorted_view($display_id = NULL) {
  // As the custom sorting probably only works for a specific view,
  // we 'demote' the former $name function parameter of 'views_get_view_result()'
  // and set it within the function:
  $name = 'yourViewName';
  // Prepare a default output in case the view definition can not be found
  // TODO: Decide what to return in that case (using empty string for now)
  $output = '';

  // Then we create the result just as 'views_get_view_result()' would do it:
  $args = func_get_args();
  if (count($args)) {
    array_shift($args); // remove $display_id
  }

  $view = views_get_view($name);
  if (is_object($view)) {
    if (is_array($args)) {
      $view->set_arguments($args);
    }
    if (is_string($display_id)) {
      $view->set_display($display_id);
    }
    else {
      $view->init_display();
    }
    $view->pre_execute();
    $view->execute();
    // 'views_get_view_result()' would just return $view->result here,
    // but we need to go on, reordering the result:
    $important_var = important_function();
    $view->result = sorting_function($result, $important_var);
    // Now we continue the view processing and generate the rendered output
    // NOTE: $view->render will call $view->execute again,
    // but the execute method will detect that it ran already and not redo it.
    $output = $view->render();
    // Clean up after processing
    $view->post_execute();
  }

  return $output;
}

Примечание: Это много дублирования кода и, следовательно, ошибка - я не рекомендую это и скорее пойду с помощью реализации hook выше, пытаясь найти способ получить доступ к вашему " $important_var 'изнутри.

Ответ 2

В зависимости от вашей логики сортировки вы можете попытаться использовать hook_views_query_alter(), чтобы реализовать сортировку непосредственно в запросе.

Это может быть немного сложно, но вы можете ознакомиться с объектом views_query.

Вот пример реального мира, в котором я применил правило объединения на основе контекста страницы, а затем добавил правила сортировки.

/** 
 * Implementation of hook_views_query_alter(). 
 */ 
function yourmodule_views_query_alter(&$view, &$query) { 
  if ($view->name == 'view_projects' && $view->current_display == 'panel_pane_4') { 
    if (arg(0) == 'node' && is_numeric(arg(1))) { 
      $node = node_load(arg(1)); 
      if ($client_nid = $node->field_ref_client[0]['nid']) { 
        $query->table_queue['node_node_data_field_ref_client']['join']->extra = "field_ref_client_nid = " . $client_nid;
        $query->add_orderby('node', NULL, 'DESC', 'node_node_data_field_ref_client_nid'); 
        $query->add_orderby('node', 'created', 'DESC'); 
      } 
    }
  } 
}

Смотрите: http://drupalcontrib.org/api/function/hook_views_query_alter/6

Ответ 3

Я использую для этого такой код:

/**
 * Implementation of hook_views_post_execute()
 *
 * @param view $view
 */
function YourModuleName_views_post_execute(&$view) {
  // Check if this is the view and display you want to manipulate
  // NOTE: Adjust/Remove the display check, if you want to manipulate some/all displays of the view
  if ('YourViewName' == $view->name && 'YourDisplayName' == $view->current_display) {
    // EXAMPLE: Just reverse result order
    // TODO: Replace with your desired (re)ordering logic
    $view->result = array_reverse($view->result);
  }
}

hook_views_pre_render не работает для меня.

Ответ 4

Я объединил приведенные выше примеры и переписал его следующим образом. В моем случае мне пришлось сортировать элементы по отдельности.

ПРИМЕЧАНИЕ. Я не включил условие соединения, и я не пробовал его с настраиваемым полем. Но я чувствую, что вы можете легко понять это.

/** 
 * Implementation of hook_views_query_alter(). 
 */ 
function yourmodule_views_query_alter(&$view, &$query) { 
  if ($view->name == 'your_view_name' && $view->current_display == 'your_pane_name') {
    if ($query->orderby[0]['field'] == 'my_order_field') {
      $query->orderby[0]['field'] = "FIELD(my_order_field, 'ord3','ord1','ord2')";
    }
  }
}