search_engines.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. /*
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2008, 2009, StatusNet, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('STATUSNET') && !defined('LACONICA')) {
  20. exit(1);
  21. }
  22. class SearchEngine
  23. {
  24. protected $target;
  25. protected $table;
  26. function __construct($target, $table)
  27. {
  28. $this->target = $target;
  29. $this->table = $table;
  30. }
  31. function query($q)
  32. {
  33. }
  34. function limit($offset, $count, $rss = false)
  35. {
  36. return $this->target->limit($offset, $count);
  37. }
  38. function set_sort_mode($mode)
  39. {
  40. switch ($mode) {
  41. case 'chron':
  42. return $this->target->orderBy('created DESC');
  43. break;
  44. case 'reverse_chron':
  45. return $this->target->orderBy('created ASC');
  46. break;
  47. case 'nickname_desc':
  48. if ($this->table != 'profile') {
  49. throw new Exception(
  50. 'nickname_desc sort mode can only be use when searching profile.'
  51. );
  52. } else {
  53. return $this->target->orderBy(sprintf('%1$s.nickname DESC', $this->table));
  54. }
  55. break;
  56. case 'nickname_asc':
  57. if ($this->table != 'profile') {
  58. throw new Exception(
  59. 'nickname_desc sort mode can only be use when searching profile.'
  60. );
  61. } else {
  62. return $this->target->orderBy(sprintf('%1$s.nickname ASC', $this->table));
  63. }
  64. break;
  65. default:
  66. return $this->target->orderBy('created DESC');
  67. break;
  68. }
  69. }
  70. }
  71. class MySQLSearch extends SearchEngine
  72. {
  73. function query($q)
  74. {
  75. if ('profile' === $this->table) {
  76. $this->target->whereAdd(
  77. sprintf('MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' .
  78. 'AGAINST ("%1$s" IN BOOLEAN MODE)',
  79. $this->target->escape($q, true),
  80. $this->table)
  81. );
  82. if (strtolower($q) != $q) {
  83. $this->target->whereAdd(
  84. sprintf('MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' .
  85. 'AGAINST ("%1$s" IN BOOLEAN MODE)',
  86. $this->target->escape(strtolower($q), true),
  87. $this->table),
  88. 'OR'
  89. );
  90. }
  91. return true;
  92. } else if ('notice' === $this->table) {
  93. // Don't show imported notices
  94. $this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
  95. $this->target->whereAdd(
  96. sprintf('MATCH (%2$s.content) AGAINST ("%1$s" IN BOOLEAN MODE)',
  97. $this->target->escape($q, true),
  98. $this->table)
  99. );
  100. if (strtolower($q) != $q) {
  101. $this->target->whereAdd(
  102. sprintf('MATCH (%2$s.content) AGAINST ("%1$s" IN BOOLEAN MODE)',
  103. $this->target->escape(strtolower($q), true),
  104. $this->table),
  105. 'OR'
  106. );
  107. }
  108. return true;
  109. } else {
  110. throw new ServerException('Unknown table: ' . $this->table);
  111. }
  112. }
  113. }
  114. class MySQLLikeSearch extends SearchEngine
  115. {
  116. function query($q)
  117. {
  118. if ('profile' === $this->table) {
  119. $qry = sprintf('(%2$s.nickname LIKE "%%%1$s%%" OR ' .
  120. ' %2$s.fullname LIKE "%%%1$s%%" OR ' .
  121. ' %2$s.location LIKE "%%%1$s%%" OR ' .
  122. ' %2$s.bio LIKE "%%%1$s%%" OR ' .
  123. ' %2$s.homepage LIKE "%%%1$s%%")',
  124. $this->target->escape($q, true),
  125. $this->table);
  126. } else if ('notice' === $this->table) {
  127. $qry = sprintf('content LIKE "%%%1$s%%"', $this->target->escape($q, true));
  128. } else {
  129. throw new ServerException('Unknown table: ' . $this->table);
  130. }
  131. $this->target->whereAdd($qry);
  132. return true;
  133. }
  134. }
  135. class PGSearch extends SearchEngine
  136. {
  137. function query($q)
  138. {
  139. if ('profile' === $this->table) {
  140. return $this->target->whereAdd('textsearch @@ plainto_tsquery(\'' . $this->target->escape($q) . '\')');
  141. } else if ('notice' === $this->table) {
  142. // XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
  143. return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\'' . $this->target->escape($q) . '\')');
  144. } else {
  145. throw new ServerException('Unknown table: ' . $this->table);
  146. }
  147. }
  148. }