search_engines.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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')) { exit(1); }
  20. class SearchEngine
  21. {
  22. protected $target;
  23. protected $table;
  24. function __construct($target, $table)
  25. {
  26. $this->target = $target;
  27. $this->table = $table;
  28. }
  29. function query($q)
  30. {
  31. }
  32. function limit($offset, $count, $rss = false)
  33. {
  34. return $this->target->limit($offset, $count);
  35. }
  36. function set_sort_mode($mode)
  37. {
  38. switch ($mode) {
  39. case 'chron':
  40. return $this->target->orderBy('created DESC');
  41. break;
  42. case 'reverse_chron':
  43. return $this->target->orderBy('created ASC');
  44. break;
  45. case 'nickname_desc':
  46. if ($this->table != 'profile') {
  47. throw new Exception(
  48. 'nickname_desc sort mode can only be use when searching profile.'
  49. );
  50. } else {
  51. return $this->target->orderBy(sprintf('%1$s.nickname DESC', $this->table));
  52. }
  53. break;
  54. case 'nickname_asc':
  55. if ($this->table != 'profile') {
  56. throw new Exception(
  57. 'nickname_desc sort mode can only be use when searching profile.'
  58. );
  59. } else {
  60. return $this->target->orderBy(sprintf('%1$s.nickname ASC', $this->table));
  61. }
  62. break;
  63. default:
  64. return $this->target->orderBy('created DESC');
  65. break;
  66. }
  67. }
  68. }
  69. class MySQLSearch extends SearchEngine
  70. {
  71. function query($q)
  72. {
  73. if ('profile' === $this->table) {
  74. $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
  75. 'AGAINST (\''.$this->target->escape($q).'\' IN BOOLEAN MODE)');
  76. if (strtolower($q) != $q) {
  77. $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
  78. 'AGAINST (\''.$this->target->escape(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR');
  79. }
  80. return true;
  81. } else if ('notice' === $this->table) {
  82. // Don't show imported notices
  83. $this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
  84. if (strtolower($q) != $q) {
  85. $this->target->whereAdd("( MATCH(content) AGAINST ('" . $this->target->escape($q) .
  86. "' IN BOOLEAN MODE)) OR ( MATCH(content) " .
  87. "AGAINST ('" . $this->target->escape(strtolower($q)) .
  88. "' IN BOOLEAN MODE))");
  89. } else {
  90. $this->target->whereAdd('MATCH(content) ' .
  91. 'AGAINST (\''.$this->target->escape($q).'\' IN BOOLEAN MODE)');
  92. }
  93. return true;
  94. } else {
  95. throw new ServerException('Unknown table: ' . $this->table);
  96. }
  97. }
  98. }
  99. class MySQLLikeSearch extends SearchEngine
  100. {
  101. function query($q)
  102. {
  103. if ('profile' === $this->table) {
  104. $qry = sprintf('(%2$s.nickname LIKE "%%%1$s%%" OR '.
  105. ' %2$s.fullname LIKE "%%%1$s%%" OR '.
  106. ' %2$s.location LIKE "%%%1$s%%" OR '.
  107. ' %2$s.bio LIKE "%%%1$s%%" OR '.
  108. ' %2$s.homepage LIKE "%%%1$s%%")',
  109. $this->target->escape($q, true),
  110. $this->table);
  111. } else if ('notice' === $this->table) {
  112. $qry = sprintf('content LIKE "%%%1$s%%"', $this->target->escape($q, true));
  113. } else {
  114. throw new ServerException('Unknown table: ' . $this->table);
  115. }
  116. $this->target->whereAdd($qry);
  117. return true;
  118. }
  119. }
  120. class PGSearch extends SearchEngine
  121. {
  122. function query($q)
  123. {
  124. if ('profile' === $this->table) {
  125. return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
  126. } else if ('notice' === $this->table) {
  127. // XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
  128. return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
  129. } else {
  130. throw new ServerException('Unknown table: ' . $this->table);
  131. }
  132. }
  133. }