7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
16 * @package Zend_Search_Lucene
18 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: BooleanExpressionRecognizer.php 16971 2009-07-22 18:05:45Z mikaelkael $
24 /** Zend_Search_Lucene_FSM */
25 require_once 'Zend/Search/Lucene/FSM.php';
27 /** Zend_Search_Lucene_Search_QueryToken */
28 require_once 'Zend/Search/Lucene/Search/QueryToken.php';
30 /** Zend_Search_Lucene_Search_QueryParser */
31 require_once 'Zend/Search/Lucene/Search/QueryParser.php';
35 * @package Zend_Search_Lucene
37 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
38 * @license http://framework.zend.com/license/new-bsd New BSD License
40 class Zend_Search_Lucene_Search_BooleanExpressionRecognizer extends Zend_Search_Lucene_FSM
42 /** State Machine states */
45 const ST_NOT_OPERATOR = 2;
46 const ST_AND_OPERATOR = 3;
47 const ST_OR_OPERATOR = 4;
51 const IN_NOT_OPERATOR = 1;
52 const IN_AND_OPERATOR = 2;
53 const IN_OR_OPERATOR = 3;
61 private $_negativeLiteral = false;
72 * Set of boolean query conjunctions
74 * Each conjunction is an array of conjunction elements
75 * Each conjunction element is presented with two-elements array:
76 * array(<literal>, <is_negative>)
78 * So, it has a structure:
79 * array( array( array(<literal>, <is_negative>), // first literal of first conjuction
80 * array(<literal>, <is_negative>), // second literal of first conjuction
82 * array(<literal>, <is_negative>)
83 * ), // end of first conjuction
84 * array( array(<literal>, <is_negative>), // first literal of second conjuction
85 * array(<literal>, <is_negative>), // second literal of second conjuction
87 * array(<literal>, <is_negative>)
88 * ), // end of second conjuction
90 * ) // end of structure
94 private $_conjunctions = array();
101 private $_currentConjunction = array();
107 public function __construct()
109 parent::__construct( array(self::ST_START,
111 self::ST_NOT_OPERATOR,
112 self::ST_AND_OPERATOR,
113 self::ST_OR_OPERATOR),
114 array(self::IN_LITERAL,
115 self::IN_NOT_OPERATOR,
116 self::IN_AND_OPERATOR,
117 self::IN_OR_OPERATOR));
119 $emptyOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyOperatorAction');
120 $emptyNotOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyNotOperatorAction');
122 $this->addRules(array( array(self::ST_START, self::IN_LITERAL, self::ST_LITERAL),
123 array(self::ST_START, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR),
125 array(self::ST_LITERAL, self::IN_AND_OPERATOR, self::ST_AND_OPERATOR),
126 array(self::ST_LITERAL, self::IN_OR_OPERATOR, self::ST_OR_OPERATOR),
127 array(self::ST_LITERAL, self::IN_LITERAL, self::ST_LITERAL, $emptyOperatorAction),
128 array(self::ST_LITERAL, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR, $emptyNotOperatorAction),
130 array(self::ST_NOT_OPERATOR, self::IN_LITERAL, self::ST_LITERAL),
132 array(self::ST_AND_OPERATOR, self::IN_LITERAL, self::ST_LITERAL),
133 array(self::ST_AND_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR),
135 array(self::ST_OR_OPERATOR, self::IN_LITERAL, self::ST_LITERAL),
136 array(self::ST_OR_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR),
139 $notOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'notOperatorAction');
140 $orOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'orOperatorAction');
141 $literalAction = new Zend_Search_Lucene_FSMAction($this, 'literalAction');
144 $this->addEntryAction(self::ST_NOT_OPERATOR, $notOperatorAction);
145 $this->addEntryAction(self::ST_OR_OPERATOR, $orOperatorAction);
146 $this->addEntryAction(self::ST_LITERAL, $literalAction);
151 * Process next operator.
153 * Operators are defined by class constants: IN_AND_OPERATOR, IN_OR_OPERATOR and IN_NOT_OPERATOR
155 * @param integer $operator
157 public function processOperator($operator)
159 $this->process($operator);
163 * Process expression literal.
165 * @param integer $operator
167 public function processLiteral($literal)
169 $this->_literal = $literal;
171 $this->process(self::IN_LITERAL);
175 * Finish an expression and return result
177 * Result is a set of boolean query conjunctions
179 * Each conjunction is an array of conjunction elements
180 * Each conjunction element is presented with two-elements array:
181 * array(<literal>, <is_negative>)
183 * So, it has a structure:
184 * array( array( array(<literal>, <is_negative>), // first literal of first conjuction
185 * array(<literal>, <is_negative>), // second literal of first conjuction
187 * array(<literal>, <is_negative>)
188 * ), // end of first conjuction
189 * array( array(<literal>, <is_negative>), // first literal of second conjuction
190 * array(<literal>, <is_negative>), // second literal of second conjuction
192 * array(<literal>, <is_negative>)
193 * ), // end of second conjuction
195 * ) // end of structure
198 * @throws Zend_Search_Lucene_Exception
200 public function finishExpression()
202 if ($this->getState() != self::ST_LITERAL) {
203 require_once 'Zend/Search/Lucene/Exception.php';
204 throw new Zend_Search_Lucene_Exception('Literal expected.');
207 $this->_conjunctions[] = $this->_currentConjunction;
209 return $this->_conjunctions;
214 /*********************************************************************
215 * Actions implementation
216 *********************************************************************/
219 * default (omitted) operator processing
221 public function emptyOperatorAction()
223 if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) {
226 $this->orOperatorAction();
230 $this->literalAction();
234 * default (omitted) + NOT operator processing
236 public function emptyNotOperatorAction()
238 if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) {
241 $this->orOperatorAction();
244 // Process NOT operator
245 $this->notOperatorAction();
250 * NOT operator processing
252 public function notOperatorAction()
254 $this->_negativeLiteral = true;
258 * OR operator processing
259 * Close current conjunction
261 public function orOperatorAction()
263 $this->_conjunctions[] = $this->_currentConjunction;
264 $this->_currentConjunction = array();
270 public function literalAction()
272 // Add literal to the current conjunction
273 $this->_currentConjunction[] = array($this->_literal, !$this->_negativeLiteral);
275 // Switch off negative signal
276 $this->_negativeLiteral = false;