protected SearchQuery::parseSearchExpression()
Parses the search query into SQL conditions.
Sets up the following variables:
- $this->keys
- $this->words
- $this->conditions
- $this->simple
- $this->matches
File
- core/modules/search/src/SearchQuery.php, line 224
Class
- SearchQuery
- Search query extender and helper functions.
Namespace
Drupal\search
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | protected function parseSearchExpression() { // Matches words optionally prefixed by a - sign. A word in this case is // something between two spaces, optionally quoted. preg_match_all( '/ (-?)("[^"]+"|[^" ]+)/i' , ' ' . $this ->searchExpression, $keywords , PREG_SET_ORDER); if ( count ( $keywords ) == 0) { return ; } // Classify tokens. $in_or = FALSE; $limit_combinations = \Drupal::config( 'search.settings' )->get( 'and_or_limit' ); // The first search expression does not count as AND. $and_count = -1; $or_count = 0; foreach ( $keywords as $match ) { if ( $or_count && $and_count + $or_count >= $limit_combinations ) { // Ignore all further search expressions to prevent Denial-of-Service // attacks using a high number of AND/OR combinations. $this ->status |= SearchQuery::EXPRESSIONS_IGNORED; break ; } // Strip off phrase quotes. $phrase = FALSE; if ( $match [2]{0} == '"' ) { $match [2] = substr ( $match [2], 1, -1); $phrase = TRUE; $this ->simple = FALSE; } // Simplify keyword according to indexing rules and external // preprocessors. Use same process as during search indexing, so it // will match search index. $words = search_simplify( $match [2]); // Re-explode in case simplification added more words, except when // matching a phrase. $words = $phrase ? array ( $words ) : preg_split( '/ /' , $words , -1, PREG_SPLIT_NO_EMPTY); // Negative matches. if ( $match [1] == '-' ) { $this ->keys[ 'negative' ] = array_merge ( $this ->keys[ 'negative' ], $words ); } // OR operator: instead of a single keyword, we store an array of all // OR'd keywords. elseif ( $match [2] == 'OR' && count ( $this ->keys[ 'positive' ])) { $last = array_pop ( $this ->keys[ 'positive' ]); // Starting a new OR? if (! is_array ( $last )) { $last = array ( $last ); } $this ->keys[ 'positive' ][] = $last ; $in_or = TRUE; $or_count ++; continue ; } // AND operator: implied, so just ignore it. elseif ( $match [2] == 'AND' || $match [2] == 'and' ) { continue ; } // Plain keyword. else { if ( $match [2] == 'or' ) { // Lower-case "or" instead of "OR" is a warning condition. $this ->status |= SearchQuery::LOWER_CASE_OR; } if ( $in_or ) { // Add to last element (which is an array). $this ->keys[ 'positive' ][ count ( $this ->keys[ 'positive' ]) - 1] = array_merge ( $this ->keys[ 'positive' ][ count ( $this ->keys[ 'positive' ]) - 1], $words ); } else { $this ->keys[ 'positive' ] = array_merge ( $this ->keys[ 'positive' ], $words ); $and_count ++; } } $in_or = FALSE; } // Convert keywords into SQL statements. $has_and = FALSE; $has_or = FALSE; // Positive matches. foreach ( $this ->keys[ 'positive' ] as $key ) { // Group of ORed terms. if ( is_array ( $key ) && count ( $key )) { // If we had already found one OR, this is another one AND-ed with the // first, meaning it is not a simple query. if ( $has_or ) { $this ->simple = FALSE; } $has_or = TRUE; $has_new_scores = FALSE; $queryor = db_or(); foreach ( $key as $or ) { list( $num_new_scores ) = $this ->parseWord( $or ); $has_new_scores |= $num_new_scores ; $queryor ->condition( 'd.data' , "% $or %" , 'LIKE' ); } if ( count ( $queryor )) { $this ->conditions->condition( $queryor ); // A group of OR keywords only needs to match once. $this ->matches += ( $has_new_scores > 0); } } // Single ANDed term. else { $has_and = TRUE; list( $num_new_scores , $num_valid_words ) = $this ->parseWord( $key ); $this ->conditions->condition( 'd.data' , "% $key %" , 'LIKE' ); if (! $num_valid_words ) { $this ->simple = FALSE; } // Each AND keyword needs to match at least once. $this ->matches += $num_new_scores ; } } if ( $has_and && $has_or ) { $this ->simple = FALSE; } // Negative matches. foreach ( $this ->keys[ 'negative' ] as $key ) { $this ->conditions->condition( 'd.data' , "% $key %" , 'NOT LIKE' ); $this ->simple = FALSE; } } |
Please login to continue.