/** * Sets up required mocks and the CommentStatistics service under test. */ protected function setUp() { $this->statement = $this->getMockBuilder('Drupal\\Core\\Database\\Driver\\sqlite\\Statement')->disableOriginalConstructor()->getMock(); $this->statement->expects($this->any())->method('fetchObject')->will($this->returnCallback(array($this, 'fetchObjectCallback'))); $this->select = $this->getMockBuilder('Drupal\\Core\\Database\\Query\\Select')->disableOriginalConstructor()->getMock(); $this->select->expects($this->any())->method('fields')->will($this->returnSelf()); $this->select->expects($this->any())->method('condition')->will($this->returnSelf()); $this->select->expects($this->any())->method('execute')->will($this->returnValue($this->statement)); $this->database = $this->getMockBuilder('Drupal\\Core\\Database\\Connection')->disableOriginalConstructor()->getMock(); $this->database->expects($this->once())->method('select')->will($this->returnValue($this->select)); $this->commentStatistics = new CommentStatistics($this->database, $this->getMock('Drupal\\Core\\Session\\AccountInterface'), $this->getMock('Drupal\\Core\\Entity\\EntityManagerInterface'), $this->getMock('Drupal\\Core\\State\\StateInterface')); }
/** * Builds the SQL for the join this object represents. * * @param \Drupal\Core\Database\Query\SelectInterface $select_query * The select query object. * @param string $table * The base table to join. * @param \Drupal\views\Plugin\views\query\QueryPluginBase $view_query * The source views query. */ public function buildJoin($select_query, $table, $view_query) { if (empty($this->configuration['table formula'])) { $right_table = "{" . $this->table . "}"; } else { $right_table = $this->configuration['table formula']; } // Add our join condition, using a subquery on the left instead of a field. $condition = "({$this->left_query}) = {$table['alias']}.{$this->field}"; $arguments = array(); // Tack on the extra. // This is just copied verbatim from the parent class, which itself has a // bug: https://www.drupal.org/node/1118100. if (isset($this->extra)) { if (is_array($this->extra)) { $extras = array(); foreach ($this->extra as $info) { // Figure out the table name. Remember, only use aliases provided // if at all possible. $join_table = ''; if (!array_key_exists('table', $info)) { $join_table = $table['alias'] . '.'; } elseif (isset($info['table'])) { $join_table = $info['table'] . '.'; } $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder(); if (is_array($info['value'])) { $operator = !empty($info['operator']) ? $info['operator'] : 'IN'; // Transform from IN() notation to = notation if just one value. if (count($info['value']) == 1) { $info['value'] = array_shift($info['value']); $operator = $operator == 'NOT IN' ? '!=' : '='; } } else { $operator = !empty($info['operator']) ? $info['operator'] : '='; } $extras[] = "{$join_table}{$info['field']} {$operator} {$placeholder}"; $arguments[$placeholder] = $info['value']; } if ($extras) { if (count($extras) == 1) { $condition .= ' AND ' . array_shift($extras); } else { $condition .= ' AND (' . implode(' ' . $this->extraOperator . ' ', $extras) . ')'; } } } elseif ($this->extra && is_string($this->extra)) { $condition .= " AND ({$this->extra})"; } } $select_query->addJoin($this->type, $right_table, $table['alias'], $condition, $arguments); }
/** * Preprocesses and validates the query. * * @return bool * TRUE if the validation was successful, FALSE if not. * * @throws \Drupal\Core\Database\Query\FieldsOverlapException * @throws \Drupal\Core\Database\Query\NoFieldsException */ protected function preExecute() { // Confirm that the user did not try to specify an identical // field and default field. if (array_intersect($this->insertFields, $this->defaultFields)) { throw new FieldsOverlapException('You may not specify the same field to have a value and a schema-default value.'); } if (!empty($this->fromQuery)) { // We have to assume that the used aliases match the insert fields. // Regular fields are added to the query before expressions, maintain the // same order for the insert fields. // This behavior can be overridden by calling fields() manually as only the // first call to fields() does have an effect. $this->fields(array_merge(array_keys($this->fromQuery->getFields()), array_keys($this->fromQuery->getExpressions()))); } else { // Don't execute query without fields. if (count($this->insertFields) + count($this->defaultFields) == 0) { throw new NoFieldsException('There are no fields available to insert with.'); } } // If no values have been added, silently ignore this query. This can happen // if values are added conditionally, so we don't want to throw an // exception. if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->fromQuery)) { return FALSE; } return TRUE; }
/** * Translates the string operators to SQL equivalents. * * @param array $condition * The condition array. * @param \Drupal\Core\Database\Query\SelectInterface $sql_query * Select query instance. * @param bool|null $case_sensitive * If the condition should be case sensitive or not, NULL if the field does * not define it. * * @see \Drupal\Core\Database\Query\ConditionInterface::condition() */ public static function translateCondition(&$condition, SelectInterface $sql_query, $case_sensitive) { // There is nothing to do for IN () queries except for PostgreSQL for which // the condition arguments need to have case lowered to support not case // sensitive fields. if (is_array($condition['value'])) { $entityQueryCondition = Database::getConnection()->getDriverClass('EntityQuery\\Condition'); $entityQueryCondition::translateCondition($condition, $case_sensitive); return; } // Ensure that the default operator is set to simplify the cases below. if (empty($condition['operator'])) { $condition['operator'] = '='; } switch ($condition['operator']) { case '=': // If a field explicitly requests that queries should not be case // sensitive, use the LIKE operator, otherwise keep =. if ($case_sensitive === FALSE) { $condition['value'] = $sql_query->escapeLike($condition['value']); $condition['operator'] = 'LIKE'; } break; case '<>': // If a field explicitly requests that queries should not be case // sensitive, use the NOT LIKE operator, otherwise keep <>. if ($case_sensitive === FALSE) { $condition['value'] = $sql_query->escapeLike($condition['value']); $condition['operator'] = 'NOT LIKE'; } break; case 'STARTS_WITH': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = $sql_query->escapeLike($condition['value']) . '%'; break; case 'CONTAINS': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = '%' . $sql_query->escapeLike($condition['value']) . '%'; break; case 'ENDS_WITH': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = '%' . $sql_query->escapeLike($condition['value']); break; } }
protected function addJoin($type, $table, $join_condition, $langcode) { $arguments = array(); if ($langcode) { $placeholder = ':langcode' . $this->sqlQuery->nextPlaceholder(); $join_condition .= ' AND %alias.langcode = ' . $placeholder; $arguments[$placeholder] = $langcode; } return $this->sqlQuery->addJoin($type, $table, NULL, $join_condition, $arguments); }
/** * {@inheritdoc} */ public static function translateCondition(&$condition, SelectInterface $sql_query, $case_sensitive) { if (is_array($condition['value']) && $case_sensitive === FALSE) { $condition['where'] = 'LOWER(' . $sql_query->escapeField($condition['real_field']) . ') ' . $condition['operator'] . ' ('; $condition['where_args'] = []; $n = 1; // Only use the array values in case an associative array is passed as an // argument following similar pattern in // \Drupal\Core\Database\Connection::expandArguments(). foreach ($condition['value'] as $value) { $condition['where'] .= 'LOWER(:value' . $n . '),'; $condition['where_args'][':value' . $n] = $value; $n++; } $condition['where'] = trim($condition['where'], ','); $condition['where'] .= ')'; return; } parent::translateCondition($condition, $sql_query, $case_sensitive); }
/** * Translates the string operators to SQL equivalents. * * @param array $condition * The condition array. * @param \Drupal\Core\Database\Query\SelectInterface $sql_query * Select query instance. * @param bool|null $case_sensitive * If the condition should be case sensitive or not, NULL if the field does * not define it. * * @see \Drupal\Core\Database\Query\ConditionInterface::condition() */ public static function translateCondition(&$condition, SelectInterface $sql_query, $case_sensitive) { // // There is nothing we can do for IN (). if (is_array($condition['value'])) { return; } // Ensure that the default operator is set to simplify the cases below. if (empty($condition['operator'])) { $condition['operator'] = '='; } switch ($condition['operator']) { case '=': // If a field explicitly requests that queries should not be case // sensitive, use the LIKE operator, otherwise keep =. if ($case_sensitive === FALSE) { $condition['value'] = $sql_query->escapeLike($condition['value']); $condition['operator'] = 'LIKE'; } break; case '<>': // If a field explicitly requests that queries should not be case // sensitive, use the NOT LIKE operator, otherwise keep <>. if ($case_sensitive === FALSE) { $condition['value'] = $sql_query->escapeLike($condition['value']); $condition['operator'] = 'NOT LIKE'; } break; case 'STARTS_WITH': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = $sql_query->escapeLike($condition['value']) . '%'; break; case 'CONTAINS': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = '%' . $sql_query->escapeLike($condition['value']) . '%'; break; case 'ENDS_WITH': if ($case_sensitive) { $condition['operator'] = 'LIKE BINARY'; } else { $condition['operator'] = 'LIKE'; } $condition['value'] = '%' . $sql_query->escapeLike($condition['value']); break; } }
/** * {@inheritdoc} */ public function entityQueryAlter(SelectInterface $query) { if (\Drupal::currentUser()->hasPermission('administer users')) { // In addition, if the user is administrator, we need to make sure to // match the anonymous user, that doesn't actually have a name in the // database. $conditions =& $query->conditions(); foreach ($conditions as $key => $condition) { if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users_field_data.name') { // Remove the condition. unset($conditions[$key]); // Re-add the condition and a condition on uid = 0 so that we end up // with a query in the form: // WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0) $or = db_or(); $or->condition($condition['field'], $condition['value'], $condition['operator']); // Sadly, the Database layer doesn't allow us to build a condition // in the form ':placeholder = :placeholder2', because the 'field' // part of a condition is always escaped. // As a (cheap) workaround, we separately build a condition with no // field, and concatenate the field and the condition separately. $value_part = db_and(); $value_part->condition('anonymous_name', $condition['value'], $condition['operator']); $value_part->compile(Database::getConnection(), $query); $or->condition(db_and()->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => user_format_name(user_load(0))))->condition('base_table.uid', 0)); $query->condition($or); } } } // Add the filter by role option. if (!empty($this->fieldDefinition->getSetting('handler_settings')['filter'])) { $filter_settings = $this->fieldDefinition->getSetting('handler_settings')['filter']; if ($filter_settings['type'] == 'role') { $tables = $query->getTables(); $base_table = $tables['base_table']['alias']; $query->join('users_roles', 'ur', $base_table . '.uid = ur.uid'); $query->condition('ur.rid', $filter_settings['role']); } } }
/** * {@inheritdoc} */ public function entityQueryAlter(SelectInterface $query) { $tables = $query->getTables(); $data_table = 'comment_field_data'; if (!isset($tables['comment_field_data']['alias'])) { // If no conditions join against the comment data table, it should be // joined manually to allow node access processing. $query->innerJoin($data_table, NULL, "base_table.cid = {$data_table}.cid AND {$data_table}.default_langcode = 1"); } // The Comment module doesn't implement any proper comment access, // and as a consequence doesn't make sure that comments cannot be viewed // when the user doesn't have access to the node. $node_alias = $query->innerJoin('node_field_data', 'n', '%alias.nid = ' . $data_table . '.entity_id AND ' . $data_table . ".entity_type = 'node'"); // Pass the query to the node access control. $this->reAlterQuery($query, 'node_access', $node_alias); // Passing the query to node_query_node_access_alter() is sadly // insufficient for nodes. // @see SelectionEntityTypeNode::entityQueryAlter() if (!\Drupal::currentUser()->hasPermission('bypass node access') && !count(\Drupal::moduleHandler()->getImplementations('node_grants'))) { $query->condition($node_alias . '.status', 1); } }
protected function addJoin($type, $table, $join_condition, $langcode) { $arguments = array(); if ($langcode) { $entity_type_id = $this->sqlQuery->getMetaData('entity_type'); $entity_type = $this->entityManager->getDefinition($entity_type_id); // Only the data table follows the entity language key, dedicated field // tables have an hard-coded 'langcode' column. $langcode_key = $entity_type->getDataTable() == $table ? $entity_type->getKey('langcode') : 'langcode'; $placeholder = ':langcode' . $this->sqlQuery->nextPlaceholder(); $join_condition .= ' AND %alias.' . $langcode_key . ' = ' . $placeholder; $arguments[$placeholder] = $langcode; } return $this->sqlQuery->addJoin($type, $table, NULL, $join_condition, $arguments); }
/** * {@inheritdoc} */ protected function setUp() { parent::setUp(); // Create a Mock database connection object. $this->connection = $this->getMockBuilder('Drupal\\Core\\Database\\Connection')->disableOriginalConstructor()->getMock(); // Create a Mock Statement object $this->statement = $this->getMockBuilder('Drupal\\Core\\Database\\Driver\\sqlite\\Statement')->disableOriginalConstructor()->getMock(); // Create a Mock Select object and set expectations. $this->select = $this->getMockBuilder('Drupal\\Core\\Database\\Query\\Select')->disableOriginalConstructor()->getMock(); $this->select->expects($this->any())->method('fields')->will($this->returnSelf()); $this->select->expects($this->any())->method('condition')->will($this->returnSelf()); $this->select->expects($this->any())->method('range')->will($this->returnSelf()); $this->select->expects($this->any())->method('orderBy')->will($this->returnSelf()); $this->select->expects($this->any())->method('execute')->will($this->returnValue($this->statement)); $this->connection->expects($this->any())->method('select')->will($this->returnValue($this->select)); // Create a Mock Delete object and set expectations. $this->delete = $this->getMockBuilder('Drupal\\Core\\Database\\Query\\Delete')->disableOriginalConstructor()->getMock(); $this->delete->expects($this->any())->method('condition')->will($this->returnSelf()); $this->delete->expects($this->any())->method('execute')->will($this->returnValue($this->statement)); }
/** * {@inheritdoc} */ public function entityQueryAlter(SelectInterface $query) { // Bail out early if we do not need to match the Anonymous user. $handler_settings = $this->configuration['handler_settings']; if (isset($handler_settings['include_anonymous']) && !$handler_settings['include_anonymous']) { return; } if ($this->currentUser->hasPermission('administer users')) { // In addition, if the user is administrator, we need to make sure to // match the anonymous user, that doesn't actually have a name in the // database. $conditions =& $query->conditions(); foreach ($conditions as $key => $condition) { if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users_field_data.name') { // Remove the condition. unset($conditions[$key]); // Re-add the condition and a condition on uid = 0 so that we end up // with a query in the form: // WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0) $or = db_or(); $or->condition($condition['field'], $condition['value'], $condition['operator']); // Sadly, the Database layer doesn't allow us to build a condition // in the form ':placeholder = :placeholder2', because the 'field' // part of a condition is always escaped. // As a (cheap) workaround, we separately build a condition with no // field, and concatenate the field and the condition separately. $value_part = db_and(); $value_part->condition('anonymous_name', $condition['value'], $condition['operator']); $value_part->compile($this->connection, $query); $or->condition(db_and()->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => user_format_name($this->userStorage->load(0))))->condition('base_table.uid', 0)); $query->condition($or); } } } }
/** * Generates a hash from a query object, to be used as part of the cache key. * * This smart caching strategy saves Drupal from querying and rendering to * HTML when the underlying query is unchanged. * * Expensive queries should use the query builder to create the query and then * call this function. Executing the query and formatting results should * happen in a #pre_render callback. * * @param \Drupal\Core\Database\Query\SelectInterface $query * A select query object. * * @return string * A hash of the query arguments. */ public static function keyFromQuery(SelectInterface $query) { $query->preExecute(); $keys = array((string) $query, $query->getArguments()); return hash('sha256', serialize($keys)); }
/** * Adds fields to the query. * * @param \Drupal\Core\Database\Query\SelectInterface $query * The drupal query object. */ protected function compileFields($query) { foreach ($this->fields as $field) { $string = ''; if (!empty($field['table'])) { $string .= $field['table'] . '.'; } $string .= $field['field']; $fieldname = (!empty($field['alias']) ? $field['alias'] : $string); if (!empty($field['count'])) { // Retained for compatibility. $field['function'] = 'count'; } if (!empty($field['function'])) { $info = $this->getAggregationInfo(); if (!empty($info[$field['function']]['method']) && is_callable(array($this, $info[$field['function']]['method']))) { $string = $this::{$info[$field['function']]['method']}($field['function'], $string); $placeholders = !empty($field['placeholders']) ? $field['placeholders'] : array(); $query->addExpression($string, $fieldname, $placeholders); } $this->hasAggregate = TRUE; } // This is a formula, using no tables. elseif (empty($field['table'])) { $placeholders = !empty($field['placeholders']) ? $field['placeholders'] : array(); $query->addExpression($string, $fieldname, $placeholders); } elseif ($this->distinct && !in_array($fieldname, $this->groupby)) { $query->addField(!empty($field['table']) ? $field['table'] : $this->view->storage->get('base_table'), $field['field'], $fieldname); } elseif (empty($field['aggregate'])) { $query->addField(!empty($field['table']) ? $field['table'] : $this->view->storage->get('base_table'), $field['field'], $fieldname); } if ($this->getCountOptimized) { // We only want the first field in this case. break; } } }
/** * Extends a query object for URL redirect filters. * * @param $query * Query object that should be filtered. * @param $keys * The filter string to use. */ protected function filterQuery(SelectInterface $query, array $fields, $keys = '') { if ($keys && $fields) { // Replace wildcards with PDO wildcards. $conditions = db_or(); $wildcard = '%' . trim(preg_replace('!\\*+!', '%', db_like($keys)), '%') . '%'; foreach ($fields as $field) { $conditions->condition($field, $wildcard, 'LIKE'); } $query->condition($conditions); } }
/** * Implementation of MigrateSource::performRewind(). * * We could simply execute the query and be functionally correct, but * we will take advantage of the PDO-based API to optimize the query up-front. */ protected function initializeIterator() { $this->prepareQuery(); $high_water_property = $this->migration->get('highWaterProperty'); // Get the key values, for potential use in joining to the map table. $keys = array(); // The rules for determining what conditions to add to the query are as // follows (applying first applicable rule) // 1. If the map is joinable, join it. We will want to accept all rows // which are either not in the map, or marked in the map as NEEDS_UPDATE. // Note that if high water fields are in play, we want to accept all rows // above the high water mark in addition to those selected by the map // conditions, so we need to OR them together (but AND with any existing // conditions in the query). So, ultimately the SQL condition will look // like (original conditions) AND (map IS NULL OR map needs update // OR above high water). $conditions = $this->query->orConditionGroup(); $condition_added = FALSE; if (empty($this->configuration['ignore_map']) && $this->mapJoinable()) { // Build the join to the map table. Because the source key could have // multiple fields, we need to build things up. $count = 1; $map_join = ''; $delimiter = ''; foreach ($this->getIds() as $field_name => $field_schema) { if (isset($field_schema['alias'])) { $field_name = $field_schema['alias'] . '.' . $field_name; } $map_join .= "{$delimiter}{$field_name} = map.sourceid" . $count++; $delimiter = ' AND '; } $alias = $this->query->leftJoin($this->migration->getIdMap()->getQualifiedMapTableName(), 'map', $map_join); $conditions->isNull($alias . '.sourceid1'); $conditions->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE); $condition_added = TRUE; // And as long as we have the map table, add its data to the row. $n = count($this->getIds()); for ($count = 1; $count <= $n; $count++) { $map_key = 'sourceid' . $count; $this->query->addField($alias, $map_key, "migrate_map_{$map_key}"); } if ($n = count($this->migration->get('destinationIds'))) { for ($count = 1; $count <= $n; $count++) { $map_key = 'destid' . $count++; $this->query->addField($alias, $map_key, "migrate_map_{$map_key}"); } } $this->query->addField($alias, 'source_row_status', 'migrate_map_source_row_status'); } // 2. If we are using high water marks, also include rows above the mark. // But, include all rows if the high water mark is not set. if (isset($high_water_property['name']) && ($high_water = $this->migration->getHighWater()) !== '') { if (isset($high_water_property['alias'])) { $high_water = $high_water_property['alias'] . '.' . $high_water_property['name']; } else { $high_water = $high_water_property['name']; } $conditions->condition($high_water, $high_water, '>'); $condition_added = TRUE; } if ($condition_added) { $this->query->condition($conditions); } return new \IteratorIterator($this->query->execute()); }
public function notExists(SelectInterface $select) { $this->query->notExists($select); return $this; }
/** * Executes a select query while making sure the database table exists. * * @param \Drupal\Core\Database\Query\SelectInterface $query * The select object to be executed. * * @return \Drupal\Core\Database\StatementInterface|null * A prepared statement, or NULL if the query is not valid. * * @throws \Exception * Thrown if the table could not be created or the database connection * failed. */ protected function safeExecuteSelect(SelectInterface $query) { try { return $query->execute(); } catch (\Exception $e) { // If there was an exception, try to create the table. if ($this->ensureTableExists()) { return $query->execute(); } // Some other failure that we can not recover from. throw $e; } }
/** * Creates a temporary table from a select query. * * Will return the name of a table containing the item IDs of all results, or * FALSE on failure. * * @param \Drupal\Core\Database\Query\SelectInterface $db_query * The select query whose results should be stored in the temporary table. * * @return string|false * The name of the temporary table, or FALSE on failure. */ protected function getTemporaryResultsTable(SelectInterface $db_query) { // We only need the id field, not the score. $fields =& $db_query->getFields(); unset($fields['score']); if (count($fields) != 1 || !isset($fields['item_id'])) { $this->getLogger()->warning('Error while adding facets: only "item_id" field should be used, used are: @fields.', array('@fields' => implode(', ', array_keys($fields)))); return FALSE; } $expressions =& $db_query->getExpressions(); $expressions = array(); // If there's a GROUP BY for item_id, we leave that, all others need to be // discarded. $group_by =& $db_query->getGroupBy(); $group_by = array_intersect_key($group_by, array('t.item_id' => TRUE)); $db_query->distinct(); if (!$db_query->preExecute()) { return FALSE; } $args = $db_query->getArguments(); try { $result = $this->database->queryTemporary((string) $db_query, $args); } catch (\PDOException $e) { watchdog_exception('search_api', $e, '%type while trying to create a temporary table: @message in %function (line %line of %file).'); return FALSE; } return $result; }
/** * Returns whether the query requires GROUP BY and ORDER BY MIN/MAX. * * @return bool */ protected function isSimpleQuery() { return !$this->pager && !$this->range && !$this->count || $this->sqlQuery->getMetaData('simple_query'); }
/** * Adapt our query for translations. * * @param \Drupal\Core\Database\Query\SelectInterface * The generated query. */ protected function handleTranslations(SelectInterface $query) { // Check whether or not we want translations. if (empty($this->configuration['translations'])) { // No translations: Yield untranslated nodes, or default translations. $query->where('n.tnid = 0 OR n.tnid = n.nid'); } else { // Translations: Yield only non-default translations. $query->where('n.tnid <> 0 AND n.tnid <> n.nid'); } }
/** * Creates a temporary table from a select query. * * Will return the name of a table containing the item IDs of all results, or * FALSE on failure. * * @param \Drupal\Core\Database\Query\SelectInterface $db_query * The select query whose results should be stored in the temporary table. * * @return string|false * The name of the temporary table, or FALSE on failure. */ protected function getTemporaryResultsTable(SelectInterface $db_query) { // We only need the id field, not the score. $fields = &$db_query->getFields(); unset($fields['score']); if (count($fields) != 1 || !isset($fields['item_id'])) { $this->getLogger()->warning('Error while adding facets: only "item_id" field should be used, used are: @fields.', array('@fields' => implode(', ', array_keys($fields)))); return FALSE; } $expressions = &$db_query->getExpressions(); $expressions = array(); $db_query->distinct(); if (!$db_query->preExecute()) { return FALSE; } $args = $db_query->getArguments(); return $this->database->queryTemporary((string) $db_query, $args); }