addRules( array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT) )); $this->addRules( array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM), array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM), array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM), array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT) )); $this->addRules( array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM), array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM), array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM), array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT) )); $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry'); $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry'); $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField'); $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign'); $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier'); $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter'); $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart'); $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd'); $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator'); $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm'); $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm'); $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm'); $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm'); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction); $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction); $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction); $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction); $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction); $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer(); } /** * Set query string default encoding * * @param string $encoding */ public static function setDefaultEncoding($encoding) { if (self::$_instance === null) { self::$_instance = new Zend_Search_Lucene_Search_QueryParser(); } self::$_instance->_defaultEncoding = $encoding; } /** * Get query string default encoding * * @return string */ public static function getDefaultEncoding() { if (self::$_instance === null) { self::$_instance = new Zend_Search_Lucene_Search_QueryParser(); } return self::$_instance->_defaultEncoding; } /** * Set default boolean operator * * @param integer $operator */ public static function setDefaultOperator($operator) { if (self::$_instance === null) { self::$_instance = new Zend_Search_Lucene_Search_QueryParser(); } self::$_instance->_defaultOperator = $operator; } /** * Get default boolean operator * * @return integer */ public static function getDefaultOperator() { if (self::$_instance === null) { self::$_instance = new Zend_Search_Lucene_Search_QueryParser(); } return self::$_instance->_defaultOperator; } /** * Parses a query string * * @param string $strQuery * @param string $encoding * @return Zend_Search_Lucene_Search_Query * @throws Zend_Search_Lucene_Search_QueryParserException */ static public function parse($strQuery, $encoding = null) { if (self::$_instance === null) { self::$_instance = new Zend_Search_Lucene_Search_QueryParser(); } self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding; self::$_instance->_lastToken = null; self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding); self::$_instance->_contextStack = array(); self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding); // Empty query if (count(self::$_instance->_tokens) == 0) { return new Zend_Search_Lucene_Search_Query_Empty(); } foreach (self::$_instance->_tokens as $token) { try { self::$_instance->_currentToken = $token; self::$_instance->process($token->type); self::$_instance->_lastToken = $token; } catch (Exception $e) { if (strpos($e->getMessage(), 'There is no any rule for') !== false) { throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.' ); } throw $e; } } if (count(self::$_instance->_contextStack) != 0) { throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' ); } return self::$_instance->_context->getQuery(); } /********************************************************************* * Actions implementation * * Actions affect on recognized lexemes list *********************************************************************/ /** * Add term to a query */ public function addTermEntry() { $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField()); $this->_context->addEntry($entry); } /** * Add phrase to a query */ public function addPhraseEntry() { $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField()); $this->_context->addEntry($entry); } /** * Set entry field */ public function setField() { $this->_context->setNextEntryField($this->_currentToken->text); } /** * Set entry sign */ public function setSign() { $this->_context->setNextEntrySign($this->_currentToken->type); } /** * Process fuzzy search/proximity modifier - '~' */ public function processFuzzyProximityModifier() { $this->_context->processFuzzyProximityModifier(); } /** * Process modifier parameter * * @throws Zend_Search_Lucene_Exception */ public function processModifierParameter() { if ($this->_lastToken === null) { throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); } switch ($this->_lastToken->type) { case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK: $this->_context->processFuzzyProximityModifier($this->_currentToken->text); break; case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK: $this->_context->boost($this->_currentToken->text); break; default: // It's not a user input exception throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position .' ); } } /** * Start subquery */ public function subqueryStart() { $this->_contextStack[] = $this->_context; $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField()); } /** * End subquery */ public function subqueryEnd() { if (count($this->_contextStack) == 0) { throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' ); } $query = $this->_context->getQuery(); $this->_context = array_pop($this->_contextStack); $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query)); } /** * Process logical operator */ public function logicalOperator() { $this->_context->addLogicalOperator($this->_currentToken->type); } /** * Process first range query term (opened interval) */ public function openedRQFirstTerm() { $this->_rqFirstTerm = $this->_currentToken->text; } /** * Process last range query term (opened interval) * * @throws Zend_Search_Lucene_Search_QueryParserException */ public function openedRQLastTerm() { throw new Zend_Search_Lucene_Search_QueryParserException('Range queries are not supported yet.'); // $firstTerm = new Zend_Search_Lucene_Index_Term($this->_rqFirstTerm, $this->_context->getField()); // $lastTerm = new Zend_Search_Lucene_Index_Term($this->_currentToken->text, $this->_context->getField()); // $query = new Zend_Search_Lucene_Search_Query_Range($firstTerm, $lastTerm, false); // $this->_context->addentry($query); } /** * Process first range query term (closed interval) */ public function closedRQFirstTerm() { $this->_rqFirstTerm = $this->_currentToken->text; } /** * Process last range query term (closed interval) * * @throws Zend_Search_Lucene_Search_QueryParserException */ public function closedRQLastTerm() { throw new Zend_Search_Lucene_Search_QueryParserException('Range queries are not supported yet.'); // $firstTerm = new Zend_Search_Lucene_Index_Term($this->_rqFirstTerm, $this->_context->getField()); // $lastTerm = new Zend_Search_Lucene_Index_Term($this->_currentToken->text, $this->_context->getField()); // $query = new Zend_Search_Lucene_Search_Query_Range($firstTerm, $lastTerm, true); // $this->_context->addentry($query); } }