File indexing completed on 2024-06-23 05:55:39
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Search_Lucene 0017 * @subpackage Search 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** Internally used classes */ 0025 0026 /** Zend_Search_Lucene_Analysis_Analyzer */ 0027 // require_once 'Zend/Search/Lucene/Analysis/Analyzer.php'; 0028 0029 /** Zend_Search_Lucene_Search_QueryToken */ 0030 // require_once 'Zend/Search/Lucene/Search/QueryToken.php'; 0031 0032 0033 0034 /** Zend_Search_Lucene_FSM */ 0035 // require_once 'Zend/Search/Lucene/FSM.php'; 0036 0037 /** 0038 * @category Zend 0039 * @package Zend_Search_Lucene 0040 * @subpackage Search 0041 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0042 * @license http://framework.zend.com/license/new-bsd New BSD License 0043 */ 0044 class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM 0045 { 0046 /** 0047 * Parser instance 0048 * 0049 * @var Zend_Search_Lucene_Search_QueryParser 0050 */ 0051 private static $_instance = null; 0052 0053 0054 /** 0055 * Query lexer 0056 * 0057 * @var Zend_Search_Lucene_Search_QueryLexer 0058 */ 0059 private $_lexer; 0060 0061 /** 0062 * Tokens list 0063 * Array of Zend_Search_Lucene_Search_QueryToken objects 0064 * 0065 * @var array 0066 */ 0067 private $_tokens; 0068 0069 /** 0070 * Current token 0071 * 0072 * @var integer|string 0073 */ 0074 private $_currentToken; 0075 0076 /** 0077 * Last token 0078 * 0079 * It can be processed within FSM states, but this addirional state simplifies FSM 0080 * 0081 * @var Zend_Search_Lucene_Search_QueryToken 0082 */ 0083 private $_lastToken = null; 0084 0085 /** 0086 * Range query first term 0087 * 0088 * @var string 0089 */ 0090 private $_rqFirstTerm = null; 0091 0092 /** 0093 * Current query parser context 0094 * 0095 * @var Zend_Search_Lucene_Search_QueryParserContext 0096 */ 0097 private $_context; 0098 0099 /** 0100 * Context stack 0101 * 0102 * @var array 0103 */ 0104 private $_contextStack; 0105 0106 /** 0107 * Query string encoding 0108 * 0109 * @var string 0110 */ 0111 private $_encoding; 0112 0113 /** 0114 * Query string default encoding 0115 * 0116 * @var string 0117 */ 0118 private $_defaultEncoding = ''; 0119 0120 /** 0121 * Defines query parsing mode. 0122 * 0123 * If this option is turned on, then query parser suppress query parser exceptions 0124 * and constructs multi-term query using all words from a query. 0125 * 0126 * That helps to avoid exceptions caused by queries, which don't conform to query language, 0127 * but limits possibilities to check, that query entered by user has some inconsistencies. 0128 * 0129 * 0130 * Default is true. 0131 * 0132 * Use {@link Zend_Search_Lucene::suppressQueryParsingExceptions()}, 0133 * {@link Zend_Search_Lucene::dontSuppressQueryParsingExceptions()} and 0134 * {@link Zend_Search_Lucene::checkQueryParsingExceptionsSuppressMode()} to operate 0135 * with this setting. 0136 * 0137 * @var boolean 0138 */ 0139 private $_suppressQueryParsingExceptions = true; 0140 0141 /** 0142 * Boolean operators constants 0143 */ 0144 const B_OR = 0; 0145 const B_AND = 1; 0146 0147 /** 0148 * Default boolean queries operator 0149 * 0150 * @var integer 0151 */ 0152 private $_defaultOperator = self::B_OR; 0153 0154 0155 /** Query parser State Machine states */ 0156 const ST_COMMON_QUERY_ELEMENT = 0; // Terms, phrases, operators 0157 const ST_CLOSEDINT_RQ_START = 1; // Range query start (closed interval) - '[' 0158 const ST_CLOSEDINT_RQ_FIRST_TERM = 2; // First term in '[term1 to term2]' construction 0159 const ST_CLOSEDINT_RQ_TO_TERM = 3; // 'TO' lexeme in '[term1 to term2]' construction 0160 const ST_CLOSEDINT_RQ_LAST_TERM = 4; // Second term in '[term1 to term2]' construction 0161 const ST_CLOSEDINT_RQ_END = 5; // Range query end (closed interval) - ']' 0162 const ST_OPENEDINT_RQ_START = 6; // Range query start (opened interval) - '{' 0163 const ST_OPENEDINT_RQ_FIRST_TERM = 7; // First term in '{term1 to term2}' construction 0164 const ST_OPENEDINT_RQ_TO_TERM = 8; // 'TO' lexeme in '{term1 to term2}' construction 0165 const ST_OPENEDINT_RQ_LAST_TERM = 9; // Second term in '{term1 to term2}' construction 0166 const ST_OPENEDINT_RQ_END = 10; // Range query end (opened interval) - '}' 0167 0168 /** 0169 * Parser constructor 0170 */ 0171 public function __construct() 0172 { 0173 parent::__construct(array(self::ST_COMMON_QUERY_ELEMENT, 0174 self::ST_CLOSEDINT_RQ_START, 0175 self::ST_CLOSEDINT_RQ_FIRST_TERM, 0176 self::ST_CLOSEDINT_RQ_TO_TERM, 0177 self::ST_CLOSEDINT_RQ_LAST_TERM, 0178 self::ST_CLOSEDINT_RQ_END, 0179 self::ST_OPENEDINT_RQ_START, 0180 self::ST_OPENEDINT_RQ_FIRST_TERM, 0181 self::ST_OPENEDINT_RQ_TO_TERM, 0182 self::ST_OPENEDINT_RQ_LAST_TERM, 0183 self::ST_OPENEDINT_RQ_END 0184 ), 0185 Zend_Search_Lucene_Search_QueryToken::getTypes()); 0186 0187 $this->addRules( 0188 array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT), 0189 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT), 0190 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT), 0191 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT), 0192 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT), 0193 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT), 0194 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT), 0195 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START), 0196 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START), 0197 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT), 0198 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT), 0199 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT), 0200 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT), 0201 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT), 0202 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT) 0203 )); 0204 $this->addRules( 0205 array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM), 0206 array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM), 0207 array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM), 0208 array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT) 0209 )); 0210 $this->addRules( 0211 array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM), 0212 array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM), 0213 array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM), 0214 array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT) 0215 )); 0216 0217 0218 0219 $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry'); 0220 $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry'); 0221 $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField'); 0222 $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign'); 0223 $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier'); 0224 $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter'); 0225 $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart'); 0226 $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd'); 0227 $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator'); 0228 $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm'); 0229 $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm'); 0230 $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm'); 0231 $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm'); 0232 0233 0234 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction); 0235 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction); 0236 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction); 0237 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction); 0238 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction); 0239 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction); 0240 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction); 0241 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction); 0242 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction); 0243 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction); 0244 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction); 0245 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction); 0246 0247 $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction); 0248 $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction); 0249 $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction); 0250 $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction); 0251 0252 0253 // require_once 'Zend/Search/Lucene/Search/QueryLexer.php'; 0254 $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer(); 0255 } 0256 0257 /** 0258 * Get query parser instance 0259 * 0260 * @return Zend_Search_Lucene_Search_QueryParser 0261 */ 0262 private static function _getInstance() 0263 { 0264 if (self::$_instance === null) { 0265 self::$_instance = new self(); 0266 } 0267 return self::$_instance; 0268 } 0269 0270 /** 0271 * Set query string default encoding 0272 * 0273 * @param string $encoding 0274 */ 0275 public static function setDefaultEncoding($encoding) 0276 { 0277 self::_getInstance()->_defaultEncoding = $encoding; 0278 } 0279 0280 /** 0281 * Get query string default encoding 0282 * 0283 * @return string 0284 */ 0285 public static function getDefaultEncoding() 0286 { 0287 return self::_getInstance()->_defaultEncoding; 0288 } 0289 0290 /** 0291 * Set default boolean operator 0292 * 0293 * @param integer $operator 0294 */ 0295 public static function setDefaultOperator($operator) 0296 { 0297 self::_getInstance()->_defaultOperator = $operator; 0298 } 0299 0300 /** 0301 * Get default boolean operator 0302 * 0303 * @return integer 0304 */ 0305 public static function getDefaultOperator() 0306 { 0307 return self::_getInstance()->_defaultOperator; 0308 } 0309 0310 /** 0311 * Turn on 'suppress query parser exceptions' mode. 0312 */ 0313 public static function suppressQueryParsingExceptions() 0314 { 0315 self::_getInstance()->_suppressQueryParsingExceptions = true; 0316 } 0317 /** 0318 * Turn off 'suppress query parser exceptions' mode. 0319 */ 0320 public static function dontSuppressQueryParsingExceptions() 0321 { 0322 self::_getInstance()->_suppressQueryParsingExceptions = false; 0323 } 0324 /** 0325 * Check 'suppress query parser exceptions' mode. 0326 * @return boolean 0327 */ 0328 public static function queryParsingExceptionsSuppressed() 0329 { 0330 return self::_getInstance()->_suppressQueryParsingExceptions; 0331 } 0332 0333 0334 /** 0335 * Escape keyword to force it to be parsed as one term 0336 * 0337 * @param string $keyword 0338 * @return string 0339 */ 0340 public static function escape($keyword) 0341 { 0342 return '\\' . implode('\\', str_split($keyword)); 0343 } 0344 0345 /** 0346 * Parses a query string 0347 * 0348 * @param string $strQuery 0349 * @param string $encoding 0350 * @return Zend_Search_Lucene_Search_Query 0351 * @throws Zend_Search_Lucene_Search_QueryParserException 0352 */ 0353 public static function parse($strQuery, $encoding = null) 0354 { 0355 self::_getInstance(); 0356 0357 // Reset FSM if previous parse operation didn't return it into a correct state 0358 self::$_instance->reset(); 0359 0360 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0361 try { 0362 // require_once 'Zend/Search/Lucene/Search/QueryParserContext.php'; 0363 0364 self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding; 0365 self::$_instance->_lastToken = null; 0366 self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding); 0367 self::$_instance->_contextStack = array(); 0368 self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding); 0369 0370 // Empty query 0371 if (count(self::$_instance->_tokens) == 0) { 0372 // require_once 'Zend/Search/Lucene/Search/Query/Insignificant.php'; 0373 return new Zend_Search_Lucene_Search_Query_Insignificant(); 0374 } 0375 0376 0377 foreach (self::$_instance->_tokens as $token) { 0378 try { 0379 self::$_instance->_currentToken = $token; 0380 self::$_instance->process($token->type); 0381 0382 self::$_instance->_lastToken = $token; 0383 } catch (Exception $e) { 0384 if (strpos($e->getMessage(), 'There is no any rule for') !== false) { 0385 throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.', 0, $e); 0386 } 0387 0388 // require_once 'Zend/Search/Lucene/Exception.php'; 0389 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 0390 } 0391 } 0392 0393 if (count(self::$_instance->_contextStack) != 0) { 0394 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' ); 0395 } 0396 0397 return self::$_instance->_context->getQuery(); 0398 } catch (Zend_Search_Lucene_Search_QueryParserException $e) { 0399 if (self::$_instance->_suppressQueryParsingExceptions) { 0400 $queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding); 0401 0402 // require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php'; 0403 $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); 0404 $termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true /* required term */ : 0405 null /* optional term */; 0406 0407 // require_once 'Zend/Search/Lucene/Index/Term.php'; 0408 foreach ($queryTokens as $token) { 0409 $query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign); 0410 } 0411 0412 0413 return $query; 0414 } else { 0415 // require_once 'Zend/Search/Lucene/Exception.php'; 0416 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 0417 } 0418 } 0419 } 0420 0421 /********************************************************************* 0422 * Actions implementation 0423 * 0424 * Actions affect on recognized lexemes list 0425 *********************************************************************/ 0426 0427 /** 0428 * Add term to a query 0429 */ 0430 public function addTermEntry() 0431 { 0432 // require_once 'Zend/Search/Lucene/Search/QueryEntry/Term.php'; 0433 $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField()); 0434 $this->_context->addEntry($entry); 0435 } 0436 0437 /** 0438 * Add phrase to a query 0439 */ 0440 public function addPhraseEntry() 0441 { 0442 // require_once 'Zend/Search/Lucene/Search/QueryEntry/Phrase.php'; 0443 $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField()); 0444 $this->_context->addEntry($entry); 0445 } 0446 0447 /** 0448 * Set entry field 0449 */ 0450 public function setField() 0451 { 0452 $this->_context->setNextEntryField($this->_currentToken->text); 0453 } 0454 0455 /** 0456 * Set entry sign 0457 */ 0458 public function setSign() 0459 { 0460 $this->_context->setNextEntrySign($this->_currentToken->type); 0461 } 0462 0463 0464 /** 0465 * Process fuzzy search/proximity modifier - '~' 0466 */ 0467 public function processFuzzyProximityModifier() 0468 { 0469 $this->_context->processFuzzyProximityModifier(); 0470 } 0471 0472 /** 0473 * Process modifier parameter 0474 * 0475 * @throws Zend_Search_Lucene_Exception 0476 */ 0477 public function processModifierParameter() 0478 { 0479 if ($this->_lastToken === null) { 0480 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0481 throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); 0482 } 0483 0484 switch ($this->_lastToken->type) { 0485 case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK: 0486 $this->_context->processFuzzyProximityModifier($this->_currentToken->text); 0487 break; 0488 0489 case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK: 0490 $this->_context->boost($this->_currentToken->text); 0491 break; 0492 0493 default: 0494 // It's not a user input exception 0495 // require_once 'Zend/Search/Lucene/Exception.php'; 0496 throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); 0497 } 0498 } 0499 0500 0501 /** 0502 * Start subquery 0503 */ 0504 public function subqueryStart() 0505 { 0506 // require_once 'Zend/Search/Lucene/Search/QueryParserContext.php'; 0507 0508 $this->_contextStack[] = $this->_context; 0509 $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField()); 0510 } 0511 0512 /** 0513 * End subquery 0514 */ 0515 public function subqueryEnd() 0516 { 0517 if (count($this->_contextStack) == 0) { 0518 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0519 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' ); 0520 } 0521 0522 $query = $this->_context->getQuery(); 0523 $this->_context = array_pop($this->_contextStack); 0524 0525 // require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php'; 0526 $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query)); 0527 } 0528 0529 /** 0530 * Process logical operator 0531 */ 0532 public function logicalOperator() 0533 { 0534 $this->_context->addLogicalOperator($this->_currentToken->type); 0535 } 0536 0537 /** 0538 * Process first range query term (opened interval) 0539 */ 0540 public function openedRQFirstTerm() 0541 { 0542 $this->_rqFirstTerm = $this->_currentToken->text; 0543 } 0544 0545 /** 0546 * Process last range query term (opened interval) 0547 * 0548 * @throws Zend_Search_Lucene_Search_QueryParserException 0549 */ 0550 public function openedRQLastTerm() 0551 { 0552 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); 0553 if (count($tokens) > 1) { 0554 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0555 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); 0556 } else if (count($tokens) == 1) { 0557 // require_once 'Zend/Search/Lucene/Index/Term.php'; 0558 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); 0559 } else { 0560 $from = null; 0561 } 0562 0563 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); 0564 if (count($tokens) > 1) { 0565 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0566 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); 0567 } else if (count($tokens) == 1) { 0568 // require_once 'Zend/Search/Lucene/Index/Term.php'; 0569 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); 0570 } else { 0571 $to = null; 0572 } 0573 0574 if ($from === null && $to === null) { 0575 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0576 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); 0577 } 0578 0579 // require_once 'Zend/Search/Lucene/Search/Query/Range.php'; 0580 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false); 0581 // require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php'; 0582 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); 0583 $this->_context->addEntry($entry); 0584 } 0585 0586 /** 0587 * Process first range query term (closed interval) 0588 */ 0589 public function closedRQFirstTerm() 0590 { 0591 $this->_rqFirstTerm = $this->_currentToken->text; 0592 } 0593 0594 /** 0595 * Process last range query term (closed interval) 0596 * 0597 * @throws Zend_Search_Lucene_Search_QueryParserException 0598 */ 0599 public function closedRQLastTerm() 0600 { 0601 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); 0602 if (count($tokens) > 1) { 0603 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0604 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); 0605 } else if (count($tokens) == 1) { 0606 // require_once 'Zend/Search/Lucene/Index/Term.php'; 0607 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); 0608 } else { 0609 $from = null; 0610 } 0611 0612 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); 0613 if (count($tokens) > 1) { 0614 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0615 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); 0616 } else if (count($tokens) == 1) { 0617 // require_once 'Zend/Search/Lucene/Index/Term.php'; 0618 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); 0619 } else { 0620 $to = null; 0621 } 0622 0623 if ($from === null && $to === null) { 0624 // require_once 'Zend/Search/Lucene/Search/QueryParserException.php'; 0625 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); 0626 } 0627 0628 // require_once 'Zend/Search/Lucene/Search/Query/Range.php'; 0629 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true); 0630 // require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php'; 0631 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); 0632 $this->_context->addEntry($entry); 0633 } 0634 } 0635