/** * Handles queries that return results, running the results through a * an optional callback function. This is for R queries (from CRUD). * * @param string $query The select query to execute * @param string $callback An optional callback function to run on each row * @param bool $single Return only a single result? * @param array $params Query params. E.g. [1, 'steve'] or [':id' => 1, ':name' => 'steve'] * * @return array An array of database result objects or callback function results. If the query * returned nothing, an empty array. * @throws \DatabaseException */ protected function getResults($query, $callback = null, $single = false, array $params = []) { // Since we want to cache results of running the callback, we need to // need to namespace the query with the callback and single result request. // https://github.com/elgg/elgg/issues/4049 $query_id = (int) $single . $query . '|'; if ($params) { $query_id .= serialize($params) . '|'; } if ($callback) { if (!is_callable($callback)) { $inspector = new \Elgg\Debug\Inspector(); throw new \RuntimeException('$callback must be a callable function. Given ' . $inspector->describeCallable($callback)); } $query_id .= $this->fingerprintCallback($callback); } // MD5 yields smaller mem usage for cache and cleaner logs $hash = md5($query_id); // Is cached? if ($this->query_cache) { if (isset($this->query_cache[$hash])) { if ($this->logger) { // TODO add params in $query here $this->logger->info("DB query {$query} results returned from cache (hash: {$hash})"); } return $this->query_cache[$hash]; } } $return = array(); $stmt = $this->executeQuery($query, $this->getConnection('read'), $params); while ($row = $stmt->fetch()) { if ($callback) { $row = call_user_func($callback, $row); } if ($single) { $return = $row; break; } else { $return[] = $row; } } // Cache result if ($this->query_cache) { $this->query_cache[$hash] = $return; if ($this->logger) { // TODO add params in $query here $this->logger->info("DB query {$query} results cached (hash: {$hash})"); } } return $return; }
/** * Count the total results available at this moment. * * As this performs a separate query, the count returned may not match the number of results you can * fetch via iteration on a very active DB. * * @see Countable::count() * @return int */ public function count() { if (!is_callable($this->getter)) { $inspector = new \Elgg\Debug\Inspector(); throw new RuntimeException("Getter is not callable: " . $inspector->describeCallable($this->getter)); } $options = $this->options + ['count' => true]; return call_user_func($this->getter, $options); }