Overview

Namespaces

  • PHP
  • vierbergenlars
    • Forage
      • ODM
        • HydrationSettings
      • QueryParser
      • SearchIndex
      • SearchQuery
      • SearchResult
      • Transport

Classes

  • Compiler
  • Token

Exceptions

  • ParseException
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace vierbergenlars\Forage\QueryParser;
  4: 
  5: use vierbergenlars\Forage\SearchQuery\QueryBuilder;
  6: use vierbergenlars\Forage\QueryParser\Token;
  7: 
  8: /**
  9:  * Compiles a string query to an executable query.
 10:  */
 11: class Compiler
 12: {
 13: 
 14:     /**
 15:      * The query builder the query gets inserted to
 16:      * @var \vierbergenlars\Forage\SearchQuery\QueryBuilder
 17:      */
 18:     protected $queryBuilder;
 19: 
 20:     /**
 21:      * List of fields that are allowed with T_FIELD_SEARCH
 22:      * @var array
 23:      */
 24:     protected $allowedSearchFields = array();
 25: 
 26:     /**
 27:      * List of fields that are allowed with T_FIELD_NAME
 28:      * @var array
 29:      */
 30:     protected $allowedFieldNames = array();
 31: 
 32:     /**
 33:      * List of tokens that are allowed
 34:      * @var array
 35:      */
 36:     protected $allowedTokens = array();
 37: 
 38:     /**
 39:      * Create a new compiler
 40:      * @param \vierbergenlars\Forage\SearchQuery\QueryBuilder $queryBuilder The query builder to compile the query on
 41:      */
 42:     public function __construct(QueryBuilder $queryBuilder)
 43:     {
 44:         $this->queryBuilder = $queryBuilder;
 45:     }
 46: 
 47:     /**
 48:      * Sets the allowed field names
 49:      * @param array $fieldNames
 50:      * @return \vierbergenlars\Forage\QueryParser\Compiler
 51:      */
 52:     public function setAllowedFieldNames(array $fieldNames)
 53:     {
 54:         $this->allowedFieldNames = $fieldNames;
 55:         return $this;
 56:     }
 57: 
 58:     /**
 59:      * Checks if a field name is allowed
 60:      * @param string $field
 61:      * @return bool
 62:      */
 63:     protected function isAllowedFieldName($field)
 64:     {
 65:         return empty($this->allowedFieldNames) || in_array($field, $this->allowedFieldNames, true);
 66:     }
 67: 
 68:     /**
 69:      * Sets the allowed search fields
 70:      * @param array $fieldNames
 71:      * @return \vierbergenlars\Forage\QueryParser\Compiler
 72:      */
 73:     public function setAllowedSearchFields(array $fieldNames)
 74:     {
 75:         $this->allowedSearchFields = $fieldNames;
 76:         return $this;
 77:     }
 78: 
 79:     /**
 80:      * Checks if a search field is allowed
 81:      * @param string $field
 82:      * @return bool
 83:      */
 84:     protected function isAllowedSearchField($field)
 85:     {
 86:         return empty($this->allowedSearchFields) || in_array($field, $this->allowedSearchFields, true);
 87:     }
 88: 
 89:     /**
 90:      * Sets the allowed tokens
 91:      * @param array $tokens
 92:      * @return \vierbergenlars\Forage\QueryParser\Compiler
 93:      */
 94:     public function setAllowedTokens(array $tokens)
 95:     {
 96:         $this->allowedTokens = $tokens;
 97:         return $this;
 98:     }
 99: 
100:     /**
101:      * Checks if a token is allowed
102:      * @param \vierbergenlars\Forage\QueryParser\Token $token
103:      * @return bool
104:      */
105:     protected function isAllowedToken(Token $token)
106:     {
107:         return empty($this->allowedTokens) || in_array($token->getType(), $this->allowedTokens, true);
108:     }
109: 
110:     /**
111:      * Compiles the search query
112:      * @param string $queryExpr
113:      * @return \vierbergenlars\Forage\QueryParser\Compiler
114:      * @throws ParseException
115:      */
116:     public function compileQuery($queryExpr)
117:     {
118:         $tokens = Lexer::tokenize($queryExpr);
119:         $searchQuery = '';
120:         while(false !== ($token = current($tokens))) {
121:             if(!$this->isAllowedToken($token))
122:                 throw new ParseException(Token::getName($token->getType()) . ' is disabled', $queryExpr, $token->getStartPosition());
123:             switch($token->getType()) {
124:                 case Token::T_STRING:
125:                     $searchQuery.= ' ' . $token->getData();
126:                     break;
127:                 case Token::T_FIELD_NAME:
128:                     if(!$this->isAllowedFieldName($token->getData()))
129:                         throw new ParseException('Field name not allowed', $queryExpr, $token->getStartPosition());
130:                     $nextToken = next($tokens);
131:                     if($nextToken === false)
132:                         throw new ParseException('Unexpected end of token stream', $queryExpr, strlen($queryExpr));
133:                     if(!$this->isAllowedToken($nextToken))
134:                         throw new ParseException(Token::getName($nextToken->getType()) . ' is disabled', $queryExpr, $nextToken->getStartPosition());
135:                     switch($nextToken->getType()) {
136:                         case Token::T_FIELD_VALUE:
137:                             $this->queryBuilder->addFilter($token->getData(), $nextToken->getData());
138:                             break;
139:                         case Token::T_FIELD_WEIGHT:
140:                             $this->queryBuilder->addWeight($token->getData(), $nextToken->getData());
141:                             break;
142:                         default:
143:                             throw new ParseException('Unexpected ' . Token::getName($nextToken->getType()), $queryExpr, $nextToken->getStartPosition());
144:                     }
145:                     break;
146:                 case Token::T_FIELD_SEARCH:
147:                     if(!$this->isAllowedSearchField($token->getData()))
148:                         throw new ParseException('Search field not allowed', $queryExpr, $token->getStartPosition());
149:                     $this->queryBuilder->addSearchField($token->getData());
150:                     break;
151:                 default:
152:                     throw new ParseException('Unexpected ' . Token::getName($token->getType()) . ' (This is a lexer bug, please report it)', $queryExpr, $token->getStartPosition());
153:             }
154:             next($tokens);
155:         }
156:         $this->queryBuilder->setSearchQuery(substr($searchQuery, 1));
157:         return $this;
158:     }
159: 
160:     /**
161:      * Gets the query builder
162:      * @return \vierbergenlars\Forage\SearchQuery\QueryBuilder
163:      */
164:     public function getQueryBuilder()
165:     {
166:         return $this->queryBuilder;
167:     }
168: 
169:     /**
170:      * Gets the query
171:      * @return vierbergenlars\Forage\SearchQuery\Query
172:      */
173:     public function getQuery()
174:     {
175:         return $this->queryBuilder->getQuery();
176:     }
177: 
178:     public function __clone()
179:     {
180:         $this->queryBuilder = clone $this->queryBuilder;
181:     }
182: 
183: }
184: 
Forage-PHP-Client API documentation generated by ApiGen 2.8.0