function search($search_for, $type, $user, $page = 1, $per_page = 30) {
$page = (integer) $page;
$per_page = (integer) $per_page;
$search_index_table = TABLE_PREFIX . 'search_index';
$offset = ($page - 1) * $per_page;
// Search in projects
if($type == 'ProjectObject') {
$type_filter = ProjectUsers::getVisibleTypesFilter($user, array(PROJECT_STATUS_ACTIVE, PROJECT_STATUS_PAUSED, PROJECT_STATUS_COMPLETED, PROJECT_STATUS_CANCELED));
if(empty($type_filter)) {
return array(null, new Pager(1, 0, $per_page));
} // if
$project_objects_table = TABLE_PREFIX . 'project_objects';
//$total_items = (integer) array_var(db_execute_one("SELECT COUNT($project_objects_table.id) AS 'row_count' FROM $project_objects_table, $search_index_table WHERE $type_filter AND MATCH ($search_index_table.content) AGAINST (? IN BOOLEAN MODE) AND $project_objects_table.id = $search_index_table.object_id AND $search_index_table.type = ? AND state >= ? AND visibility >= ?", $search_for, $type, STATE_VISIBLE, $user->getVisibility()), 'row_count');
$total_items = (integer) array_var(db_execute_one("SELECT COUNT($project_objects_table.id) AS 'row_count' FROM $project_objects_table, $search_index_table WHERE $type_filter AND MATCH ($search_index_table.content) AGAINST (?) AND $project_objects_table.id = $search_index_table.object_id AND $search_index_table.type = ? AND state >= ? AND visibility >= ?", $search_for, $type, STATE_VISIBLE, $user->getVisibility()), 'row_count');
if($total_items) {
// $items = ProjectObjects::findBySQL("SELECT $project_objects_table.* FROM $project_objects_table, $search_index_table WHERE $type_filter AND MATCH ($search_index_table.content) AGAINST (? IN BOOLEAN MODE) AND $project_objects_table.id = $search_index_table.object_id AND $search_index_table.type = ? AND state >= ? AND visibility >= ? LIMIT $offset, $per_page", array($search_for, $type, STATE_VISIBLE, $user->getVisibility()));
$items = ProjectObjects::findBySQL("SELECT $project_objects_table.*, MATCH ($search_index_table.content) AGAINST (?) as score FROM $project_objects_table, $search_index_table WHERE $type_filter AND MATCH ($search_index_table.content) AGAINST (?) AND $project_objects_table.id = $search_index_table.object_id AND $search_index_table.type = ? AND state >= ? AND visibility >= ? ORDER BY score DESC, $project_objects_table.updated_on DESC, $project_objects_table.name LIMIT $offset, $per_page", array($search_for, $search_for, $type, STATE_VISIBLE, $user->getVisibility()));
} else {
$items = null;
} // if
return array($items, new Pager($page, $total_items, $per_page));
// Search for projects
} elseif($type == 'Project') {
$project_ids = Projects::findProjectIdsByUser($user, null, true);
if(!is_foreachable($project_ids)) {
return array(null, new Pager(1, 0, $per_page));
} // if
$projects_table = TABLE_PREFIX . 'projects';
//$total_items = (integer) array_var(db_execute_one("SELECT COUNT($projects_table.id) AS 'row_count' FROM $projects_table, $search_index_table WHERE $projects_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (? IN BOOLEAN MODE) AND $projects_table.id = $search_index_table.object_id AND $search_index_table.type = ?", $project_ids, $search_for, 'Project'), 'row_count');
$total_items = (integer) array_var(db_execute_one("SELECT COUNT($projects_table.id) AS 'row_count' FROM $projects_table, $search_index_table WHERE $projects_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (?) AND $projects_table.id = $search_index_table.object_id AND $search_index_table.type = ?", $project_ids, $search_for, 'Project'), 'row_count');
if($total_items) {
//$items = Projects::findBySQL("SELECT * FROM $projects_table, $search_index_table WHERE $projects_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (? IN BOOLEAN MODE) AND $projects_table.id = $search_index_table.object_id AND $search_index_table.type = ? LIMIT $offset, $per_page", array($project_ids, $search_for, 'Project'));
$items = Projects::findBySQL("SELECT *, MATCH ($search_index_table.content) AGAINST (?) as score FROM $projects_table, $search_index_table WHERE $projects_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (?) AND $projects_table.id = $search_index_table.object_id AND $search_index_table.type = ? ORDER BY score DESC, updated_on DESC, name ASC LIMIT $offset, $per_page", array($search_for, $project_ids, $search_for, 'Project'));
} else {
$items = null;
} // if
return array($items, new Pager($page, $total_items, $per_page));
// Search for users
} elseif($type == 'User') {
$user_ids = $user->visibleUserIds();
if(!is_foreachable($user_ids)) {
return array(null, new Pager(1, 0, $per_page));
} // if
$users_table = TABLE_PREFIX . 'users';
$total_items = (integer) array_var(db_execute_one("SELECT COUNT($users_table.id) AS 'row_count' FROM $users_table, $search_index_table WHERE $users_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (?) AND $users_table.id = $search_index_table.object_id AND $search_index_table.type = ?", $user_ids, $search_for, 'User'), 'row_count');
if($total_items) {
$items = Users::findBySQL("SELECT * FROM $users_table, $search_index_table WHERE $users_table.id IN (?) AND MATCH ($search_index_table.content) AGAINST (?) AND $users_table.id = $search_index_table.object_id AND $search_index_table.type = ? LIMIT $offset, $per_page", array($user_ids, $search_for, 'User'));
} else {
$items = null;
} // if
return array($items, new Pager($page, $total_items, $per_page));
// Unknown search type
} else {
return array(null, new Pager(1, 0, $per_page));
} // if
} // search
Article about search operators is not yet moved to the new docs, but it's pretty simple:
1. "some phrase" - exact multiword match
2. +word - must contain a word
3. -word - without a word
You can also check MySQL docs for the full list of available operators, but these are basically the ones that are the most useful.