diff options
| author | Tristan Zur <tzur@webserver.ccwn.org> | 2015-06-10 20:55:53 +0200 |
|---|---|---|
| committer | Tristan Zur <tzur@webserver.ccwn.org> | 2015-06-10 20:55:53 +0200 |
| commit | 406abd7c4df1ace2cd3e4e17159e8941a2e8c0c4 (patch) | |
| tree | a324be16021f44f2fd6d55e609f47024e945b1db /modules/search/helpers | |
Initial import
Diffstat (limited to 'modules/search/helpers')
| -rw-r--r-- | modules/search/helpers/search.php | 163 | ||||
| -rw-r--r-- | modules/search/helpers/search_event.php | 39 | ||||
| -rw-r--r-- | modules/search/helpers/search_installer.php | 50 | ||||
| -rw-r--r-- | modules/search/helpers/search_task.php | 84 | ||||
| -rw-r--r-- | modules/search/helpers/search_theme.php | 29 |
5 files changed, 365 insertions, 0 deletions
diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php new file mode 100644 index 0000000..c84b70b --- /dev/null +++ b/modules/search/helpers/search.php @@ -0,0 +1,163 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class search_Core { + /** + * Add more terms to the query by wildcarding the stem value of the first + * few terms in the query. + */ + static function add_query_terms($q) { + $MAX_TERMS = 5; + $terms = explode(" ", $q, $MAX_TERMS); + for ($i = 0; $i < min(count($terms), $MAX_TERMS - 1); $i++) { + // Don't wildcard quoted or already wildcarded terms + if ((substr($terms[$i], 0, 1) != '"') && (substr($terms[$i], -1, 1) != "*")) { + $terms[] = rtrim($terms[$i], "s") . "*"; + } + } + return implode(" ", $terms); + } + + static function search($q, $limit, $offset) { + return search::search_within_album($q, item::root(), $limit, $offset); + } + + static function search_within_album($q, $album, $limit, $offset) { + $db = Database::instance(); + + $query = self::_build_query_base($q, $album) . + " ORDER BY `score` DESC" . + " LIMIT $limit OFFSET " . (int)$offset; + + $data = $db->query($query); + $count = $db->query("SELECT FOUND_ROWS() as c")->current()->c; + + return array($count, new ORM_Iterator(ORM::factory("item"), $data)); + } + + private static function _build_query_base($q, $album, $where=array()) { + $db = Database::instance(); + $q = $db->escape($q); + + if (!identity::active_user()->admin) { + foreach (identity::group_ids_for_active_user() as $id) { + $fields[] = "`view_$id` = TRUE"; // access::ALLOW + } + $access_sql = " AND (" . join(" OR ", $fields) . ")"; + } else { + $access_sql = ""; + } + + if ($album->id == item::root()->id) { + $album_sql = ""; + } else { + $album_sql = + " AND {items}.left_ptr > " . $db->escape($album->left_ptr) . + " AND {items}.right_ptr <= " . $db->escape($album->right_ptr); + } + + return + "SELECT SQL_CALC_FOUND_ROWS {items}.*, " . + " MATCH({search_records}.`data`) AGAINST ('$q') AS `score` " . + "FROM {items} JOIN {search_records} ON ({items}.`id` = {search_records}.`item_id`) " . + "WHERE MATCH({search_records}.`data`) AGAINST ('$q' IN BOOLEAN MODE)" . + $album_sql . + (empty($where) ? "" : " AND " . join(" AND ", $where)) . + $access_sql; + } + + /** + * @return string An error message suitable for inclusion in the task log + */ + static function check_index() { + list ($remaining) = search::stats(); + if ($remaining) { + site_status::warning( + t('Your search index needs to be updated. <a href="%url" class="g-dialog-link">Fix this now</a>', + array("url" => html::mark_clean(url::site("admin/maintenance/start/search_task::update_index?csrf=__CSRF__")))), + "search_index_out_of_date"); + } + } + + static function update($item) { + $data = new ArrayObject(); + $record = ORM::factory("search_record")->where("item_id", "=", $item->id)->find(); + if (!$record->loaded()) { + $record->item_id = $item->id; + } + + $item = $record->item(); + module::event("item_index_data", $item, $data); + $record->data = join(" ", (array)$data); + $record->dirty = 0; + $record->save(); + } + + static function stats() { + $remaining = db::build() + ->from("items") + ->join("search_records", "items.id", "search_records.item_id", "left") + ->and_open() + ->where("search_records.item_id", "IS", null) + ->or_where("search_records.dirty", "=", 1) + ->close() + ->count_records(); + + $total = ORM::factory("item")->count_all(); + $percent = round(100 * ($total - $remaining) / $total); + + return array($remaining, $total, $percent); + } + + static function get_position($item, $q) { + return search::get_position_within_album($item, $q, item::root()); + } + + static function get_position_within_album($item, $q, $album) { + $page_size = module::get_var("gallery", "page_size", 9); + $query = self::_build_query_base($q, $album, array("{items}.id = " . $item->id)) . + " ORDER BY `score` DESC"; + $db = Database::instance(); + + // Truncate the score by two decimal places as this resolves the issues + // that arise due to inexact numeric conversions. + $current = $db->query($query)->current(); + if (!$current) { + // We can't find this result in our result set - perhaps we've fallen out of context? Clear + // the context and try again. + item::clear_display_context_callback(); + url::redirect(url::current()); + } + $score = $current->score; + if (strlen($score) > 7) { + $score = substr($score, 0, strlen($score) - 2); + } + + // Redo the query but only look for results greater than or equal to our current location + // then seek backwards until we find our item. + $data = $db->query(self::_build_query_base($q, $album) . " HAVING `score` >= " . $score . + " ORDER BY `score` DESC"); + $data->seek($data->count() - 1); + + while ($data->get("id") != $item->id && $data->prev()->valid()) { + } + + return $data->key() + 1; + } +} diff --git a/modules/search/helpers/search_event.php b/modules/search/helpers/search_event.php new file mode 100644 index 0000000..a20935b --- /dev/null +++ b/modules/search/helpers/search_event.php @@ -0,0 +1,39 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class search_event_Core { + static function item_created($item) { + search::update($item); + } + + static function item_updated($original, $new) { + search::update($new); + } + + static function item_deleted($item) { + db::build() + ->delete("search_records") + ->where("item_id", "=", $item->id) + ->execute(); + } + + static function item_related_update($item) { + search::update($item); + } +} diff --git a/modules/search/helpers/search_installer.php b/modules/search/helpers/search_installer.php new file mode 100644 index 0000000..c9e8f26 --- /dev/null +++ b/modules/search/helpers/search_installer.php @@ -0,0 +1,50 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class search_installer { + static function install() { + $db = Database::instance(); + $db->query("CREATE TABLE {search_records} ( + `id` int(9) NOT NULL auto_increment, + `item_id` int(9), + `dirty` boolean default 1, + `data` LONGTEXT default NULL, + PRIMARY KEY (`id`), + KEY(`item_id`), + FULLTEXT INDEX (`data`)) + ENGINE=MyISAM + DEFAULT CHARSET=utf8;"); + } + + static function activate() { + // Update the root item. This is a quick hack because the search module is activated as part + // of the official install, so this way we don't start off with a "your index is out of date" + // banner. + search::update(model_cache::get("item", 1)); + search::check_index(); + } + + static function deactivate() { + site_status::clear("search_index_out_of_date"); + } + + static function uninstall() { + Database::instance()->query("DROP TABLE {search_records}"); + } +} diff --git a/modules/search/helpers/search_task.php b/modules/search/helpers/search_task.php new file mode 100644 index 0000000..18348a2 --- /dev/null +++ b/modules/search/helpers/search_task.php @@ -0,0 +1,84 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class search_task_Core { + static function available_tasks() { + // Delete extra search_records + db::build() + ->delete("search_records") + ->where("item_id", "NOT IN", db::build()->select("id")->from("items")) + ->execute(); + + list ($remaining, $total, $percent) = search::stats(); + return array(Task_Definition::factory() + ->callback("search_task::update_index") + ->name(t("Update Search Index")) + ->description( + $remaining + ? t2("1 photo or album needs to be scanned", + "%count (%percent%) of your photos and albums need to be scanned", + $remaining, array("percent" => (100 - $percent))) + : t("Search data is up-to-date")) + ->severity($remaining ? log::WARNING : log::SUCCESS)); + } + + static function update_index($task) { + try { + $completed = $task->get("completed", 0); + + $start = microtime(true); + foreach (ORM::factory("item") + ->join("search_records", "items.id", "search_records.item_id", "left") + ->where("search_records.item_id", "IS", null) + ->or_where("search_records.dirty", "=", 1) + ->find_all(100) as $item) { + // The query above can take a long time, so start the timer after its done + // to give ourselves a little time to actually process rows. + if (!isset($start)) { + $start = microtime(true); + } + + search::update($item); + $completed++; + + if (microtime(true) - $start > .75) { + break; + } + } + + list ($remaining, $total, $percent) = search::stats(); + $task->set("completed", $completed); + if ($remaining == 0 || !($remaining + $completed)) { + $task->done = true; + $task->state = "success"; + site_status::clear("search_index_out_of_date"); + $task->percent_complete = 100; + } else { + $task->percent_complete = round(100 * $completed / ($remaining + $completed)); + } + $task->status = t2("one record updated, index is %percent% up-to-date", + "%count records updated, index is %percent% up-to-date", + $completed, array("percent" => $percent)); + } catch (Exception $e) { + $task->done = true; + $task->state = "error"; + $task->status = $e->getMessage(); + } + } +} diff --git a/modules/search/helpers/search_theme.php b/modules/search/helpers/search_theme.php new file mode 100644 index 0000000..e8735d1 --- /dev/null +++ b/modules/search/helpers/search_theme.php @@ -0,0 +1,29 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2013 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class search_theme_Core { + static function header_top($theme) { + if ($theme->page_subtype() != "login") { + $view = new View("search_link.html"); + return $view->render(); + } else { + return ""; + } + } +}
\ No newline at end of file |
