/inc/search/Search.php

https://github.com/spidaboy7/kumva · PHP · 191 lines · 82 code · 30 blank · 79 comment · 17 complexity · 931698a914dbaa28c82bb4f796b02067 MD5 · raw file

  1. <?php
  2. /**
  3. * This file is part of Kumva.
  4. *
  5. * Kumva is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Kumva is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with Kumva. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * Copyright Rowan Seymour 2010
  19. *
  20. * Purpose: Search class
  21. */
  22. /**
  23. * Enumeration of search types
  24. */
  25. class SearchType extends Enum {
  26. const FORM = 0;
  27. const STEM = 1;
  28. const SOUND = 2;
  29. protected static $strings = array('form', 'stem', 'sound');
  30. }
  31. /**
  32. * Class to represent a full dictionary search
  33. */
  34. class Search {
  35. private $dictionary;
  36. private $query;
  37. private $paging;
  38. private $defaultOrderBy = OrderBy::ENTRY;
  39. private $results = NULL;
  40. private $iteration;
  41. private $suggestion = NULL;
  42. private $time = 0;
  43. // Minimum length of query patterns on which to perform a smart search
  44. const MIN_SMART_QUERY_LEN = 4;
  45. /**
  46. * Creates a search object
  47. * @param string string the search string
  48. * @param bool incProposals TRUE if proposal revisions should be included, else FALSE
  49. * @param Paging paging the paging object
  50. */
  51. public function __construct($string, $paging) {
  52. $this->query = Query::parse($string);
  53. $this->paging = $paging;
  54. // If the user has specified a pattern and not a match relationship then default to relevance ordering
  55. $this->defaultOrderBy = $this->query->getPattern() && $this->query->getRelationship() == NULL
  56. ? OrderBy::RELEVANCE : OrderBy::ENTRY;
  57. }
  58. /**
  59. * Runs the search
  60. * @param string source the source of this query, e.g. 'os' for opensearch plugin
  61. * @return array the array of revisions found
  62. */
  63. public function run($source = NULL) {
  64. $start = microtime(TRUE);
  65. $initSearchType = $this->query->isPartialMatch() ? SearchType::FORM : SearchType::STEM;
  66. $orderBy = ($this->query->getOrderBy() !== NULL) ? $this->query->getOrderBy() : $this->defaultOrderBy;
  67. $this->results = Dictionary::getSearchService()->search($this->query, $initSearchType, $orderBy, $this->paging);
  68. $this->iteration = 1;
  69. // Only do smart search if this is not a partial match, we didn't find anything yet, and the pattern is long enough
  70. $doSmartSearch = !$this->query->isPartialMatch() && ($this->results !== FALSE) && (strlen($this->query->getPattern()) >= self::MIN_SMART_QUERY_LEN);
  71. if ($doSmartSearch && !$this->hasResults()) {
  72. // Do sounds-like search
  73. $this->results = Dictionary::getSearchService()->search($this->query, SearchType::SOUND, $orderBy, $this->paging);
  74. $this->iteration = 2;
  75. // If that fails to find results then perform suggestions search
  76. if (!$this->hasResults()) {
  77. // Clone query object to create suggestion query
  78. $this->suggestion = clone $this->query;
  79. // Create suggestions based on query language
  80. $suggestionsLang = $this->query->getLang() ? $this->query->getLang() : KUMVA_LANG_DEFS;
  81. $suggestions = Lexical::suggestions($suggestionsLang, $this->query->getPattern());
  82. foreach ($suggestions as $suggestion) {
  83. $this->suggestion->setPattern($suggestion);
  84. $this->results = Dictionary::getSearchService()->search($this->suggestion, SearchType::STEM, $orderBy, $this->paging);
  85. $this->iteration = 3;
  86. // If results found quit searching
  87. if ($this->hasResults())
  88. break;
  89. }
  90. }
  91. }
  92. $this->time = (int)((microtime(true) - $start) * 1000);
  93. // Only log the search if its not a robot or an authenticated user
  94. if (!Request::isRobot() && !Session::getCurrent()->isAuthenticated() && $source != NULL)
  95. Dictionary::getSearchService()->logSearch($this->query->getRawQuery(), $this->getSuggestionPattern(), $this->iteration, $this->getTotalCount(), $this->time, $source);
  96. }
  97. /**
  98. * Gets whether search returned any results
  99. */
  100. public function hasResults() {
  101. return $this->results != null && count($this->results) > 0;
  102. }
  103. /**
  104. * Gets the results as array of revisions
  105. */
  106. public function getResults() {
  107. return $this->results;
  108. }
  109. /**
  110. * Gets the number of results
  111. * @return int the total
  112. */
  113. public function getResultCount() {
  114. return count($this->results);
  115. }
  116. /**
  117. * Gets the total number of available results
  118. * @return int the total
  119. */
  120. public function getTotalCount() {
  121. return ($this->paging != NULL) ? $this->paging->getTotal() : count($this->results);
  122. }
  123. /**
  124. * Gets the query
  125. */
  126. public function getQuery() {
  127. return $this->query;
  128. }
  129. /**
  130. * Sets the default order by
  131. * @param int orderBy the default order by
  132. */
  133. public function setDefaultOrderBy($orderBy) {
  134. return $this->defaultOrderBy = $orderBy;
  135. }
  136. /**
  137. * Gets if search used a suggestion
  138. */
  139. public function isBySuggestion() {
  140. return $this->iteration > 1;
  141. }
  142. /**
  143. * Gets if search used a "sounds-like" suggestion
  144. */
  145. public function isBySoundSuggestion() {
  146. return $this->iteration == 2;
  147. }
  148. /**
  149. * Gets the suggested query pattern from a smart search
  150. */
  151. public function getSuggestionPattern() {
  152. return ($this->suggestion != NULL) ? $this->suggestion->getPattern() : NULL;
  153. }
  154. /**
  155. * Gets the time taken for the search
  156. */
  157. public function getTime() {
  158. return $this->time;
  159. }
  160. }
  161. ?>