2010-03-18 3 views
11

Я пытаюсь взять результаты представления - используя функцию 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 
+0

Можете ли вы отредактировать SQL-запрос, который создает интерфейс Views, чтобы выполнить сортировку в запросе? – alxp

+0

Нет, сортировка зависит от некоторых переменных, которые недоступны в этом контексте. – Ace

ответ

17

Модуль просмотров provides some hooks для 'внешних' манипуляций, так же, как ядра 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' изнутри этого ,

+0

Звучит очень хорошо!Но что, если у меня есть какая-то внешняя переменная, которая мне нужна для сортировки? – Ace

+0

@Ace: Либо вы можете получить содержимое внешней переменной в реализацию хука (вызывая 'important_function()' оттуда, либо через ранее заполненный глобальный, либо вызывая функцию get_x(), которая использует статическую для хранения ранее вычисленная переменная), или вам нужно обработать обработку «вручную» - я обновлю свой ответ, чтобы показать последний вариант. –

+3

Использование hook_views_pre_render не работает с пейджером. Он будет сортировать результаты текущей страницы. – eSentrik

8

В зависимости от вашей логики сортировки вы можете попытаться использовать 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

+0

Другой пример с оператором SQL ['ORDER BY CASE'] (http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#operator_case) находится в [этом ответе] (http://drupal.stackexchange.com/a/44871/16305). Позволяет произвольный порядок сортировки для полей списка. – tanius

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 не работает для меня.

0

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

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

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