search_engines.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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('nickname DESC');
  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('nickname ASC');
  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('(nickname LIKE "%%%1$s%%" OR '.
  105. ' fullname LIKE "%%%1$s%%" OR '.
  106. ' location LIKE "%%%1$s%%" OR '.
  107. ' bio LIKE "%%%1$s%%" OR '.
  108. ' homepage LIKE "%%%1$s%%")', $this->target->escape($q, true));
  109. } else if ('notice' === $this->table) {
  110. $qry = sprintf('content LIKE "%%%1$s%%"', $this->target->escape($q, true));
  111. } else {
  112. throw new ServerException('Unknown table: ' . $this->table);
  113. }
  114. $this->target->whereAdd($qry);
  115. return true;
  116. }
  117. }
  118. class PGSearch extends SearchEngine
  119. {
  120. function query($q)
  121. {
  122. if ('profile' === $this->table) {
  123. return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
  124. } else if ('notice' === $this->table) {
  125. // XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
  126. return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.$this->target->escape($q).'\')');
  127. } else {
  128. throw new ServerException('Unknown table: ' . $this->table);
  129. }
  130. }
  131. }