/** * Filter the query for list. * * @param \SelectQuery $query * The query object. * * @throws BadRequestException * * @see \RestfulEntityBase::getQueryForList */ protected function queryForListFilter(\SelectQuery $query) { foreach ($this->parseRequestForListFilter() as $filter) { /* @var ResourceFieldDbColumnInterface $filter_field */ if (!($filter_field = $this->fieldDefinitions->get($filter['public_field']))) { continue; } $column_name = $filter_field->getColumnForQuery(); if (in_array(strtoupper($filter['operator'][0]), array('IN', 'NOT IN', 'BETWEEN'))) { $query->condition($column_name, $filter['value'], $filter['operator'][0]); continue; } $condition = db_condition($filter['conjunction']); for ($index = 0; $index < count($filter['value']); $index++) { $condition->condition($column_name, $filter['value'][$index], $filter['operator'][$index]); } $query->condition($condition); } }
/** * Creates a database query condition for a given search filter. * * Used as a helper method in createDbQuery(). * * @param \Drupal\search_api\Query\FilterInterface $filter * The filter for which a condition should be created. * @param array $fields * Internal information about the index's fields. * @param \Drupal\Core\Database\Query\SelectInterface $db_query * The database query to which the condition will be added. * @param \Drupal\search_api\IndexInterface $index * The index we're searching on. * * @return \Drupal\Core\Database\Query\ConditionInterface|null * The condition to set on the query, or NULL if none is necessary. * * @throws \Drupal\search_api\SearchApiException * Thrown if an unknown field was used in the filter. */ protected function createFilterCondition(FilterInterface $filter, array $fields, SelectInterface $db_query, IndexInterface $index) { $cond = db_condition($filter->getConjunction()); $empty = TRUE; // Store whether a JOIN already occurred for a field, so we don't JOIN // repeatedly for OR filters. $first_join = array(); // Store the table aliases for the fields in this condition group. $tables = array(); foreach ($filter->getFilters() as $f) { if (is_object($f)) { $c = $this->createFilterCondition($f, $fields, $db_query, $index); if ($c) { $empty = FALSE; $cond->condition($c); } } else { $empty = FALSE; // We don't index the datasource explicitly, so this needs a bit of // magic. // @todo Index the datasource explicitly so this doesn't need magic. if ($f[0] === 'search_api_datasource') { $alias = $this->getTableAlias(array('table' => $this->configuration['index_tables'][$index->id()]), $db_query); // @todo Stop recognizing "!=" as an operator. $operator = $f[2] == '<>' || $f[2] == '!=' ? 'NOT LIKE' : 'LIKE'; $prefix = Utility::createCombinedId($f[1], ''); $cond->condition($alias . '.item_id', db_like($prefix) . '%', $operator); continue; } if (!isset($fields[$f[0]])) { throw new SearchApiException(SafeMarkup::format('Unknown field in filter clause: @field.', array('@field' => $f[0]))); } $field = $fields[$f[0]]; // Fields have their own table, so we have to check for NULL values in // a special way (i.e., check for missing entries in that table). // @todo This can probably always use the denormalized table. if ($f[1] === NULL) { $query = $this->database->select($field['table'], 't')->fields('t', array('item_id')); $cond->condition('t.item_id', $query, $f[2] == '<>' || $f[2] == '!=' ? 'IN' : 'NOT IN'); continue; } if (Utility::isTextType($field['type'])) { $keys = $this->prepareKeys($f[1]); $query = $this->createKeysQuery($keys, array($f[0] => $field), $fields, $index); // We don't need the score, so we remove it. The score might either be // an expression or a field. $query_expressions =& $query->getExpressions(); if ($query_expressions) { $query_expressions = array(); } else { $query_fields =& $query->getFields(); unset($query_fields['score']); unset($query_fields); } unset($query_expressions); $cond->condition('t.item_id', $query, $f[2] == '<>' || $f[2] == '!=' ? 'NOT IN' : 'IN'); } else { $new_join = $filter->getConjunction() == 'AND' || empty($first_join[$f[0]]); if ($new_join || empty($tables[$f[0]])) { $tables[$f[0]] = $this->getTableAlias($field, $db_query, $new_join); $first_join[$f[0]] = TRUE; } $column = $tables[$f[0]] . '.' . 'value'; if ($f[1] !== NULL) { $cond->condition($column, $f[1], $f[2]); } else { $method = $f[2] == '=' ? 'isNull' : 'isNotNull'; $cond->{$method}($column); } } } } return $empty ? NULL : $cond; }
/** * Build the SQL WHERE clause OR condition from the various condition arrays * Alias of `db_conditionOR()` * * @param array $cond [,$cond2,$cond3,...] The condition array(s), for example * * array( * 'fieldName1' => $value1, * 'fieldName2 >=' => $value2, * 'fieldName3 => NULL * ) * * ### Operators allowed in condition array * >, >=, <, <=, !=, between, nbetween, like, like%%, like%~, like~%, nlike, nlike%%, nlike%~, nlike~% * * @return string The built condition WHERE clause */ function db_or($cond = array()) { $conditions = func_get_args(); $builtCond = array(); foreach ($conditions as $c) { $builtCond[] = db_condition($c, 'OR'); } return implode(' OR ', $builtCond); }
/** * Filter the query for list. * * @param \SelectQuery $query * The query object. * * @throws \RestfulBadRequestException * * @see \RestfulEntityBase::getQueryForList */ protected function queryForListFilter(\SelectQuery $query) { $public_fields = $this->getPublicFields(); foreach ($this->parseRequestForListFilter() as $filter) { if (in_array(strtoupper($filter['operator'][0]), array('IN', 'BETWEEN'))) { $column_name = $this->getPropertyColumnForQuery($public_fields[$filter['public_field']]); $query->condition($column_name, $filter['value'], $filter['operator'][0]); continue; } $condition = db_condition($filter['conjunction']); for ($index = 0; $index < count($filter['value']); $index++) { $column_name = $this->getPropertyColumnForQuery($public_fields[$filter['public_field']]); $condition->condition($column_name, $filter['value'][$index], $filter['operator'][$index]); } $query->condition($condition); } }
/** * Generate a slug of human-readable keywords * * @param string $string Text to slug * @param string $table Table name to check in. If it is empty, no check in the table * @param string|array $condition Condition to append table check-in, e.g, * `fieldName != value` or `array('fieldName !=' => value)` * * @return string The generated slug */ function _slug($string, $table = '', $condition = null) { $specChars = array('`', '~', '!', '@', '#', '$', '%', '\\^', '&', '*', '(', ')', '=', '+', '{', '}', '[', ']', ':', ';', "'", '"', '<', '>', '\\', '|', '?', '/', ','); $table = ltrim($table, db_prefix()); $slug = strtolower(trim($string)); $slug = trim($slug, '-'); # clear special characters $slug = preg_replace('/(&|"|'|<|>)/i', '', $slug); $slug = str_replace($specChars, '-', $slug); $slug = str_replace(array(' ', '.'), '-', $slug); if (is_array($condition)) { $condition = db_condition($condition); } while (1 && $table) { $sql = 'SELECT slug FROM ' . $table . ' WHERE slug = ":alias"'; if ($condition) { $sql .= ' AND ' . $condition; } if ($result = db_query($sql, array(':alias' => $slug))) { if (db_numRows($result) == 0) { break; } $segments = explode('-', $slug); if (sizeof($segments) > 1 && is_numeric($segments[sizeof($segments) - 1])) { $index = array_pop($segments); $index++; } else { $index = 1; } $segments[] = $index; $slug = implode('-', $segments); } } $slug = preg_replace('/[\\-]+/', '-', $slug); return trim($slug, '-'); }