4

I'm using a view where elements are sorted by price values, under certain conditions the price values are rewritten on the display (if there are offers) but not in the database. The problem is that I need the results to be ordered by the rewritten price. I can reorder the results returned by the query using a views_pre_render hook:

https://stackoverflow.com/questions/2471361/how-to-sort-view-results-programmatically

but it only affects the current page so elements are not properly ordered within the elements not shown in the current page.

Other option would be to order the view altering the query itself but since the right price values don't actually exist in the database I don't know how this could be done. Is there a way to order the results of a the whole view when paginator exists?

I've thought about not using pagination and requesting all the elements of the view so I can create my own paginator once I've ordered the results but I'm not sure how would it affect the speed of the page.

11
  • 1
    Forget Drupal for a minute and think it through - how would you implement this in any system? Drupal is just a layer over PHP and a database, if you can come up with a method that would allow you to use external data to sort a paged sql query, you'll be able to solve this with Views :)
    – Clive
    Mar 10 '16 at 9:32
  • Yes, for solving it in any system it would require to alter the query that returns the results using the values I need which are not stored in the database. This could be done, maybe, using a temporary database in the query where i would store the values for which I want the results to be ordered by, but I don't know how this could be done. Mar 10 '16 at 9:36
  • That's definitely the right approach - getting Views to do that might be tricky though, I can't recall coming across anything that would help with that. Here's hoping there's something out there already written
    – Clive
    Mar 10 '16 at 9:44
  • hmmm, have you tried using Views PHP and then use Global php as your sort?
    – No Sssweat
    Mar 10 '16 at 12:45
  • 1
    I ended up solving it by retrieving all the view results, modifying the values and using multisort. Then I had to create my own pagination system. I'll post the solution later. It works fast and I can't perceive any delay, but I think this solution is not scalable for very big queries. Mar 18 '16 at 12:02
2

I used a view pre render hook to alter the order of the returned rows (I had to disable pagination and create my own pagination system). Here's an example of the function:

function your_theme_or_module_views_pre_render(&$view) {
  if ('your_view' == $view->name && 'your_display' == $view->current_display ) {
    if(isset($_GET['sort_order'])){
      if($_GET['sort_order'] == 'ASC'){
        $sortorder = SORT_ASC;
      }else{
        $sortorder = SORT_DESC;
      }
      if($_GET['sort_by'] == 'field_price_value'){
        $byprice = true;
      }else{
        $byprice = false;
      }    
    }else{
      $byprice = true;
      $sortorder = SORT_ASC;
    }
    $order = array();
    foreach ($view->result as $key => $row){
    /* Here you can modify the values you want to show
    and put them in an order array */
      $row->field_field_price[0]['rendered']['#markup'] = $thenewprice[$index]."€";
      $row->field_field_price[0]['raw']['value'] = $thenewprice[$index];
      $order[$key] = $thenewprice[$index]; // we will use this array for multisorting
    }

    //this will be used for pagination In my case I'll show 8 results per page
    $numpages = ceil(count($view->result)/8);
    if($byprice){
      /* we only change the rows order if we are sorting by the
      modified field, otherwise the order returned by the view is fine */
      array_multisort($order, $sortorder, $view->result);
    }

Now we create the pagination system you can use this as an example

    if(!isset($_GET['page'])){
      $view->result = array_slice($view->result, 0, 8);
    }else{
      $sumando = ((int)$_GET['page']*8);
      $view->result = array_slice($view->result, $sumando, 8);
    }
    $links = array();
    if(isset($_GET['page'])){
      $page = $_GET['page'];
      $absolute_url = full_url( $_SERVER );
      for($i=0;$i<$numpages;$i++){
        if($page == $i){
          $active = " active";
        }else{
          $active = "";
        }
        $urlconpage = str_replace("page=".$page,"page=".$i,$absolute_url);
        $links[] = "<a class='paginator ".$active."' href='".$urlconpage."'>".$i."</a>";
      }
    }else{
      $absolute_url = full_url( $_SERVER );
      $countarray = explode("?",$absolute_url);
      if(count($countarray)>1){
        for($i=0;$i<$numpages;$i++){
          if(0 == $i){
            $active = " active";
          }else{
            $active = "";
          }
          $urlconpage = $absolute_url."&page=".$i;
          $links[] = "<a class='paginator".$active."' href='".$urlconpage."'>".$i."</a>";
        }
      }else{
        for($i=0;$i<$numpages;$i++){
          if(0 == $i){
            $active = " active";
          }else{
            $active = "";
          }
          $urlconpage = $absolute_url."?page=".$i;
          $links[] = "<a class='paginador".$active."' href='".$urlconpage."'>".$i."</a>";
        }
      }
    }
    $_SESSION['links'] = $links;
  }

Most of the code in the paginator is just to keep unchanged the parameters in the url, essentials for the view returning the right results. The function full_url that I call in the code is an adaptation of the function described in:

https://stackoverflow.com/questions/6768793/get-the-full-url-in-php

Using the SESSION variable You can print the links where you prefere, For example in a global textarea in the view footer, inside an <ul> <li> structure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.