/library/Zend/Search/Lucene/Search/QueryParser.php
PHP | 635 lines | 333 code | 85 blank | 217 comment | 37 complexity | 3d2aa29cb89ecfffcf14777334d80be0 MD5 | raw file
Possible License(s): AGPL-1.0
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
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.
14 *
15 * @category Zend
16 * @package Zend_Search_Lucene
17 * @subpackage Search
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: QueryParser.php 24594 2012-01-05 21:27:01Z matthew $
21 */
22
23
24/** Internally used classes */
25
26/** Zend_Search_Lucene_Analysis_Analyzer */
27require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
28
29/** Zend_Search_Lucene_Search_QueryToken */
30require_once 'Zend/Search/Lucene/Search/QueryToken.php';
31
32
33
34/** Zend_Search_Lucene_FSM */
35require_once 'Zend/Search/Lucene/FSM.php';
36
37/**
38 * @category Zend
39 * @package Zend_Search_Lucene
40 * @subpackage Search
41 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
42 * @license http://framework.zend.com/license/new-bsd New BSD License
43 */
44class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
45{
46 /**
47 * Parser instance
48 *
49 * @var Zend_Search_Lucene_Search_QueryParser
50 */
51 private static $_instance = null;
52
53
54 /**
55 * Query lexer
56 *
57 * @var Zend_Search_Lucene_Search_QueryLexer
58 */
59 private $_lexer;
60
61 /**
62 * Tokens list
63 * Array of Zend_Search_Lucene_Search_QueryToken objects
64 *
65 * @var array
66 */
67 private $_tokens;
68
69 /**
70 * Current token
71 *
72 * @var integer|string
73 */
74 private $_currentToken;
75
76 /**
77 * Last token
78 *
79 * It can be processed within FSM states, but this addirional state simplifies FSM
80 *
81 * @var Zend_Search_Lucene_Search_QueryToken
82 */
83 private $_lastToken = null;
84
85 /**
86 * Range query first term
87 *
88 * @var string
89 */
90 private $_rqFirstTerm = null;
91
92 /**
93 * Current query parser context
94 *
95 * @var Zend_Search_Lucene_Search_QueryParserContext
96 */
97 private $_context;
98
99 /**
100 * Context stack
101 *
102 * @var array
103 */
104 private $_contextStack;
105
106 /**
107 * Query string encoding
108 *
109 * @var string
110 */
111 private $_encoding;
112
113 /**
114 * Query string default encoding
115 *
116 * @var string
117 */
118 private $_defaultEncoding = '';
119
120 /**
121 * Defines query parsing mode.
122 *
123 * If this option is turned on, then query parser suppress query parser exceptions
124 * and constructs multi-term query using all words from a query.
125 *
126 * That helps to avoid exceptions caused by queries, which don't conform to query language,
127 * but limits possibilities to check, that query entered by user has some inconsistencies.
128 *
129 *
130 * Default is true.
131 *
132 * Use {@link Zend_Search_Lucene::suppressQueryParsingExceptions()},
133 * {@link Zend_Search_Lucene::dontSuppressQueryParsingExceptions()} and
134 * {@link Zend_Search_Lucene::checkQueryParsingExceptionsSuppressMode()} to operate
135 * with this setting.
136 *
137 * @var boolean
138 */
139 private $_suppressQueryParsingExceptions = true;
140
141 /**
142 * Boolean operators constants
143 */
144 const B_OR = 0;
145 const B_AND = 1;
146
147 /**
148 * Default boolean queries operator
149 *
150 * @var integer
151 */
152 private $_defaultOperator = self::B_OR;
153
154
155 /** Query parser State Machine states */
156 const ST_COMMON_QUERY_ELEMENT = 0; // Terms, phrases, operators
157 const ST_CLOSEDINT_RQ_START = 1; // Range query start (closed interval) - '['
158 const ST_CLOSEDINT_RQ_FIRST_TERM = 2; // First term in '[term1 to term2]' construction
159 const ST_CLOSEDINT_RQ_TO_TERM = 3; // 'TO' lexeme in '[term1 to term2]' construction
160 const ST_CLOSEDINT_RQ_LAST_TERM = 4; // Second term in '[term1 to term2]' construction
161 const ST_CLOSEDINT_RQ_END = 5; // Range query end (closed interval) - ']'
162 const ST_OPENEDINT_RQ_START = 6; // Range query start (opened interval) - '{'
163 const ST_OPENEDINT_RQ_FIRST_TERM = 7; // First term in '{term1 to term2}' construction
164 const ST_OPENEDINT_RQ_TO_TERM = 8; // 'TO' lexeme in '{term1 to term2}' construction
165 const ST_OPENEDINT_RQ_LAST_TERM = 9; // Second term in '{term1 to term2}' construction
166 const ST_OPENEDINT_RQ_END = 10; // Range query end (opened interval) - '}'
167
168 /**
169 * Parser constructor
170 */
171 public function __construct()
172 {
173 parent::__construct(array(self::ST_COMMON_QUERY_ELEMENT,
174 self::ST_CLOSEDINT_RQ_START,
175 self::ST_CLOSEDINT_RQ_FIRST_TERM,
176 self::ST_CLOSEDINT_RQ_TO_TERM,
177 self::ST_CLOSEDINT_RQ_LAST_TERM,
178 self::ST_CLOSEDINT_RQ_END,
179 self::ST_OPENEDINT_RQ_START,
180 self::ST_OPENEDINT_RQ_FIRST_TERM,
181 self::ST_OPENEDINT_RQ_TO_TERM,
182 self::ST_OPENEDINT_RQ_LAST_TERM,
183 self::ST_OPENEDINT_RQ_END
184 ),
185 Zend_Search_Lucene_Search_QueryToken::getTypes());
186
187 $this->addRules(
188 array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT),
189 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT),
190 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT),
191 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT),
192 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT),
193 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT),
194 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT),
195 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START),
196 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START),
197 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT),
198 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT),
199 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
200 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
201 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
202 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT)
203 ));
204 $this->addRules(
205 array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM),
206 array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM),
207 array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM),
208 array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT)
209 ));
210 $this->addRules(
211 array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM),
212 array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM),
213 array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM),
214 array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT)
215 ));
216
217
218
219 $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry');
220 $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry');
221 $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField');
222 $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign');
223 $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier');
224 $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter');
225 $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart');
226 $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd');
227 $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator');
228 $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm');
229 $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm');
230 $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm');
231 $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm');
232
233
234 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction);
235 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction);
236 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction);
237 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction);
238 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction);
239 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction);
240 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction);
241 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction);
242 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction);
243 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction);
244 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction);
245 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction);
246
247 $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction);
248 $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction);
249 $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction);
250 $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction);
251
252
253 require_once 'Zend/Search/Lucene/Search/QueryLexer.php';
254 $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer();
255 }
256
257 /**
258 * Get query parser instance
259 *
260 * @return Zend_Search_Lucene_Search_QueryParser
261 */
262 private static function _getInstance()
263 {
264 if (self::$_instance === null) {
265 self::$_instance = new self();
266 }
267 return self::$_instance;
268 }
269
270 /**
271 * Set query string default encoding
272 *
273 * @param string $encoding
274 */
275 public static function setDefaultEncoding($encoding)
276 {
277 self::_getInstance()->_defaultEncoding = $encoding;
278 }
279
280 /**
281 * Get query string default encoding
282 *
283 * @return string
284 */
285 public static function getDefaultEncoding()
286 {
287 return self::_getInstance()->_defaultEncoding;
288 }
289
290 /**
291 * Set default boolean operator
292 *
293 * @param integer $operator
294 */
295 public static function setDefaultOperator($operator)
296 {
297 self::_getInstance()->_defaultOperator = $operator;
298 }
299
300 /**
301 * Get default boolean operator
302 *
303 * @return integer
304 */
305 public static function getDefaultOperator()
306 {
307 return self::_getInstance()->_defaultOperator;
308 }
309
310 /**
311 * Turn on 'suppress query parser exceptions' mode.
312 */
313 public static function suppressQueryParsingExceptions()
314 {
315 self::_getInstance()->_suppressQueryParsingExceptions = true;
316 }
317 /**
318 * Turn off 'suppress query parser exceptions' mode.
319 */
320 public static function dontSuppressQueryParsingExceptions()
321 {
322 self::_getInstance()->_suppressQueryParsingExceptions = false;
323 }
324 /**
325 * Check 'suppress query parser exceptions' mode.
326 * @return boolean
327 */
328 public static function queryParsingExceptionsSuppressed()
329 {
330 return self::_getInstance()->_suppressQueryParsingExceptions;
331 }
332
333
334 /**
335 * Escape keyword to force it to be parsed as one term
336 *
337 * @param string $keyword
338 * @return string
339 */
340 public static function escape($keyword)
341 {
342 return '\\' . implode('\\', str_split($keyword));
343 }
344
345 /**
346 * Parses a query string
347 *
348 * @param string $strQuery
349 * @param string $encoding
350 * @return Zend_Search_Lucene_Search_Query
351 * @throws Zend_Search_Lucene_Search_QueryParserException
352 */
353 public static function parse($strQuery, $encoding = null)
354 {
355 self::_getInstance();
356
357 // Reset FSM if previous parse operation didn't return it into a correct state
358 self::$_instance->reset();
359
360 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
361 try {
362 require_once 'Zend/Search/Lucene/Search/QueryParserContext.php';
363
364 self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding;
365 self::$_instance->_lastToken = null;
366 self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding);
367 self::$_instance->_contextStack = array();
368 self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding);
369
370 // Empty query
371 if (count(self::$_instance->_tokens) == 0) {
372 require_once 'Zend/Search/Lucene/Search/Query/Insignificant.php';
373 return new Zend_Search_Lucene_Search_Query_Insignificant();
374 }
375
376
377 foreach (self::$_instance->_tokens as $token) {
378 try {
379 self::$_instance->_currentToken = $token;
380 self::$_instance->process($token->type);
381
382 self::$_instance->_lastToken = $token;
383 } catch (Exception $e) {
384 if (strpos($e->getMessage(), 'There is no any rule for') !== false) {
385 throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.', 0, $e);
386 }
387
388 require_once 'Zend/Search/Lucene/Exception.php';
389 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e);
390 }
391 }
392
393 if (count(self::$_instance->_contextStack) != 0) {
394 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' );
395 }
396
397 return self::$_instance->_context->getQuery();
398 } catch (Zend_Search_Lucene_Search_QueryParserException $e) {
399 if (self::$_instance->_suppressQueryParsingExceptions) {
400 $queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding);
401
402 require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php';
403 $query = new Zend_Search_Lucene_Search_Query_MultiTerm();
404 $termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true /* required term */ :
405 null /* optional term */;
406
407 require_once 'Zend/Search/Lucene/Index/Term.php';
408 foreach ($queryTokens as $token) {
409 $query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign);
410 }
411
412
413 return $query;
414 } else {
415 require_once 'Zend/Search/Lucene/Exception.php';
416 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e);
417 }
418 }
419 }
420
421 /*********************************************************************
422 * Actions implementation
423 *
424 * Actions affect on recognized lexemes list
425 *********************************************************************/
426
427 /**
428 * Add term to a query
429 */
430 public function addTermEntry()
431 {
432 require_once 'Zend/Search/Lucene/Search/QueryEntry/Term.php';
433 $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField());
434 $this->_context->addEntry($entry);
435 }
436
437 /**
438 * Add phrase to a query
439 */
440 public function addPhraseEntry()
441 {
442 require_once 'Zend/Search/Lucene/Search/QueryEntry/Phrase.php';
443 $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField());
444 $this->_context->addEntry($entry);
445 }
446
447 /**
448 * Set entry field
449 */
450 public function setField()
451 {
452 $this->_context->setNextEntryField($this->_currentToken->text);
453 }
454
455 /**
456 * Set entry sign
457 */
458 public function setSign()
459 {
460 $this->_context->setNextEntrySign($this->_currentToken->type);
461 }
462
463
464 /**
465 * Process fuzzy search/proximity modifier - '~'
466 */
467 public function processFuzzyProximityModifier()
468 {
469 $this->_context->processFuzzyProximityModifier();
470 }
471
472 /**
473 * Process modifier parameter
474 *
475 * @throws Zend_Search_Lucene_Exception
476 */
477 public function processModifierParameter()
478 {
479 if ($this->_lastToken === null) {
480 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
481 throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' );
482 }
483
484 switch ($this->_lastToken->type) {
485 case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK:
486 $this->_context->processFuzzyProximityModifier($this->_currentToken->text);
487 break;
488
489 case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK:
490 $this->_context->boost($this->_currentToken->text);
491 break;
492
493 default:
494 // It's not a user input exception
495 require_once 'Zend/Search/Lucene/Exception.php';
496 throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' );
497 }
498 }
499
500
501 /**
502 * Start subquery
503 */
504 public function subqueryStart()
505 {
506 require_once 'Zend/Search/Lucene/Search/QueryParserContext.php';
507
508 $this->_contextStack[] = $this->_context;
509 $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField());
510 }
511
512 /**
513 * End subquery
514 */
515 public function subqueryEnd()
516 {
517 if (count($this->_contextStack) == 0) {
518 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
519 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' );
520 }
521
522 $query = $this->_context->getQuery();
523 $this->_context = array_pop($this->_contextStack);
524
525 require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php';
526 $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query));
527 }
528
529 /**
530 * Process logical operator
531 */
532 public function logicalOperator()
533 {
534 $this->_context->addLogicalOperator($this->_currentToken->type);
535 }
536
537 /**
538 * Process first range query term (opened interval)
539 */
540 public function openedRQFirstTerm()
541 {
542 $this->_rqFirstTerm = $this->_currentToken->text;
543 }
544
545 /**
546 * Process last range query term (opened interval)
547 *
548 * @throws Zend_Search_Lucene_Search_QueryParserException
549 */
550 public function openedRQLastTerm()
551 {
552 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
553 if (count($tokens) > 1) {
554 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
555 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
556 } else if (count($tokens) == 1) {
557 require_once 'Zend/Search/Lucene/Index/Term.php';
558 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
559 } else {
560 $from = null;
561 }
562
563 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
564 if (count($tokens) > 1) {
565 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
566 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
567 } else if (count($tokens) == 1) {
568 require_once 'Zend/Search/Lucene/Index/Term.php';
569 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
570 } else {
571 $to = null;
572 }
573
574 if ($from === null && $to === null) {
575 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
576 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
577 }
578
579 require_once 'Zend/Search/Lucene/Search/Query/Range.php';
580 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false);
581 require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php';
582 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
583 $this->_context->addEntry($entry);
584 }
585
586 /**
587 * Process first range query term (closed interval)
588 */
589 public function closedRQFirstTerm()
590 {
591 $this->_rqFirstTerm = $this->_currentToken->text;
592 }
593
594 /**
595 * Process last range query term (closed interval)
596 *
597 * @throws Zend_Search_Lucene_Search_QueryParserException
598 */
599 public function closedRQLastTerm()
600 {
601 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
602 if (count($tokens) > 1) {
603 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
604 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
605 } else if (count($tokens) == 1) {
606 require_once 'Zend/Search/Lucene/Index/Term.php';
607 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
608 } else {
609 $from = null;
610 }
611
612 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
613 if (count($tokens) > 1) {
614 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
615 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
616 } else if (count($tokens) == 1) {
617 require_once 'Zend/Search/Lucene/Index/Term.php';
618 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
619 } else {
620 $to = null;
621 }
622
623 if ($from === null && $to === null) {
624 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
625 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
626 }
627
628 require_once 'Zend/Search/Lucene/Search/Query/Range.php';
629 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true);
630 require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php';
631 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
632 $this->_context->addEntry($entry);
633 }
634}
635