I posted an issue on the Search API issue tracker, about missing calls to pre and post execute on pagers, which break for example php filters from working, i was asked to create a support request issue over here and ask how to correctly do this, as Drunken Monkey does not know exactly how to correctly do this.

Issue in Search API tracker: http://drupal.org/node/1194978

Comments

drunken monkey’s picture

Thanks for creating this issue!
Subscribing.

dawehner’s picture

To what kind of pagers do you refer?
Do you refer to views pager plugins? It's a bit hard to understand this issue

merlinofchaos’s picture

Status: Active » Fixed

Without specific questions, all I can really do is show you the code that's used to execute the pre/post execute methods on the pager:


        if ($this->pager->use_count_query() || !empty($view->get_total_rows)) {
          $this->pager->execute_count_query($count_query);
        }

        // Let the pager modify the query to add limits.
        $this->pager->pre_execute($query);

        if (!empty($this->limit) || !empty($this->offset)) {
          // We can't have an offset without a limit, so provide a very large limit instead.
          $limit  = intval(!empty($this->limit) ? $this->limit : 999999);
          $offset = intval(!empty($this->offset) ? $this->offset : 0);
          $query->range($offset, $limit);
        }

        $result = $query->execute();

        $view->result = array();
        foreach ($result as $item) {
          $view->result[] = $item;
        }

        $this->pager->post_execute($view->result);

        if ($this->pager->use_pager()) {
          $view->total_rows = $this->pager->get_total_items();
        }
merlinofchaos’s picture

The above code is part of views_plugin_query_default::execute()

dawehner’s picture

It could be that they want to move up pager->pre_execute before executing the cout query.

merlinofchaos’s picture

I don't see what benefit that would provide.

drunken monkey’s picture

This isn't about changing the code in the default query plugin, but understanding what to add for other query plugins.
The problem (according to the OP) seems to be that without calling the pager's pre_execute() and post_execute() methods, PHP filters don't seem to work. Currently the Search API doesn't call those, and as the methods take a database query as a parameter (which the Search AP does not use), it seems I also can't do this.

Now the question is: Is it really necessary to call the two methods for a correctly working PHP filters, or could something else be the reason? The pager seems to work just fine as it is (as far as I know/can tell). The OP has reported problems in that respect with the Search API Views integration.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

dkgof’s picture

Sorry, i have been away on vacation, and therefor not been able to keep up with this issue as much as i should have.

I will try to explain in greater detail.

The problem i am experiencing is that PHP Filter's added to the view to filter search results does not work, even if i add a filter that should filter every result, the search still shows all results on any given query. The reason i believe that the pre_execute() and post_execute() methods are the missing step is that i could get it somewhat working by inserting these. But with my limited understanding of the Search API code and the Views code i never got it working 100%, the search page pager sees all to many pages when my filter removes some of the search results.

The need for the filtering of search results via the PHP Filter is that we have access control on nodes, and not all users are allowed to see all nodes, so they naturally have to be excluded from the results.

dkgof’s picture

Status: Closed (fixed) » Active
drunken monkey’s picture

Project: Views (for Drupal 7) » Search API
Version: 7.x-3.x-dev » 7.x-1.x-dev
Component: Code » Views integration

But with my limited understanding of the Search API code and the Views code i never got it working 100%, the search page pager sees all to many pages when my filter removes some of the search results.

The need for the filtering of search results via the PHP Filter is that we have access control on nodes, and not all users are allowed to see all nodes, so they naturally have to be excluded from the results.

I have thought intensely about entity access checks in the Search API, and I'm pretty sure there is really no way of doing this while still having correct paging. Specifically, if you post-filter the search results with PHP code, it's both clear and inevitable that the paging will be false (as soon as any items get filtered): when you get ten results, and filter out two, there is no way to still display ten results for the page. There is also no (easy) way to tell how many results there will be in total, after they are filtered by your PHP code.

For minimizing the impact of this filtering, try to put as much of the access checks as possible into normal Search API filters. If you want to dynamically filter for the access rights of the current user, you could do this with a query alter hook, dynamically adding the filters necessary for the current user (on status, type, etc.).

drunken monkey’s picture

Title: Search API pager needs pre and post execute calls » Problems with Views PHP filter
Status: Active » Fixed

So, is the issue fixed with this information?
Would like to close this issue, as various people seem to have been confused by it.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

lex0r’s picture

Sorry to re-open this issue, but I found another use case where we need post_execute() on pager object to be called with view results to allow some post-processing. Namely, there is a module views_load_more that uses post_execute() to do some of its magic. The fix is pretty trivial if you just want to have post_execute called and pager has an implementation of it. I will probably create a patch but for now:

  public function execute(&$view) {
    if ($this->errors) {
      if (error_displayable()) {
        foreach ($this->errors as $msg) {
          drupal_set_message(check_plain($msg), 'error');
        }
      }
      $view->result = array();
      $view->total_rows = 0;
      $view->execute_time = 0;
      return;
    }

    try {
      $start = microtime(TRUE);

      // Execute the search.
      $results = $this->query->execute();
      $this->search_api_results = $results;

      // Store the results.
      $this->pager->total_items = $view->total_rows = $results['result count'];
      if (!empty($this->pager->options['offset'])) {
        $this->pager->total_items -= $this->pager->options['offset'];
      }
      $this->pager->update_page_info();
      $view->result = array();
      if (!empty($results['results'])) {
        $this->addResults($results['results'], $view);
      }

      // Let the pager modify the result (as vanilla views implementation does).
      if (method_exists($this->pager, 'post_execute')) {
        $this->pager->post_execute($view->result);
      }

      // We shouldn't use $results['performance']['complete'] here, since
      // extracting the results probably takes considerable time as well.
      $view->execute_time = microtime(TRUE) - $start;
    }
    catch (Exception $e) {
      $this->errors[] = $e->getMessage();
      // Recursion to get the same error behaviour as above.
      return $this->execute($view);
    }
  }

This part does the job:

      // Let the pager modify the result (as vanilla views implementation does).
      if (method_exists($this->pager, 'post_execute')) {
        $this->pager->post_execute($view->result);
      }
drunken monkey’s picture

Issue summary: View changes

You didn't re-open the issue, you just posted to it which normally no-one would see. Change the status back from "Closed" if you want people to see your comment.

Anyways, this is already fixed in newer versions of the Search API. Just use a recent release, or the newest dev version, and things should work fine.