class SolrFilterSubQuery in Apache Solr Search 7
Same name and namespace in other branches
- 8 Solr_Base_Query.php \SolrFilterSubQuery
- 6.3 Solr_Base_Query.php \SolrFilterSubQuery
This class allows you to make operations on a query that will be sent to Apache Solr. methods such as adding and removing sorts, remove and replace parameters, adding and removing filters, getters and setters for various parameters and more @file Class that defines the base query for the Apache Solr Drupal module.
Hierarchy
- class \SolrFilterSubQuery
Expanded class hierarchy of SolrFilterSubQuery
1 string reference to 'SolrFilterSubQuery'
- apachesolr_drupal_subquery in ./
apachesolr.module - Factory function for query objects.
File
- ./
Solr_Base_Query.php, line 11 - This class allows you to make operations on a query that will be sent to Apache Solr. methods such as adding and removing sorts, remove and replace parameters, adding and removing filters, getters and setters for various parameters and more
View source
class SolrFilterSubQuery {
/**
* Static shared by all instances, used to increment ID numbers.
*/
protected static $idCount = 0;
/**
* Each query/subquery will have a unique ID.
*/
public $id;
public $operator;
public $exclude;
/**
* A keyed array where the key is a position integer and the value
* is an array with #name and #value properties. Each value is a
* used for filter queries, e.g. array('#name' => 'is_uid', '#value' => 0)
* for anonymous content.
*/
protected $fields = array();
/**
* An array of subqueries.
*/
protected $subqueries = array();
function __construct($operator = 'OR', $exclude = FALSE) {
$this->operator = $operator;
$this->exclude = $exclude;
$this->id = ++SolrFilterSubQuery::$idCount;
}
function __clone() {
$this->id = ++SolrFilterSubQuery::$idCount;
}
public function getFilters($name = NULL) {
if (empty($name)) {
return $this->fields;
}
reset($this->fields);
$matches = array();
foreach ($this->fields as $filter) {
if ($filter['#name'] == $name) {
$matches[] = $filter;
}
}
return $matches;
}
public function hasFilter($name, $value, $exclude = FALSE) {
foreach ($this->fields as $pos => $values) {
if ($values['#name'] == $name && $values['#value'] == $value && $values['#exclude'] == $exclude) {
return TRUE;
}
}
return FALSE;
}
public function addFilter($name, $value, $exclude = FALSE, $local = '') {
// @todo - escape the value if it has spaces in it and is not a range query or parenthesized.
$filter = array(
'#exclude' => (bool) $exclude,
'#name' => trim($name),
'#value' => trim($value),
'#local' => trim($local),
);
$this->fields[] = $filter;
return $this;
}
public function removeFilter($name, $value = NULL, $exclude = FALSE) {
// Remove from the public list of filters.
$this
->unsetFilter($this->fields, $name, $value, $exclude);
return $this;
}
protected function unsetFilter(&$fields, $name, $value, $exclude) {
if (!isset($value)) {
foreach ($fields as $pos => $values) {
if ($values['#name'] == $name) {
unset($fields[$pos]);
}
}
}
else {
foreach ($fields as $pos => $values) {
if ($values['#name'] == $name && $values['#value'] == $value && $values['#exclude'] == $exclude) {
unset($fields[$pos]);
}
}
}
}
public function getFilterSubQueries() {
return $this->subqueries;
}
public function addFilterSubQuery(SolrFilterSubQuery $query) {
$this->subqueries[$query->id] = $query;
return $this;
}
public function removeFilterSubQuery(SolrFilterSubQuery $query) {
unset($this->subqueries[$query->id]);
return $this;
}
public function removeFilterSubQueries() {
$this->subqueries = array();
return $this;
}
public function makeFilterQuery(array $filter) {
$prefix = empty($filter['#exclude']) ? '' : '-';
if ($filter['#local']) {
$prefix = '{!' . $filter['#local'] . '}' . $prefix;
}
// If the field value contains a colon or a space, wrap it in double quotes,
// unless it is a range query or is already wrapped in double quotes or
// parentheses.
if (preg_match('/[ :]/', $filter['#value']) && !preg_match('/^[\\[\\{]\\S+ TO \\S+[\\]\\}]$/', $filter['#value']) && !preg_match('/^["\\(].*["\\)]$/', $filter['#value'])) {
$filter['#value'] = '"' . $filter['#value'] . '"';
}
return $prefix . $filter['#name'] . ':' . $filter['#value'];
}
/**
* Make sure our query matches the pattern name:value or name:"value"
* Make sure that if we are ranges we use name:[ AND ]
* allowed inputs :
* a. bundle:article
* b. date:[1970-12-31T23:59:59Z TO NOW]
* Split the text in 4 different parts
* 1. name, eg.: bundle or date
* 2. The first opening bracket (or nothing), eg.: [
* 3. The value of the field, eg. article or 1970-12-31T23:59:59Z TO NOW
* 4. The last closing bracket, eg.: ]
* @param string $filter
* The filter to validate
* @return boolean
*/
public static function validFilterValue($filter) {
$name = NULL;
$value = NULL;
$matches = array();
$datefields = array();
$datefield_match = array();
if (preg_match('/(?P<name>[^:]+):(?P<value>.+)?$/', $filter, $matches)) {
foreach ($matches as $match_id => $match) {
switch ($match_id) {
case 'name':
$name = $match;
break;
case 'value':
$value = $match;
break;
}
}
// For the name we allow any character that fits between the A-Z0-9 range and
// any alternative for this in other languages. No special characters allowed.
// Negative filters may have a leading "-".
if (!preg_match('/^-?[a-zA-Z0-9_\\x7f-\\xff]+$/', $name)) {
return FALSE;
}
// For the value we allow anything that is UTF8
if (!drupal_validate_utf8($value)) {
return FALSE;
}
// Check our bracket count. If it does not match it is also not valid
$valid_brackets = TRUE;
$brackets['opening']['{'] = substr_count($value, '{');
$brackets['closing']['}'] = substr_count($value, '}');
$valid_brackets = $valid_brackets && $brackets['opening']['{'] == $brackets['closing']['}'];
$brackets['opening']['['] = substr_count($value, '[');
$brackets['closing'][']'] = substr_count($value, ']');
$valid_brackets = $valid_brackets && $brackets['opening']['['] == $brackets['closing'][']'];
$brackets['opening']['('] = substr_count($value, '(');
$brackets['closing'][')'] = substr_count($value, ')');
$valid_brackets = $valid_brackets && $brackets['opening']['('] == $brackets['closing'][')'];
if (!$valid_brackets) {
return FALSE;
}
// Check the date field inputs
if (preg_match('/\\[(.+) TO (.+)\\]$/', $value, $datefields)) {
// Only Allow a value in the form of
// http://lucene.apache.org/solr/api/org/apache/solr/schema/DateField.html
// http://lucene.apache.org/solr/api/org/apache/solr/util/DateMathParser.html
// http://wiki.apache.org/solr/SolrQuerySyntax
// 1976-03-06T23:59:59.999Z (valid)
// * (valid)
// 1995-12-31T23:59:59.999Z (valid)
// 2007-03-06T00:00:00Z (valid)
// NOW-1YEAR/DAY (valid)
// NOW/DAY+1DAY (valid)
// 1976-03-06T23:59:59.999Z (valid)
// 1976-03-06T23:59:59.999Z+1YEAR (valid)
// 1976-03-06T23:59:59.999Z/YEAR (valid)
// 1976-03-06T23:59:59.999Z (valid)
// 1976-03-06T23::59::59.999Z (invalid)
if (!empty($datefields[1]) && !empty($datefields[2])) {
// Do not check to full value, only the splitted ones
unset($datefields[0]);
// Check if both matches are valid datefields
foreach ($datefields as $datefield) {
if (!preg_match('/(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:[\\d\\.]{2,6}Z(\\S)*)|(^([A-Z\\*]+)(\\A-Z0-9\\+\\-\\/)*)/', $datefield, $datefield_match)) {
return FALSE;
}
}
}
}
}
return TRUE;
}
/**
* Builds a set of filter queries from $this->fields and all subqueries.
*
* Returns an array of strings that can be combined into
* a URL query parameter or passed to Solr as fq paramters.
*/
protected function rebuildFq() {
$fq = array();
foreach ($this->fields as $pos => $field) {
$fq[] = $this
->makeFilterQuery($field);
}
foreach ($this->subqueries as $subquery) {
$subfq = $subquery
->rebuildFq();
if ($subfq) {
$operator = $subquery->operator;
$prefix = $subquery->exclude ? '-' : '';
$fq[] = "{$prefix}(" . implode(" {$operator} ", $subfq) . ")";
}
}
return $fq;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
SolrFilterSubQuery:: |
public | property | ||
SolrFilterSubQuery:: |
protected | property | A keyed array where the key is a position integer and the value is an array with #name and #value properties. Each value is a used for filter queries, e.g. array('#name' => 'is_uid', '#value' => 0) for anonymous… | |
SolrFilterSubQuery:: |
public | property | Each query/subquery will have a unique ID. | |
SolrFilterSubQuery:: |
protected static | property | Static shared by all instances, used to increment ID numbers. | |
SolrFilterSubQuery:: |
public | property | ||
SolrFilterSubQuery:: |
protected | property | An array of subqueries. | |
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
protected | function | Builds a set of filter queries from $this->fields and all subqueries. | |
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
public | function | ||
SolrFilterSubQuery:: |
protected | function | ||
SolrFilterSubQuery:: |
public static | function | Make sure our query matches the pattern name:value or name:"value" Make sure that if we are ranges we use name:[ AND ] allowed inputs : a. bundle:article b. date:[1970-12-31T23:59:59Z TO NOW] Split the text in 4 different parts 1. name, eg.:… | |
SolrFilterSubQuery:: |
function | |||
SolrFilterSubQuery:: |
function | 1 |