/** * @param callable|null $filter Accepts an array of objects found in a single query * as its only argument and returns an array of accepted objects. * @return PagerPage */ public function getPage($filter = null) { $numNeeded = $this->options['pager-limit'] + 1; $options = $this->options + array('limit' => $numNeeded, 'offset-dir' => $this->options['pager-dir'], 'offset-id' => $this->options['pager-offset'], 'include-offset' => $this->options['pager-include-offset'], 'offset-elastic' => true); $offset = $this->options['pager-offset']; $results = array(); $queries = 0; do { if ($queries === 2) { // if we hit a third query ask for more items $options['limit'] = min(self::MAX_LIMIT, $this->options['pager-limit'] * 5); } // Retrieve results $found = $this->storage->find($this->query, array('offset-id' => $offset) + $options); if (!$found) { // nothing found break; } $filtered = $filter ? call_user_func($filter, $found) : $found; if ($this->options['pager-dir'] === 'rev') { // Paging A-Z with pager-offset F, pager-dir rev, pager-limit 2 gives // DE on first query, BC on second, and A on third. The output // needs to be ABCDE $results = array_merge($filtered, $results); } else { $results = array_merge($results, $filtered); } if (count($found) !== $options['limit']) { // last page break; } // setup offset for next query if ($this->options['pager-dir'] === 'rev') { $last = reset($found); } else { $last = end($found); } $offset = $this->storage->serializeOffset($last, $this->sort); } while (count($results) < $numNeeded && ++$queries < self::MAX_QUERIES); if ($queries >= self::MAX_QUERIES) { $count = count($results); $limit = $this->options['pager-limit']; wfDebugLog('Flow', __METHOD__ . "Reached maximum of {$queries} queries with {$count} results of {$limit} requested with query of " . json_encode($this->query) . ' and options ' . json_encode($options)); } if ($results) { return $this->processPage($results); } else { return new PagerPage(array(), array(), $this); } }