/web/concrete/libraries/3rdparty/Zend/Search/Lucene/Search/QueryParserContext.php
PHP | 401 lines | 182 code | 65 blank | 154 comment | 32 complexity | 05018c8093d1b9a65648391958b51f6d MD5 | raw file
Possible License(s): MIT, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
- <?php
- /**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category Zend
- * @package Zend_Search_Lucene
- * @subpackage Search
- * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- * @version $Id: QueryParserContext.php 23775 2011-03-01 17:25:24Z ralph $
- */
- /** Zend_Search_Lucene_Search_QueryToken */
- require_once 'Zend/Search/Lucene/Search/QueryToken.php';
- /**
- * @category Zend
- * @package Zend_Search_Lucene
- * @subpackage Search
- * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
- class Zend_Search_Lucene_Search_QueryParserContext
- {
- /**
- * Default field for the context.
- *
- * null means, that term should be searched through all fields
- * Zend_Search_Lucene_Search_Query::rewriteQuery($index) transletes such queries to several
- *
- * @var string|null
- */
- private $_defaultField;
- /**
- * Field specified for next entry
- *
- * @var string
- */
- private $_nextEntryField = null;
- /**
- * True means, that term is required.
- * False means, that term is prohibited.
- * null means, that term is neither prohibited, nor required
- *
- * @var boolean
- */
- private $_nextEntrySign = null;
- /**
- * Entries grouping mode
- */
- const GM_SIGNS = 0; // Signs mode: '+term1 term2 -term3 +(subquery1) -(subquery2)'
- const GM_BOOLEAN = 1; // Boolean operators mode: 'term1 and term2 or (subquery1) and not (subquery2)'
- /**
- * Grouping mode
- *
- * @var integer
- */
- private $_mode = null;
- /**
- * Entries signs.
- * Used in GM_SIGNS grouping mode
- *
- * @var arrays
- */
- private $_signs = array();
- /**
- * Query entries
- * Each entry is a Zend_Search_Lucene_Search_QueryEntry object or
- * boolean operator (Zend_Search_Lucene_Search_QueryToken class constant)
- *
- * @var array
- */
- private $_entries = array();
- /**
- * Query string encoding
- *
- * @var string
- */
- private $_encoding;
- /**
- * Context object constructor
- *
- * @param string $encoding
- * @param string|null $defaultField
- */
- public function __construct($encoding, $defaultField = null)
- {
- $this->_encoding = $encoding;
- $this->_defaultField = $defaultField;
- }
- /**
- * Get context default field
- *
- * @return string|null
- */
- public function getField()
- {
- return ($this->_nextEntryField !== null) ? $this->_nextEntryField : $this->_defaultField;
- }
- /**
- * Set field for next entry
- *
- * @param string $field
- */
- public function setNextEntryField($field)
- {
- $this->_nextEntryField = $field;
- }
- /**
- * Set sign for next entry
- *
- * @param integer $sign
- * @throws Zend_Search_Lucene_Exception
- */
- public function setNextEntrySign($sign)
- {
- if ($this->_mode === self::GM_BOOLEAN) {
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.');
- }
- $this->_mode = self::GM_SIGNS;
- if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED) {
- $this->_nextEntrySign = true;
- } else if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED) {
- $this->_nextEntrySign = false;
- } else {
- require_once 'Zend/Search/Lucene/Exception.php';
- throw new Zend_Search_Lucene_Exception('Unrecognized sign type.');
- }
- }
- /**
- * Add entry to a query
- *
- * @param Zend_Search_Lucene_Search_QueryEntry $entry
- */
- public function addEntry(Zend_Search_Lucene_Search_QueryEntry $entry)
- {
- if ($this->_mode !== self::GM_BOOLEAN) {
- $this->_signs[] = $this->_nextEntrySign;
- }
- $this->_entries[] = $entry;
- $this->_nextEntryField = null;
- $this->_nextEntrySign = null;
- }
- /**
- * Process fuzzy search or proximity search modifier
- *
- * @throws Zend_Search_Lucene_Search_QueryParserException
- */
- public function processFuzzyProximityModifier($parameter = null)
- {
- // Check, that modifier has came just after word or phrase
- if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) {
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.');
- }
- $lastEntry = array_pop($this->_entries);
- if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) {
- // there are no entries or last entry is boolean operator
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.');
- }
- $lastEntry->processFuzzyProximityModifier($parameter);
- $this->_entries[] = $lastEntry;
- }
- /**
- * Set boost factor to the entry
- *
- * @param float $boostFactor
- */
- public function boost($boostFactor)
- {
- // Check, that modifier has came just after word or phrase
- if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) {
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.');
- }
- $lastEntry = array_pop($this->_entries);
- if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) {
- // there are no entries or last entry is boolean operator
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.');
- }
- $lastEntry->boost($boostFactor);
- $this->_entries[] = $lastEntry;
- }
- /**
- * Process logical operator
- *
- * @param integer $operator
- */
- public function addLogicalOperator($operator)
- {
- if ($this->_mode === self::GM_SIGNS) {
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.');
- }
- $this->_mode = self::GM_BOOLEAN;
- $this->_entries[] = $operator;
- }
- /**
- * Generate 'signs style' query from the context
- * '+term1 term2 -term3 +(<subquery1>) ...'
- *
- * @return Zend_Search_Lucene_Search_Query
- */
- public function _signStyleExpressionQuery()
- {
- require_once 'Zend/Search/Lucene/Search/Query/Boolean.php';
- $query = new Zend_Search_Lucene_Search_Query_Boolean();
- require_once 'Zend/Search/Lucene/Search/QueryParser.php';
- if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) {
- $defaultSign = true; // required
- } else {
- // Zend_Search_Lucene_Search_QueryParser::B_OR
- $defaultSign = null; // optional
- }
- foreach ($this->_entries as $entryId => $entry) {
- $sign = ($this->_signs[$entryId] !== null) ? $this->_signs[$entryId] : $defaultSign;
- $query->addSubquery($entry->getQuery($this->_encoding), $sign);
- }
- return $query;
- }
- /**
- * Generate 'boolean style' query from the context
- * 'term1 and term2 or term3 and (<subquery1>) and not (<subquery2>)'
- *
- * @return Zend_Search_Lucene_Search_Query
- * @throws Zend_Search_Lucene
- */
- private function _booleanExpressionQuery()
- {
- /**
- * We treat each level of an expression as a boolean expression in
- * a Disjunctive Normal Form
- *
- * AND operator has higher precedence than OR
- *
- * Thus logical query is a disjunction of one or more conjunctions of
- * one or more query entries
- */
- require_once 'Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php';
- $expressionRecognizer = new Zend_Search_Lucene_Search_BooleanExpressionRecognizer();
- require_once 'Zend/Search/Lucene/Exception.php';
- try {
- foreach ($this->_entries as $entry) {
- if ($entry instanceof Zend_Search_Lucene_Search_QueryEntry) {
- $expressionRecognizer->processLiteral($entry);
- } else {
- switch ($entry) {
- case Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME:
- $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_AND_OPERATOR);
- break;
- case Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME:
- $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_OR_OPERATOR);
- break;
- case Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME:
- $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_NOT_OPERATOR);
- break;
- default:
- throw new Zend_Search_Lucene('Boolean expression error. Unknown operator type.');
- }
- }
- }
- $conjuctions = $expressionRecognizer->finishExpression();
- } catch (Zend_Search_Exception $e) {
- // throw new Zend_Search_Lucene_Search_QueryParserException('Boolean expression error. Error message: \'' .
- // $e->getMessage() . '\'.' );
- // It's query syntax error message and it should be user friendly. So FSM message is omitted
- require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
- throw new Zend_Search_Lucene_Search_QueryParserException('Boolean expression error.', 0, $e);
- }
- // Remove 'only negative' conjunctions
- foreach ($conjuctions as $conjuctionId => $conjuction) {
- $nonNegativeEntryFound = false;
- foreach ($conjuction as $conjuctionEntry) {
- if ($conjuctionEntry[1]) {
- $nonNegativeEntryFound = true;
- break;
- }
- }
- if (!$nonNegativeEntryFound) {
- unset($conjuctions[$conjuctionId]);
- }
- }
- $subqueries = array();
- foreach ($conjuctions as $conjuction) {
- // Check, if it's a one term conjuction
- if (count($conjuction) == 1) {
- $subqueries[] = $conjuction[0][0]->getQuery($this->_encoding);
- } else {
- require_once 'Zend/Search/Lucene/Search/Query/Boolean.php';
- $subquery = new Zend_Search_Lucene_Search_Query_Boolean();
- foreach ($conjuction as $conjuctionEntry) {
- $subquery->addSubquery($conjuctionEntry[0]->getQuery($this->_encoding), $conjuctionEntry[1]);
- }
- $subqueries[] = $subquery;
- }
- }
- if (count($subqueries) == 0) {
- require_once 'Zend/Search/Lucene/Search/Query/Insignificant.php';
- return new Zend_Search_Lucene_Search_Query_Insignificant();
- }
- if (count($subqueries) == 1) {
- return $subqueries[0];
- }
- require_once 'Zend/Search/Lucene/Search/Query/Boolean.php';
- $query = new Zend_Search_Lucene_Search_Query_Boolean();
- foreach ($subqueries as $subquery) {
- // Non-requirered entry/subquery
- $query->addSubquery($subquery);
- }
- return $query;
- }
- /**
- * Generate query from current context
- *
- * @return Zend_Search_Lucene_Search_Query
- */
- public function getQuery()
- {
- if ($this->_mode === self::GM_BOOLEAN) {
- return $this->_booleanExpressionQuery();
- } else {
- return $this->_signStyleExpressionQuery();
- }
- }
- }