diff --git a/admin/settings/development.php b/admin/settings/development.php index 192df5b8d30..d6c9e4f0634 100644 --- a/admin/settings/development.php +++ b/admin/settings/development.php @@ -7,11 +7,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page // Experimental settings page $ADMIN->add('development', new admin_category('experimental', get_string('experimental','admin'))); - require_once($CFG->dirroot .'/search/lib.php'); $temp = new admin_settingpage('experimentalsettings', get_string('experimentalsettings', 'admin')); - $englobalsearch = new admin_setting_configcheckbox('enableglobalsearch', get_string('enableglobalsearch', 'admin'), get_string('configenableglobalsearch', 'admin'), 0); - $englobalsearch->set_updatedcallback('search_updatedcallback'); - $temp->add($englobalsearch); //TODO: Re-enable cc-import once re-implemented in 2.0.x //$temp->add(new admin_setting_configcheckbox('enableimsccimport', get_string('enable_cc_import', 'imscc'), get_string('enable_cc_import_description', 'imscc'), 0)); $temp->add(new admin_setting_configcheckbox('enablesafebrowserintegration', get_string('enablesafebrowserintegration', 'admin'), get_string('configenablesafebrowserintegration', 'admin'), 0)); diff --git a/blocks/search/README.txt b/blocks/search/README.txt deleted file mode 100644 index 48dfb9f4679..00000000000 --- a/blocks/search/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -This block is a revamping of the Google Summer Of Code Project (2006) on Global Search engine -for Moodle. New block version is completed and internationalized according to Moodle multilengual support. - -This block instanciates a startup database model for the search engine. - -## Installing - -You need installing the following elements in order the global search to be available : - -1. The global search bloc (this block) -2. update the /search root package from CVS -3. The antiword libraries -4. The xpdf libraries - -Both last libraries are provided as a patch called "global_search_libraries" in the contrib section. \ No newline at end of file diff --git a/blocks/search/block_search.php b/blocks/search/block_search.php deleted file mode 100644 index 1aeb08c085e..00000000000 --- a/blocks/search/block_search.php +++ /dev/null @@ -1,73 +0,0 @@ -title = get_string('pluginname', 'block_search'); - } //init - - // only one instance of this block is required - function instance_allow_multiple() { - return false; - } //instance_allow_multiple - - // label and button values can be set in admin - function has_config() { - return true; - } //has_config - - function get_content() { - global $CFG; - - if (empty($CFG->enableglobalsearch)) { - return ''; - } - - //cache block contents - if ($this->content !== NULL) { - return $this->content; - } //if - - $this->content = new stdClass; - - //basic search form - $this->content->text = - '
' - . '' - . '' - . '' - . '' - . '
'; - - //no footer, thanks - $this->content->footer = ''; - - return $this->content; - } //get_content - - function specialisation() { - //empty! - } //specialisation - - /** - * wraps up to search engine cron - */ - function cron(){ - global $CFG; - - include($CFG->dirroot.'/search/cron.php'); - } - - } //block_search - diff --git a/blocks/search/db/install.php b/blocks/search/db/install.php deleted file mode 100644 index f8a13cf7f20..00000000000 --- a/blocks/search/db/install.php +++ /dev/null @@ -1,10 +0,0 @@ -set_field('block', 'visible', 0, array('name'=>'search')); - -} - diff --git a/blocks/search/db/install.xml b/blocks/search/db/install.xml deleted file mode 100644 index c5c2b52d29c..00000000000 --- a/blocks/search/db/install.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
\ No newline at end of file diff --git a/blocks/search/db/upgrade.php b/blocks/search/db/upgrade.php deleted file mode 100644 index 952a1297e59..00000000000 --- a/blocks/search/db/upgrade.php +++ /dev/null @@ -1,94 +0,0 @@ -. - -/** - * Keeps track of upgrades to the global search block - * - * @package blocks - * @subpackage search - * @copyright 2010 Aparup Banerjee - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -function xmldb_block_search_upgrade($oldversion) { - global $CFG, $DB; - - require('upgradelib.php'); - $result = TRUE; - $dbman = $DB->get_manager(); - - if ($oldversion < 2010101800) { - // See MDL-24374 - // Changing type of field docdate on table block_search_documents to int - // Changing type of field updated on table block_search_documents to int - $table = new xmldb_table('block_search_documents'); - - $field_docdate_new = new xmldb_field('docdate_new', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'docdate'); - $field_updated_new = new xmldb_field('updated_new', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'updated'); - $field_docdate_old = new xmldb_field('docdate'); - $field_updated_old = new xmldb_field('updated'); - - // Conditionally launch add temporary fields - if (!$dbman->field_exists($table, $field_docdate_new)) { - $dbman->add_field($table, $field_docdate_new); - } - if (!$dbman->field_exists($table, $field_updated_new)) { - $dbman->add_field($table, $field_updated_new); - } - - $sql = "SELECT id, docdate, updated FROM {block_search_documents}"; - $search_documents = $DB->get_records_sql($sql); - if ($search_documents) { - foreach ($search_documents as $sd) { - $sd->docdate_new = convert_datetime_upgrade($sd->docdate); - $sd->updated_new = convert_datetime_upgrade($sd->updated); - $DB->update_record('block_search_documents', $sd); - } - } - // Conditionally launch drop the old fields - if ($dbman->field_exists($table, $field_docdate_old)) { - $dbman->drop_field($table, $field_docdate_old); - } - if ($dbman->field_exists($table, $field_updated_old)) { - $dbman->drop_field($table, $field_updated_old); - } - - //rename the new fields to the original field names. - $dbman->rename_field($table, $field_docdate_new, 'docdate'); - $dbman->rename_field($table, $field_updated_new, 'updated'); - - // search savepoint reached - upgrade_block_savepoint(true, 2010101800, 'search'); - } - - if ($oldversion < 2010110900) { - unset_config('block_search_text'); - unset_config('block_search_button'); - upgrade_block_savepoint(true, 2010110900, 'search'); - } - - if ($oldversion < 2010111100) { - // set block to hidden if global search is disabled. - if ($CFG->enableglobalsearch != 1) { - $DB->set_field('block', 'visible', 0, array('name'=>'search')); // Hide block - } - upgrade_block_savepoint(true, 2010111100, 'search'); - } - return $result; -} diff --git a/blocks/search/db/upgradelib.php b/blocks/search/db/upgradelib.php deleted file mode 100644 index a85c452b5b3..00000000000 --- a/blocks/search/db/upgradelib.php +++ /dev/null @@ -1,46 +0,0 @@ -. - -/** - * Global search block upgrade related helper functions - * - * @package blocks - * @subpackage search - * @copyright 2010 Aparup Banerjee - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -/* -* Function to turn a mysql(datetime) or postgres(timestamp without timezone data) or any generic date string (YYYY-MM-DD HH:MM:SS) -* read in from a database's date/time field (ie:valid) into a unix timestamp -* @param str The string to be converted to timestamp -* @return timestamp or 0 -*/ - -function convert_datetime_upgrade($str) { - - $timestamp = strtotime($str); - //process different failure returns due to different php versions - if ($timestamp === false || $timestamp < 1) { - return 0; - } else { - return $timestamp; - } -} - diff --git a/blocks/search/lang/en/block_search.php b/blocks/search/lang/en/block_search.php deleted file mode 100644 index 06df0ed30c2..00000000000 --- a/blocks/search/lang/en/block_search.php +++ /dev/null @@ -1,57 +0,0 @@ -. - -/** - * Strings for component 'block_search', language 'en', branch 'MOODLE_20_STABLE' - * - * @package block_search - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -$string['blockssearchswitches'] = 'Indexer activation for blocks'; -$string['bytes'] = 'bytes (0 stands for no limits)'; -$string['configenablefileindexing'] = 'Enable file indexing'; -$string['configfiletypes'] = 'File types handled'; -$string['configlimitindexbody'] = 'Indexed body size limitation'; -$string['configpdftotextcmd'] = 'Path to command pdftotext'; -$string['configtypetotxtcmd'] = 'Converter\'s command line'; -$string['configtypetotxtenv'] = 'Environment define for converter'; -$string['configwordtotextcmd'] = 'Path to command doctotext'; -$string['configwordtotextenv'] = 'Environment setting for the MSWord converter'; -$string['cmdtoconverttotextfor'] = 'Command to convert {$a} to text'; -$string['enablefileindexing'] = 'Turn on indexing of different file types'; -$string['enableindexinginmodule'] = 'Allow indexing of the {$a} module'; -$string['enableindexinginblock'] = 'Allow indexing of the {$a} block'; -$string['envforcmdtotextfor'] = 'Environment for {$a} conversion command to text'; -$string['go'] = 'Go!'; -$string['handlingfor'] = 'Extra handling for'; -$string['indexbodylimit'] = 'The limit of indexing the body'; -$string['listoffiletypes'] = 'The list of file types handled'; -$string['modulessearchswitches'] = 'Indexer activation for modules'; -$string['nosearchableblocks'] = 'No searchable blocks'; -$string['nosearchablemodules'] = 'No searchable modules'; -$string['pdfhandling'] = 'Acrobat PDF handling'; -$string['pdftotextcmd'] = 'Command to convert PDF to text'; -$string['pluginname'] = 'Global search'; -$string['searchdiscovery'] = 'Searchable items discovery'; -$string['searchmoodle'] = 'Search Moodle'; -$string['usemoodleroot'] = 'Use moodle root for external converters'; -$string['usemoodlerootdescription'] = 'Use moodle root for external converters'; -$string['wordhandling'] = 'Microsoft Word handling'; -$string['wordtotextcmd'] = 'Command to convert Microsoft Word to text'; -$string['wordtotextenv'] = 'Environment setup for Microsoft Word to text converter'; diff --git a/blocks/search/settings.php b/blocks/search/settings.php deleted file mode 100644 index 44fee6c8bcf..00000000000 --- a/blocks/search/settings.php +++ /dev/null @@ -1,123 +0,0 @@ -fulltree) { - - //Enable file indexing (y/n) - $settings->add(new admin_setting_configcheckbox('block_search_enable_file_indexing', get_string('configenablefileindexing', 'block_search'), - get_string('enablefileindexing', 'block_search'), 0, 1, 0)); - - //file types - $defaultfiletypes = 'PDF,TXT,HTML,PPT,XML,DOC,HTM'; - $settings->add(new admin_setting_configtext('block_search_filetypes', get_string('configfiletypes', 'block_search'), - get_string('listoffiletypes', 'block_search'), $defaultfiletypes, PARAM_TEXT)); - - // usemoodleroot - $settings->add(new admin_setting_configcheckbox('block_search_usemoodleroot', get_string('usemoodleroot', 'block_search'), - get_string('usemoodlerootdescription', 'block_search'), 1, 1, 0)); - - //limit_index_body - $settings->add(new admin_setting_configtext('block_search_limit_index_body', get_string('configlimitindexbody', 'block_search'), - get_string('indexbodylimit', 'block_search'), '', PARAM_INT)); - - //setup default paths for following configs. - if ($CFG->ostype == 'WINDOWS') { - $default_pdf_to_text_cmd = "lib/xpdf/win32/pdftotext.exe -eol dos -enc UTF-8 -q"; - $default_word_to_text_cmd = "lib/antiword/win32/antiword/antiword.exe "; - $default_word_to_text_env = "HOME={$CFG->dirroot}\\lib\\antiword\\win32"; - } else { - $default_pdf_to_text_cmd = "lib/xpdf/linux/pdftotext -enc UTF-8 -eol unix -q"; - $default_word_to_text_cmd = "lib/antiword/linux/usr/bin/antiword"; - $default_word_to_text_env = "ANTIWORDHOME={$CFG->dirroot}/lib/antiword/linux/usr/share/antiword"; - } - - //pdf_to_text_cmd - $settings->add(new admin_setting_configtext('block_search_pdf_to_text_cmd', get_string('configpdftotextcmd', 'block_search'), - get_string('pdftotextcmd', 'block_search'), $default_pdf_to_text_cmd, PARAM_RAW, 60)); - - //word_to_text_cmd - $settings->add(new admin_setting_configtext('block_search_word_to_text_cmd', get_string('configwordtotextcmd', 'block_search'), - get_string('wordtotextcmd', 'block_search'), $default_word_to_text_cmd, PARAM_RAW, 60)); - - //word_to_text_env - $settings->add(new admin_setting_configtext('block_search_word_to_text_env', get_string('configwordtotextenv', 'block_search'), - get_string('wordtotextenv', 'block_search'), $default_word_to_text_env, PARAM_RAW, 60)); - - - // modules activations - if (isset($CFG->block_search_filetypes)) { - $types = explode(',', $CFG->block_search_filetypes); - } else { - $types = explode(',', $defaultfiletypes); - } - - if (!empty($types)) { - foreach($types as $type) { - $utype = strtoupper($type); - $type = strtolower($type); - $type = trim($type); - if (preg_match("/\\b$type\\b/i", $defaultfiletypes)) continue; - - //header - $propname = 'block_search_'.$type.'_to_text'; - $settings->add(new admin_setting_heading($propname, get_string('handlingfor', 'block_search').' '.$utype , '')); - - //word_to_text_cmd - $propname = 'block_search_'.$type.'_to_text_cmd'; - $settings->add(new admin_setting_configtext($propname, get_string('configtypetotxtcmd', 'block_search'), - get_string('cmdtoconverttotextfor', 'block_search', $type), '', PARAM_PATH, 60)); - - //word_to_text_env - $propname = 'block_search_'.$type.'_to_text_env'; - $settings->add(new admin_setting_configtext($propname, get_string('configtypetotxtenv', 'block_search'), - get_string('envforcmdtotextfor', 'block_search', $type), '', PARAM_PATH, 60)); - - } - } - - require_once($CFG->dirroot.'/search/lib.php' ); - $searchnames = search_collect_searchables(true, false); - list($searchable_list, $params) = $DB->get_in_or_equal($searchnames); - - //header - $propname = 'block_search_'.$type.'_to_text'; - $settings->add(new admin_setting_heading($propname, get_string('searchdiscovery', 'block_search') , '')); - - $found_searchable_modules = 0; - if ($modules = $DB->get_records_select('modules', "name $searchable_list", $params, 'name', 'id,name')){ - foreach($modules as $module){ - $keyname = 'search_in_'.$module->name; - $settings->add(new admin_setting_configcheckbox($keyname, get_string('modulename', $module->name), - get_string('enableindexinginmodule', 'block_search', $module->name), 1, 1, 0)); - $found_searchable_modules = 1; - } - } - - if (!$found_searchable_modules) { - //header - $propname = 'block_search_nosearchablemodules'; - $settings->add(new admin_setting_heading($propname, get_string('nosearchablemodules', 'block_search') , '')); - } - - //header - $propname = 'block_search_searchswitches'; - $settings->add(new admin_setting_heading($propname, get_string('blockssearchswitches', 'block_search') , '')); - - $found_searchable_blocks = 0; - if ($blocks = $DB->get_records_select('block', "name $searchable_list", $params, 'name', 'id,name')){ - foreach($blocks as $block){ - $keyname = 'search_in_'.$block->name; - $settings->add(new admin_setting_configcheckbox($keyname, get_string('pluginname', 'block_'.$block->name), - get_string('enableindexinginblock', 'block_search', $block->name), 1, 1, 0)); - $found_searchable_blocks = 1; - } - } - if (!$found_searchable_blocks) { - //header - $propname = 'block_search_nosearchableblocks'; - $settings->add(new admin_setting_heading($propname, get_string('nosearchableblocks', 'block_search') , '')); - } - -} - diff --git a/blocks/search/version.php b/blocks/search/version.php deleted file mode 100644 index b7456820a7b..00000000000 --- a/blocks/search/version.php +++ /dev/null @@ -1,19 +0,0 @@ -. - -$plugin->version = 2010111100; -$plugin->cron = 1; diff --git a/lang/en/admin.php b/lang/en/admin.php index 5dfe0f234e7..fcb3a957a34 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -189,7 +189,6 @@ $string['configenableajax'] = 'This setting allows you to control the use of AJA $string['configenablecalendarexport'] = 'Enable exporting or subscribing to calendars.'; $string['configenablecomments'] = 'Enable comments'; $string['configenablecourserequests'] = 'This will allow any user to request a course be created.'; -$string['configenableglobalsearch'] = 'This setting enables global text searching in resources and activities, it is not compatible with PHP 4.'; $string['configenablegroupmembersonly'] = 'If enabled, access to activities can be restricted to group members only. This may result in an increased server load. In addition, gradebook categories must be set up in a certain way to ensure that activities are hidden from non-group members.'; $string['configenablemobilewebservice'] = 'Enable mobile service for the official Moodle app or other app requesting it. For more information, read the {$a}'; $string['configenablerssfeeds'] = 'This switch will enable RSS feeds from across the site. To actually see any change you will need to enable RSS feeds in the individual modules too - go to the Modules settings under Admin Configuration.'; @@ -468,7 +467,6 @@ $string['enablecourseajax'] = 'Enable AJAX course editing'; $string['enablecourseajax_desc'] = 'Allow AJAX when editing main course pages. Note that the course format and the theme must support AJAX editing and the user has to enable AJAX in their profiles, too.'; $string['enablecourserequests'] = 'Enable course requests'; $string['enabledevicedetection'] = 'Enable device detection'; -$string['enableglobalsearch'] = 'Enable global search'; $string['enablegravatar'] = 'Enable Gravatar'; $string['enablegravatar_help'] = 'When enabled Moodle will attempt to fetch a user profile picture from Gravatar if the user has not uploaded an image.'; $string['enablegroupmembersonly'] = 'Enable group members only'; diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 0184da5f5ca..647f27d5db4 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -6808,6 +6808,38 @@ FROM upgrade_main_savepoint(true, 2011101900.02); } + if ($oldversion < 2011102700.01) { + // purge everything related to abandoned experimental global search + + // unset setting - this disables it in case user does not delete the dirs + unset_config('enableglobalsearch'); + + // Delete block, instances and db table + $table = new xmldb_table('block_search_documents'); + if ($dbman->table_exists($table)) { + $instances = $DB->get_records('block_instances', array('blockname'=>'search')); + foreach($instances as $instance) { + context_helper::delete_instance(CONTEXT_BLOCK, $instance->id); + $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id)); + $DB->delete_records('block_instances', array('id' => $instance->id)); + } + $DB->delete_records('block', array('name'=>'search')); + + $dbman->drop_table($table); + } + + // purge all settings used by the search block + $like = $DB->sql_like('name', '?', true, true, false, '|'); + $params = array($DB->sql_like_escape('block_search_', '|') . '%', $DB->sql_like_escape('search_in_', '|') . '%'); + $settings = $DB->get_records_select('config', "$like OR $like", $params); + foreach ($settings as $setting) { + unset_config($setting->name); + } + + upgrade_main_savepoint(true, 2011102700.01); + } + + return true; } diff --git a/lib/pluginlib.php b/lib/pluginlib.php index 02719a771ae..32bcca0e484 100644 --- a/lib/pluginlib.php +++ b/lib/pluginlib.php @@ -298,7 +298,7 @@ class plugin_manager { 'login', 'mentees', 'messages', 'mnet_hosts', 'myprofile', 'navigation', 'news_items', 'online_users', 'participants', 'private_files', 'quiz_results', 'recent_activity', - 'rss_client', 'search', 'search_forums', 'section_links', + 'rss_client', 'search_forums', 'section_links', 'selfcompletion', 'settings', 'site_main_menu', 'social_activities', 'tag_flickr', 'tag_youtube', 'tags' ), diff --git a/search/.cvsignore b/search/.cvsignore deleted file mode 100644 index 04fd92e9f34..00000000000 --- a/search/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -delete_log.php diff --git a/search/LISEZMOI.txt b/search/LISEZMOI.txt deleted file mode 100644 index 16e4450b968..00000000000 --- a/search/LISEZMOI.txt +++ /dev/null @@ -1,89 +0,0 @@ -Cette distribution partielle contient une refonte du moteur de -recherche globale de Moodle. - -Le moteur de recherche est capable d'indexer et de rechercher -des informations dans un grand nombre de contenus stockés -dans la plate-forme à travers la manipulation des activités et -des blocs. - -Le moteur de recherche procède à une première indexation des -ressources disponibles par action de l'administrateur. Une fois -cette indexation effectuée, le moteur maintient régulièrement les -indexes, en ajoutant les nouvelles entrées et en nettoyant les -entrées obsolètes. - -La recherche permet d'obtenir des références d'accès au contexte -qui diffuse cette information, au nom de l'utilisateur courant. -Le filtrage des résultats enlève de la liste des réponses toute -ressource que la situation de l'utilisateur empêcherait de voir -s'il y accédait dans son contexte habituel. - -Mise en oeuvre -############## - -La distribution fait désormais partie du noyau de Moodle. - -Il sera probablement nécessaire d'ajouter un certain nombre de librairies additionnelles -pour la conversion de documents physiques en vue de leur indexation. Ces librairies sont -actuellement fournies dans le CVS dans la rubrique contrib/patches/global_search_libraries -(antiword et xpdf). La prise en charge des fichiers "shockwave" est assurée, sous réserve -de l'obtention des libairies de conversion auprès de Adobe (http://www.adobe.com/licensing/developer/) - -1. Allez sur le bloc d'administration et réglez les paramètres du bloc Recherche Globale. -Ceci initialisera un certain nombre de fonctions dans le moteur. - -2. Insérer un nouveau bloc de recherche globale dans la plate-forme - -3. Effectuer une recherche vide (en administrateur) - -4. Aller sur la page des statistiques - -5. Activer l'indexation (indexsplash.php). Attention, si la plate-form contient beaucoup de contenus cette indexation peut être TRES LONGUE. - -Pour effectuer des recherches, une fois la première indexation terminée, retourner au bloc de recherche et tenter une recherche. - -Eléments pris en charge -####################### - -Dans l'état actuel, les éléments indexés par le moteur sont : - -- les entrées de forum -- les fiches de base de données -- les commentaires sur fiches de données -- les entrées de glossaire -- les commentaires sur entrées de glossaire -- les ressources natives Moodle -- les ressources physiques de type MSWord -- les ressources physiques de type PDF -- les ressources physiques de type fichier texte (.txt) -- les ressources physiques de type HTML (.htm et .html) -- les ressources physiques de type XML (.xml) -- les ressources physiques de type (Microsoft) Powerpoint (.ppt) -- les pages de wiki -- les sessions de chat - -Des modules tiers ont été rendus indexables - -- Techproject - -Extensions -########## - -L'API du moteur de recherche permet désormais : - -- l'indexation de contenus de blocs. -- l'indexation de modules contenant une information complexe ou de plusieurs types distincts -- la sécurisation des informations indexées lors des extractions de résultats -- l'indexation de tout module tiers par ajout d'un fichier php calibré -- l'indexation de toute nouvelle resource physique par ajout d'un fichier php calibré - -Extensions futures -################## - -- De nouvelles prises en charge de contenus tels que les attachements des forums, les attachement des glossaires, ainsi que d'autres modules non encore -implémentés. - -- l'extension mnet de la recherche dans un réseau de moodle interconnectés. - - - diff --git a/search/README.txt b/search/README.txt deleted file mode 100644 index 02b7d5786a5..00000000000 --- a/search/README.txt +++ /dev/null @@ -1,85 +0,0 @@ -This directoery contains the central implementation of -Moodle's Global Search Engine. - -The Global Search Engine stores indexes about a huge quantity -of information from within modules, block or resources stored -by Moodle either in the database or the file system. - -The administrator initialy indexes the existing content. Once this -first initialization performed, the search engine maintains indexes -regularily, adding new entries, deleting obsolete one or updating -some that have changed. - -Search will produce links for acceding the information in a similar -context as usually accessed, from the current user point of view. -Results filtering removes from results any link to information the -current user would not be allowed to acces on a straight situation. - -Deployement -########### - -The search engine is now part of Moodle core distribution. - -Some extra libraries might be added for converting physical documents to text -so it can be indexed. Moodle CVS (entry contrib/patches/global_search_libraries) -provides packs for antiword and xpdf GPL libraries the search engine is ready for -shockwave indexing, but will not provide Adobe Search converters that should be -obtained at http://www.adobe.com/licensing/developer/ - -1. Go to the block administration panel and setup once the Global Search -block. This will initialize useful parameters for the global search engine. - -2. Insert a new Global Search block somewhere in a course or top-level screen. - -3. Launch an empty search (you must be administrator). - -4. Go to the statistics screen. - -5. Activate indexation (indexersplash.php). Beware, if your Moodle has -a large amount of content, indexing process may be VERY LONG. - -To search, go back to the search block and try a query. - -Handled information for indexing -################################ - -In the actual state, the engine indexes the following information: - -- assignment descriptions -- forum posts -- database records (using textual fields only) -- database comments -- glossary entries -- glossary comments on entries -- Moodle native resources -- physical MSWord files as resources (.doc) -- physical Powerpoint files as resources (.ppt) -- physical PDF files as resources -- physical text files as resources (.txt) -- physical html files as resources (.htm and .html) -- physical xml files as resources (.xml) -- wiki pages -- chat sessions -- lesson pages - -Some third party plugins are also searchable using the new Search API implementation - -- Techproject - -Extensions -########## - -The reviewed search engine API allows: - -- indexing of blocks contents -- indexation of modules or blocks containing a complex information model -- securing the access to the results -- adding indexing handling for additional modules and plugins adding a php calibrated script -- adding physical filetype handling adding a php calibrated script - -Future extensions -################# - -- Should be added more information to index such as forum and glossary attachements, - so will other standard module contents. -- extending the search capability to a mnet network information space by aggregating remote search responses. \ No newline at end of file diff --git a/search/README_ARCHIVE.txt b/search/README_ARCHIVE.txt deleted file mode 100644 index 64296be2f0b..00000000000 --- a/search/README_ARCHIVE.txt +++ /dev/null @@ -1,153 +0,0 @@ -2006/09/08 ----------- -Google Summer of Code is finished, spent a couple of weeks away from -the project to think about it and also to take a break. Working on it -now I discovered bugs in the query parser (now fixed), and I also -un-convoluted the querylib logic (well slighlty). - -Updated ZFS files to latest SVN. - -2006/08/21 ----------- -Fixed index document count, and created new config variable to store -the size. (Search now has 3 global vars in $CFG, date, size and complete, -see indexer.php for var names). Index size is cached to provide an always -current value for the index - this is to take into account the fact that -deleted documents are in fact not removed from the index, but instead just -marked as deleted and not returned in search results. The actual document -still features in the index, and skews sizes. When the index optimiser is -completed in ZFS, then these deleted documents will be pruned, thus -correctly modifying the index size. - -Additional commenting added. - -Query page logic very slightly modified to clean up GET string a bit (removed -'p' variable). - -Add/delete functions added to other document types. - -A few TODO fields added to source, indicating changes still to come (or at -least to be considered). - -2006/08/16 ----------- -Add/delete/update cron functions finished - can be called seperately -or all at once via cron.php. - -Document date field added to index and database summary. - -Some index db functionality abstracted out to indexlib.php - can -use IndexDBControl class to add/del documents from database, and -to make sure the db table is functioning. - -DB sql files changed to add some extra fields. - -Default 'simple' query modified to search title and author, as well -as contents of document, to provide better results for users. - -2006/08/14 ----------- -First revision of the advanced search page completed. Functional, -but needs a date search field still. - -2006/08/02 ----------- -Added resource search type, and the ability to specify custom 'virtual' -models to search - allowing for non-module specific information to be -indexed. Specify the extra search types to use in lib.php. - -2006/07/28 ----------- -Added delete logic to documents; the moodle database log is checked -and any found delete events are used to remove the referenced documents -from the database table and search index. - -Added database table name constant to lib.php, must change files using -the static table name. - -Changed documents to use 'docid' instead of 'id' to reference the moodle -instance id, since Zend Search adds it's own internal 'id' field. Noticed -this whilst working on deletions. - -Added some additional fields to the permissions checking method, must still -implement it though. - -2006/07/25 ----------- -Query logic moved into the SearchQuery class in querylib.php. Should be able -to include this file in any page and run a query against the index (PHP 5 -checks must be added to those pages then, though). - -Index info can be retrieved using IndexInfo class in indexlib.php. - -Abstracted some stuff away, to reduce rendundancy and decrease the -likelihood of errors. Improved the stats.php page to include some -diagnostics for adminstrators. - -delete.php skeleton created for removing deleted documents from the -index. cron.php will contain the logic for running delete.php, -update.php and eventually add.php. - -2006/07/11 ----------- -(Warning: It took me 1900 seconds to index the forum, go make coffee -whilst you wait.) [Moodle.org forum data] - -Forum search functions changed to use 'get_recordset' instead of -'get_records', for speed reasons. This provides a significant improvement, -but indexing is still slow - getting data from the database and Zend's -tokenising _seem_ to be the prime suspects at the moment. - -/search/tests/ added - index.php can be used to see which modules are -ready to be included in the search index, and it informs you of any -errors - should be a prerequisite for indexing. - -Search result pagination added to query.php, will default to 20 until -an admin page for the search module is written. - -2006/07/07 ----------- -Search-enabling functions moved out've the mod's lib.php files and into -/search/documents/mod_document.php - this requires the search module to -operate without requiring modification of lib files. - -SearchDocument base class improved, and the way module documents extend -it. A custom-data field has been added to allow modules to add any custom -data they wish to be stored in the index - this field is serialised into -the index as a binary field. - -Database field 'type' renamed to 'doctype' to match the renaming in the -index, 'type' seems to be a reserved word in Lucene. Several index field -names change to be more descriptive (cid -> course_id). URLs are now -stored in the index, and don't have to be generated on the fly during -display of query results. - -2006/07/05 ------- -Started cleaning and standardising things. - -cvs v1.1 --------- -This is the initial release (prototype) of Moodle's new search module - -so basically watch out for sharp edges. - -The structure has not been finalised, but this is what is working at the -moment, when I start looking at other content to index, it will most likely -change. I don't recommend trying to make your own content modules indexable, -at least not until the whole flow is finalised. I will be implementing the -functions needed to index all of the default content modules on Moodle, so -expect that around mid-August. - -Wiki pages were my goal for this release, they can be indexed and searched, -but not updated or deleted at this stage (was waiting for ZF 0.14 actually). - -I need to check the PostgreSQL sql file, I don't have a PG7 install lying -around to test on, so the script is untested. - -To index for the first time, login as an admin user and browse to /search/index.php -or /search/stats.php - there will be a message and a link telling you to go index. - --- Michael Champanis (mchampan) - email: cynnical@gmail.com - skype: mchampan - Summer of Code 2006 \ No newline at end of file diff --git a/search/Zend/Exception.php b/search/Zend/Exception.php deleted file mode 100644 index c47fffba307..00000000000 --- a/search/Zend/Exception.php +++ /dev/null @@ -1,30 +0,0 @@ -getFileObject('segments.gen', false); - - $format = $genFile->readInt(); - if ($format != (int)0xFFFFFFFE) { - throw new Zend_Search_Lucene_Exception('Wrong segments.gen file format'); - } - - $gen1 = $genFile->readLong(); - $gen2 = $genFile->readLong(); - - if ($gen1 == $gen2) { - return $gen1; - } - - usleep(self::GENERATION_RETRIEVE_PAUSE * 1000); - } - - // All passes are failed - throw new Zend_Search_Lucene_Exception('Index is under processing now'); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'is not readable') !== false) { - try { - // Try to open old style segments file - $segmentsFile = $directory->getFileObject('segments', false); - - // It's pre-2.1 index - return 0; - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'is not readable') !== false) { - return -1; - } else { - throw $e; - } - } - } else { - throw $e; - } - } - - return -1; - } - - /** - * Get segments file name - * - * @param integer $generation - * @return string - */ - public static function getSegmentFileName($generation) - { - if ($generation == 0) { - return 'segments'; - } - - return 'segments_' . base_convert($generation, 10, 36); - } - - /** - * Read segments file for pre-2.1 Lucene index format - */ - private function _readPre21SegmentsFile() - { - $segmentsFile = $this->_directory->getFileObject('segments'); - - $format = $segmentsFile->readInt(); - - if ($format != (int)0xFFFFFFFF) { - throw new Zend_Search_Lucene_Exception('Wrong segments file format'); - } - - // read version - // $segmentsFile->readLong(); - $segmentsFile->readInt(); $segmentsFile->readInt(); - - // read segment name counter - $segmentsFile->readInt(); - - $segments = $segmentsFile->readInt(); - - $this->_docCount = 0; - - // read segmentInfos - for ($count = 0; $count < $segments; $count++) { - $segName = $segmentsFile->readString(); - $segSize = $segmentsFile->readInt(); - $this->_docCount += $segSize; - - $this->_segmentInfos[$segName] = - new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, - $segName, - $segSize); - } - } - - /** - * Read segments file - * - * @throws Zend_Search_Lucene_Exception - */ - private function _readSegmentsFile() - { - $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); - - $format = $segmentsFile->readInt(); - - if ($format != (int)0xFFFFFFFD) { - throw new Zend_Search_Lucene_Exception('Wrong segments file format'); - } - - // read version - // $segmentsFile->readLong(); - $segmentsFile->readInt(); $segmentsFile->readInt(); - - // read segment name counter - $segmentsFile->readInt(); - - $segments = $segmentsFile->readInt(); - - $this->_docCount = 0; - - // read segmentInfos - for ($count = 0; $count < $segments; $count++) { - $segName = $segmentsFile->readString(); - $segSize = $segmentsFile->readInt(); - - // 2.1+ specific properties - //$delGen = $segmentsFile->readLong(); - $delGenHigh = $segmentsFile->readInt(); - $delGenLow = $segmentsFile->readInt(); - if ($delGenHigh == (int)0xFFFFFFFF && $delGenLow == (int)0xFFFFFFFF) { - $delGen = -1; // There are no deletes - } else { - $delGen = ($delGenHigh << 32) | $delGenLow; - } - - $hasSingleNormFile = $segmentsFile->readByte(); - $numField = $segmentsFile->readInt(); - - $normGens = array(); - if ($numField != (int)0xFFFFFFFF) { - for ($count1 = 0; $count1 < $numField; $count1++) { - $normGens[] = $segmentsFile->readLong(); - } - - throw new Zend_Search_Lucene_Exception('Separate norm files are not supported. Optimize index to use it with Zend_Search_Lucene.'); - } - - $isCompound = $segmentsFile->readByte(); - - - $this->_docCount += $segSize; - - $this->_segmentInfos[$segName] = - new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, - $segName, - $segSize, - $delGen, - $hasSingleNormFile, - $isCompound); - } - } - - /** - * Opens the index. - * - * IndexReader constructor needs Directory as a parameter. It should be - * a string with a path to the index folder or a Directory object. - * - * @param mixed $directory - * @throws Zend_Search_Lucene_Exception - */ - public function __construct($directory = null, $create = false) - { - if ($directory === null) { - throw new Zend_Search_Exception('No index directory specified'); - } - - if ($directory instanceof Zend_Search_Lucene_Storage_Directory_Filesystem) { - $this->_directory = $directory; - $this->_closeDirOnExit = false; - } else { - $this->_directory = new Zend_Search_Lucene_Storage_Directory_Filesystem($directory); - $this->_closeDirOnExit = true; - } - - $this->_segmentInfos = array(); - - // Mark index as "under processing" to prevent other processes from premature index cleaning - Zend_Search_Lucene_LockManager::obtainReadLock($this->_directory); - - // Escalate read lock to prevent current generation index files to be deleted while opening process is not done - Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory); - - - $this->_generation = self::getActualGeneration($this->_directory); - - if ($create) { - try { - Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'Can\'t obtain exclusive index lock') === false) { - throw $e; - } else { - throw new Zend_Search_Lucene_Exception('Can\'t create index. It\'s under processing now'); - } - } - - if ($this->_generation == -1) { - // Directory doesn't contain existing index, start from 1 - $this->_generation = 1; - $nameCounter = 0; - } else { - // Directory contains existing index - $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); - $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) - - $nameCounter = $segmentsFile->readInt(); - $this->_generation++; - } - - Zend_Search_Lucene_Index_Writer::createIndex($this->_directory, $this->_generation, $nameCounter); - - Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); - } - - if ($this->_generation == -1) { - throw new Zend_Search_Lucene_Exception('Index doesn\'t exists in the specified directory.'); - } else if ($this->_generation == 0) { - $this->_readPre21SegmentsFile(); - } else { - $this->_readSegmentsFile(); - } - - // De-escalate read lock to prevent current generation index files to be deleted while opening process is not done - Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory); - } - - /** - * Close current index and free resources - */ - private function _close() - { - if ($this->_closed) { - // index is already closed and resources are cleaned up - return; - } - - $this->commit(); - - // Release "under processing" flag - Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory); - - if ($this->_closeDirOnExit) { - $this->_directory->close(); - } - - $this->_directory = null; - $this->_writer = null; - $this->_segmentInfos = null; - - $this->_closed = true; - } - - /** - * Add reference to the index object - * - * @internal - */ - public function addReference() - { - $this->_refCount++; - } - - /** - * Remove reference from the index object - * - * When reference count becomes zero, index is closed and resources are cleaned up - * - * @internal - */ - public function removeReference() - { - $this->_refCount--; - - if ($this->_refCount == 0) { - $this->_close(); - } - } - - /** - * Object destructor - */ - public function __destruct() - { - $this->_close(); - } - - /** - * Returns an instance of Zend_Search_Lucene_Index_Writer for the index - * - * @internal - * @return Zend_Search_Lucene_Index_Writer - */ - public function getIndexWriter() - { - if (!$this->_writer instanceof Zend_Search_Lucene_Index_Writer) { - $this->_writer = new Zend_Search_Lucene_Index_Writer($this->_directory, $this->_segmentInfos); - } - - return $this->_writer; - } - - - /** - * Returns the Zend_Search_Lucene_Storage_Directory instance for this index. - * - * @return Zend_Search_Lucene_Storage_Directory - */ - public function getDirectory() - { - return $this->_directory; - } - - - /** - * Returns the total number of documents in this index (including deleted documents). - * - * @return integer - */ - public function count() - { - return $this->_docCount; - } - - /** - * Returns one greater than the largest possible document number. - * This may be used to, e.g., determine how big to allocate a structure which will have - * an element for every document number in an index. - * - * @return integer - */ - public function maxDoc() - { - return $this->count(); - } - - /** - * Returns the total number of non-deleted documents in this index. - * - * @return integer - */ - public function numDocs() - { - $numDocs = 0; - - foreach ($this->_segmentInfos as $segmentInfo) { - $numDocs += $segmentInfo->numDocs(); - } - - return $numDocs; - } - - /** - * Checks, that document is deleted - * - * @param integer $id - * @return boolean - * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range - */ - public function isDeleted($id) - { - if ($id >= $this->_docCount) { - throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); - } - - $segmentStartId = 0; - foreach ($this->_segmentInfos as $segmentInfo) { - if ($segmentStartId + $segmentInfo->count() > $id) { - break; - } - - $segmentStartId += $segmentInfo->count(); - } - - return $segmentInfo->isDeleted($id - $segmentStartId); - } - - /** - * Set default search field. - * - * Null means, that search is performed through all fields by default - * - * Default value is null - * - * @param string $fieldName - */ - public static function setDefaultSearchField($fieldName) - { - self::$_defaultSearchField = $fieldName; - } - - /** - * Get default search field. - * - * Null means, that search is performed through all fields by default - * - * @return string - */ - public static function getDefaultSearchField() - { - return self::$_defaultSearchField; - } - - /** - * Set result set limit. - * - * 0 (default) means no limit - * - * @param integer $limit - */ - public static function setResultSetLimit($limit) - { - self::$_resultSetLimit = $limit; - } - - /** - * Set result set limit. - * - * 0 means no limit - * - * @return integer - */ - public static function getResultSetLimit() - { - return self::$_resultSetLimit; - } - - /** - * Retrieve index maxBufferedDocs option - * - * maxBufferedDocs is a minimal number of documents required before - * the buffered in-memory documents are written into a new Segment - * - * Default value is 10 - * - * @return integer - */ - public function getMaxBufferedDocs() - { - return $this->getIndexWriter()->maxBufferedDocs; - } - - /** - * Set index maxBufferedDocs option - * - * maxBufferedDocs is a minimal number of documents required before - * the buffered in-memory documents are written into a new Segment - * - * Default value is 10 - * - * @param integer $maxBufferedDocs - */ - public function setMaxBufferedDocs($maxBufferedDocs) - { - $this->getIndexWriter()->maxBufferedDocs = $maxBufferedDocs; - } - - /** - * Retrieve index maxMergeDocs option - * - * maxMergeDocs is a largest number of documents ever merged by addDocument(). - * Small values (e.g., less than 10,000) are best for interactive indexing, - * as this limits the length of pauses while indexing to a few seconds. - * Larger values are best for batched indexing and speedier searches. - * - * Default value is PHP_INT_MAX - * - * @return integer - */ - public function getMaxMergeDocs() - { - return $this->getIndexWriter()->maxMergeDocs; - } - - /** - * Set index maxMergeDocs option - * - * maxMergeDocs is a largest number of documents ever merged by addDocument(). - * Small values (e.g., less than 10,000) are best for interactive indexing, - * as this limits the length of pauses while indexing to a few seconds. - * Larger values are best for batched indexing and speedier searches. - * - * Default value is PHP_INT_MAX - * - * @param integer $maxMergeDocs - */ - public function setMaxMergeDocs($maxMergeDocs) - { - $this->getIndexWriter()->maxMergeDocs = $maxMergeDocs; - } - - /** - * Retrieve index mergeFactor option - * - * mergeFactor determines how often segment indices are merged by addDocument(). - * With smaller values, less RAM is used while indexing, - * and searches on unoptimized indices are faster, - * but indexing speed is slower. - * With larger values, more RAM is used during indexing, - * and while searches on unoptimized indices are slower, - * indexing is faster. - * Thus larger values (> 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @return integer - */ - public function getMergeFactor() - { - return $this->getIndexWriter()->mergeFactor; - } - - /** - * Set index mergeFactor option - * - * mergeFactor determines how often segment indices are merged by addDocument(). - * With smaller values, less RAM is used while indexing, - * and searches on unoptimized indices are faster, - * but indexing speed is slower. - * With larger values, more RAM is used during indexing, - * and while searches on unoptimized indices are slower, - * indexing is faster. - * Thus larger values (> 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @param integer $maxMergeDocs - */ - public function setMergeFactor($mergeFactor) - { - $this->getIndexWriter()->mergeFactor = $mergeFactor; - } - - /** - * Performs a query against the index and returns an array - * of Zend_Search_Lucene_Search_QueryHit objects. - * Input is a string or Zend_Search_Lucene_Search_Query. - * - * @param mixed $query - * @return array Zend_Search_Lucene_Search_QueryHit - * @throws Zend_Search_Lucene_Exception - */ - public function find($query) - { - if (is_string($query)) { - $query = Zend_Search_Lucene_Search_QueryParser::parse($query); - } - - if (!$query instanceof Zend_Search_Lucene_Search_Query) { - throw new Zend_Search_Lucene_Exception('Query must be a string or Zend_Search_Lucene_Search_Query object'); - } - - $this->commit(); - - $hits = array(); - $scores = array(); - $ids = array(); - - $query = $query->rewrite($this)->optimize($this); - - $query->execute($this); - - $topScore = 0; - - foreach ($query->matchedDocs() as $id => $num) { - $docScore = $query->score($id, $this); - if( $docScore != 0 ) { - $hit = new Zend_Search_Lucene_Search_QueryHit($this); - $hit->id = $id; - $hit->score = $docScore; - - $hits[] = $hit; - $ids[] = $id; - $scores[] = $docScore; - - if ($docScore > $topScore) { - $topScore = $docScore; - } - } - - if (self::$_resultSetLimit != 0 && count($hits) >= self::$_resultSetLimit) { - break; - } - } - - if (count($hits) == 0) { - // skip sorting, which may cause a error on empty index - return array(); - } - - if ($topScore > 1) { - foreach ($hits as $hit) { - $hit->score /= $topScore; - } - } - - if (func_num_args() == 1) { - // sort by scores - array_multisort($scores, SORT_DESC, SORT_NUMERIC, - $ids, SORT_ASC, SORT_NUMERIC, - $hits); - } else { - // sort by given field names - - $argList = func_get_args(); - $fieldNames = $this->getFieldNames(); - $sortArgs = array(); - - for ($count = 1; $count < count($argList); $count++) { - $fieldName = $argList[$count]; - - if (!is_string($fieldName)) { - throw new Zend_Search_Lucene_Exception('Field name must be a string.'); - } - - if (!in_array($fieldName, $fieldNames)) { - throw new Zend_Search_Lucene_Exception('Wrong field name.'); - } - - $valuesArray = array(); - foreach ($hits as $hit) { - try { - $value = $hit->getDocument()->getFieldValue($fieldName); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'not found') === false) { - throw $e; - } else { - $value = null; - } - } - - $valuesArray[] = $value; - } - - $sortArgs[] = $valuesArray; - - if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { - $count++; - $sortArgs[] = $argList[$count]; - - if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { - $count++; - $sortArgs[] = $argList[$count]; - } else { - if ($argList[$count] == SORT_ASC || $argList[$count] == SORT_DESC) { - $sortArgs[] = SORT_REGULAR; - } else { - $sortArgs[] = SORT_ASC; - } - } - } else { - $sortArgs[] = SORT_ASC; - $sortArgs[] = SORT_REGULAR; - } - } - - // Sort by id's if values are equal - $sortArgs[] = $ids; - $sortArgs[] = SORT_ASC; - $sortArgs[] = SORT_NUMERIC; - - // Array to be sorted - $sortArgs[] = &$hits; - - // Do sort - call_user_func_array('array_multisort', $sortArgs); - } - - return $hits; - } - - - /** - * Returns a list of all unique field names that exist in this index. - * - * @param boolean $indexed - * @return array - */ - public function getFieldNames($indexed = false) - { - $result = array(); - foreach( $this->_segmentInfos as $segmentInfo ) { - $result = array_merge($result, $segmentInfo->getFields($indexed)); - } - return $result; - } - - - /** - * Returns a Zend_Search_Lucene_Document object for the document - * number $id in this index. - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @return Zend_Search_Lucene_Document - */ - public function getDocument($id) - { - if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { - /* @var $id Zend_Search_Lucene_Search_QueryHit */ - $id = $id->id; - } - - if ($id >= $this->_docCount) { - throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); - } - - $segmentStartId = 0; - foreach ($this->_segmentInfos as $segmentInfo) { - if ($segmentStartId + $segmentInfo->count() > $id) { - break; - } - - $segmentStartId += $segmentInfo->count(); - } - - $fdxFile = $segmentInfo->openCompoundFile('.fdx'); - $fdxFile->seek( ($id-$segmentStartId)*8, SEEK_CUR ); - $fieldValuesPosition = $fdxFile->readLong(); - - $fdtFile = $segmentInfo->openCompoundFile('.fdt'); - $fdtFile->seek($fieldValuesPosition, SEEK_CUR); - $fieldCount = $fdtFile->readVInt(); - - $doc = new Zend_Search_Lucene_Document(); - for ($count = 0; $count < $fieldCount; $count++) { - $fieldNum = $fdtFile->readVInt(); - $bits = $fdtFile->readByte(); - - $fieldInfo = $segmentInfo->getField($fieldNum); - - if (!($bits & 2)) { // Text data - $field = new Zend_Search_Lucene_Field($fieldInfo->name, - $fdtFile->readString(), - 'UTF-8', - true, - $fieldInfo->isIndexed, - $bits & 1 ); - } else { // Binary data - $field = new Zend_Search_Lucene_Field($fieldInfo->name, - $fdtFile->readBinary(), - '', - true, - $fieldInfo->isIndexed, - $bits & 1, - true ); - } - - $doc->addField($field); - } - - return $doc; - } - - - /** - * Returns true if index contain documents with specified term. - * - * Is used for query optimization. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return boolean - */ - public function hasTerm(Zend_Search_Lucene_Index_Term $term) - { - foreach ($this->_segmentInfos as $segInfo) { - if ($segInfo->getTermInfo($term) instanceof Zend_Search_Lucene_Index_TermInfo) { - return true; - } - } - - return false; - } - - /** - * Returns IDs of all the documents containing term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termDocs(Zend_Search_Lucene_Index_Term $term) - { - $result = array(); - $segmentStartDocId = 0; - - foreach ($this->_segmentInfos as $segInfo) { - $termInfo = $segInfo->getTermInfo($term); - - if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { - $segmentStartDocId += $segInfo->count(); - continue; - } - - $frqFile = $segInfo->openCompoundFile('.frq'); - $frqFile->seek($termInfo->freqPointer,SEEK_CUR); - $docId = 0; - for( $count=0; $count < $termInfo->docFreq; $count++ ) { - $docDelta = $frqFile->readVInt(); - if( $docDelta % 2 == 1 ) { - $docId += ($docDelta-1)/2; - } else { - $docId += $docDelta/2; - // read freq - $frqFile->readVInt(); - } - - $result[] = $segmentStartDocId + $docId; - } - - $segmentStartDocId += $segInfo->count(); - } - - return $result; - } - - - /** - * Returns an array of all term freqs. - * Result array structure: array(docId => freq, ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function termFreqs(Zend_Search_Lucene_Index_Term $term) - { - $result = array(); - $segmentStartDocId = 0; - foreach ($this->_segmentInfos as $segmentInfo) { - $result += $segmentInfo->termFreqs($term, $segmentStartDocId); - - $segmentStartDocId += $segmentInfo->count(); - } - - return $result; - } - - /** - * Returns an array of all term positions in the documents. - * Result array structure: array(docId => array(pos1, pos2, ...), ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termPositions(Zend_Search_Lucene_Index_Term $term) - { - $result = array(); - $segmentStartDocId = 0; - foreach ($this->_segmentInfos as $segmentInfo) { - $result += $segmentInfo->termPositions($term, $segmentStartDocId); - - $segmentStartDocId += $segmentInfo->count(); - } - - return $result; - } - - - /** - * Returns the number of documents in this index containing the $term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function docFreq(Zend_Search_Lucene_Index_Term $term) - { - $result = 0; - foreach ($this->_segmentInfos as $segInfo) { - $termInfo = $segInfo->getTermInfo($term); - if ($termInfo !== null) { - $result += $termInfo->docFreq; - } - } - - return $result; - } - - - /** - * Retrive similarity used by index reader - * - * @return Zend_Search_Lucene_Search_Similarity - */ - public function getSimilarity() - { - return Zend_Search_Lucene_Search_Similarity::getDefault(); - } - - - /** - * Returns a normalization factor for "field, document" pair. - * - * @param integer $id - * @param string $fieldName - * @return float - */ - public function norm($id, $fieldName) - { - if ($id >= $this->_docCount) { - return null; - } - - $segmentStartId = 0; - foreach ($this->_segmentInfos as $segInfo) { - if ($segmentStartId + $segInfo->count() > $id) { - break; - } - - $segmentStartId += $segInfo->count(); - } - - if ($segInfo->isDeleted($id - $segmentStartId)) { - return 0; - } - - return $segInfo->norm($id - $segmentStartId, $fieldName); - } - - /** - * Returns true if any documents have been deleted from this index. - * - * @return boolean - */ - public function hasDeletions() - { - foreach ($this->_segmentInfos as $segmentInfo) { - if ($segmentInfo->hasDeletions()) { - return true; - } - } - - return false; - } - - - /** - * Deletes a document from the index. - * $id is an internal document id - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @throws Zend_Search_Lucene_Exception - */ - public function delete($id) - { - if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { - /* @var $id Zend_Search_Lucene_Search_QueryHit */ - $id = $id->id; - } - - if ($id >= $this->_docCount) { - throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); - } - - $segmentStartId = 0; - foreach ($this->_segmentInfos as $segmentInfo) { - if ($segmentStartId + $segmentInfo->count() > $id) { - break; - } - - $segmentStartId += $segmentInfo->count(); - } - $segmentInfo->delete($id - $segmentStartId); - - $this->_hasChanges = true; - } - - - - /** - * Adds a document to this index. - * - * @param Zend_Search_Lucene_Document $document - */ - public function addDocument(Zend_Search_Lucene_Document $document) - { - $this->getIndexWriter()->addDocument($document); - $this->_docCount++; - - $this->_hasChanges = true; - } - - - /** - * Update document counter - */ - private function _updateDocCount() - { - $this->_docCount = 0; - foreach ($this->_segmentInfos as $segInfo) { - $this->_docCount += $segInfo->count(); - } - } - - /** - * Commit changes resulting from delete() or undeleteAll() operations. - * - * @todo undeleteAll processing. - */ - public function commit() - { - if ($this->_hasChanges) { - foreach ($this->_segmentInfos as $segInfo) { - $segInfo->writeChanges(); - } - - $this->getIndexWriter()->commit(); - - $this->_updateDocCount(); - - $this->_hasChanges = false; - } - } - - - /** - * Optimize index. - * - * Merges all segments into one - */ - public function optimize() - { - // Commit changes if any changes have been made - $this->commit(); - - if (count($this->_segmentInfos) > 1 || $this->hasDeletions()) { - $this->getIndexWriter()->optimize(); - $this->_updateDocCount(); - } - } - - - /** - * Returns an array of all terms in this index. - * - * @return array - */ - public function terms() - { - $result = array(); - - $segmentInfoQueue = new Zend_Search_Lucene_Index_SegmentInfoPriorityQueue(); - - foreach ($this->_segmentInfos as $segmentInfo) { - $segmentInfo->reset(); - - // Skip "empty" segments - if ($segmentInfo->currentTerm() !== null) { - $segmentInfoQueue->put($segmentInfo); - } - } - - while (($segmentInfo = $segmentInfoQueue->pop()) !== null) { - if ($segmentInfoQueue->top() === null || - $segmentInfoQueue->top()->currentTerm()->key() != - $segmentInfo->currentTerm()->key()) { - // We got new term - $result[] = $segmentInfo->currentTerm(); - } - - if ($segmentInfo->nextTerm() !== null) { - // Put segment back into the priority queue - $segmentInfoQueue->put($segmentInfo); - } - } - - return $result; - } - - - /** - * Terms stream queue - * - * @var Zend_Search_Lucene_Index_SegmentInfoPriorityQueue - */ - private $_termsStreamQueue = null; - - /** - * Last Term in a terms stream - * - * @var Zend_Search_Lucene_Index_Term - */ - private $_lastTerm = null; - - /** - * Reset terms stream. - */ - public function resetTermsStream() - { - $this->_termsStreamQueue = new Zend_Search_Lucene_Index_SegmentInfoPriorityQueue(); - - foreach ($this->_segmentInfos as $segmentInfo) { - $segmentInfo->reset(); - - // Skip "empty" segments - if ($segmentInfo->currentTerm() !== null) { - $this->_termsStreamQueue->put($segmentInfo); - } - } - - $this->nextTerm(); - } - - /** - * Skip terms stream up to specified term preffix. - * - * Prefix contains fully specified field info and portion of searched term - * - * @param Zend_Search_Lucene_Index_Term $prefix - */ - public function skipTo(Zend_Search_Lucene_Index_Term $prefix) - { - $segments = array(); - - while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) { - $segments[] = $segmentInfo; - } - - foreach ($segments as $segmentInfo) { - $segmentInfo->skipTo($prefix); - - if ($segmentInfo->currentTerm() !== null) { - $this->_termsStreamQueue->put($segmentInfo); - } - } - - $this->nextTerm(); - } - - /** - * Scans terms dictionary and returns next term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function nextTerm() - { - while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) { - if ($this->_termsStreamQueue->top() === null || - $this->_termsStreamQueue->top()->currentTerm()->key() != - $segmentInfo->currentTerm()->key()) { - // We got new term - $this->_lastTerm = $segmentInfo->currentTerm(); - - if ($segmentInfo->nextTerm() !== null) { - // Put segment back into the priority queue - $this->_termsStreamQueue->put($segmentInfo); - } - - return $this->_lastTerm; - } - - if ($segmentInfo->nextTerm() !== null) { - // Put segment back into the priority queue - $this->_termsStreamQueue->put($segmentInfo); - } - } - - // End of stream - $this->_lastTerm = null; - - return null; - } - - /** - * Returns term in current position - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function currentTerm() - { - return $this->_lastTerm; - } - - /** - * Close terms stream - * - * Should be used for resources clean up if stream is not read up to the end - */ - public function closeTermsStream() - { - while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) { - $segmentInfo->closeTermsStream(); - } - - $this->_termsStreamQueue = null; - $this->_lastTerm = null; - } - - - /************************************************************************* - @todo UNIMPLEMENTED - *************************************************************************/ - /** - * Undeletes all documents currently marked as deleted in this index. - * - * @todo Implementation - */ - public function undeleteAll() - {} -} diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer.php b/search/Zend/Search/Lucene/Analysis/Analyzer.php deleted file mode 100644 index def78ac5906..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer.php +++ /dev/null @@ -1,176 +0,0 @@ -dirroot}/search/Zend/Search/Lucene/Analysis/Token.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8/CaseInsensitive.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num/CaseInsensitive.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Text */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php"; - -/** Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php"; - -/** Zend_Search_Lucene_Analysis_TokenFilter_StopWords */ -require_once 'Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php'; - -/** Zend_Search_Lucene_Analysis_TokenFilter_ShortWords */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php"; - - -/** - * An Analyzer is used to analyze text. - * It thus represents a policy for extracting index terms from text. - * - * Note: - * Lucene Java implementation is oriented to streams. It provides effective work - * with a huge documents (more then 20Mb). - * But engine itself is not oriented such documents. - * Thus Zend_Search_Lucene analysis API works with data strings and sets (arrays). - * - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Analysis - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ - -abstract class Zend_Search_Lucene_Analysis_Analyzer -{ - /** - * The Analyzer implementation used by default. - * - * @var Zend_Search_Lucene_Analysis_Analyzer - */ - private static $_defaultImpl; - - /** - * Input string - * - * @var string - */ - protected $_input = null; - - /** - * Input string encoding - * - * @var string - */ - protected $_encoding = ''; - - /** - * Tokenize text to a terms - * Returns array of Zend_Search_Lucene_Analysis_Token objects - * - * Tokens are returned in UTF-8 (internal Zend_Search_Lucene encoding) - * - * @param string $data - * @return array - */ - public function tokenize($data, $encoding = '') - { - $this->setInput($data, $encoding); - - $tokenList = array(); - while (($nextToken = $this->nextToken()) !== null) { - $tokenList[] = $nextToken; - } - - return $tokenList; - } - - - /** - * Tokenization stream API - * Set input - * - * @param string $data - */ - public function setInput($data, $encoding = '') - { - $this->_input = $data; - $this->_encoding = $encoding; - $this->reset(); - } - - /** - * Reset token stream - */ - abstract public function reset(); - - /** - * Tokenization stream API - * Get next token - * Returns null at the end of stream - * - * Tokens are returned in UTF-8 (internal Zend_Search_Lucene encoding) - * - * @return Zend_Search_Lucene_Analysis_Token|null - */ - abstract public function nextToken(); - - - - - /** - * Set the default Analyzer implementation used by indexing code. - * - * @param Zend_Search_Lucene_Analysis_Analyzer $similarity - */ - public static function setDefault(Zend_Search_Lucene_Analysis_Analyzer $analyzer) - { - self::$_defaultImpl = $analyzer; - } - - - /** - * Return the default Analyzer implementation used by indexing code. - * - * @return Zend_Search_Lucene_Analysis_Analyzer - */ - public static function getDefault() - { - if (!self::$_defaultImpl instanceof Zend_Search_Lucene_Analysis_Analyzer) { - self::$_defaultImpl = new Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive(); - } - - return self::$_defaultImpl; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php deleted file mode 100644 index 01164d8874f..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php +++ /dev/null @@ -1,80 +0,0 @@ -_filters[] = $filter; - } - - /** - * Apply filters to the token. Can return null when the token was removed. - * - * @param Zend_Search_Lucene_Analysis_Token $token - * @return Zend_Search_Lucene_Analysis_Token - */ - public function normalize(Zend_Search_Lucene_Analysis_Token $token) - { - foreach ($this->_filters as $filter) { - $token = $filter->normalize($token); - - // resulting token can be null if the filter removes it - if (is_null($token)) { - return null; - } - } - - return $token; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php deleted file mode 100644 index 46bf196e12b..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php +++ /dev/null @@ -1,95 +0,0 @@ -_position = 0; - - if ($this->_input === null) { - return; - } - - // convert input into ascii - //$this->_input = iconv($this->_encoding, 'ASCII//TRANSLIT', $this->_input); - $this->_input = mb_convert_encoding($this->_input, 'ASCII', 'auto'); - - $this->_encoding = 'ASCII'; - } - - /** - * Tokenization stream API - * Get next token - * Returns null at the end of stream - * - * @return Zend_Search_Lucene_Analysis_Token|null - */ - public function nextToken() - { - if ($this->_input === null) { - return null; - } - - - do { - if (! preg_match('/[a-zA-Z]+/', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_position)) { - // It covers both cases a) there are no matches (preg_match(...) === 0) - // b) error occured (preg_match(...) === FALSE) - return null; - } - - $str = $match[0][0]; - $pos = $match[0][1]; - $endpos = $pos + strlen($str); - - $this->_position = $endpos; - - $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($str, $pos, $endpos)); - } while ($token === null); // try again if token is skipped - - return $token; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php deleted file mode 100644 index 4e3dd662a73..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php +++ /dev/null @@ -1,46 +0,0 @@ -addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCase()); - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php deleted file mode 100644 index b8aca5d95f7..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php +++ /dev/null @@ -1,92 +0,0 @@ -_position = 0; - - if ($this->_input === null) { - return; - } - - // convert input into ascii - $this->_input = iconv($this->_encoding, 'ASCII//TRANSLIT', $this->_input); - $this->_encoding = 'ASCII'; - } - - /** - * Tokenization stream API - * Get next token - * Returns null at the end of stream - * - * @return Zend_Search_Lucene_Analysis_Token|null - */ - public function nextToken() - { - if ($this->_input === null) { - return null; - } - - do { - if (! preg_match('/[a-zA-Z0-9]+/', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_position)) { - // It covers both cases a) there are no matches (preg_match(...) === 0) - // b) error occured (preg_match(...) === FALSE) - return null; - } - - $str = $match[0][0]; - $pos = $match[0][1]; - $endpos = $pos + strlen($str); - - $this->_position = $endpos; - - $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($str, $pos, $endpos)); - } while ($token === null); // try again if token is skipped - - return $token; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php deleted file mode 100644 index 89873f10f17..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php +++ /dev/null @@ -1,46 +0,0 @@ -addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCase()); - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php deleted file mode 100644 index 768e7847c6f..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php +++ /dev/null @@ -1,125 +0,0 @@ -_position = 0; - $this->_bytePosition = 0; - - // convert input into UTF-8 - if (strcasecmp($this->_encoding, 'utf8' ) != 0 && - strcasecmp($this->_encoding, 'utf-8') != 0 ) { - $this->_input = @iconv($this->_encoding, 'UTF-8', $this->_input); - $this->_encoding = 'UTF-8'; - } - } - - /** - * Tokenization stream API - * Get next token - * Returns null at the end of stream - * - * @return Zend_Search_Lucene_Analysis_Token|null - */ - public function nextToken() - { - if ($this->_input === null) { - return null; - } - - do { - if (! preg_match('/[\p{L}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) { - // It covers both cases a) there are no matches (preg_match(...) === 0) - // b) error occured (preg_match(...) === FALSE) - return null; - } - - // matched string - $matchedWord = $match[0][0]; - - // binary position of the matched word in the input stream - $binStartPos = $match[0][1]; - - // character position of the matched word in the input stream - $startPos = $this->_position + - iconv_strlen(substr($this->_input, - $this->_bytePosition, - $binStartPos - $this->_bytePosition), - 'UTF-8'); - // character postion of the end of matched word in the input stream - $endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8'); - - $this->_bytePosition = $binStartPos + strlen($matchedWord); - $this->_position = $endPos; - - $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos)); - } while ($token === null); // try again if token is skipped - - return $token; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8/CaseInsensitive.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8/CaseInsensitive.php deleted file mode 100644 index 4213fb32842..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8/CaseInsensitive.php +++ /dev/null @@ -1,48 +0,0 @@ -addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8()); - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php deleted file mode 100644 index 74c89be0c21..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php +++ /dev/null @@ -1,125 +0,0 @@ -_position = 0; - $this->_bytePosition = 0; - - // convert input into UTF-8 - if (strcasecmp($this->_encoding, 'utf8' ) != 0 && - strcasecmp($this->_encoding, 'utf-8') != 0 ) { - $this->_input = iconv($this->_encoding, 'UTF-8', $this->_input); - $this->_encoding = 'UTF-8'; - } - } - - /** - * Tokenization stream API - * Get next token - * Returns null at the end of stream - * - * @return Zend_Search_Lucene_Analysis_Token|null - */ - public function nextToken() - { - if ($this->_input === null) { - return null; - } - - do { - if (! preg_match('/[\p{L}\p{N}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) { - // It covers both cases a) there are no matches (preg_match(...) === 0) - // b) error occured (preg_match(...) === FALSE) - return null; - } - - // matched string - $matchedWord = $match[0][0]; - - // binary position of the matched word in the input stream - $binStartPos = $match[0][1]; - - // character position of the matched word in the input stream - $startPos = $this->_position + - iconv_strlen(substr($this->_input, - $this->_bytePosition, - $binStartPos - $this->_bytePosition), - 'UTF-8'); - // character postion of the end of matched word in the input stream - $endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8'); - - $this->_bytePosition = $binStartPos + strlen($matchedWord); - $this->_position = $endPos; - - $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos)); - } while ($token === null); // try again if token is skipped - - return $token; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num/CaseInsensitive.php b/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num/CaseInsensitive.php deleted file mode 100644 index 1ec0d5c3b7a..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num/CaseInsensitive.php +++ /dev/null @@ -1,48 +0,0 @@ -addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8()); - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/Token.php b/search/Zend/Search/Lucene/Analysis/Token.php deleted file mode 100644 index 3097992a9b8..00000000000 --- a/search/Zend/Search/Lucene/Analysis/Token.php +++ /dev/null @@ -1,153 +0,0 @@ -_termText = $text; - $this->_startOffset = $start; - $this->_endOffset = $end; - - $this->_positionIncrement = 1; - } - - - /** - * positionIncrement setter - * - * @param integer $positionIncrement - */ - public function setPositionIncrement($positionIncrement) - { - $this->_positionIncrement = $positionIncrement; - } - - /** - * Returns the position increment of this Token. - * - * @return integer - */ - public function getPositionIncrement() - { - return $this->_positionIncrement; - } - - /** - * Returns the Token's term text. - * - * @return string - */ - public function getTermText() - { - return $this->_termText; - } - - /** - * Returns this Token's starting offset, the position of the first character - * corresponding to this token in the source text. - * - * Note: - * The difference between getEndOffset() and getStartOffset() may not be equal - * to strlen(Zend_Search_Lucene_Analysis_Token::getTermText()), as the term text may have been altered - * by a stemmer or some other filter. - * - * @return integer - */ - public function getStartOffset() - { - return $this->_startOffset; - } - - /** - * Returns this Token's ending offset, one greater than the position of the - * last character corresponding to this token in the source text. - * - * @return integer - */ - public function getEndOffset() - { - return $this->_endOffset; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/TokenFilter.php b/search/Zend/Search/Lucene/Analysis/TokenFilter.php deleted file mode 100644 index 5c582024a15..00000000000 --- a/search/Zend/Search/Lucene/Analysis/TokenFilter.php +++ /dev/null @@ -1,47 +0,0 @@ -getTermText() ), - $srcToken->getStartOffset(), - $srcToken->getEndOffset()); - - $newToken->setPositionIncrement($srcToken->getPositionIncrement()); - - return $newToken; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/TokenFilter/LowerCaseUtf8.php b/search/Zend/Search/Lucene/Analysis/TokenFilter/LowerCaseUtf8.php deleted file mode 100644 index 78cb5e680f8..00000000000 --- a/search/Zend/Search/Lucene/Analysis/TokenFilter/LowerCaseUtf8.php +++ /dev/null @@ -1,70 +0,0 @@ -dirroot}/search/Zend/Search/Lucene/Analysis/TokenFilter.php"; - - -/** - * Lower case Token filter. - * - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Analysis - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ - -class Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8 extends Zend_Search_Lucene_Analysis_TokenFilter -{ - /** - * Object constructor - */ - public function __construct() - { - global $CFG; - if (!function_exists('mb_strtolower')) { - // mbstring extension is disabled - require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Exception.php"; - throw new Zend_Search_Lucene_Exception('Utf8 compatible lower case filter needs mbstring extension to be enabled.'); - } - } - - /** - * Normalize Token or remove it (if null is returned) - * - * @param Zend_Search_Lucene_Analysis_Token $srcToken - * @return Zend_Search_Lucene_Analysis_Token - */ - public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken) - { - $newToken = new Zend_Search_Lucene_Analysis_Token( - mb_strtolower($srcToken->getTermText(), 'UTF-8'), - $srcToken->getStartOffset(), - $srcToken->getEndOffset()); - - $newToken->setPositionIncrement($srcToken->getPositionIncrement()); - - return $newToken; - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php b/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php deleted file mode 100644 index 50c3f50d60a..00000000000 --- a/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php +++ /dev/null @@ -1,68 +0,0 @@ -length = $length; - } - - /** - * Normalize Token or remove it (if null is returned) - * - * @param Zend_Search_Lucene_Analysis_Token $srcToken - * @return Zend_Search_Lucene_Analysis_Token - */ - public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken) { - if (strlen($srcToken->getTermText()) < $this->length) { - return null; - } else { - return $srcToken; - } - } -} - diff --git a/search/Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php b/search/Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php deleted file mode 100644 index 55b7567c1bf..00000000000 --- a/search/Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php +++ /dev/null @@ -1,100 +0,0 @@ - 1, 'an' => '1'); - * - * We do recommend to provide all words in lowercase and concatenate this class after the lowercase filter. - * - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Analysis - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ - -class Zend_Search_Lucene_Analysis_TokenFilter_StopWords extends Zend_Search_Lucene_Analysis_TokenFilter -{ - /** - * Stop Words - * @var array - */ - private $_stopSet; - - /** - * Constructs new instance of this filter. - * - * @param array $stopwords array (set) of words that will be filtered out - */ - public function __construct($stopwords = array()) { - $this->_stopSet = array_flip($stopwords); - } - - /** - * Normalize Token or remove it (if null is returned) - * - * @param Zend_Search_Lucene_Analysis_Token $srcToken - * @return Zend_Search_Lucene_Analysis_Token - */ - public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken) { - if (array_key_exists($srcToken->getTermText(), $this->_stopSet)) { - return null; - } else { - return $srcToken; - } - } - - /** - * Fills stopwords set from a text file. Each line contains one stopword, lines with '#' in the first - * column are ignored (as comments). - * - * You can call this method one or more times. New stopwords are always added to current set. - * - * @param string $filepath full path for text file with stopwords - * @throws Zend_Search_Exception When the file doesn`t exists or is not readable. - */ - public function loadFromFile($filepath = null) { - if (! $filepath || ! file_exists($filepath)) { - throw new Zend_Search_Exception('You have to provide valid file path'); - } - $fd = fopen($filepath, "r"); - if (! $fd) { - throw new Zend_Search_Exception('Cannot open file ' . $filepath); - } - while (!feof ($fd)) { - $buffer = trim(fgets($fd)); - if (strlen($buffer) > 0 && $buffer[0] != '#') { - $this->_stopSet[$buffer] = 1; - } - } - if (!fclose($fd)) { - throw new Zend_Search_Exception('Cannot close file ' . $filepath); - } - } -} - diff --git a/search/Zend/Search/Lucene/Document.php b/search/Zend/Search/Lucene/Document.php deleted file mode 100644 index de4281efa7c..00000000000 --- a/search/Zend/Search/Lucene/Document.php +++ /dev/null @@ -1,121 +0,0 @@ -getFieldValue($offset); - } - - - /** - * Add a field object to this document. - * - * @param Zend_Search_Lucene_Field $field - */ - public function addField(Zend_Search_Lucene_Field $field) - { - $this->_fields[$field->name] = $field; - } - - - /** - * Return an array with the names of the fields in this document. - * - * @return array - */ - public function getFieldNames() - { - return array_keys($this->_fields); - } - - - /** - * Returns Zend_Search_Lucene_Field object for a named field in this document. - * - * @param string $fieldName - * @return Zend_Search_Lucene_Field - */ - public function getField($fieldName) - { - if (!array_key_exists($fieldName, $this->_fields)) { - throw new Zend_Search_Lucene_Exception("Field name \"$fieldName\" not found in document."); - } - return $this->_fields[$fieldName]; - } - - - /** - * Returns the string value of a named field in this document. - * - * @see __get() - * @return string - */ - public function getFieldValue($fieldName) - { - return $this->getField($fieldName)->value; - } - - /** - * Returns the string value of a named field in UTF-8 encoding. - * - * @see __get() - * @return string - */ - public function getFieldUtf8Value($fieldName) - { - return $this->getField($fieldName)->getUtf8Value(); - } -} diff --git a/search/Zend/Search/Lucene/Document/Html.php b/search/Zend/Search/Lucene/Document/Html.php deleted file mode 100644 index e7cd2f90f4f..00000000000 --- a/search/Zend/Search/Lucene/Document/Html.php +++ /dev/null @@ -1,310 +0,0 @@ -_doc = new DOMDocument(); - $this->_doc->substituteEntities = true; - - if ($isFile) { - @$this->_doc->loadHTMLFile($data); - } else{ - @$this->_doc->loadHTML($data); - } - - $xpath = new DOMXPath($this->_doc); - - $docTitle = ''; - $titleNodes = $xpath->query('/html/head/title'); - foreach ($titleNodes as $titleNode) { - // title should always have only one entry, but we process all nodeset entries - $docTitle .= $titleNode->nodeValue . ' '; - } - $this->addField(Zend_Search_Lucene_Field::Text('title', $docTitle, $this->_doc->actualEncoding)); - - $metaNodes = $xpath->query('/html/head/meta[@name]'); - foreach ($metaNodes as $metaNode) { - $this->addField(Zend_Search_Lucene_Field::Text($metaNode->getAttribute('name'), - $metaNode->getAttribute('content'), - $this->_doc->actualEncoding)); - } - - $docBody = ''; - $bodyNodes = $xpath->query('/html/body'); - foreach ($bodyNodes as $bodyNode) { - // body should always have only one entry, but we process all nodeset entries - $this->_retrieveNodeText($bodyNode, $docBody); - } - if ($storeContent) { - $this->addField(Zend_Search_Lucene_Field::Text('body', $docBody, $this->_doc->actualEncoding)); - } else { - $this->addField(Zend_Search_Lucene_Field::UnStored('body', $docBody, $this->_doc->actualEncoding)); - } - - $linkNodes = $this->_doc->getElementsByTagName('a'); - foreach ($linkNodes as $linkNode) { - if (($href = $linkNode->getAttribute('href')) != '') { - $this->_links[] = $href; - } - } - $this->_links = array_unique($this->_links); - - $linkNodes = $xpath->query('/html/head/link'); - foreach ($linkNodes as $linkNode) { - if (($href = $linkNode->getAttribute('href')) != '') { - $this->_headerLinks[] = $href; - } - } - $this->_headerLinks = array_unique($this->_headerLinks); - } - - /** - * Get node text - * - * We should exclude scripts, which may be not included into comment tags, CDATA sections, - * - * @param DOMNode $node - * @param string &$text - */ - private function _retrieveNodeText(DOMNode $node, &$text) - { - if ($node->nodeType == XML_TEXT_NODE) { - $text .= $node->nodeValue ; - $text .= ' '; - } else if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName != 'script') { - foreach ($node->childNodes as $childNode) { - $this->_retrieveNodeText($childNode, $text); - } - } - } - - /** - * Get document HREF links - * - * @return array - */ - public function getLinks() - { - return $this->_links; - } - - /** - * Get document header links - * - * @return array - */ - public function getHeaderLinks() - { - return $this->_headerLinks; - } - - /** - * Load HTML document from a string - * - * @param string $data - * @param boolean $storeContent - * @return Zend_Search_Lucene_Document_Html - */ - public static function loadHTML($data, $storeContent = false) - { - return new Zend_Search_Lucene_Document_Html($data, false, $storeContent); - } - - /** - * Load HTML document from a file - * - * @param string $file - * @param boolean $storeContent - * @return Zend_Search_Lucene_Document_Html - */ - public static function loadHTMLFile($file, $storeContent = false) - { - return new Zend_Search_Lucene_Document_Html($file, true, $storeContent); - } - - - /** - * Highlight text in text node - * - * @param DOMText $node - * @param array $wordsToHighlight - * @param string $color - */ - public function _highlightTextNode(DOMText $node, $wordsToHighlight, $color) - { - $analyzer = Zend_Search_Lucene_Analysis_Analyzer::getDefault(); - $analyzer->setInput($node->nodeValue, $this->_doc->encoding); - - $matchedTokens = array(); - - while (($token = $analyzer->nextToken()) !== null) { - if (isset($wordsToHighlight[$token->getTermText()])) { - $matchedTokens[] = $token; - } - } - - if (count($matchedTokens) == 0) { - return; - } - - $matchedTokens = array_reverse($matchedTokens); - - foreach ($matchedTokens as $token) { - // Cut text after matched token - $node->splitText($token->getEndOffset()); - - // Cut matched node - $matchedWordNode = $node->splitText($token->getStartOffset()); - - $highlightedNode = $this->_doc->createElement('b', $matchedWordNode->nodeValue); - $highlightedNode->setAttribute('style', 'color:black;background-color:' . $color); - - $node->parentNode->replaceChild($highlightedNode, $matchedWordNode); - } - } - - - /** - * highlight words in content of the specified node - * - * @param DOMNode $contextNode - * @param array $wordsToHighlight - * @param string $color - */ - public function _highlightNode(DOMNode $contextNode, $wordsToHighlight, $color) - { - $textNodes = array(); - - if (!$contextNode->hasChildNodes()) { - return; - } - - foreach ($contextNode->childNodes as $childNode) { - if ($childNode->nodeType == XML_TEXT_NODE) { - // process node later to leave childNodes structure untouched - $textNodes[] = $childNode; - } else { - // Skip script nodes - if ($childNode->nodeName != 'script') { - $this->_highlightNode($childNode, $wordsToHighlight, $color); - } - } - } - - foreach ($textNodes as $textNode) { - $this->_highlightTextNode($textNode, $wordsToHighlight, $color); - } - } - - - - /** - * Highlight text with specified color - * - * @param string|array $words - * @param string $color - * @return string - */ - public function highlight($words, $color = '#66ffff') - { - if (!is_array($words)) { - $words = array($words); - } - $wordsToHighlight = array(); - - $analyzer = Zend_Search_Lucene_Analysis_Analyzer::getDefault(); - foreach ($words as $wordString) { - $wordsToHighlight = array_merge($wordsToHighlight, $analyzer->tokenize($wordString)); - } - - if (count($wordsToHighlight) == 0) { - return $this->_doc->saveHTML(); - } - - $wordsToHighlightFlipped = array(); - foreach ($wordsToHighlight as $id => $token) { - $wordsToHighlightFlipped[$token->getTermText()] = $id; - } - - $xpath = new DOMXPath($this->_doc); - - $matchedNodes = $xpath->query("/html/body"); - foreach ($matchedNodes as $matchedNode) { - $this->_highlightNode($matchedNode, $wordsToHighlightFlipped, $color); - } - - } - - /** - * Get HTML - * - * @return string - */ - public function getHTML() - { - return $this->_doc->saveHTML(); - } -} - diff --git a/search/Zend/Search/Lucene/Exception.php b/search/Zend/Search/Lucene/Exception.php deleted file mode 100644 index d08b30dbb1d..00000000000 --- a/search/Zend/Search/Lucene/Exception.php +++ /dev/null @@ -1,36 +0,0 @@ - targetState - * - * @var array - */ - private $_rules = array(); - - /** - * List of entry actions - * Each action executes when entering the state - * - * [state] => action - * - * @var array - */ - private $_entryActions = array(); - - /** - * List of exit actions - * Each action executes when exiting the state - * - * [state] => action - * - * @var array - */ - private $_exitActions = array(); - - /** - * List of input actions - * Each action executes when entering the state - * - * [state][input] => action - * - * @var array - */ - private $_inputActions = array(); - - /** - * List of input actions - * Each action executes when entering the state - * - * [state1][state2] => action - * - * @var array - */ - private $_transitionActions = array(); - - /** - * Finite State machine constructor - * - * $states is an array of integers or strings with a list of possible machine states - * constructor treats fist list element as a sturt state (assignes it to $_current state). - * It may be reassigned by setState() call. - * States list may be empty and can be extended later by addState() or addStates() calls. - * - * $inputAphabet is the same as $states, but represents input alphabet - * it also may be extended later by addInputSymbols() or addInputSymbol() calls. - * - * $rules parameter describes FSM transitions and has a structure: - * array( array(sourseState, input, targetState[, inputAction]), - * array(sourseState, input, targetState[, inputAction]), - * array(sourseState, input, targetState[, inputAction]), - * ... - * ) - * Rules also can be added later by addRules() and addRule() calls. - * - * FSM actions are very flexible and may be defined by addEntryAction(), addExitAction(), - * addInputAction() and addTransitionAction() calls. - * - * @param array $states - * @param array $inputAphabet - * @param array $rules - */ - public function __construct($states = array(), $inputAphabet = array(), $rules = array()) - { - $this->addStates($states); - $this->addInputSymbols($inputAphabet); - $this->addRules($rules); - } - - /** - * Add states to the state machine - * - * @param array $states - */ - public function addStates($states) - { - foreach ($states as $state) { - $this->addState($state); - } - } - - /** - * Add state to the state machine - * - * @param integer|string $state - */ - public function addState($state) - { - $this->_states[$state] = $state; - - if ($this->_currentState === null) { - $this->_currentState = $state; - } - } - - /** - * Set FSM state. - * No any action is invoked - * - * @param integer|string $state - * @throws Zend_Search_Exception - */ - public function setState($state) - { - if (!isset($this->_states[$state])) { - throw new Zend_Search_Exception('State \'' . $state . '\' is not on of the possible FSM states.'); - } - - $this->_currentState = $state; - } - - /** - * Get FSM state. - * - * @return integer|string $state|null - */ - public function getState() - { - return $this->_currentState; - } - - /** - * Add symbols to the input alphabet - * - * @param array $inputAphabet - */ - public function addInputSymbols($inputAphabet) - { - foreach ($inputAphabet as $inputSymbol) { - $this->addInputSymbol($inputSymbol); - } - } - - /** - * Add symbol to the input alphabet - * - * @param integer|string $inputSymbol - */ - public function addInputSymbol($inputSymbol) - { - $this->_inputAphabet[$inputSymbol] = $inputSymbol; - } - - - /** - * Add transition rules - * - * array structure: - * array( array(sourseState, input, targetState[, inputAction]), - * array(sourseState, input, targetState[, inputAction]), - * array(sourseState, input, targetState[, inputAction]), - * ... - * ) - * - * @param array $rules - */ - public function addRules($rules) - { - foreach ($rules as $rule) { - $this->addrule($rule[0], $rule[1], $rule[2], isset($rule[3])?$rule[3]:null); - } - } - - /** - * Add symbol to the input alphabet - * - * @param integer|string $sourceState - * @param integer|string $input - * @param integer|string $targetState - * @param Zend_Search_Lucene_FSMAction|null $inputAction - * @throws Zend_Search_Exception - */ - public function addRule($sourceState, $input, $targetState, $inputAction = null) - { - if (!isset($this->_states[$sourceState])) { - throw new Zend_Search_Exception('Undefined source state (' . $sourceState . ').'); - } - if (!isset($this->_states[$targetState])) { - throw new Zend_Search_Exception('Undefined target state (' . $targetState . ').'); - } - if (!isset($this->_inputAphabet[$input])) { - throw new Zend_Search_Exception('Undefined input symbol (' . $input . ').'); - } - - if (!isset($this->_rules[$sourceState])) { - $this->_rules[$sourceState] = array(); - } - if (isset($this->_rules[$sourceState][$input])) { - throw new Zend_Search_Exception('Rule for {state,input} pair (' . $sourceState . ', '. $input . ') is already defined.'); - } - - $this->_rules[$sourceState][$input] = $targetState; - - - if ($inputAction !== null) { - $this->addInputAction($sourceState, $input, $inputAction); - } - } - - - /** - * Add state entry action. - * Several entry actions are allowed. - * Action execution order is defined by addEntryAction() calls - * - * @param integer|string $state - * @param Zend_Search_Lucene_FSMAction $action - */ - public function addEntryAction($state, Zend_Search_Lucene_FSMAction $action) - { - if (!isset($this->_states[$state])) { - throw new Zend_Search_Exception('Undefined state (' . $state. ').'); - } - - if (!isset($this->_entryActions[$state])) { - $this->_entryActions[$state] = array(); - } - - $this->_entryActions[$state][] = $action; - } - - /** - * Add state exit action. - * Several exit actions are allowed. - * Action execution order is defined by addEntryAction() calls - * - * @param integer|string $state - * @param Zend_Search_Lucene_FSMAction $action - */ - public function addExitAction($state, Zend_Search_Lucene_FSMAction $action) - { - if (!isset($this->_states[$state])) { - throw new Zend_Search_Exception('Undefined state (' . $state. ').'); - } - - if (!isset($this->_exitActions[$state])) { - $this->_exitActions[$state] = array(); - } - - $this->_exitActions[$state][] = $action; - } - - /** - * Add input action (defined by {state, input} pair). - * Several input actions are allowed. - * Action execution order is defined by addInputAction() calls - * - * @param integer|string $state - * @param integer|string $input - * @param Zend_Search_Lucene_FSMAction $action - */ - public function addInputAction($state, $inputSymbol, Zend_Search_Lucene_FSMAction $action) - { - if (!isset($this->_states[$state])) { - throw new Zend_Search_Exception('Undefined state (' . $state. ').'); - } - if (!isset($this->_inputAphabet[$inputSymbol])) { - throw new Zend_Search_Exception('Undefined input symbol (' . $inputSymbol. ').'); - } - - if (!isset($this->_inputActions[$state])) { - $this->_inputActions[$state] = array(); - } - if (!isset($this->_inputActions[$state][$inputSymbol])) { - $this->_inputActions[$state][$inputSymbol] = array(); - } - - $this->_inputActions[$state][$inputSymbol][] = $action; - } - - /** - * Add transition action (defined by {state, input} pair). - * Several transition actions are allowed. - * Action execution order is defined by addTransitionAction() calls - * - * @param integer|string $sourceState - * @param integer|string $targetState - * @param Zend_Search_Lucene_FSMAction $action - */ - public function addTransitionAction($sourceState, $targetState, Zend_Search_Lucene_FSMAction $action) - { - if (!isset($this->_states[$sourceState])) { - throw new Zend_Search_Exception('Undefined source state (' . $sourceState. ').'); - } - if (!isset($this->_states[$targetState])) { - throw new Zend_Search_Exception('Undefined source state (' . $targetState. ').'); - } - - if (!isset($this->_transitionActions[$sourceState])) { - $this->_transitionActions[$sourceState] = array(); - } - if (!isset($this->_transitionActions[$sourceState][$targetState])) { - $this->_transitionActions[$sourceState][$targetState] = array(); - } - - $this->_transitionActions[$sourceState][$targetState][] = $action; - } - - - /** - * Process an input - * - * @param mixed $input - * @throws Zend_Search_Exception - */ - public function process($input) - { - if (!isset($this->_rules[$this->_currentState])) { - throw new Zend_Search_Exception('There is no any rule for current state (' . $this->_currentState . ').'); - } - if (!isset($this->_rules[$this->_currentState][$input])) { - throw new Zend_Search_Exception('There is no any rule for {current state, input} pair (' . $this->_currentState . ', ' . $input . ').'); - } - - $sourceState = $this->_currentState; - $targetState = $this->_rules[$this->_currentState][$input]; - - if ($sourceState != $targetState && isset($this->_exitActions[$sourceState])) { - foreach ($this->_exitActions[$sourceState] as $action) { - $action->doAction(); - } - } - if (isset($this->_inputActions[$sourceState]) && - isset($this->_inputActions[$sourceState][$input])) { - foreach ($this->_inputActions[$sourceState][$input] as $action) { - $action->doAction(); - } - } - - - $this->_currentState = $targetState; - - if (isset($this->_transitionActions[$sourceState]) && - isset($this->_transitionActions[$sourceState][$targetState])) { - foreach ($this->_transitionActions[$sourceState][$targetState] as $action) { - $action->doAction(); - } - } - if ($sourceState != $targetState && isset($this->_entryActions[$targetState])) { - foreach ($this->_entryActions[$targetState] as $action) { - $action->doAction(); - } - } - } - - public function reset() - { - if (count($this->_states) == 0) { - throw new Zend_Search_Exception('There is no any state defined for FSM.'); - } - - $this->_currentState = $this->_states[0]; - } -} - diff --git a/search/Zend/Search/Lucene/FSMAction.php b/search/Zend/Search/Lucene/FSMAction.php deleted file mode 100644 index fdbd6ff659a..00000000000 --- a/search/Zend/Search/Lucene/FSMAction.php +++ /dev/null @@ -1,65 +0,0 @@ -_object = $object; - $this->_method = $method; - } - - public function doAction() - { - $methodName = $this->_method; - $this->_object->$methodName(); - } -} - diff --git a/search/Zend/Search/Lucene/Field.php b/search/Zend/Search/Lucene/Field.php deleted file mode 100644 index d02f1d94979..00000000000 --- a/search/Zend/Search/Lucene/Field.php +++ /dev/null @@ -1,192 +0,0 @@ -name = $name; - $this->value = $value; - - if (!$isBinary) { - $this->encoding = $encoding; - $this->isTokenized = $isTokenized; - } else { - $this->encoding = ''; - $this->isTokenized = false; - } - - $this->isStored = $isStored; - $this->isIndexed = $isIndexed; - $this->isBinary = $isBinary; - - $this->storeTermVector = false; - $this->boost = 1.0; - } - - - /** - * Constructs a String-valued Field that is not tokenized, but is indexed - * and stored. Useful for non-text fields, e.g. date or url. - * - * @param string $name - * @param string $value - * @param string $encoding - * @return Zend_Search_Lucene_Field - */ - public static function Keyword($name, $value, $encoding = '') - { - return new self($name, $value, $encoding, true, true, false); - } - - - /** - * Constructs a String-valued Field that is not tokenized nor indexed, - * but is stored in the index, for return with hits. - * - * @param string $name - * @param string $value - * @param string $encoding - * @return Zend_Search_Lucene_Field - */ - public static function UnIndexed($name, $value, $encoding = '') - { - return new self($name, $value, $encoding, true, false, false); - } - - - /** - * Constructs a Binary String valued Field that is not tokenized nor indexed, - * but is stored in the index, for return with hits. - * - * @param string $name - * @param string $value - * @param string $encoding - * @return Zend_Search_Lucene_Field - */ - public static function Binary($name, $value) - { - return new self($name, $value, '', true, false, false, true); - } - - /** - * Constructs a String-valued Field that is tokenized and indexed, - * and is stored in the index, for return with hits. Useful for short text - * fields, like "title" or "subject". Term vector will not be stored for this field. - * - * @param string $name - * @param string $value - * @param string $encoding - * @return Zend_Search_Lucene_Field - */ - public static function Text($name, $value, $encoding = '') - { - return new self($name, $value, $encoding, true, true, true); - } - - - /** - * Constructs a String-valued Field that is tokenized and indexed, - * but that is not stored in the index. - * - * @param string $name - * @param string $value - * @param string $encoding - * @return Zend_Search_Lucene_Field - */ - public static function UnStored($name, $value, $encoding = '') - { - return new self($name, $value, $encoding, false, true, true); - } - - /** - * Get field value in UTF-8 encoding - * - * @return string - */ - public function getUtf8Value() - { - if (strcasecmp($this->encoding, 'utf8' ) == 0 || - strcasecmp($this->encoding, 'utf-8') == 0 ) { - return $this->value; - } else { - return iconv($this->encoding, 'UTF-8', $this->value); - } - } -} - diff --git a/search/Zend/Search/Lucene/Index/DictionaryLoader.php b/search/Zend/Search/Lucene/Index/DictionaryLoader.php deleted file mode 100644 index f01be7b4b13..00000000000 --- a/search/Zend/Search/Lucene/Index/DictionaryLoader.php +++ /dev/null @@ -1,260 +0,0 @@ -.tii index file data and - * returns two arrays - term and tremInfo lists. - * - * See Zend_Search_Lucene_Index_SegmintInfo class for details - * - * @param string $data - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public static function load($data) - { - $termDictionary = array(); - $termInfos = array(); - $pos = 0; - - // $tiVersion = $tiiFile->readInt(); - $tiVersion = ord($data[0]) << 24 | ord($data[1]) << 16 | ord($data[2]) << 8 | ord($data[3]); - $pos += 4; - if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ && - $tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) { - throw new Zend_Search_Lucene_Exception('Wrong TermInfoIndexFile file format'); - } - - // $indexTermCount = $tiiFile->readLong(); - if (PHP_INT_SIZE > 4) { - $indexTermCount = ord($data[$pos]) << 56 | - ord($data[$pos+1]) << 48 | - ord($data[$pos+2]) << 40 | - ord($data[$pos+3]) << 32 | - ord($data[$pos+4]) << 24 | - ord($data[$pos+5]) << 16 | - ord($data[$pos+6]) << 8 | - ord($data[$pos+7]); - } else { - if ((ord($data[$pos]) != 0) || - (ord($data[$pos+1]) != 0) || - (ord($data[$pos+2]) != 0) || - (ord($data[$pos+3]) != 0) || - ((ord($data[$pos+4]) & 0x80) != 0)) { - throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); - } - - $indexTermCount = ord($data[$pos+4]) << 24 | - ord($data[$pos+5]) << 16 | - ord($data[$pos+6]) << 8 | - ord($data[$pos+7]); - } - $pos += 8; - - // $tiiFile->readInt(); // IndexInterval - $pos += 4; - - // $skipInterval = $tiiFile->readInt(); - $skipInterval = ord($data[$pos]) << 24 | ord($data[$pos+1]) << 16 | ord($data[$pos+2]) << 8 | ord($data[$pos+3]); - $pos += 4; - if ($indexTermCount < 1) { - throw new Zend_Search_Lucene_Exception('Wrong number of terms in a term dictionary index'); - } - - if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) { - /* Skip MaxSkipLevels value */ - $pos += 4; - } - - $prevTerm = ''; - $freqPointer = 0; - $proxPointer = 0; - $indexPointer = 0; - for ($count = 0; $count < $indexTermCount; $count++) { - //$termPrefixLength = $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $termPrefixLength = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $termPrefixLength |= ($nbyte & 0x7F) << $shift; - } - - // $termSuffix = $tiiFile->readString(); - $nbyte = ord($data[$pos++]); - $len = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $len |= ($nbyte & 0x7F) << $shift; - } - if ($len == 0) { - $termSuffix = ''; - } else { - $termSuffix = substr($data, $pos, $len); - $pos += $len; - for ($count1 = 0; $count1 < $len; $count1++ ) { - if (( ord($termSuffix[$count1]) & 0xC0 ) == 0xC0) { - $addBytes = 1; - if (ord($termSuffix[$count1]) & 0x20 ) { - $addBytes++; - } - $termSuffix .= substr($data, $pos, $addBytes); - $pos += $addBytes; - $len += $addBytes; - - // Check for null character. Java2 encodes null character - // in two bytes. - if (ord($termSuffix[$count1]) == 0xC0 && - ord($termSuffix[$count1+1]) == 0x80 ) { - $termSuffix[$count1] = 0; - $termSuffix = substr($termSuffix,0,$count1+1) - . substr($termSuffix,$count1+2); - } - $count1 += $addBytes; - } - } - } - - // $termValue = Zend_Search_Lucene_Index_Term::getPrefix($prevTerm, $termPrefixLength) . $termSuffix; - $pb = 0; $pc = 0; - while ($pb < strlen($prevTerm) && $pc < $termPrefixLength) { - $charBytes = 1; - if ((ord($prevTerm[$pb]) & 0xC0) == 0xC0) { - $charBytes++; - if (ord($prevTerm[$pb]) & 0x20 ) { - $charBytes++; - if (ord($prevTerm[$pb]) & 0x10 ) { - $charBytes++; - } - } - } - - if ($pb + $charBytes > strlen($data)) { - // wrong character - break; - } - - $pc++; - $pb += $charBytes; - } - $termValue = substr($prevTerm, 0, $pb) . $termSuffix; - - // $termFieldNum = $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $termFieldNum = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $termFieldNum |= ($nbyte & 0x7F) << $shift; - } - - // $docFreq = $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $docFreq = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $docFreq |= ($nbyte & 0x7F) << $shift; - } - - // $freqPointer += $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $vint = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $vint |= ($nbyte & 0x7F) << $shift; - } - $freqPointer += $vint; - - // $proxPointer += $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $vint = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $vint |= ($nbyte & 0x7F) << $shift; - } - $proxPointer += $vint; - - if( $docFreq >= $skipInterval ) { - // $skipDelta = $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $vint = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $vint |= ($nbyte & 0x7F) << $shift; - } - $skipDelta = $vint; - } else { - $skipDelta = 0; - } - - // $indexPointer += $tiiFile->readVInt(); - $nbyte = ord($data[$pos++]); - $vint = $nbyte & 0x7F; - for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { - $nbyte = ord($data[$pos++]); - $vint |= ($nbyte & 0x7F) << $shift; - } - $indexPointer += $vint; - - - // $this->_termDictionary[] = new Zend_Search_Lucene_Index_Term($termValue, $termFieldNum); - $termDictionary[] = array($termFieldNum, $termValue); - - $termInfos[] = - // new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipDelta, $indexPointer); - array($docFreq, $freqPointer, $proxPointer, $skipDelta, $indexPointer); - - $prevTerm = $termValue; - } - - // Check special index entry mark - if ($termDictionary[0][0] != (int)0xFFFFFFFF) { - throw new Zend_Search_Lucene_Exception('Wrong TermInfoIndexFile file format'); - } else if (PHP_INT_SIZE > 4){ - // Treat 64-bit 0xFFFFFFFF as -1 - $termDictionary[0][0] = -1; - } - - return array(&$termDictionary, &$termInfos); - } -} - diff --git a/search/Zend/Search/Lucene/Index/FieldInfo.php b/search/Zend/Search/Lucene/Index/FieldInfo.php deleted file mode 100644 index 0a91872e3e5..00000000000 --- a/search/Zend/Search/Lucene/Index/FieldInfo.php +++ /dev/null @@ -1,45 +0,0 @@ -name = $name; - $this->isIndexed = $isIndexed; - $this->number = $number; - $this->storeTermVector = $storeTermVector; - } -} - diff --git a/search/Zend/Search/Lucene/Index/SegmentInfo.php b/search/Zend/Search/Lucene/Index/SegmentInfo.php deleted file mode 100644 index 5270ee60612..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentInfo.php +++ /dev/null @@ -1,1484 +0,0 @@ - $termValue - * [1] -> $termFieldNum - * - * Corresponding Zend_Search_Lucene_Index_TermInfo object stored in the $_termDictionaryInfos - * - * @var array - */ - private $_termDictionary; - - /** - * Term Dictionary Index TermInfos - * - * Array of arrays (Zend_Search_Lucene_Index_TermInfo objects are represented as arrays because - * of performance considerations) - * [0] -> $docFreq - * [1] -> $freqPointer - * [2] -> $proxPointer - * [3] -> $skipOffset - * [4] -> $indexPointer - * - * @var array - */ - private $_termDictionaryInfos; - - /** - * Segment fields. Array of Zend_Search_Lucene_Index_FieldInfo objects for this segment - * - * @var array - */ - private $_fields; - - /** - * Field positions in a dictionary. - * (Term dictionary contains filelds ordered by names) - * - * @var array - */ - private $_fieldsDicPositions; - - - /** - * Associative array where the key is the file name and the value is data offset - * in a compound segment file (.csf). - * - * @var array - */ - private $_segFiles; - - /** - * Associative array where the key is the file name and the value is file size (.csf). - * - * @var array - */ - private $_segFileSizes; - - /** - * Delete file generation number - * - * -1 means 'there is no delete file' - * 0 means pre-2.1 format delete file - * X specifies used delete file - * - * @var integer - */ - private $_delGen; - - /** - * Segment has single norms file - * - * If true then one .nrm file is used for all fields - * Otherwise .fN files are used - * - * @var boolean - */ - private $_hasSingleNormFile; - - /** - * Use compound segment file (*.cfs) to collect all other segment files - * (excluding .del files) - * - * @var boolean - */ - private $_isCompound; - - - /** - * File system adapter. - * - * @var Zend_Search_Lucene_Storage_Directory_Filesystem - */ - private $_directory; - - /** - * Normalization factors. - * An array fieldName => normVector - * normVector is a binary string. - * Each byte corresponds to an indexed document in a segment and - * encodes normalization factor (float value, encoded by - * Zend_Search_Lucene_Search_Similarity::encodeNorm()) - * - * @var array - */ - private $_norms = array(); - - /** - * List of deleted documents. - * bitset if bitset extension is loaded or array otherwise. - * - * @var mixed - */ - private $_deleted = null; - - /** - * $this->_deleted update flag - * - * @var boolean - */ - private $_deletedDirty = false; - - - /** - * Zend_Search_Lucene_Index_SegmentInfo constructor - * - * @param Zend_Search_Lucene_Storage_Directory $directory - * @param string $name - * @param integer $docCount - * @param integer $delGen - * @param boolean $isCompound - */ - public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name, $docCount, $delGen = 0, $hasSingleNormFile = false, $isCompound = null) - { - $this->_directory = $directory; - $this->_name = $name; - $this->_docCount = $docCount; - $this->_hasSingleNormFile = $hasSingleNormFile; - $this->_delGen = $delGen; - $this->_termDictionary = null; - - if (!is_null($isCompound)) { - $this->_isCompound = $isCompound; - } else { - // It's a pre-2.1 segment - // detect if it uses compond file - $this->_isCompound = true; - - try { - // Try to open compound file - $this->_directory->getFileObject($name . '.cfs'); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'is not readable') !== false) { - // Compound file is not found or is not readable - $this->_isCompound = false; - } else { - throw $e; - } - } - } - - $this->_segFiles = array(); - if ($this->_isCompound) { - $cfsFile = $this->_directory->getFileObject($name . '.cfs'); - $segFilesCount = $cfsFile->readVInt(); - - for ($count = 0; $count < $segFilesCount; $count++) { - $dataOffset = $cfsFile->readLong(); - if ($count != 0) { - $this->_segFileSizes[$fileName] = $dataOffset - end($this->_segFiles); - } - $fileName = $cfsFile->readString(); - $this->_segFiles[$fileName] = $dataOffset; - } - if ($count != 0) { - $this->_segFileSizes[$fileName] = $this->_directory->fileLength($name . '.cfs') - $dataOffset; - } - } - - $fnmFile = $this->openCompoundFile('.fnm'); - $fieldsCount = $fnmFile->readVInt(); - $fieldNames = array(); - $fieldNums = array(); - $this->_fields = array(); - for ($count=0; $count < $fieldsCount; $count++) { - $fieldName = $fnmFile->readString(); - $fieldBits = $fnmFile->readByte(); - $this->_fields[$count] = new Zend_Search_Lucene_Index_FieldInfo($fieldName, - $fieldBits & 1, - $count, - $fieldBits & 2 ); - if ($fieldBits & 0x10) { - // norms are omitted for the indexed field - $this->_norms[$count] = str_repeat(chr(Zend_Search_Lucene_Search_Similarity::encodeNorm(1.0)), $docCount); - } - - $fieldNums[$count] = $count; - $fieldNames[$count] = $fieldName; - } - array_multisort($fieldNames, SORT_ASC, SORT_REGULAR, $fieldNums); - $this->_fieldsDicPositions = array_flip($fieldNums); - - if ($this->_delGen == -1) { - // There is no delete file for this segment - // Do nothing - } else if ($this->_delGen == 0) { - // It's a segment with pre-2.1 format delete file - // Try to find delete file - try { - // '.del' files always stored in a separate file - // Segment compound is not used - $delFile = $this->_directory->getFileObject($this->_name . '.del'); - - $byteCount = $delFile->readInt(); - $byteCount = ceil($byteCount/8); - $bitCount = $delFile->readInt(); - - if ($bitCount == 0) { - $delBytes = ''; - } else { - $delBytes = $delFile->readBytes($byteCount); - } - - if (extension_loaded('bitset')) { - $this->_deleted = $delBytes; - } else { - $this->_deleted = array(); - for ($count = 0; $count < $byteCount; $count++) { - $byte = ord($delBytes{$count}); - for ($bit = 0; $bit < 8; $bit++) { - if ($byte & (1<<$bit)) { - $this->_deleted[$count*8 + $bit] = 1; - } - } - } - } - } catch(Zend_Search_Exception $e) { - if (strpos($e->getMessage(), 'is not readable') === false ) { - throw $e; - } - // There is no delete file - // Do nothing - } - } else { - // It's 2.1+ format delete file - $delFile = $this->_directory->getFileObject($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del'); - - $format = $delFile->readInt(); - - if ($format == (int)0xFFFFFFFF) { - /** - * @todo Implement support of DGaps delete file format. - * See Lucene file format for details - http://lucene.apache.org/java/docs/fileformats.html#Deleted%20Documents - */ - throw new Zend_Search_Lucene_Exception('DGaps delete file format is not supported. Optimize index to use it with Zend_Search_Lucene'); - } else { - // $format is actually byte count - $byteCount = ceil($format/8); - $bitCount = $delFile->readInt(); - - if ($bitCount == 0) { - $delBytes = ''; - } else { - $delBytes = $delFile->readBytes($byteCount); - } - - if (extension_loaded('bitset')) { - $this->_deleted = $delBytes; - } else { - $this->_deleted = array(); - for ($count = 0; $count < $byteCount; $count++) { - $byte = ord($delBytes{$count}); - for ($bit = 0; $bit < 8; $bit++) { - if ($byte & (1<<$bit)) { - $this->_deleted[$count*8 + $bit] = 1; - } - } - } - } - } - } - } - - /** - * Opens index file stoted within compound index file - * - * @param string $extension - * @param boolean $shareHandler - * @throws Zend_Search_Lucene_Exception - * @return Zend_Search_Lucene_Storage_File - */ - public function openCompoundFile($extension, $shareHandler = true) - { - $filename = $this->_name . $extension; - - if (!$this->_isCompound) { - return $this->_directory->getFileObject($filename, $shareHandler); - } - - if( !isset($this->_segFiles[$filename]) ) { - throw new Zend_Search_Lucene_Exception('Segment compound file doesn\'t contain ' - . $filename . ' file.' ); - } - - $file = $this->_directory->getFileObject($this->_name . '.cfs', $shareHandler); - $file->seek($this->_segFiles[$filename]); - return $file; - } - - /** - * Get compound file length - * - * @param string $extension - * @return integer - */ - public function compoundFileLength($extension) - { - $filename = $this->_name . $extension; - - // Try to get common file first - if ($this->_directory->fileExists($filename)) { - return $this->_directory->fileLength($filename); - } - - if( !isset($this->_segFileSizes[$filename]) ) { - throw new Zend_Search_Lucene_Exception('Index compound file doesn\'t contain ' - . $filename . ' file.' ); - } - - return $this->_segFileSizes[$filename]; - } - - /** - * Returns field index or -1 if field is not found - * - * @param string $fieldName - * @return integer - */ - public function getFieldNum($fieldName) - { - foreach( $this->_fields as $field ) { - if( $field->name == $fieldName ) { - return $field->number; - } - } - - return -1; - } - - /** - * Returns field info for specified field - * - * @param integer $fieldNum - * @return Zend_Search_Lucene_Index_FieldInfo - */ - public function getField($fieldNum) - { - return $this->_fields[$fieldNum]; - } - - /** - * Returns array of fields. - * if $indexed parameter is true, then returns only indexed fields. - * - * @param boolean $indexed - * @return array - */ - public function getFields($indexed = false) - { - $result = array(); - foreach( $this->_fields as $field ) { - if( (!$indexed) || $field->isIndexed ) { - $result[ $field->name ] = $field->name; - } - } - return $result; - } - - /** - * Returns array of FieldInfo objects. - * - * @return array - */ - public function getFieldInfos() - { - return $this->_fields; - } - - /** - * Returns actual deletions file generation number. - * - * @return integer - */ - public function getDelGen() - { - return $this->_delGen; - } - - /** - * Returns the total number of documents in this segment (including deleted documents). - * - * @return integer - */ - public function count() - { - return $this->_docCount; - } - - /** - * Returns number of deleted documents. - * - * @return integer - */ - private function _deletedCount() - { - if ($this->_deleted === null) { - return 0; - } - - if (extension_loaded('bitset')) { - return count(bitset_to_array($this->_deleted)); - } else { - return count($this->_deleted); - } - } - - /** - * Returns the total number of non-deleted documents in this segment. - * - * @return integer - */ - public function numDocs() - { - if ($this->hasDeletions()) { - return $this->_docCount - $this->_deletedCount(); - } else { - return $this->_docCount; - } - } - - /** - * Get field position in a fields dictionary - * - * @param integer $fieldNum - * @return integer - */ - private function _getFieldPosition($fieldNum) { - // Treat values which are not in a translation table as a 'direct value' - return isset($this->_fieldsDicPositions[$fieldNum]) ? - $this->_fieldsDicPositions[$fieldNum] : $fieldNum; - } - - /** - * Return segment name - * - * @return string - */ - public function getName() - { - return $this->_name; - } - - - /** - * TermInfo cache - * - * Size is 1024. - * Numbers are used instead of class constants because of performance considerations - * - * @var array - */ - private $_termInfoCache = array(); - - private function _cleanUpTermInfoCache() - { - // Clean 256 term infos - foreach ($this->_termInfoCache as $key => $termInfo) { - unset($this->_termInfoCache[$key]); - - // leave 768 last used term infos - if (count($this->_termInfoCache) == 768) { - break; - } - } - } - - /** - * Load terms dictionary index - * - * @throws Zend_Search_Lucene_Exception - */ - private function _loadDictionaryIndex() - { - // Check, if index is already serialized - if ($this->_directory->fileExists($this->_name . '.sti')) { - // Load serialized dictionary index data - $stiFile = $this->_directory->getFileObject($this->_name . '.sti'); - $stiFileData = $stiFile->readBytes($this->_directory->fileLength($this->_name . '.sti')); - - // Load dictionary index data - if (($unserializedData = @unserialize($stiFileData)) !== false) { - list($this->_termDictionary, $this->_termDictionaryInfos) = $unserializedData; - return; - } - } - - // Load data from .tii file and generate .sti file - - // Prefetch dictionary index data - $tiiFile = $this->openCompoundFile('.tii'); - $tiiFileData = $tiiFile->readBytes($this->compoundFileLength('.tii')); - - // Load dictionary index data - list($this->_termDictionary, $this->_termDictionaryInfos) = - Zend_Search_Lucene_Index_DictionaryLoader::load($tiiFileData); - - $stiFileData = serialize(array($this->_termDictionary, $this->_termDictionaryInfos)); - $stiFile = $this->_directory->createFile($this->_name . '.sti'); - $stiFile->writeBytes($stiFileData); - } - - /** - * Scans terms dictionary and returns term info - * - * @param Zend_Search_Lucene_Index_Term $term - * @return Zend_Search_Lucene_Index_TermInfo - */ - public function getTermInfo(Zend_Search_Lucene_Index_Term $term) - { - $termKey = $term->key(); - if (isset($this->_termInfoCache[$termKey])) { - $termInfo = $this->_termInfoCache[$termKey]; - - // Move termInfo to the end of cache - unset($this->_termInfoCache[$termKey]); - $this->_termInfoCache[$termKey] = $termInfo; - - return $termInfo; - } - - - if ($this->_termDictionary === null) { - $this->_loadDictionaryIndex(); - } - - $searchField = $this->getFieldNum($term->field); - - if ($searchField == -1) { - return null; - } - $searchDicField = $this->_getFieldPosition($searchField); - - // search for appropriate value in dictionary - $lowIndex = 0; - $highIndex = count($this->_termDictionary)-1; - while ($highIndex >= $lowIndex) { - // $mid = ($highIndex - $lowIndex)/2; - $mid = ($highIndex + $lowIndex) >> 1; - $midTerm = $this->_termDictionary[$mid]; - - $fieldNum = $this->_getFieldPosition($midTerm[0] /* field */); - $delta = $searchDicField - $fieldNum; - if ($delta == 0) { - $delta = strcmp($term->text, $midTerm[1] /* text */); - } - - if ($delta < 0) { - $highIndex = $mid-1; - } elseif ($delta > 0) { - $lowIndex = $mid+1; - } else { - // return $this->_termDictionaryInfos[$mid]; // We got it! - $a = $this->_termDictionaryInfos[$mid]; - $termInfo = new Zend_Search_Lucene_Index_TermInfo($a[0], $a[1], $a[2], $a[3], $a[4]); - - // Put loaded termInfo into cache - $this->_termInfoCache[$termKey] = $termInfo; - - return $termInfo; - } - } - - if ($highIndex == -1) { - // Term is out of the dictionary range - return null; - } - - $prevPosition = $highIndex; - $prevTerm = $this->_termDictionary[$prevPosition]; - $prevTermInfo = $this->_termDictionaryInfos[$prevPosition]; - - $tisFile = $this->openCompoundFile('.tis'); - $tiVersion = $tisFile->readInt(); - if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ && - $tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) { - throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format'); - } - - $termCount = $tisFile->readLong(); - $indexInterval = $tisFile->readInt(); - $skipInterval = $tisFile->readInt(); - if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) { - $maxSkipLevels = $tisFile->readInt(); - } - - $tisFile->seek($prevTermInfo[4] /* indexPointer */ - (($tiVersion == (int)0xFFFFFFFD)? 24 : 20) /* header size*/, SEEK_CUR); - - $termValue = $prevTerm[1] /* text */; - $termFieldNum = $prevTerm[0] /* field */; - $freqPointer = $prevTermInfo[1] /* freqPointer */; - $proxPointer = $prevTermInfo[2] /* proxPointer */; - for ($count = $prevPosition*$indexInterval + 1; - $count <= $termCount && - ( $this->_getFieldPosition($termFieldNum) < $searchDicField || - ($this->_getFieldPosition($termFieldNum) == $searchDicField && - strcmp($termValue, $term->text) < 0) ); - $count++) { - $termPrefixLength = $tisFile->readVInt(); - $termSuffix = $tisFile->readString(); - $termFieldNum = $tisFile->readVInt(); - $termValue = Zend_Search_Lucene_Index_Term::getPrefix($termValue, $termPrefixLength) . $termSuffix; - - $docFreq = $tisFile->readVInt(); - $freqPointer += $tisFile->readVInt(); - $proxPointer += $tisFile->readVInt(); - if( $docFreq >= $skipInterval ) { - $skipOffset = $tisFile->readVInt(); - } else { - $skipOffset = 0; - } - } - - if ($termFieldNum == $searchField && $termValue == $term->text) { - $termInfo = new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipOffset); - } else { - $termInfo = null; - } - - // Put loaded termInfo into cache - $this->_termInfoCache[$termKey] = $termInfo; - - if (count($this->_termInfoCache) == 1024) { - $this->_cleanUpTermInfoCache(); - } - - return $termInfo; - } - - /** - * Returns term freqs array. - * Result array structure: array(docId => freq, ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @param integer $shift - * @return Zend_Search_Lucene_Index_TermInfo - */ - public function termFreqs(Zend_Search_Lucene_Index_Term $term, $shift = 0) - { - $termInfo = $this->getTermInfo($term); - - if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { - return array(); - } - - $frqFile = $this->openCompoundFile('.frq'); - $frqFile->seek($termInfo->freqPointer,SEEK_CUR); - $result = array(); - $docId = 0; - - for ($count = 0; $count < $termInfo->docFreq; $count++) { - $docDelta = $frqFile->readVInt(); - if ($docDelta % 2 == 1) { - $docId += ($docDelta-1)/2; - $result[$shift + $docId] = 1; - } else { - $docId += $docDelta/2; - $result[$shift + $docId] = $frqFile->readVInt(); - } - } - - return $result; - } - - /** - * Returns term positions array. - * Result array structure: array(docId => array(pos1, pos2, ...), ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @param integer $shift - * @return Zend_Search_Lucene_Index_TermInfo - */ - public function termPositions(Zend_Search_Lucene_Index_Term $term, $shift = 0) - { - $termInfo = $this->getTermInfo($term); - - if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { - return array(); - } - - $frqFile = $this->openCompoundFile('.frq'); - $frqFile->seek($termInfo->freqPointer,SEEK_CUR); - $freqs = array(); - $docId = 0; - - for ($count = 0; $count < $termInfo->docFreq; $count++) { - $docDelta = $frqFile->readVInt(); - if ($docDelta % 2 == 1) { - $docId += ($docDelta-1)/2; - $freqs[$docId] = 1; - } else { - $docId += $docDelta/2; - $freqs[$docId] = $frqFile->readVInt(); - } - } - - $result = array(); - $prxFile = $this->openCompoundFile('.prx'); - $prxFile->seek($termInfo->proxPointer, SEEK_CUR); - foreach ($freqs as $docId => $freq) { - $termPosition = 0; - $positions = array(); - - for ($count = 0; $count < $freq; $count++ ) { - $termPosition += $prxFile->readVInt(); - $positions[] = $termPosition; - } - - $result[$shift + $docId] = $positions; - } - - return $result; - } - - /** - * Load normalizatin factors from an index file - * - * @param integer $fieldNum - * @throws Zend_Search_Lucene_Exception - */ - private function _loadNorm($fieldNum) - { - if ($this->_hasSingleNormFile) { - $normfFile = $this->openCompoundFile('.nrm'); - - $header = $normfFile->readBytes(3); - $headerFormatVersion = $normfFile->readByte(); - - if ($header != 'NRM' || $headerFormatVersion != (int)0xFF) { - throw new Zend_Search_Lucene_Exception('Wrong norms file format.'); - } - - foreach ($this->_fields as $fieldNum => $fieldInfo) { - if ($fieldInfo->isIndexed) { - $this->_norms[$fieldNum] = $normfFile->readBytes($this->_docCount); - } - } - } else { - $fFile = $this->openCompoundFile('.f' . $fieldNum); - $this->_norms[$fieldNum] = $fFile->readBytes($this->_docCount); - } - } - - /** - * Returns normalization factor for specified documents - * - * @param integer $id - * @param string $fieldName - * @return float - */ - public function norm($id, $fieldName) - { - $fieldNum = $this->getFieldNum($fieldName); - - if ( !($this->_fields[$fieldNum]->isIndexed) ) { - return null; - } - - if (!isset($this->_norms[$fieldNum])) { - $this->_loadNorm($fieldNum); - } - - return Zend_Search_Lucene_Search_Similarity::decodeNorm( ord($this->_norms[$fieldNum]{$id}) ); - } - - /** - * Returns norm vector, encoded in a byte string - * - * @param string $fieldName - * @return string - */ - public function normVector($fieldName) - { - $fieldNum = $this->getFieldNum($fieldName); - - if ($fieldNum == -1 || !($this->_fields[$fieldNum]->isIndexed)) { - $similarity = Zend_Search_Lucene_Search_Similarity::getDefault(); - - return str_repeat(chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )), - $this->_docCount); - } - - if (!isset($this->_norms[$fieldNum])) { - $this->_loadNorm($fieldNum); - } - - return $this->_norms[$fieldNum]; - } - - - /** - * Returns true if any documents have been deleted from this index segment. - * - * @return boolean - */ - public function hasDeletions() - { - return $this->_deleted !== null; - } - - - /** - * Returns true if segment has single norms file. - * - * @return boolean - */ - public function hasSingleNormFile() - { - return $this->_hasSingleNormFile ? 1 : 0; - } - - /** - * Returns true if segment is stored using compound segment file. - * - * @return boolean - */ - public function isCompound() - { - return $this->_isCompound ? 1 : 0; - } - - /** - * Deletes a document from the index segment. - * $id is an internal document id - * - * @param integer - */ - public function delete($id) - { - $this->_deletedDirty = true; - - if (extension_loaded('bitset')) { - if ($this->_deleted === null) { - $this->_deleted = bitset_empty($id); - } - bitset_incl($this->_deleted, $id); - } else { - if ($this->_deleted === null) { - $this->_deleted = array(); - } - - $this->_deleted[$id] = 1; - } - } - - /** - * Checks, that document is deleted - * - * @param integer - * @return boolean - */ - public function isDeleted($id) - { - if ($this->_deleted === null) { - return false; - } - - if (extension_loaded('bitset')) { - return bitset_in($this->_deleted, $id); - } else { - return isset($this->_deleted[$id]); - } - } - - - /** - * Write changes if it's necessary. - */ - public function writeChanges() - { - if (!$this->_deletedDirty) { - return; - } - - if (extension_loaded('bitset')) { - $delBytes = $this->_deleted; - $bitCount = count(bitset_to_array($delBytes)); - } else { - $byteCount = floor($this->_docCount/8)+1; - $delBytes = str_repeat(chr(0), $byteCount); - for ($count = 0; $count < $byteCount; $count++) { - $byte = 0; - for ($bit = 0; $bit < 8; $bit++) { - if (isset($this->_deleted[$count*8 + $bit])) { - $byte |= (1<<$bit); - } - } - $delBytes{$count} = chr($byte); - } - $bitCount = count($this->_deleted); - } - - - // Get new generation number - Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); - - $delFileList = array(); - foreach ($this->_directory->fileList() as $file) { - if ($file == $this->_name . '.del') { - // Matches .del file name - $delFileList[] = 0; - } else if (preg_match('/^' . $this->_name . '_([a-zA-Z0-9]+)\.del$/i', $file, $matches)) { - // Matches _NNN.del file names - $delFileList[] = (int)base_convert($matches[1], 36, 10); - } - } - - if (count($delFileList) == 0) { - // There is no deletions file for current segment in the directory - // Set detetions file generation number to 1 - $this->_delGen = 1; - } else { - // There are some deletions files for current segment in the directory - // Set detetions file generation number to the highest + 1 - $this->_delGen = max($delFileList) + 1; - } - - $delFile = $this->_directory->createFile($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del'); - - Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); - - - $delFile->writeInt($this->_docCount); - $delFile->writeInt($bitCount); - $delFile->writeBytes($delBytes); - - $this->_deletedDirty = false; - } - - - - /** - * Term Dictionary File object for stream like terms reading - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_tisFile = null; - - /** - * Actual offset of the .tis file data - * - * @var integer - */ - private $_tisFileOffset; - - /** - * Frequencies File object for stream like terms reading - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_frqFile = null; - - /** - * Actual offset of the .frq file data - * - * @var integer - */ - private $_frqFileOffset; - - /** - * Positions File object for stream like terms reading - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_prxFile = null; - - /** - * Actual offset of the .prx file in the compound file - * - * @var integer - */ - private $_prxFileOffset; - - - /** - * Actual number of terms in term stream - * - * @var integer - */ - private $_termCount = 0; - - /** - * Overall number of terms in term stream - * - * @var integer - */ - private $_termNum = 0; - - /** - * Segment index interval - * - * @var integer - */ - private $_indexInterval; - - /** - * Segment skip interval - * - * @var integer - */ - private $_skipInterval; - - /** - * Last TermInfo in a terms stream - * - * @var Zend_Search_Lucene_Index_TermInfo - */ - private $_lastTermInfo = null; - - /** - * Last Term in a terms stream - * - * @var Zend_Search_Lucene_Index_Term - */ - private $_lastTerm = null; - - /** - * Map of the document IDs - * Used to get new docID after removing deleted documents. - * It's not very effective from memory usage point of view, - * but much more faster, then other methods - * - * @var array|null - */ - private $_docMap = null; - - /** - * An array of all term positions in the documents. - * Array structure: array( docId => array( pos1, pos2, ...), ...) - * - * Is set to null if term positions loading has to be skipped - * - * @var array|null - */ - private $_lastTermPositions; - - - /** - * Terms scan mode - * - * Values: - * - * self::SM_TERMS_ONLY - terms are scanned, no additional info is retrieved - * self::SM_MERGE_INFO - terms are scanned, frequency and position info is retrieved - * document numbers are compacted (shifted if segment has deleted documents) - * - * @var integer - */ - private $_termsScanMode; - - /** Scan modes */ - const SM_TERMS_ONLY = 0; // terms are scanned, no additional info is retrieved - const SM_FULL_INFO = 1; // terms are scanned, frequency and position info is retrieved - const SM_MERGE_INFO = 2; // terms are scanned, frequency and position info is retrieved - // document numbers are compacted (shifted if segment contains deleted documents) - - /** - * Reset terms stream - * - * $startId - id for the fist document - * $compact - remove deleted documents - * - * Returns start document id for the next segment - * - * @param integer $startId - * @param integer $mode - * @throws Zend_Search_Lucene_Exception - * @return integer - */ - public function reset($startId = 0, $mode = self::SM_TERMS_ONLY) - { - if ($this->_tisFile !== null) { - $this->_tisFile = null; - } - - $this->_tisFile = $this->openCompoundFile('.tis', false); - $this->_tisFileOffset = $this->_tisFile->tell(); - - $tiVersion = $this->_tisFile->readInt(); - if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ && - $tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) { - throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format'); - } - - $this->_termCount = - $this->_termNum = $this->_tisFile->readLong(); // Read terms count - $this->_indexInterval = $this->_tisFile->readInt(); // Read Index interval - $this->_skipInterval = $this->_tisFile->readInt(); // Read skip interval - if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) { - $maxSkipLevels = $this->_tisFile->readInt(); - } - - if ($this->_frqFile !== null) { - $this->_frqFile = null; - } - if ($this->_prxFile !== null) { - $this->_prxFile = null; - } - $this->_docMap = array(); - - $this->_lastTerm = new Zend_Search_Lucene_Index_Term('', -1); - $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo(0, 0, 0, 0); - $this->_lastTermPositions = null; - - $this->_termsScanMode = $mode; - - switch ($mode) { - case self::SM_TERMS_ONLY: - // Do nothing - break; - - case self::SM_FULL_INFO: - // break intentionally omitted - case self::SM_MERGE_INFO: - $this->_frqFile = $this->openCompoundFile('.frq', false); - $this->_frqFileOffset = $this->_frqFile->tell(); - - $this->_prxFile = $this->openCompoundFile('.prx', false); - $this->_prxFileOffset = $this->_prxFile->tell(); - - for ($count = 0; $count < $this->_docCount; $count++) { - if (!$this->isDeleted($count)) { - $this->_docMap[$count] = $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $count); - } - } - break; - - default: - throw new Zend_Search_Lucene_Exception('Wrong terms scaning mode specified.'); - break; - } - - - $this->nextTerm(); - return $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $this->_docCount); - } - - - /** - * Skip terms stream up to specified term preffix. - * - * Prefix contains fully specified field info and portion of searched term - * - * @param Zend_Search_Lucene_Index_Term $prefix - * @throws Zend_Search_Lucene_Exception - */ - public function skipTo(Zend_Search_Lucene_Index_Term $prefix) - { - if ($this->_termDictionary === null) { - $this->_loadDictionaryIndex(); - } - - $searchField = $this->getFieldNum($prefix->field); - - if ($searchField == -1) { - /** - * Field is not presented in this segment - * Go to the end of dictionary - */ - $this->_tisFile = null; - $this->_frqFile = null; - $this->_prxFile = null; - - $this->_lastTerm = null; - $this->_lastTermInfo = null; - $this->_lastTermPositions = null; - - return; - } - $searchDicField = $this->_getFieldPosition($searchField); - - // search for appropriate value in dictionary - $lowIndex = 0; - $highIndex = count($this->_termDictionary)-1; - while ($highIndex >= $lowIndex) { - // $mid = ($highIndex - $lowIndex)/2; - $mid = ($highIndex + $lowIndex) >> 1; - $midTerm = $this->_termDictionary[$mid]; - - $fieldNum = $this->_getFieldPosition($midTerm[0] /* field */); - $delta = $searchDicField - $fieldNum; - if ($delta == 0) { - $delta = strcmp($prefix->text, $midTerm[1] /* text */); - } - - if ($delta < 0) { - $highIndex = $mid-1; - } elseif ($delta > 0) { - $lowIndex = $mid+1; - } else { - // We have reached term we are looking for - break; - } - } - - if ($highIndex == -1) { - // Term is out of the dictionary range - $this->_tisFile = null; - $this->_frqFile = null; - $this->_prxFile = null; - - $this->_lastTerm = null; - $this->_lastTermInfo = null; - $this->_lastTermPositions = null; - - return; - } - - $prevPosition = $highIndex; - $prevTerm = $this->_termDictionary[$prevPosition]; - $prevTermInfo = $this->_termDictionaryInfos[$prevPosition]; - - if ($this->_tisFile === null) { - // The end of terms stream is reached and terms dictionary file is closed - // Perform mini-reset operation - $this->_tisFile = $this->openCompoundFile('.tis', false); - - if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { - $this->_frqFile = $this->openCompoundFile('.frq', false); - $this->_prxFile = $this->openCompoundFile('.prx', false); - } - } - $this->_tisFile->seek($this->_tisFileOffset + $prevTermInfo[4], SEEK_SET); - - $this->_lastTerm = new Zend_Search_Lucene_Index_Term($prevTerm[1] /* text */, - ($prevTerm[0] == -1) ? '' : $this->_fields[$prevTerm[0] /* field */]->name); - $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($prevTermInfo[0] /* docFreq */, - $prevTermInfo[1] /* freqPointer */, - $prevTermInfo[2] /* proxPointer */, - $prevTermInfo[3] /* skipOffset */); - $this->_termCount = $this->_termNum - $prevPosition*$this->_indexInterval; - - if ($highIndex == 0) { - // skip start entry - $this->nextTerm(); - } else if ($prefix->field == $this->_lastTerm->field && $prefix->text == $this->_lastTerm->text) { - // We got exact match in the dictionary index - - if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { - $this->_lastTermPositions = array(); - - $this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET); - $freqs = array(); $docId = 0; - for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) { - $docDelta = $this->_frqFile->readVInt(); - if( $docDelta % 2 == 1 ) { - $docId += ($docDelta-1)/2; - $freqs[ $docId ] = 1; - } else { - $docId += $docDelta/2; - $freqs[ $docId ] = $this->_frqFile->readVInt(); - } - } - - $this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET); - foreach ($freqs as $docId => $freq) { - $termPosition = 0; $positions = array(); - - for ($count = 0; $count < $freq; $count++ ) { - $termPosition += $this->_prxFile->readVInt(); - $positions[] = $termPosition; - } - - if (isset($this->_docMap[$docId])) { - $this->_lastTermPositions[$this->_docMap[$docId]] = $positions; - } - } - } - - return; - } - - // Search term matching specified prefix - while ($this->_lastTerm !== null) { - if ( strcmp($this->_lastTerm->field, $prefix->field) > 0 || - ($prefix->field == $this->_lastTerm->field && strcmp($this->_lastTerm->text, $prefix->text) >= 0) ) { - // Current term matches or greate than the pattern - return; - } - - $this->nextTerm(); - } - } - - - /** - * Scans terms dictionary and returns next term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function nextTerm() - { - if ($this->_tisFile === null || $this->_termCount == 0) { - $this->_lastTerm = null; - $this->_lastTermInfo = null; - $this->_lastTermPositions = null; - $this->_docMap = null; - - // may be necessary for "empty" segment - $this->_tisFile = null; - $this->_frqFile = null; - $this->_prxFile = null; - - return null; - } - - $termPrefixLength = $this->_tisFile->readVInt(); - $termSuffix = $this->_tisFile->readString(); - $termFieldNum = $this->_tisFile->readVInt(); - $termValue = Zend_Search_Lucene_Index_Term::getPrefix($this->_lastTerm->text, $termPrefixLength) . $termSuffix; - - $this->_lastTerm = new Zend_Search_Lucene_Index_Term($termValue, $this->_fields[$termFieldNum]->name); - - $docFreq = $this->_tisFile->readVInt(); - $freqPointer = $this->_lastTermInfo->freqPointer + $this->_tisFile->readVInt(); - $proxPointer = $this->_lastTermInfo->proxPointer + $this->_tisFile->readVInt(); - if ($docFreq >= $this->_skipInterval) { - $skipOffset = $this->_tisFile->readVInt(); - } else { - $skipOffset = 0; - } - - $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipOffset); - - - if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { - $this->_lastTermPositions = array(); - - $this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET); - $freqs = array(); $docId = 0; - for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) { - $docDelta = $this->_frqFile->readVInt(); - if( $docDelta % 2 == 1 ) { - $docId += ($docDelta-1)/2; - $freqs[ $docId ] = 1; - } else { - $docId += $docDelta/2; - $freqs[ $docId ] = $this->_frqFile->readVInt(); - } - } - - $this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET); - foreach ($freqs as $docId => $freq) { - $termPosition = 0; $positions = array(); - - for ($count = 0; $count < $freq; $count++ ) { - $termPosition += $this->_prxFile->readVInt(); - $positions[] = $termPosition; - } - - if (isset($this->_docMap[$docId])) { - $this->_lastTermPositions[$this->_docMap[$docId]] = $positions; - } - } - } - - $this->_termCount--; - if ($this->_termCount == 0) { - $this->_tisFile = null; - $this->_frqFile = null; - $this->_prxFile = null; - } - - return $this->_lastTerm; - } - - /** - * Close terms stream - * - * Should be used for resources clean up if stream is not read up to the end - */ - public function closeTermsStream() - { - $this->_tisFile = null; - $this->_frqFile = null; - $this->_prxFile = null; - - $this->_lastTerm = null; - $this->_lastTermInfo = null; - $this->_lastTermPositions = null; - - $this->_docMap = null; - } - - - /** - * Returns term in current position - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function currentTerm() - { - return $this->_lastTerm; - } - - - /** - * Returns an array of all term positions in the documents. - * Return array structure: array( docId => array( pos1, pos2, ...), ...) - * - * @return array - */ - public function currentTermPositions() - { - return $this->_lastTermPositions; - } -} - diff --git a/search/Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php b/search/Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php deleted file mode 100644 index 233d7987545..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php +++ /dev/null @@ -1,53 +0,0 @@ -currentTerm()->key(), $segmentInfo2->currentTerm()->key()) < 0; - } - -} diff --git a/search/Zend/Search/Lucene/Index/SegmentMerger.php b/search/Zend/Search/Lucene/Index/SegmentMerger.php deleted file mode 100644 index 97ce4bf6d80..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentMerger.php +++ /dev/null @@ -1,273 +0,0 @@ -][] => - * - * @var array - */ - private $_fieldsMap = array(); - - - - /** - * Object constructor. - * - * Creates new segment merger with $directory as target to merge segments into - * and $name as a name of new segment - * - * @param Zend_Search_Lucene_Storage_Directory $directory - * @param string $name - */ - public function __construct($directory, $name) - { - $this->_writer = new Zend_Search_Lucene_Index_SegmentWriter_StreamWriter($directory, $name); - } - - - /** - * Add segmnet to a collection of segments to be merged - * - * @param Zend_Search_Lucene_Index_SegmentInfo $segment - */ - public function addSource(Zend_Search_Lucene_Index_SegmentInfo $segmentInfo) - { - $this->_segmentInfos[$segmentInfo->getName()] = $segmentInfo; - } - - - /** - * Do merge. - * - * Returns number of documents in newly created segment - * - * @return Zend_Search_Lucene_Index_SegmentInfo - * @throws Zend_Search_Lucene_Exception - */ - public function merge() - { - if ($this->_mergeDone) { - throw new Zend_Search_Lucene_Exception('Merge is already done.'); - } - - if (count($this->_segmentInfos) < 1) { - throw new Zend_Search_Lucene_Exception('Wrong number of segments to be merged (' - . count($this->_segmentInfos) - . ').'); - } - - $this->_mergeFields(); - $this->_mergeNorms(); - $this->_mergeStoredFields(); - $this->_mergeTerms(); - - $this->_mergeDone = true; - - return $this->_writer->close(); - } - - - /** - * Merge fields information - */ - private function _mergeFields() - { - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - foreach ($segmentInfo->getFieldInfos() as $fieldInfo) { - $this->_fieldsMap[$segName][$fieldInfo->number] = $this->_writer->addFieldInfo($fieldInfo); - } - } - } - - /** - * Merge field's normalization factors - */ - private function _mergeNorms() - { - foreach ($this->_writer->getFieldInfos() as $fieldInfo) { - if ($fieldInfo->isIndexed) { - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - if ($segmentInfo->hasDeletions()) { - $srcNorm = $segmentInfo->normVector($fieldInfo->name); - $norm = ''; - $docs = $segmentInfo->count(); - for ($count = 0; $count < $docs; $count++) { - if (!$segmentInfo->isDeleted($count)) { - $norm .= $srcNorm[$count]; - } - } - $this->_writer->addNorm($fieldInfo->name, $norm); - } else { - $this->_writer->addNorm($fieldInfo->name, $segmentInfo->normVector($fieldInfo->name)); - } - } - } - } - } - - /** - * Merge fields information - */ - private function _mergeStoredFields() - { - $this->_docCount = 0; - - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - $fdtFile = $segmentInfo->openCompoundFile('.fdt'); - - for ($count = 0; $count < $segmentInfo->count(); $count++) { - $fieldCount = $fdtFile->readVInt(); - $storedFields = array(); - - for ($count2 = 0; $count2 < $fieldCount; $count2++) { - $fieldNum = $fdtFile->readVInt(); - $bits = $fdtFile->readByte(); - $fieldInfo = $segmentInfo->getField($fieldNum); - - if (!($bits & 2)) { // Text data - $storedFields[] = - new Zend_Search_Lucene_Field($fieldInfo->name, - $fdtFile->readString(), - 'UTF-8', - true, - $fieldInfo->isIndexed, - $bits & 1 ); - } else { // Binary data - $storedFields[] = - new Zend_Search_Lucene_Field($fieldInfo->name, - $fdtFile->readBinary(), - '', - true, - $fieldInfo->isIndexed, - $bits & 1, - true); - } - } - - if (!$segmentInfo->isDeleted($count)) { - $this->_docCount++; - $this->_writer->addStoredFields($storedFields); - } - } - } - } - - - /** - * Merge fields information - */ - private function _mergeTerms() - { - $segmentInfoQueue = new Zend_Search_Lucene_Index_SegmentInfoPriorityQueue(); - - $segmentStartId = 0; - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - $segmentStartId = $segmentInfo->reset($segmentStartId, Zend_Search_Lucene_Index_SegmentInfo::SM_MERGE_INFO); - - // Skip "empty" segments - if ($segmentInfo->currentTerm() !== null) { - $segmentInfoQueue->put($segmentInfo); - } - } - - $this->_writer->initializeDictionaryFiles(); - - $termDocs = array(); - while (($segmentInfo = $segmentInfoQueue->pop()) !== null) { - // Merge positions array - $termDocs += $segmentInfo->currentTermPositions(); - - if ($segmentInfoQueue->top() === null || - $segmentInfoQueue->top()->currentTerm()->key() != - $segmentInfo->currentTerm()->key()) { - // We got new term - ksort($termDocs, SORT_NUMERIC); - - // Add term if it's contained in any document - if (count($termDocs) > 0) { - $this->_writer->addTerm($segmentInfo->currentTerm(), $termDocs); - } - $termDocs = array(); - } - - $segmentInfo->nextTerm(); - // check, if segment dictionary is finished - if ($segmentInfo->currentTerm() !== null) { - // Put segment back into the priority queue - $segmentInfoQueue->put($segmentInfo); - } - } - - $this->_writer->closeDictionaryFiles(); - } -} diff --git a/search/Zend/Search/Lucene/Index/SegmentWriter.php b/search/Zend/Search/Lucene/Index/SegmentWriter.php deleted file mode 100644 index 21e9a04d0de..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentWriter.php +++ /dev/null @@ -1,630 +0,0 @@ - normVector - * normVector is a binary string. - * Each byte corresponds to an indexed document in a segment and - * encodes normalization factor (float value, encoded by - * Zend_Search_Lucene_Search_Similarity::encodeNorm()) - * - * @var array - */ - protected $_norms = array(); - - - /** - * '.fdx' file - Stored Fields, the field index. - * - * @var Zend_Search_Lucene_Storage_File - */ - protected $_fdxFile = null; - - /** - * '.fdt' file - Stored Fields, the field data. - * - * @var Zend_Search_Lucene_Storage_File - */ - protected $_fdtFile = null; - - - /** - * Object constructor. - * - * @param Zend_Search_Lucene_Storage_Directory $directory - * @param string $name - */ - public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name) - { - $this->_directory = $directory; - $this->_name = $name; - } - - - /** - * Add field to the segment - * - * Returns actual field number - * - * @param Zend_Search_Lucene_Field $field - * @return integer - */ - public function addField(Zend_Search_Lucene_Field $field) - { - if (!isset($this->_fields[$field->name])) { - $fieldNumber = count($this->_fields); - $this->_fields[$field->name] = - new Zend_Search_Lucene_Index_FieldInfo($field->name, - $field->isIndexed, - $fieldNumber, - $field->storeTermVector); - - return $fieldNumber; - } else { - $this->_fields[$field->name]->isIndexed |= $field->isIndexed; - $this->_fields[$field->name]->storeTermVector |= $field->storeTermVector; - - return $this->_fields[$field->name]->number; - } - } - - /** - * Add fieldInfo to the segment - * - * Returns actual field number - * - * @param Zend_Search_Lucene_Index_FieldInfo $fieldInfo - * @return integer - */ - public function addFieldInfo(Zend_Search_Lucene_Index_FieldInfo $fieldInfo) - { - if (!isset($this->_fields[$fieldInfo->name])) { - $fieldNumber = count($this->_fields); - $this->_fields[$fieldInfo->name] = - new Zend_Search_Lucene_Index_FieldInfo($fieldInfo->name, - $fieldInfo->isIndexed, - $fieldNumber, - $fieldInfo->storeTermVector); - - return $fieldNumber; - } else { - $this->_fields[$fieldInfo->name]->isIndexed |= $fieldInfo->isIndexed; - $this->_fields[$fieldInfo->name]->storeTermVector |= $fieldInfo->storeTermVector; - - return $this->_fields[$fieldInfo->name]->number; - } - } - - /** - * Returns array of FieldInfo objects. - * - * @return array - */ - public function getFieldInfos() - { - return $this->_fields; - } - - /** - * Add stored fields information - * - * @param array $storedFields array of Zend_Search_Lucene_Field objects - */ - public function addStoredFields($storedFields) - { - if (!isset($this->_fdxFile)) { - $this->_fdxFile = $this->_directory->createFile($this->_name . '.fdx'); - $this->_fdtFile = $this->_directory->createFile($this->_name . '.fdt'); - - $this->_files[] = $this->_name . '.fdx'; - $this->_files[] = $this->_name . '.fdt'; - } - - $this->_fdxFile->writeLong($this->_fdtFile->tell()); - $this->_fdtFile->writeVInt(count($storedFields)); - foreach ($storedFields as $field) { - $this->_fdtFile->writeVInt($this->_fields[$field->name]->number); - $fieldBits = ($field->isTokenized ? 0x01 : 0x00) | - ($field->isBinary ? 0x02 : 0x00) | - 0x00; /* 0x04 - third bit, compressed (ZLIB) */ - $this->_fdtFile->writeByte($fieldBits); - if ($field->isBinary) { - $this->_fdtFile->writeVInt(strlen($field->value)); - $this->_fdtFile->writeBytes($field->value); - } else { - $this->_fdtFile->writeString($field->getUtf8Value()); - } - } - - $this->_docCount++; - } - - /** - * Returns the total number of documents in this segment. - * - * @return integer - */ - public function count() - { - return $this->_docCount; - } - - /** - * Return segment name - * - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * Dump Field Info (.fnm) segment file - */ - protected function _dumpFNM() - { - $fnmFile = $this->_directory->createFile($this->_name . '.fnm'); - $fnmFile->writeVInt(count($this->_fields)); - - $nrmFile = $this->_directory->createFile($this->_name . '.nrm'); - // Write header - $nrmFile->writeBytes('NRM'); - // Write format specifier - $nrmFile->writeByte((int)0xFF); - - foreach ($this->_fields as $field) { - $fnmFile->writeString($field->name); - $fnmFile->writeByte(($field->isIndexed ? 0x01 : 0x00) | - ($field->storeTermVector ? 0x02 : 0x00) -// not supported yet 0x04 /* term positions are stored with the term vectors */ | -// not supported yet 0x08 /* term offsets are stored with the term vectors */ | - ); - - if ($field->isIndexed) { - // pre-2.1 index mode (not used now) - // $normFileName = $this->_name . '.f' . $field->number; - // $fFile = $this->_directory->createFile($normFileName); - // $fFile->writeBytes($this->_norms[$field->name]); - // $this->_files[] = $normFileName; - - $nrmFile->writeBytes($this->_norms[$field->name]); - } - } - - $this->_files[] = $this->_name . '.fnm'; - $this->_files[] = $this->_name . '.nrm'; - } - - - - /** - * Term Dictionary file - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_tisFile = null; - - /** - * Term Dictionary index file - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_tiiFile = null; - - /** - * Frequencies file - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_frqFile = null; - - /** - * Positions file - * - * @var Zend_Search_Lucene_Storage_File - */ - private $_prxFile = null; - - /** - * Number of written terms - * - * @var integer - */ - private $_termCount; - - - /** - * Last saved term - * - * @var Zend_Search_Lucene_Index_Term - */ - private $_prevTerm; - - /** - * Last saved term info - * - * @var Zend_Search_Lucene_Index_TermInfo - */ - private $_prevTermInfo; - - /** - * Last saved index term - * - * @var Zend_Search_Lucene_Index_Term - */ - private $_prevIndexTerm; - - /** - * Last saved index term info - * - * @var Zend_Search_Lucene_Index_TermInfo - */ - private $_prevIndexTermInfo; - - /** - * Last term dictionary file position - * - * @var integer - */ - private $_lastIndexPosition; - - /** - * Create dicrionary, frequency and positions files and write necessary headers - */ - public function initializeDictionaryFiles() - { - $this->_tisFile = $this->_directory->createFile($this->_name . '.tis'); - $this->_tisFile->writeInt((int)0xFFFFFFFD); - $this->_tisFile->writeLong(0 /* dummy data for terms count */); - $this->_tisFile->writeInt(self::$indexInterval); - $this->_tisFile->writeInt(self::$skipInterval); - $this->_tisFile->writeInt(self::$maxSkipLevels); - - $this->_tiiFile = $this->_directory->createFile($this->_name . '.tii'); - $this->_tiiFile->writeInt((int)0xFFFFFFFD); - $this->_tiiFile->writeLong(0 /* dummy data for terms count */); - $this->_tiiFile->writeInt(self::$indexInterval); - $this->_tiiFile->writeInt(self::$skipInterval); - $this->_tiiFile->writeInt(self::$maxSkipLevels); - - /** Dump dictionary header */ - $this->_tiiFile->writeVInt(0); // preffix length - $this->_tiiFile->writeString(''); // suffix - $this->_tiiFile->writeInt((int)0xFFFFFFFF); // field number - $this->_tiiFile->writeByte((int)0x0F); - $this->_tiiFile->writeVInt(0); // DocFreq - $this->_tiiFile->writeVInt(0); // FreqDelta - $this->_tiiFile->writeVInt(0); // ProxDelta - $this->_tiiFile->writeVInt(24); // IndexDelta - - $this->_frqFile = $this->_directory->createFile($this->_name . '.frq'); - $this->_prxFile = $this->_directory->createFile($this->_name . '.prx'); - - $this->_files[] = $this->_name . '.tis'; - $this->_files[] = $this->_name . '.tii'; - $this->_files[] = $this->_name . '.frq'; - $this->_files[] = $this->_name . '.prx'; - - $this->_prevTerm = null; - $this->_prevTermInfo = null; - $this->_prevIndexTerm = null; - $this->_prevIndexTermInfo = null; - $this->_lastIndexPosition = 24; - $this->_termCount = 0; - - } - - /** - * Add term - * - * Term positions is an array( docId => array(pos1, pos2, pos3, ...), ... ) - * - * @param Zend_Search_Lucene_Index_Term $termEntry - * @param array $termDocs - */ - public function addTerm($termEntry, $termDocs) - { - $freqPointer = $this->_frqFile->tell(); - $proxPointer = $this->_prxFile->tell(); - - $prevDoc = 0; - foreach ($termDocs as $docId => $termPositions) { - $docDelta = ($docId - $prevDoc)*2; - $prevDoc = $docId; - if (count($termPositions) > 1) { - $this->_frqFile->writeVInt($docDelta); - $this->_frqFile->writeVInt(count($termPositions)); - } else { - $this->_frqFile->writeVInt($docDelta + 1); - } - - $prevPosition = 0; - foreach ($termPositions as $position) { - $this->_prxFile->writeVInt($position - $prevPosition); - $prevPosition = $position; - } - } - - if (count($termDocs) >= self::$skipInterval) { - /** - * @todo Write Skip Data to a freq file. - * It's not used now, but make index more optimal - */ - $skipOffset = $this->_frqFile->tell() - $freqPointer; - } else { - $skipOffset = 0; - } - - $term = new Zend_Search_Lucene_Index_Term($termEntry->text, - $this->_fields[$termEntry->field]->number); - $termInfo = new Zend_Search_Lucene_Index_TermInfo(count($termDocs), - $freqPointer, $proxPointer, $skipOffset); - - $this->_dumpTermDictEntry($this->_tisFile, $this->_prevTerm, $term, $this->_prevTermInfo, $termInfo); - - if (($this->_termCount + 1) % self::$indexInterval == 0) { - $this->_dumpTermDictEntry($this->_tiiFile, $this->_prevIndexTerm, $term, $this->_prevIndexTermInfo, $termInfo); - - $indexPosition = $this->_tisFile->tell(); - $this->_tiiFile->writeVInt($indexPosition - $this->_lastIndexPosition); - $this->_lastIndexPosition = $indexPosition; - - } - $this->_termCount++; - } - - /** - * Close dictionary - */ - public function closeDictionaryFiles() - { - $this->_tisFile->seek(4); - $this->_tisFile->writeLong($this->_termCount); - - $this->_tiiFile->seek(4); - $this->_tiiFile->writeLong(ceil(($this->_termCount + 2)/self::$indexInterval)); - } - - - /** - * Dump Term Dictionary segment file entry. - * Used to write entry to .tis or .tii files - * - * @param Zend_Search_Lucene_Storage_File $dicFile - * @param Zend_Search_Lucene_Index_Term $prevTerm - * @param Zend_Search_Lucene_Index_Term $term - * @param Zend_Search_Lucene_Index_TermInfo $prevTermInfo - * @param Zend_Search_Lucene_Index_TermInfo $termInfo - */ - protected function _dumpTermDictEntry(Zend_Search_Lucene_Storage_File $dicFile, - &$prevTerm, Zend_Search_Lucene_Index_Term $term, - &$prevTermInfo, Zend_Search_Lucene_Index_TermInfo $termInfo) - { - if (isset($prevTerm) && $prevTerm->field == $term->field) { - $matchedBytes = 0; - $maxBytes = min(strlen($prevTerm->text), strlen($term->text)); - while ($matchedBytes < $maxBytes && - $prevTerm->text[$matchedBytes] == $term->text[$matchedBytes]) { - $matchedBytes++; - } - - // Calculate actual matched UTF-8 pattern - $prefixBytes = 0; - $prefixChars = 0; - while ($prefixBytes < $matchedBytes) { - $charBytes = 1; - if ((ord($term->text[$prefixBytes]) & 0xC0) == 0xC0) { - $charBytes++; - if (ord($term->text[$prefixBytes]) & 0x20 ) { - $charBytes++; - if (ord($term->text[$prefixBytes]) & 0x10 ) { - $charBytes++; - } - } - } - - if ($prefixBytes + $charBytes > $matchedBytes) { - // char crosses matched bytes boundary - // skip char - break; - } - - $prefixChars++; - $prefixBytes += $charBytes; - } - - // Write preffix length - $dicFile->writeVInt($prefixChars); - // Write suffix - $dicFile->writeString(substr($term->text, $prefixBytes)); - } else { - // Write preffix length - $dicFile->writeVInt(0); - // Write suffix - $dicFile->writeString($term->text); - } - // Write field number - $dicFile->writeVInt($term->field); - // DocFreq (the count of documents which contain the term) - $dicFile->writeVInt($termInfo->docFreq); - - $prevTerm = $term; - - if (!isset($prevTermInfo)) { - // Write FreqDelta - $dicFile->writeVInt($termInfo->freqPointer); - // Write ProxDelta - $dicFile->writeVInt($termInfo->proxPointer); - } else { - // Write FreqDelta - $dicFile->writeVInt($termInfo->freqPointer - $prevTermInfo->freqPointer); - // Write ProxDelta - $dicFile->writeVInt($termInfo->proxPointer - $prevTermInfo->proxPointer); - } - // Write SkipOffset - it's not 0 when $termInfo->docFreq > self::$skipInterval - if ($termInfo->skipOffset != 0) { - $dicFile->writeVInt($termInfo->skipOffset); - } - - $prevTermInfo = $termInfo; - } - - - /** - * Generate compound index file - */ - protected function _generateCFS() - { - $cfsFile = $this->_directory->createFile($this->_name . '.cfs'); - $cfsFile->writeVInt(count($this->_files)); - - $dataOffsetPointers = array(); - foreach ($this->_files as $fileName) { - $dataOffsetPointers[$fileName] = $cfsFile->tell(); - $cfsFile->writeLong(0); // write dummy data - $cfsFile->writeString($fileName); - } - - foreach ($this->_files as $fileName) { - // Get actual data offset - $dataOffset = $cfsFile->tell(); - // Seek to the data offset pointer - $cfsFile->seek($dataOffsetPointers[$fileName]); - // Write actual data offset value - $cfsFile->writeLong($dataOffset); - // Seek back to the end of file - $cfsFile->seek($dataOffset); - - $dataFile = $this->_directory->getFileObject($fileName); - - $byteCount = $this->_directory->fileLength($fileName); - while ($byteCount > 0) { - $data = $dataFile->readBytes(min($byteCount, 131072 /*128Kb*/)); - $byteCount -= strlen($data); - $cfsFile->writeBytes($data); - } - - $this->_directory->deleteFile($fileName); - } - } - - - /** - * Close segment, write it to disk and return segment info - * - * @return Zend_Search_Lucene_Index_SegmentInfo - */ - abstract public function close(); -} - diff --git a/search/Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php b/search/Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php deleted file mode 100644 index 56d226512a8..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php +++ /dev/null @@ -1,216 +0,0 @@ -_termDocs = array(); - $this->_termDictionary = array(); - } - - - /** - * Adds a document to this segment. - * - * @param Zend_Search_Lucene_Document $document - * @throws Zend_Search_Lucene_Exception - */ - public function addDocument(Zend_Search_Lucene_Document $document) - { - $storedFields = array(); - $docNorms = array(); - $similarity = Zend_Search_Lucene_Search_Similarity::getDefault(); - - foreach ($document->getFieldNames() as $fieldName) { - $field = $document->getField($fieldName); - $this->addField($field); - - if ($field->storeTermVector) { - /** - * @todo term vector storing support - */ - throw new Zend_Search_Lucene_Exception('Store term vector functionality is not supported yet.'); - } - - if ($field->isIndexed) { - if ($field->isTokenized) { - $analyzer = Zend_Search_Lucene_Analysis_Analyzer::getDefault(); - $analyzer->setInput($field->value, $field->encoding); - - $position = 0; - $tokenCounter = 0; - while (($token = $analyzer->nextToken()) !== null) { - $tokenCounter++; - - $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $field->name); - $termKey = $term->key(); - - if (!isset($this->_termDictionary[$termKey])) { - // New term - $this->_termDictionary[$termKey] = $term; - $this->_termDocs[$termKey] = array(); - $this->_termDocs[$termKey][$this->_docCount] = array(); - } else if (!isset($this->_termDocs[$termKey][$this->_docCount])) { - // Existing term, but new term entry - $this->_termDocs[$termKey][$this->_docCount] = array(); - } - $position += $token->getPositionIncrement(); - $this->_termDocs[$termKey][$this->_docCount][] = $position; - } - - $docNorms[$field->name] = chr($similarity->encodeNorm( $similarity->lengthNorm($field->name, - $tokenCounter)* - $document->boost* - $field->boost )); - } else { - $term = new Zend_Search_Lucene_Index_Term($field->getUtf8Value(), $field->name); - $termKey = $term->key(); - - if (!isset($this->_termDictionary[$termKey])) { - // New term - $this->_termDictionary[$termKey] = $term; - $this->_termDocs[$termKey] = array(); - $this->_termDocs[$termKey][$this->_docCount] = array(); - } else if (!isset($this->_termDocs[$termKey][$this->_docCount])) { - // Existing term, but new term entry - $this->_termDocs[$termKey][$this->_docCount] = array(); - } - $this->_termDocs[$termKey][$this->_docCount][] = 0; // position - - $docNorms[$field->name] = chr($similarity->encodeNorm( $similarity->lengthNorm($field->name, 1)* - $document->boost* - $field->boost )); - } - } - - if ($field->isStored) { - $storedFields[] = $field; - } - } - - - foreach ($this->_fields as $fieldName => $field) { - if (!$field->isIndexed) { - continue; - } - - if (!isset($this->_norms[$fieldName])) { - $this->_norms[$fieldName] = str_repeat(chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )), - $this->_docCount); - } - - if (isset($docNorms[$fieldName])){ - $this->_norms[$fieldName] .= $docNorms[$fieldName]; - } else { - $this->_norms[$fieldName] .= chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )); - } - } - - $this->addStoredFields($storedFields); - } - - - /** - * Dump Term Dictionary (.tis) and Term Dictionary Index (.tii) segment files - */ - protected function _dumpDictionary() - { - ksort($this->_termDictionary, SORT_STRING); - - $this->initializeDictionaryFiles(); - - foreach ($this->_termDictionary as $termId => $term) { - $this->addTerm($term, $this->_termDocs[$termId]); - } - - $this->closeDictionaryFiles(); - } - - - /** - * Close segment, write it to disk and return segment info - * - * @return Zend_Search_Lucene_Index_SegmentInfo - */ - public function close() - { - if ($this->_docCount == 0) { - return null; - } - - $this->_dumpFNM(); - $this->_dumpDictionary(); - - $this->_generateCFS(); - - return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, - $this->_name, - $this->_docCount, - -1, - true, - true); - } - -} - diff --git a/search/Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php b/search/Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php deleted file mode 100644 index 318a3a39889..00000000000 --- a/search/Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php +++ /dev/null @@ -1,97 +0,0 @@ -_fdxFile = $this->_directory->createFile($this->_name . '.fdx'); - $this->_fdtFile = $this->_directory->createFile($this->_name . '.fdt'); - - $this->_files[] = $this->_name . '.fdx'; - $this->_files[] = $this->_name . '.fdt'; - } - - public function addNorm($fieldName, $normVector) - { - if (isset($this->_norms[$fieldName])) { - $this->_norms[$fieldName] .= $normVector; - } else { - $this->_norms[$fieldName] = $normVector; - } - } - - /** - * Close segment, write it to disk and return segment info - * - * @return Zend_Search_Lucene_Index_SegmentInfo - */ - public function close() - { - if ($this->_docCount == 0) { - return null; - } - - $this->_dumpFNM(); - $this->_generateCFS(); - - return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, - $this->_name, - $this->_docCount, - -1, - true, - true); - } -} - diff --git a/search/Zend/Search/Lucene/Index/Term.php b/search/Zend/Search/Lucene/Index/Term.php deleted file mode 100644 index 1a5ac62caf9..00000000000 --- a/search/Zend/Search/Lucene/Index/Term.php +++ /dev/null @@ -1,143 +0,0 @@ -field = ($field === null)? Zend_Search_Lucene::getDefaultSearchField() : $field; - $this->text = $text; - } - - - /** - * Returns term key - * - * @return string - */ - public function key() - { - return $this->field . chr(0) . $this->text; - } - - /** - * Get term prefix - * - * @param string $str - * @param integer $length - * @return string - */ - public static function getPrefix($str, $length) - { - $prefixBytes = 0; - $prefixChars = 0; - while ($prefixBytes < strlen($str) && $prefixChars < $length) { - $charBytes = 1; - if ((ord($str[$prefixBytes]) & 0xC0) == 0xC0) { - $charBytes++; - if (ord($str[$prefixBytes]) & 0x20 ) { - $charBytes++; - if (ord($str[$prefixBytes]) & 0x10 ) { - $charBytes++; - } - } - } - - if ($prefixBytes + $charBytes > strlen($str)) { - // wrong character - break; - } - - $prefixChars++; - $prefixBytes += $charBytes; - } - - return substr($str, 0, $prefixBytes); - } - - /** - * Get UTF-8 string length - * - * @param string $str - * @return string - */ - public static function getLength($str) - { - $bytes = 0; - $chars = 0; - while ($bytes < strlen($str)) { - $charBytes = 1; - if ((ord($str[$bytes]) & 0xC0) == 0xC0) { - $charBytes++; - if (ord($str[$bytes]) & 0x20 ) { - $charBytes++; - if (ord($str[$bytes]) & 0x10 ) { - $charBytes++; - } - } - } - - if ($bytes + $charBytes > strlen($str)) { - // wrong character - break; - } - - $chars++; - $bytes += $charBytes; - } - - return $chars; - } -} - diff --git a/search/Zend/Search/Lucene/Index/TermInfo.php b/search/Zend/Search/Lucene/Index/TermInfo.php deleted file mode 100644 index 2d46724bd9f..00000000000 --- a/search/Zend/Search/Lucene/Index/TermInfo.php +++ /dev/null @@ -1,79 +0,0 @@ -docFreq = $docFreq; - $this->freqPointer = $freqPointer; - $this->proxPointer = $proxPointer; - $this->skipOffset = $skipOffset; - $this->indexPointer = $indexPointer; - } -} - diff --git a/search/Zend/Search/Lucene/Index/Writer.php b/search/Zend/Search/Lucene/Index/Writer.php deleted file mode 100644 index fb681516d91..00000000000 --- a/search/Zend/Search/Lucene/Index/Writer.php +++ /dev/null @@ -1,770 +0,0 @@ - 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @var integer - */ - public $mergeFactor = 10; - - /** - * File system adapter. - * - * @var Zend_Search_Lucene_Storage_Directory - */ - private $_directory = null; - - - /** - * Changes counter. - * - * @var integer - */ - private $_versionUpdate = 0; - - /** - * List of the segments, created by index writer - * Array of Zend_Search_Lucene_Index_SegmentInfo objects - * - * @var array - */ - private $_newSegments = array(); - - /** - * List of segments to be deleted on commit - * - * @var array - */ - private $_segmentsToDelete = array(); - - /** - * Current segment to add documents - * - * @var Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter - */ - private $_currentSegment = null; - - /** - * Array of Zend_Search_Lucene_Index_SegmentInfo objects for this index. - * - * It's a reference to the corresponding Zend_Search_Lucene::$_segmentInfos array - * - * @var array Zend_Search_Lucene_Index_SegmentInfo - */ - private $_segmentInfos; - - /** - * List of indexfiles extensions - * - * @var array - */ - private static $_indexExtensions = array('.cfs' => '.cfs', - '.fnm' => '.fnm', - '.fdx' => '.fdx', - '.fdt' => '.fdt', - '.tis' => '.tis', - '.tii' => '.tii', - '.frq' => '.frq', - '.prx' => '.prx', - '.tvx' => '.tvx', - '.tvd' => '.tvd', - '.tvf' => '.tvf', - '.del' => '.del', - '.sti' => '.sti' ); - - - /** - * Create empty index - * - * @param Zend_Search_Lucene_Storage_Directory $directory - * @param integer $generation - * @param integer $nameCount - */ - public static function createIndex(Zend_Search_Lucene_Storage_Directory $directory, $generation, $nameCount) - { - if ($generation == 0) { - // Create index in pre-2.1 mode - - foreach ($directory->fileList() as $file) { - if ($file == 'deletable' || - $file == 'segments' || - isset(self::$_indexExtensions[ substr($file, strlen($file)-4)]) || - preg_match('/\.f\d+$/i', $file) /* matches .f file names */) { - $directory->deleteFile($file); - } - } - - $segmentsFile = $directory->createFile('segments'); - $segmentsFile->writeInt((int)0xFFFFFFFF); - - // write version (is initialized by current time - // $segmentsFile->writeLong((int)microtime(true)); - $version = microtime(true); - $segmentsFile->writeInt((int)($version/((double)0xFFFFFFFF + 1))); - $segmentsFile->writeInt((int)($version & 0xFFFFFFFF)); - - // write name counter - $segmentsFile->writeInt($nameCount); - // write segment counter - $segmentsFile->writeInt(0); - - $deletableFile = $directory->createFile('deletable'); - // write counter - $deletableFile->writeInt(0); - } else { - $genFile = $directory->createFile('segments.gen'); - - $genFile->writeInt((int)0xFFFFFFFE); - // Write generation two times - $genFile->writeLong($generation); - $genFile->writeLong($generation); - - $segmentsFile = $directory->createFile(Zend_Search_Lucene::getSegmentFileName($generation)); - $segmentsFile->writeInt((int)0xFFFFFFFD); - - // write version (is initialized by current time - // $segmentsFile->writeLong((int)microtime(true)); - $version = microtime(true); - $segmentsFile->writeInt((int)($version/((double)0xFFFFFFFF + 1))); - $segmentsFile->writeInt((int)($version & 0xFFFFFFFF)); - - // write name counter - $segmentsFile->writeInt($nameCount); - // write segment counter - $segmentsFile->writeInt(0); - } - } - - /** - * Open the index for writing - * - * IndexWriter constructor needs Directory as a parameter. It should be - * a string with a path to the index folder or a Directory object. - * Second constructor parameter create is optional - true to create the - * index or overwrite the existing one. - * - * @param Zend_Search_Lucene_Storage_Directory $directory - * @param array $segmentInfos - * @param Zend_Search_Lucene_Storage_File $cleanUpLock - */ - public function __construct(Zend_Search_Lucene_Storage_Directory $directory, &$segmentInfos) - { - $this->_directory = $directory; - $this->_segmentInfos = &$segmentInfos; - } - - /** - * Adds a document to this index. - * - * @param Zend_Search_Lucene_Document $document - */ - public function addDocument(Zend_Search_Lucene_Document $document) - { - if ($this->_currentSegment === null) { - $this->_currentSegment = - new Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter($this->_directory, $this->_newSegmentName()); - } - $this->_currentSegment->addDocument($document); - - if ($this->_currentSegment->count() >= $this->maxBufferedDocs) { - $this->commit(); - } - - $this->_maybeMergeSegments(); - - $this->_versionUpdate++; - } - - - /** - * Check if we have anything to merge - * - * @return boolean - */ - private function _hasAnythingToMerge() - { - $segmentSizes = array(); - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - $segmentSizes[$segName] = $segmentInfo->count(); - } - - $mergePool = array(); - $poolSize = 0; - $sizeToMerge = $this->maxBufferedDocs; - asort($segmentSizes, SORT_NUMERIC); - foreach ($segmentSizes as $segName => $size) { - // Check, if segment comes into a new merging block - while ($size >= $sizeToMerge) { - // Merge previous block if it's large enough - if ($poolSize >= $sizeToMerge) { - return true; - } - $mergePool = array(); - $poolSize = 0; - - $sizeToMerge *= $this->mergeFactor; - - if ($sizeToMerge > $this->maxMergeDocs) { - return false; - } - } - - $mergePool[] = $this->_segmentInfos[$segName]; - $poolSize += $size; - } - - if ($poolSize >= $sizeToMerge) { - return true; - } - - return false; - } - - /** - * Merge segments if necessary - */ - private function _maybeMergeSegments() - { - if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { - return; - } - - - if (!$this->_hasAnythingToMerge()) { - Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); - return; - } - - // Update segments list to be sure all segments are not merged yet by other process - $this->_updateSegments(); - - - // Perform standard auto-optimization procedure - $segmentSizes = array(); - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - $segmentSizes[$segName] = $segmentInfo->count(); - } - - $mergePool = array(); - $poolSize = 0; - $sizeToMerge = $this->maxBufferedDocs; - asort($segmentSizes, SORT_NUMERIC); - foreach ($segmentSizes as $segName => $size) { - // Check, if segment comes into a new merging block - while ($size >= $sizeToMerge) { - // Merge previous block if it's large enough - if ($poolSize >= $sizeToMerge) { - $this->_mergeSegments($mergePool); - } - $mergePool = array(); - $poolSize = 0; - - $sizeToMerge *= $this->mergeFactor; - - if ($sizeToMerge > $this->maxMergeDocs) { - Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); - return; - } - } - - $mergePool[] = $this->_segmentInfos[$segName]; - $poolSize += $size; - } - - if ($poolSize >= $sizeToMerge) { - $this->_mergeSegments($mergePool); - } - - Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); - } - - /** - * Merge specified segments - * - * $segments is an array of SegmentInfo objects - * - * @param array $segments - */ - private function _mergeSegments($segments) - { - $newName = $this->_newSegmentName(); - $merger = new Zend_Search_Lucene_Index_SegmentMerger($this->_directory, - $newName); - foreach ($segments as $segmentInfo) { - $merger->addSource($segmentInfo); - $this->_segmentsToDelete[$segmentInfo->getName()] = $segmentInfo->getName(); - } - - $newSegment = $merger->merge(); - if ($newSegment !== null) { - $this->_newSegments[$newSegment->getName()] = $newSegment; - } - - $this->commit(); - } - - /** - * Update segments file by adding current segment to a list - * - * @throws Zend_Search_Lucene_Exception - */ - private function _updateSegments() - { - // Get an exclusive index lock - Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); - - $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); - $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); - $newSegmentFile = $this->_directory->createFile(Zend_Search_Lucene::getSegmentFileName(++$generation), false); - - try { - $genFile = $this->_directory->getFileObject('segments.gen', false); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'is not readable') !== false) { - $genFile = $this->_directory->createFile('segments.gen'); - } else { - throw $e; - } - } - - $genFile->writeInt((int)0xFFFFFFFE); - // Write generation (first copy) - $genFile->writeLong($generation); - - try { - // Write format marker - $newSegmentFile->writeInt((int)0xFFFFFFFD); - - // Skip format identifier - $segmentsFile->seek(4, SEEK_CUR); - // $version = $segmentsFile->readLong() + $this->_versionUpdate; - // Process version on 32-bit platforms - $versionHigh = $segmentsFile->readInt(); - $versionLow = $segmentsFile->readInt(); - $version = $versionHigh * ((double)0xFFFFFFFF + 1) + - (($versionLow < 0)? (double)0xFFFFFFFF - (-1 - $versionLow) : $versionLow); - $version += $this->_versionUpdate; - $this->_versionUpdate = 0; - $newSegmentFile->writeInt((int)($version/((double)0xFFFFFFFF + 1))); - $newSegmentFile->writeInt((int)($version & 0xFFFFFFFF)); - - // Write segment name counter - $newSegmentFile->writeInt($segmentsFile->readInt()); - - // Get number of segments offset - $numOfSegmentsOffset = $newSegmentFile->tell(); - // Write dummy data (segment counter) - $newSegmentFile->writeInt(0); - - // Read number of segemnts - $segmentsCount = $segmentsFile->readInt(); - - $segments = array(); - for ($count = 0; $count < $segmentsCount; $count++) { - $segName = $segmentsFile->readString(); - $segSize = $segmentsFile->readInt(); - - if ($generation == 1 /* retrieved generation is 0 */) { - // pre-2.1 index format - $delGenHigh = 0; - $delGenLow = 0; - $hasSingleNormFile = false; - $numField = (int)0xFFFFFFFF; - $isCompound = 1; - } else { - //$delGen = $segmentsFile->readLong(); - $delGenHigh = $segmentsFile->readInt(); - $delGenLow = $segmentsFile->readInt(); - $hasSingleNormFile = $segmentsFile->readByte(); - $numField = $segmentsFile->readInt(); - - $normGens = array(); - if ($numField != (int)0xFFFFFFFF) { - for ($count1 = 0; $count1 < $numField; $count1++) { - $normGens[] = $segmentsFile->readLong(); - } - } - $isCompound = $segmentsFile->readByte(); - } - - if (!in_array($segName, $this->_segmentsToDelete)) { - // Load segment if necessary - if (!isset($this->_segmentInfos[$segName])) { - $delGen = $delGenHigh * ((double)0xFFFFFFFF + 1) + - (($delGenLow < 0)? (double)0xFFFFFFFF - (-1 - $delGenLow) : $delGenLow); - $this->_segmentInfos[$segName] = - new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, - $segName, - $segSize, - $delGen, - $hasSingleNormFile, - $isCompound); - } else { - // Retrieve actual detetions file generation number - $delGen = $this->_segmentInfos[$segName]->getDelGen(); - - if ($delGen >= 0) { - $delGenHigh = (int)($delGen/((double)0xFFFFFFFF + 1)); - $delGenLow =(int)($delGen & 0xFFFFFFFF); - } else { - $delGenHigh = $delGenLow = (int)0xFFFFFFFF; - } - } - - $newSegmentFile->writeString($segName); - $newSegmentFile->writeInt($segSize); - $newSegmentFile->writeInt($delGenHigh); - $newSegmentFile->writeInt($delGenLow); - $newSegmentFile->writeByte($hasSingleNormFile); - $newSegmentFile->writeInt($numField); - if ($numField != (int)0xFFFFFFFF) { - foreach ($normGens as $normGen) { - $newSegmentFile->writeLong($normGen); - } - } - $newSegmentFile->writeByte($isCompound); - - $segments[$segName] = $segSize; - } - } - $segmentsFile->close(); - - $segmentsCount = count($segments) + count($this->_newSegments); - - foreach ($this->_newSegments as $segName => $segmentInfo) { - $newSegmentFile->writeString($segName); - $newSegmentFile->writeInt($segmentInfo->count()); - - // delete file generation: -1 (there is no delete file yet) - $newSegmentFile->writeInt((int)0xFFFFFFFF);$newSegmentFile->writeInt((int)0xFFFFFFFF); - // HasSingleNormFile - $newSegmentFile->writeByte($segmentInfo->hasSingleNormFile()); - // NumField - $newSegmentFile->writeInt((int)0xFFFFFFFF); - // IsCompoundFile - $newSegmentFile->writeByte($segmentInfo->isCompound()); - - $segments[$segmentInfo->getName()] = $segmentInfo->count(); - $this->_segmentInfos[$segName] = $segmentInfo; - } - $this->_newSegments = array(); - - $newSegmentFile->seek($numOfSegmentsOffset); - $newSegmentFile->writeInt($segmentsCount); // Update segments count - $newSegmentFile->close(); - } catch (Exception $e) { - /** Restore previous index generation */ - $generation--; - $genFile->seek(4, SEEK_SET); - // Write generation number twice - $genFile->writeLong($generation); $genFile->writeLong($generation); - - // Release index write lock - Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); - - // Throw the exception - throw $e; - } - - // Write generation (second copy) - $genFile->writeLong($generation); - - - // Check if another update process is not running now - // If yes, skip clean-up procedure - if (Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory)) { - /** - * Clean-up directory - */ - $filesToDelete = array(); - $filesTypes = array(); - $filesNumbers = array(); - - // list of .del files of currently used segments - // each segment can have several generations of .del files - // only last should not be deleted - $delFiles = array(); - - foreach ($this->_directory->fileList() as $file) { - if ($file == 'deletable') { - // 'deletable' file - $filesToDelete[] = $file; - $filesTypes[] = 0; // delete this file first, since it's not used starting from Lucene v2.1 - $filesNumbers[] = 0; - } else if ($file == 'segments') { - // 'segments' file - - $filesToDelete[] = $file; - $filesTypes[] = 1; // second file to be deleted "zero" version of segments file (Lucene pre-2.1) - $filesNumbers[] = 0; - } else if (preg_match('/^segments_[a-zA-Z0-9]+$/i', $file)) { - // 'segments_xxx' file - // Check if it's not a just created generation file - if ($file != Zend_Search_Lucene::getSegmentFileName($generation)) { - $filesToDelete[] = $file; - $filesTypes[] = 2; // first group of files for deletions - $filesNumbers[] = (int)base_convert(substr($file, 9), 36, 10); // ordered by segment generation numbers - } - } else if (preg_match('/(^_([a-zA-Z0-9]+))\.f\d+$/i', $file, $matches)) { - // one of per segment files ('.f') - // Check if it's not one of the segments in the current segments set - if (!isset($segments[$matches[1]])) { - $filesToDelete[] = $file; - $filesTypes[] = 3; // second group of files for deletions - $filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number - } - } else if (preg_match('/(^_([a-zA-Z0-9]+))(_([a-zA-Z0-9]+))\.del$/i', $file, $matches)) { - // one of per segment files ('_.del' where is '_') - // Check if it's not one of the segments in the current segments set - if (!isset($segments[$matches[1]])) { - $filesToDelete[] = $file; - $filesTypes[] = 3; // second group of files for deletions - $filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number - } else { - $segmentNumber = (int)base_convert($matches[2], 36, 10); - $delGeneration = (int)base_convert($matches[4], 36, 10); - if (!isset($delFiles[$segmentNumber])) { - $delFiles[$segmentNumber] = array(); - } - $delFiles[$segmentNumber][$delGeneration] = $file; - } - } else if (isset(self::$_indexExtensions[substr($file, strlen($file)-4)])) { - // one of per segment files ('.') - $segmentName = substr($file, 0, strlen($file) - 4); - // Check if it's not one of the segments in the current segments set - if (!isset($segments[$segmentName]) && - ($this->_currentSegment === null || $this->_currentSegment->getName() != $segmentName)) { - $filesToDelete[] = $file; - $filesTypes[] = 3; // second group of files for deletions - $filesNumbers[] = (int)base_convert(substr($file, 1 /* skip '_' */, strlen($file)-5), 36, 10); // order by segment number - } - } - } - - $maxGenNumber = 0; - // process .del files of currently used segments - foreach ($delFiles as $segmentNumber => $segmentDelFiles) { - ksort($delFiles[$segmentNumber], SORT_NUMERIC); - array_pop($delFiles[$segmentNumber]); // remove last delete file generation from candidates for deleting - - end($delFiles[$segmentNumber]); - $lastGenNumber = key($delFiles[$segmentNumber]); - if ($lastGenNumber > $maxGenNumber) { - $maxGenNumber = $lastGenNumber; - } - } - foreach ($delFiles as $segmentNumber => $segmentDelFiles) { - foreach ($segmentDelFiles as $delGeneration => $file) { - $filesToDelete[] = $file; - $filesTypes[] = 4; // third group of files for deletions - $filesNumbers[] = $segmentNumber*$maxGenNumber + $delGeneration; // order by , pair - } - } - - // Reorder files for deleting - array_multisort($filesTypes, SORT_ASC, SORT_NUMERIC, - $filesNumbers, SORT_ASC, SORT_NUMERIC, - $filesToDelete, SORT_ASC, SORT_STRING); - - foreach ($filesToDelete as $file) { - try { - $this->_directory->deleteFile($file); - } catch (Zend_Search_Lucene_Exception $e) { - if (strpos($e->getMessage(), 'Can\'t delete file') === false) { - // That's not "file is under processing or already deleted" exception - // Pass it through - throw $e; - } - } - } - - // Return read lock into the previous state - Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory); - } else { - // Only release resources if another index reader is running now - foreach ($this->_segmentsToDelete as $segName) { - foreach (self::$_indexExtensions as $ext) { - $this->_directory->purgeFile($segName . $ext); - } - } - } - - // Clean-up _segmentsToDelete container - $this->_segmentsToDelete = array(); - - - // Release index write lock - Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); - - // Remove unused segments from segments list - foreach ($this->_segmentInfos as $segName => $segmentInfo) { - if (!isset($segments[$segName])) { - unset($this->_segmentInfos[$segName]); - } - } - } - - /** - * Commit current changes - */ - public function commit() - { - if ($this->_currentSegment !== null) { - $newSegment = $this->_currentSegment->close(); - if ($newSegment !== null) { - $this->_newSegments[$newSegment->getName()] = $newSegment; - } - $this->_currentSegment = null; - } - - $this->_updateSegments(); - } - - - /** - * Merges the provided indexes into this index. - * - * @param array $readers - * @return void - */ - public function addIndexes($readers) - { - /** - * @todo implementation - */ - } - - /** - * Merges all segments together into new one - * - * Returns true on success and false if another optimization or auto-optimization process - * is running now - * - * @return boolean - */ - public function optimize() - { - if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { - return false; - } - - $this->_mergeSegments($this->_segmentInfos); - - Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); - - return true; - } - - /** - * Get name for new segment - * - * @return string - */ - private function _newSegmentName() - { - Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); - - $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); - $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); - - $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) - $segmentNameCounter = $segmentsFile->readInt(); - - $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) - $segmentsFile->writeInt($segmentNameCounter + 1); - - // Flash output to guarantee that wrong value will not be loaded between unlock and - // return (which calls $segmentsFile destructor) - $segmentsFile->flush(); - - Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); - - return '_' . base_convert($segmentNameCounter, 10, 36); - } - -} diff --git a/search/Zend/Search/Lucene/Interface.php b/search/Zend/Search/Lucene/Interface.php deleted file mode 100644 index 4e9dea5ea75..00000000000 --- a/search/Zend/Search/Lucene/Interface.php +++ /dev/null @@ -1,385 +0,0 @@ - 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @return integer - */ - public function getMergeFactor(); - - /** - * Set index mergeFactor option - * - * mergeFactor determines how often segment indices are merged by addDocument(). - * With smaller values, less RAM is used while indexing, - * and searches on unoptimized indices are faster, - * but indexing speed is slower. - * With larger values, more RAM is used during indexing, - * and while searches on unoptimized indices are slower, - * indexing is faster. - * Thus larger values (> 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @param integer $maxMergeDocs - */ - public function setMergeFactor($mergeFactor); - - /** - * Performs a query against the index and returns an array - * of Zend_Search_Lucene_Search_QueryHit objects. - * Input is a string or Zend_Search_Lucene_Search_Query. - * - * @param mixed $query - * @return array Zend_Search_Lucene_Search_QueryHit - * @throws Zend_Search_Lucene_Exception - */ - public function find($query); - - /** - * Returns a list of all unique field names that exist in this index. - * - * @param boolean $indexed - * @return array - */ - public function getFieldNames($indexed = false); - - /** - * Returns a Zend_Search_Lucene_Document object for the document - * number $id in this index. - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @return Zend_Search_Lucene_Document - */ - public function getDocument($id); - - /** - * Returns true if index contain documents with specified term. - * - * Is used for query optimization. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return boolean - */ - public function hasTerm(Zend_Search_Lucene_Index_Term $term); - - /** - * Returns IDs of all the documents containing term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termDocs(Zend_Search_Lucene_Index_Term $term); - - /** - * Returns an array of all term freqs. - * Return array structure: array( docId => freq, ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function termFreqs(Zend_Search_Lucene_Index_Term $term); - - /** - * Returns an array of all term positions in the documents. - * Return array structure: array( docId => array( pos1, pos2, ...), ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termPositions(Zend_Search_Lucene_Index_Term $term); - - /** - * Returns the number of documents in this index containing the $term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function docFreq(Zend_Search_Lucene_Index_Term $term); - - /** - * Retrive similarity used by index reader - * - * @return Zend_Search_Lucene_Search_Similarity - */ - public function getSimilarity(); - - /** - * Returns a normalization factor for "field, document" pair. - * - * @param integer $id - * @param string $fieldName - * @return float - */ - public function norm($id, $fieldName); - - /** - * Returns true if any documents have been deleted from this index. - * - * @return boolean - */ - public function hasDeletions(); - - /** - * Deletes a document from the index. - * $id is an internal document id - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @throws Zend_Search_Lucene_Exception - */ - public function delete($id); - - /** - * Adds a document to this index. - * - * @param Zend_Search_Lucene_Document $document - */ - public function addDocument(Zend_Search_Lucene_Document $document); - - /** - * Commit changes resulting from delete() or undeleteAll() operations. - */ - public function commit(); - - /** - * Optimize index. - * - * Merges all segments into one - */ - public function optimize(); - - /** - * Returns an array of all terms in this index. - * - * @return array - */ - public function terms(); - - - /** - * Reset terms stream. - */ - public function resetTermsStream(); - - /** - * Skip terms stream up to specified term preffix. - * - * Prefix contains fully specified field info and portion of searched term - * - * @param Zend_Search_Lucene_Index_Term $prefix - */ - public function skipTo(Zend_Search_Lucene_Index_Term $prefix); - - /** - * Scans terms dictionary and returns next term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function nextTerm(); - - /** - * Returns term in current position - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function currentTerm(); - - /** - * Close terms stream - * - * Should be used for resources clean up if stream is not read up to the end - */ - public function closeTermsStream(); - - - /** - * Undeletes all documents currently marked as deleted in this index. - */ - public function undeleteAll(); - - - /** - * Add reference to the index object - * - * @internal - */ - public function addReference(); - - /** - * Remove reference from the index object - * - * When reference count becomes zero, index is closed and resources are cleaned up - * - * @internal - */ - public function removeReference(); -} diff --git a/search/Zend/Search/Lucene/LockManager.php b/search/Zend/Search/Lucene/LockManager.php deleted file mode 100644 index 4730b51a5fe..00000000000 --- a/search/Zend/Search/Lucene/LockManager.php +++ /dev/null @@ -1,161 +0,0 @@ -createFile(self::WRITE_LOCK_FILE); - if (!$lock->lock(LOCK_EX)) { - throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock'); - } - return $lock; - } - - /** - * Release exclusive write lock - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - */ - public static function releaseWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->getFileObject(self::WRITE_LOCK_FILE); - $lock->unlock(); - } - - /** - * Obtain shared read lock on the index - * - * It doesn't block other read or update processes, but prevent index from the premature cleaning-up - * - * @param Zend_Search_Lucene_Storage_Directory $defaultLockDirectory - * @return Zend_Search_Lucene_Storage_File - * @throws Zend_Search_Lucene_Exception - */ - public static function obtainReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->createFile(self::READ_LOCK_FILE); - if (!$lock->lock(LOCK_SH)) { - throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock'); - } - return $lock; - } - - /** - * Release shared read lock - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - */ - public static function releaseReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); - $lock->unlock(); - } - - /** - * Escalate Read lock to exclusive level - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - * @return boolean - */ - public static function escalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); - - // Try to escalate read lock - if (!$lock->lock(LOCK_EX, true)) { - // Restore lock state - $lock->lock(LOCK_SH); - return false; - } - return true; - } - - /** - * De-escalate Read lock to shared level - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - */ - public static function deEscalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); - $lock->lock(LOCK_SH); - } - - /** - * Obtain exclusive optimization lock on the index - * - * Returns lock object on success and false otherwise (doesn't block execution) - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - * @return mixed - */ - public static function obtainOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->createFile(self::OPTIMIZATION_LOCK_FILE); - if (!$lock->lock(LOCK_EX, true)) { - return false; - } - return $lock; - } - - /** - * Release exclusive optimization lock - * - * @param Zend_Search_Lucene_Storage_Directory $lockDirectory - */ - public static function releaseOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) - { - $lock = $lockDirectory->getFileObject(self::OPTIMIZATION_LOCK_FILE); - $lock->unlock(); - } - -} diff --git a/search/Zend/Search/Lucene/PriorityQueue.php b/search/Zend/Search/Lucene/PriorityQueue.php deleted file mode 100644 index 4712e559aca..00000000000 --- a/search/Zend/Search/Lucene/PriorityQueue.php +++ /dev/null @@ -1,170 +0,0 @@ -_heap); - $parentId = ($nodeId-1) >> 1; // floor( ($nodeId-1)/2 ) - - while ($nodeId != 0 && $this->_less($element, $this->_heap[$parentId])) { - // Move parent node down - $this->_heap[$nodeId] = $this->_heap[$parentId]; - - // Move pointer to the next level of tree - $nodeId = $parentId; - $parentId = ($nodeId-1) >> 1; // floor( ($nodeId-1)/2 ) - } - - // Put new node into the tree - $this->_heap[$nodeId] = $element; - } - - - /** - * Return least element of the queue - * - * Constant time - * - * @return mixed - */ - public function top() - { - if (count($this->_heap) == 0) { - return null; - } - - return $this->_heap[0]; - } - - - /** - * Removes and return least element of the queue - * - * O(log(N)) time - * - * @return mixed - */ - public function pop() - { - if (count($this->_heap) == 0) { - return null; - } - - $top = $this->_heap[0]; - $lastId = count($this->_heap) - 1; - - /** - * Find appropriate position for last node - */ - $nodeId = 0; // Start from a top - $childId = 1; // First child - - // Choose smaller child - if ($lastId > 2 && $this->_less($this->_heap[2], $this->_heap[1])) { - $childId = 2; - } - - while ($childId < $lastId && - $this->_less($this->_heap[$childId], $this->_heap[$lastId]) - ) { - // Move child node up - $this->_heap[$nodeId] = $this->_heap[$childId]; - - $nodeId = $childId; // Go down - $childId = ($nodeId << 1) + 1; // First child - - // Choose smaller child - if (($childId+1) < $lastId && - $this->_less($this->_heap[$childId+1], $this->_heap[$childId]) - ) { - $childId++; - } - } - - // Move last element to the new position - $this->_heap[$nodeId] = $this->_heap[$lastId]; - unset($this->_heap[$lastId]); - - return $top; - } - - - /** - * Clear queue - */ - public function clear() - { - $this->_heap = array(); - } - - - /** - * Compare elements - * - * Returns true, if $el1 is less than $el2; else otherwise - * - * @param mixed $el1 - * @param mixed $el2 - * @return boolean - */ - abstract protected function _less($el1, $el2); -} - diff --git a/search/Zend/Search/Lucene/Proxy.php b/search/Zend/Search/Lucene/Proxy.php deleted file mode 100644 index 74610877862..00000000000 --- a/search/Zend/Search/Lucene/Proxy.php +++ /dev/null @@ -1,544 +0,0 @@ -_index = $index; - $this->_index->addReference(); - } - - /** - * Object destructor - */ - public function __destruct() - { - if ($this->_index !== null) { - // This code is invoked if Zend_Search_Lucene_Interface object constructor throws an exception - $this->_index->removeReference(); - } - $this->_index = null; - } - - /** - * Returns the Zend_Search_Lucene_Storage_Directory instance for this index. - * - * @return Zend_Search_Lucene_Storage_Directory - */ - public function getDirectory() - { - return $this->_index->getDirectory(); - } - - /** - * Returns the total number of documents in this index (including deleted documents). - * - * @return integer - */ - public function count() - { - return $this->_index->count(); - } - - /** - * Returns one greater than the largest possible document number. - * This may be used to, e.g., determine how big to allocate a structure which will have - * an element for every document number in an index. - * - * @return integer - */ - public function maxDoc() - { - return $this->_index->maxDoc(); - } - - /** - * Returns the total number of non-deleted documents in this index. - * - * @return integer - */ - public function numDocs() - { - return $this->_index->numDocs(); - } - - /** - * Checks, that document is deleted - * - * @param integer $id - * @return boolean - * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range - */ - public function isDeleted($id) - { - return $this->_index->isDeleted($id); - } - - /** - * Set default search field. - * - * Null means, that search is performed through all fields by default - * - * Default value is null - * - * @param string $fieldName - */ - public static function setDefaultSearchField($fieldName) - { - Zend_Search_Lucene::setDefaultSearchField($fieldName); - } - - /** - * Get default search field. - * - * Null means, that search is performed through all fields by default - * - * @return string - */ - public static function getDefaultSearchField() - { - return Zend_Search_Lucene::getDefaultSearchField(); - } - - /** - * Set result set limit. - * - * 0 (default) means no limit - * - * @param integer $limit - */ - public static function setResultSetLimit($limit) - { - Zend_Search_Lucene::setResultSetLimit($limit); - } - - /** - * Set result set limit. - * - * 0 means no limit - * - * @return integer - */ - public static function getResultSetLimit() - { - return Zend_Search_Lucene::getResultSetLimit(); - } - - /** - * Retrieve index maxBufferedDocs option - * - * maxBufferedDocs is a minimal number of documents required before - * the buffered in-memory documents are written into a new Segment - * - * Default value is 10 - * - * @return integer - */ - public function getMaxBufferedDocs() - { - return $this->_index->getMaxBufferedDocs(); - } - - /** - * Set index maxBufferedDocs option - * - * maxBufferedDocs is a minimal number of documents required before - * the buffered in-memory documents are written into a new Segment - * - * Default value is 10 - * - * @param integer $maxBufferedDocs - */ - public function setMaxBufferedDocs($maxBufferedDocs) - { - $this->_index->setMaxBufferedDocs($maxBufferedDocs); - } - - - /** - * Retrieve index maxMergeDocs option - * - * maxMergeDocs is a largest number of documents ever merged by addDocument(). - * Small values (e.g., less than 10,000) are best for interactive indexing, - * as this limits the length of pauses while indexing to a few seconds. - * Larger values are best for batched indexing and speedier searches. - * - * Default value is PHP_INT_MAX - * - * @return integer - */ - public function getMaxMergeDocs() - { - return $this->_index->getMaxMergeDocs(); - } - - /** - * Set index maxMergeDocs option - * - * maxMergeDocs is a largest number of documents ever merged by addDocument(). - * Small values (e.g., less than 10,000) are best for interactive indexing, - * as this limits the length of pauses while indexing to a few seconds. - * Larger values are best for batched indexing and speedier searches. - * - * Default value is PHP_INT_MAX - * - * @param integer $maxMergeDocs - */ - public function setMaxMergeDocs($maxMergeDocs) - { - $this->_index->setMaxMergeDocs($maxMergeDocs); - } - - - /** - * Retrieve index mergeFactor option - * - * mergeFactor determines how often segment indices are merged by addDocument(). - * With smaller values, less RAM is used while indexing, - * and searches on unoptimized indices are faster, - * but indexing speed is slower. - * With larger values, more RAM is used during indexing, - * and while searches on unoptimized indices are slower, - * indexing is faster. - * Thus larger values (> 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @return integer - */ - public function getMergeFactor() - { - return $this->_index->getMergeFactor(); - } - - /** - * Set index mergeFactor option - * - * mergeFactor determines how often segment indices are merged by addDocument(). - * With smaller values, less RAM is used while indexing, - * and searches on unoptimized indices are faster, - * but indexing speed is slower. - * With larger values, more RAM is used during indexing, - * and while searches on unoptimized indices are slower, - * indexing is faster. - * Thus larger values (> 10) are best for batch index creation, - * and smaller values (< 10) for indices that are interactively maintained. - * - * Default value is 10 - * - * @param integer $maxMergeDocs - */ - public function setMergeFactor($mergeFactor) - { - $this->_index->setMergeFactor($mergeFactor); - } - - /** - * Performs a query against the index and returns an array - * of Zend_Search_Lucene_Search_QueryHit objects. - * Input is a string or Zend_Search_Lucene_Search_Query. - * - * @param mixed $query - * @return array Zend_Search_Lucene_Search_QueryHit - * @throws Zend_Search_Lucene_Exception - */ - public function find($query) - { - // actual parameter list - $parameters = func_get_args(); - - // invoke $this->_index->find() method with specified parameters - return call_user_func_array(array(&$this->_index, 'find'), $parameters); - } - - /** - * Returns a list of all unique field names that exist in this index. - * - * @param boolean $indexed - * @return array - */ - public function getFieldNames($indexed = false) - { - return $this->_index->getFieldNames($indexed); - } - - /** - * Returns a Zend_Search_Lucene_Document object for the document - * number $id in this index. - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @return Zend_Search_Lucene_Document - */ - public function getDocument($id) - { - return $this->_index->getDocument($id); - } - - /** - * Returns true if index contain documents with specified term. - * - * Is used for query optimization. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return boolean - */ - public function hasTerm(Zend_Search_Lucene_Index_Term $term) - { - return $this->_index->hasTerm($term); - } - - /** - * Returns IDs of all the documents containing term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termDocs(Zend_Search_Lucene_Index_Term $term) - { - return $this->_index->termDocs($term); - } - - /** - * Returns an array of all term freqs. - * Return array structure: array( docId => freq, ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function termFreqs(Zend_Search_Lucene_Index_Term $term) - { - return $this->_index->termFreqs($term); - } - - /** - * Returns an array of all term positions in the documents. - * Return array structure: array( docId => array( pos1, pos2, ...), ...) - * - * @param Zend_Search_Lucene_Index_Term $term - * @return array - */ - public function termPositions(Zend_Search_Lucene_Index_Term $term) - { - return $this->_index->termPositions($term); - } - - /** - * Returns the number of documents in this index containing the $term. - * - * @param Zend_Search_Lucene_Index_Term $term - * @return integer - */ - public function docFreq(Zend_Search_Lucene_Index_Term $term) - { - return $this->_index->docFreq($term); - } - - /** - * Retrive similarity used by index reader - * - * @return Zend_Search_Lucene_Search_Similarity - */ - public function getSimilarity() - { - return $this->_index->getSimilarity(); - } - - /** - * Returns a normalization factor for "field, document" pair. - * - * @param integer $id - * @param string $fieldName - * @return float - */ - public function norm($id, $fieldName) - { - return $this->_index->norm($id, $fieldName); - } - - /** - * Returns true if any documents have been deleted from this index. - * - * @return boolean - */ - public function hasDeletions() - { - return $this->_index->hasDeletions(); - } - - /** - * Deletes a document from the index. - * $id is an internal document id - * - * @param integer|Zend_Search_Lucene_Search_QueryHit $id - * @throws Zend_Search_Lucene_Exception - */ - public function delete($id) - { - return $this->_index->delete($id); - } - - /** - * Adds a document to this index. - * - * @param Zend_Search_Lucene_Document $document - */ - public function addDocument(Zend_Search_Lucene_Document $document) - { - $this->_index->addDocument($document); - } - - /** - * Commit changes resulting from delete() or undeleteAll() operations. - */ - public function commit() - { - $this->_index->commit(); - } - - /** - * Optimize index. - * - * Merges all segments into one - */ - public function optimize() - { - $this->_index->optimize(); - } - - /** - * Returns an array of all terms in this index. - * - * @return array - */ - public function terms() - { - return $this->_index->terms(); - } - - - /** - * Reset terms stream. - */ - public function resetTermsStream() - { - $this->_index->resetTermsStream(); - } - - /** - * Skip terms stream up to specified term preffix. - * - * Prefix contains fully specified field info and portion of searched term - * - * @param Zend_Search_Lucene_Index_Term $prefix - */ - public function skipTo(Zend_Search_Lucene_Index_Term $prefix) - { - return $this->_index->skipTo($prefix); - } - - /** - * Scans terms dictionary and returns next term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function nextTerm() - { - return $this->_index->nextTerm(); - } - - /** - * Returns term in current position - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function currentTerm() - { - return $this->_index->currentTerm(); - } - - /** - * Close terms stream - * - * Should be used for resources clean up if stream is not read up to the end - */ - public function closeTermsStream() - { - $this->_index->closeTermsStream(); - } - - - /** - * Undeletes all documents currently marked as deleted in this index. - */ - public function undeleteAll() - { - return $this->_index->undeleteAll(); - } - - /** - * Add reference to the index object - * - * @internal - */ - public function addReference() - { - return $this->_index->addReference(); - } - - /** - * Remove reference from the index object - * - * When reference count becomes zero, index is closed and resources are cleaned up - * - * @internal - */ - public function removeReference() - { - return $this->_index->removeReference(); - } -} diff --git a/search/Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php b/search/Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php deleted file mode 100644 index 649c222b9b5..00000000000 --- a/search/Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php +++ /dev/null @@ -1,280 +0,0 @@ -, ) - * - * So, it has a structure: - * array( array( array(, ), // first literal of first conjuction - * array(, ), // second literal of first conjuction - * ... - * array(, ) - * ), // end of first conjuction - * array( array(, ), // first literal of second conjuction - * array(, ), // second literal of second conjuction - * ... - * array(, ) - * ), // end of second conjuction - * ... - * ) // end of structure - * - * @var array - */ - private $_conjunctions = array(); - - /** - * Current conjuction - * - * @var array - */ - private $_currentConjunction = array(); - - - /** - * Object constructor - */ - public function __construct() - { - parent::__construct( array(self::ST_START, - self::ST_LITERAL, - self::ST_NOT_OPERATOR, - self::ST_AND_OPERATOR, - self::ST_OR_OPERATOR), - array(self::IN_LITERAL, - self::IN_NOT_OPERATOR, - self::IN_AND_OPERATOR, - self::IN_OR_OPERATOR)); - - $emptyOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyOperatorAction'); - $emptyNotOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyNotOperatorAction'); - - $this->addRules(array( array(self::ST_START, self::IN_LITERAL, self::ST_LITERAL), - array(self::ST_START, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), - - array(self::ST_LITERAL, self::IN_AND_OPERATOR, self::ST_AND_OPERATOR), - array(self::ST_LITERAL, self::IN_OR_OPERATOR, self::ST_OR_OPERATOR), - array(self::ST_LITERAL, self::IN_LITERAL, self::ST_LITERAL, $emptyOperatorAction), - array(self::ST_LITERAL, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR, $emptyNotOperatorAction), - - array(self::ST_NOT_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), - - array(self::ST_AND_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), - array(self::ST_AND_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), - - array(self::ST_OR_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), - array(self::ST_OR_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), - )); - - $notOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'notOperatorAction'); - $orOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'orOperatorAction'); - $literalAction = new Zend_Search_Lucene_FSMAction($this, 'literalAction'); - - - $this->addEntryAction(self::ST_NOT_OPERATOR, $notOperatorAction); - $this->addEntryAction(self::ST_OR_OPERATOR, $orOperatorAction); - $this->addEntryAction(self::ST_LITERAL, $literalAction); - } - - - /** - * Process next operator. - * - * Operators are defined by class constants: IN_AND_OPERATOR, IN_OR_OPERATOR and IN_NOT_OPERATOR - * - * @param integer $operator - */ - public function processOperator($operator) - { - $this->process($operator); - } - - /** - * Process expression literal. - * - * @param integer $operator - */ - public function processLiteral($literal) - { - $this->_literal = $literal; - - $this->process(self::IN_LITERAL); - } - - /** - * Finish an expression and return result - * - * Result is a set of boolean query conjunctions - * - * Each conjunction is an array of conjunction elements - * Each conjunction element is presented with two-elements array: - * array(, ) - * - * So, it has a structure: - * array( array( array(, ), // first literal of first conjuction - * array(, ), // second literal of first conjuction - * ... - * array(, ) - * ), // end of first conjuction - * array( array(, ), // first literal of second conjuction - * array(, ), // second literal of second conjuction - * ... - * array(, ) - * ), // end of second conjuction - * ... - * ) // end of structure - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function finishExpression() - { - if ($this->getState() != self::ST_LITERAL) { - throw new Zend_Search_Lucene_Exception('Literal expected.'); - } - - $this->_conjunctions[] = $this->_currentConjunction; - - return $this->_conjunctions; - } - - - - /********************************************************************* - * Actions implementation - *********************************************************************/ - - /** - * default (omitted) operator processing - */ - public function emptyOperatorAction() - { - if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { - // Do nothing - } else { - $this->orOperatorAction(); - } - - // Process literal - $this->literalAction(); - } - - /** - * default (omitted) + NOT operator processing - */ - public function emptyNotOperatorAction() - { - if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { - // Do nothing - } else { - $this->orOperatorAction(); - } - - // Process NOT operator - $this->notOperatorAction(); - } - - - /** - * NOT operator processing - */ - public function notOperatorAction() - { - $this->_negativeLiteral = true; - } - - /** - * OR operator processing - * Close current conjunction - */ - public function orOperatorAction() - { - $this->_conjunctions[] = $this->_currentConjunction; - $this->_currentConjunction = array(); - } - - /** - * Literal processing - */ - public function literalAction() - { - // Add literal to the current conjunction - $this->_currentConjunction[] = array($this->_literal, !$this->_negativeLiteral); - - // Switch off negative signal - $this->_negativeLiteral = false; - } -} diff --git a/search/Zend/Search/Lucene/Search/Query.php b/search/Zend/Search/Lucene/Search/Query.php deleted file mode 100644 index e230eba268b..00000000000 --- a/search/Zend/Search/Lucene/Search/Query.php +++ /dev/null @@ -1,223 +0,0 @@ -_boost; - } - - /** - * Sets the boost for this query clause to $boost. - * - * @param float $boost - */ - public function setBoost($boost) - { - $this->_boost = $boost; - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - abstract public function score($docId, Zend_Search_Lucene_Interface $reader); - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - */ - abstract public function matchedDocs(); - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * Query specific implementation - * - * @param Zend_Search_Lucene_Interface $reader - */ - abstract public function execute(Zend_Search_Lucene_Interface $reader); - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - */ - abstract public function createWeight(Zend_Search_Lucene_Interface $reader); - - /** - * Constructs an initializes a Weight for a _top-level_query_. - * - * @param Zend_Search_Lucene_Interface $reader - */ - protected function _initWeight(Zend_Search_Lucene_Interface $reader) - { - // Check, that it's a top-level query and query weight is not initialized yet. - if ($this->_weight !== null) { - return $this->_weight; - } - - $this->createWeight($reader); - $sum = $this->_weight->sumOfSquaredWeights(); - $queryNorm = $reader->getSimilarity()->queryNorm($sum); - $this->_weight->normalize($queryNorm); - } - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - abstract public function rewrite(Zend_Search_Lucene_Interface $index); - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - abstract public function optimize(Zend_Search_Lucene_Interface $index); - - /** - * Reset query, so it can be reused within other queries or - * with other indeces - */ - public function reset() - { - $this->_weight = null; - } - - - /** - * Print a query - * - * @return string - */ - abstract public function __toString(); - - /** - * Return query terms - * - * @return array - */ - abstract public function getQueryTerms(); - - /** - * Get highlight color and shift to next - * - * @param integer &$colorIndex - * @return string - */ - protected function _getHighlightColor(&$colorIndex) - { - $color = $this->_highlightColors[$colorIndex++]; - - $colorIndex %= count($this->_highlightColors); - - return $color; - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - abstract public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex); - - /** - * Highlight matches in $inputHTML - * - * @param string $inputHTML - * @return string - */ - public function highlightMatches($inputHTML) - { - $doc = Zend_Search_Lucene_Document_Html::loadHTML($inputHTML); - - $colorIndex = 0; - $this->highlightMatchesDOM($doc, $colorIndex); - - return $doc->getHTML(); - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Boolean.php b/search/Zend/Search/Lucene/Search/Query/Boolean.php deleted file mode 100644 index 3846aa15633..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Boolean.php +++ /dev/null @@ -1,795 +0,0 @@ -_subqueries = $subqueries; - - $this->_signs = null; - // Check if all subqueries are required - if (is_array($signs)) { - foreach ($signs as $sign ) { - if ($sign !== true) { - $this->_signs = $signs; - break; - } - } - } - } - } - - - /** - * Add a $subquery (Zend_Search_Lucene_Search_Query) to this query. - * - * The sign is specified as: - * TRUE - subquery is required - * FALSE - subquery is prohibited - * NULL - subquery is neither prohibited, nor required - * - * @param Zend_Search_Lucene_Search_Query $subquery - * @param boolean|null $sign - * @return void - */ - public function addSubquery(Zend_Search_Lucene_Search_Query $subquery, $sign=null) { - if ($sign !== true || $this->_signs !== null) { // Skip, if all subqueries are required - if ($this->_signs === null) { // Check, If all previous subqueries are required - $this->_signs = array(); - foreach ($this->_subqueries as $prevSubquery) { - $this->_signs[] = true; - } - } - $this->_signs[] = $sign; - } - - $this->_subqueries[] = $subquery; - } - - /** - * Re-write queries into primitive queries - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - $query = new Zend_Search_Lucene_Search_Query_Boolean(); - $query->setBoost($this->getBoost()); - - foreach ($this->_subqueries as $subqueryId => $subquery) { - $query->addSubquery($subquery->rewrite($index), - ($this->_signs === null)? true : $this->_signs[$subqueryId]); - } - - return $query; - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - $subqueries = array(); - $signs = array(); - - // Optimize all subqueries - foreach ($this->_subqueries as $id => $subquery) { - $subqueries[] = $subquery->optimize($index); - $signs[] = ($this->_signs === null)? true : $this->_signs[$id]; - } - - // Remove insignificant subqueries - foreach ($subqueries as $id => $subquery) { - if ($subquery instanceof Zend_Search_Lucene_Search_Query_Insignificant) { - // Insignificant subquery has to be removed anyway - unset($subqueries[$id]); - unset($signs[$id]); - } - } - if (count($subqueries) == 0) { - // Boolean query doesn't has non-insignificant subqueries - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - // Check if all non-insignificant subqueries are prohibited - $allProhibited = true; - foreach ($signs as $sign) { - if ($sign !== false) { - $allProhibited = false; - break; - } - } - if ($allProhibited) { - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - - - // Check for empty subqueries - foreach ($subqueries as $id => $subquery) { - if ($subquery instanceof Zend_Search_Lucene_Search_Query_Empty) { - if ($signs[$id] === true) { - // Matching is required, but is actually empty - return new Zend_Search_Lucene_Search_Query_Empty(); - } else { - // Matching is optional or prohibited, but is empty - // Remove it from subqueries and signs list - unset($subqueries[$id]); - unset($signs[$id]); - } - } - } - - // Check, if reduced subqueries list is empty - if (count($subqueries) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - // Check if all non-empty subqueries are prohibited - $allProhibited = true; - foreach ($signs as $sign) { - if ($sign !== false) { - $allProhibited = false; - break; - } - } - if ($allProhibited) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - - // Check, if reduced subqueries list has only one entry - if (count($subqueries) == 1) { - // It's a query with only one required or optional clause - // (it's already checked, that it's not a prohibited clause) - - if ($this->getBoost() == 1) { - return reset($subqueries); - } - - $optimizedQuery = clone reset($subqueries); - $optimizedQuery->setBoost($optimizedQuery->getBoost()*$this->getBoost()); - - return $optimizedQuery; - } - - - // Prepare first candidate for optimized query - $optimizedQuery = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs); - $optimizedQuery->setBoost($this->getBoost()); - - - $terms = array(); - $tsigns = array(); - $boostFactors = array(); - - // Try to decompose term and multi-term subqueries - foreach ($subqueries as $id => $subquery) { - if ($subquery instanceof Zend_Search_Lucene_Search_Query_Term) { - $terms[] = $subquery->getTerm(); - $tsigns[] = $signs[$id]; - $boostFactors[] = $subquery->getBoost(); - - // remove subquery from a subqueries list - unset($subqueries[$id]); - unset($signs[$id]); - } else if ($subquery instanceof Zend_Search_Lucene_Search_Query_MultiTerm) { - $subTerms = $subquery->getTerms(); - $subSigns = $subquery->getSigns(); - - if ($signs[$id] === true) { - // It's a required multi-term subquery. - // Something like '... +(+term1 -term2 term3 ...) ...' - - // Multi-term required subquery can be decomposed only if it contains - // required terms and doesn't contain prohibited terms: - // ... +(+term1 term2 ...) ... => ... +term1 term2 ... - // - // Check this - $hasRequired = false; - $hasProhibited = false; - if ($subSigns === null) { - // All subterms are required - $hasRequired = true; - } else { - foreach ($subSigns as $sign) { - if ($sign === true) { - $hasRequired = true; - } else if ($sign === false) { - $hasProhibited = true; - break; - } - } - } - // Continue if subquery has prohibited terms or doesn't have required terms - if ($hasProhibited || !$hasRequired) { - continue; - } - - foreach ($subTerms as $termId => $term) { - $terms[] = $term; - $tsigns[] = ($subSigns === null)? true : $subSigns[$termId]; - $boostFactors[] = $subquery->getBoost(); - } - - // remove subquery from a subqueries list - unset($subqueries[$id]); - unset($signs[$id]); - - } else { // $signs[$id] === null || $signs[$id] === false - // It's an optional or prohibited multi-term subquery. - // Something like '... (+term1 -term2 term3 ...) ...' - // or - // something like '... -(+term1 -term2 term3 ...) ...' - - // Multi-term optional and required subqueries can be decomposed - // only if all terms are optional. - // - // Check if all terms are optional. - $onlyOptional = true; - if ($subSigns === null) { - // All subterms are required - $onlyOptional = false; - } else { - foreach ($subSigns as $sign) { - if ($sign !== null) { - $onlyOptional = false; - break; - } - } - } - - // Continue if non-optional terms are presented in this multi-term subquery - if (!$onlyOptional) { - continue; - } - - foreach ($subTerms as $termId => $term) { - $terms[] = $term; - $tsigns[] = ($signs[$id] === null)? null /* optional */ : - false /* prohibited */; - $boostFactors[] = $subquery->getBoost(); - } - - // remove subquery from a subqueries list - unset($subqueries[$id]); - unset($signs[$id]); - } - } - } - - - // Check, if there are no decomposed subqueries - if (count($terms) == 0 ) { - // return prepared candidate - return $optimizedQuery; - } - - - // Check, if all subqueries have been decomposed and all terms has the same boost factor - if (count($subqueries) == 0 && count(array_unique($boostFactors)) == 1) { - $optimizedQuery = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $tsigns); - $optimizedQuery->setBoost(reset($boostFactors)*$this->getBoost()); - - return $optimizedQuery; - } - - - // This boolean query can't be transformed to Term/MultiTerm query and still contains - // several subqueries - - // Separate prohibited terms - $prohibitedTerms = array(); - foreach ($terms as $id => $term) { - if ($tsigns[$id] === false) { - $prohibitedTerms[] = $term; - - unset($terms[$id]); - unset($tsigns[$id]); - unset($boostFactors[$id]); - } - } - - if (count($terms) == 1) { - $clause = new Zend_Search_Lucene_Search_Query_Term(reset($terms)); - $clause->setBoost(reset($boostFactors)); - - $subqueries[] = $clause; - $signs[] = reset($tsigns); - - // Clear terms list - $terms = array(); - } else if (count($terms) > 1 && count(array_unique($boostFactors)) == 1) { - $clause = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $tsigns); - $clause->setBoost(reset($boostFactors)); - - $subqueries[] = $clause; - // Clause sign is 'required' if clause contains required terms. 'Optional' otherwise. - $signs[] = (in_array(true, $tsigns))? true : null; - - // Clear terms list - $terms = array(); - } - - if (count($prohibitedTerms) == 1) { - // (boost factors are not significant for prohibited clauses) - $subqueries[] = new Zend_Search_Lucene_Search_Query_Term(reset($prohibitedTerms)); - $signs[] = false; - - // Clear prohibited terms list - $prohibitedTerms = array(); - } else if (count($prohibitedTerms) > 1) { - // prepare signs array - $prohibitedSigns = array(); - foreach ($prohibitedTerms as $id => $term) { - // all prohibited term are grouped as optional into multi-term query - $prohibitedSigns[$id] = null; - } - - // (boost factors are not significant for prohibited clauses) - $subqueries[] = new Zend_Search_Lucene_Search_Query_MultiTerm($prohibitedTerms, $prohibitedSigns); - // Clause sign is 'prohibited' - $signs[] = false; - - // Clear terms list - $prohibitedTerms = array(); - } - - /** @todo Group terms with the same boost factors together */ - - // Check, that all terms are processed - // Replace candidate for optimized query - if (count($terms) == 0 && count($prohibitedTerms) == 0) { - $optimizedQuery = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs); - $optimizedQuery->setBoost($this->getBoost()); - } - - return $optimizedQuery; - } - - /** - * Returns subqueries - * - * @return array - */ - public function getSubqueries() - { - return $this->_subqueries; - } - - - /** - * Return subqueries signs - * - * @return array - */ - public function getSigns() - { - return $this->_signs; - } - - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - $this->_weight = new Zend_Search_Lucene_Search_Weight_Boolean($this, $reader); - return $this->_weight; - } - - - /** - * Calculate result vector for Conjunction query - * (like ' AND AND ') - */ - private function _calculateConjunctionResult() - { - $this->_resVector = null; - - if (count($this->_subqueries) == 0) { - $this->_resVector = array(); - } - - $resVectors = array(); - $resVectorsSizes = array(); - $resVectorsIds = array(); // is used to prevent arrays comparison - foreach ($this->_subqueries as $subqueryId => $subquery) { - $resVectors[] = $subquery->matchedDocs(); - $resVectorsSizes[] = count(end($resVectors)); - $resVectorsIds[] = $subqueryId; - } - // sort resvectors in order of subquery cardinality increasing - array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC, - $resVectorsIds, SORT_ASC, SORT_NUMERIC, - $resVectors); - - foreach ($resVectors as $nextResVector) { - if($this->_resVector === null) { - $this->_resVector = $nextResVector; - } else { - //$this->_resVector = array_intersect_key($this->_resVector, $nextResVector); - - /** - * This code is used as workaround for array_intersect_key() slowness problem. - */ - $updatedVector = array(); - foreach ($this->_resVector as $id => $value) { - if (isset($nextResVector[$id])) { - $updatedVector[$id] = $value; - } - } - $this->_resVector = $updatedVector; - } - - if (count($this->_resVector) == 0) { - // Empty result set, we don't need to check other terms - break; - } - } - - // ksort($this->_resVector, SORT_NUMERIC); - // Used algorithm doesn't change elements order - } - - - /** - * Calculate result vector for non Conjunction query - * (like ' AND AND NOT OR ') - */ - private function _calculateNonConjunctionResult() - { - $requiredVectors = array(); - $requiredVectorsSizes = array(); - $requiredVectorsIds = array(); // is used to prevent arrays comparison - - $optional = array(); - - foreach ($this->_subqueries as $subqueryId => $subquery) { - if ($this->_signs[$subqueryId] === true) { - // required - $requiredVectors[] = $subquery->matchedDocs(); - $requiredVectorsSizes[] = count(end($requiredVectors)); - $requiredVectorsIds[] = $subqueryId; - } elseif ($this->_signs[$subqueryId] === false) { - // prohibited - // Do nothing. matchedDocs() may include non-matching id's - // Calculating prohibited vector may take significant time, but do not affect the result - // Skipped. - } else { - // neither required, nor prohibited - // array union - $optional += $subquery->matchedDocs(); - } - } - - // sort resvectors in order of subquery cardinality increasing - array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC, - $requiredVectorsIds, SORT_ASC, SORT_NUMERIC, - $requiredVectors); - - $required = null; - foreach ($requiredVectors as $nextResVector) { - if($required === null) { - $required = $nextResVector; - } else { - //$required = array_intersect_key($required, $nextResVector); - - /** - * This code is used as workaround for array_intersect_key() slowness problem. - */ - $updatedVector = array(); - foreach ($required as $id => $value) { - if (isset($nextResVector[$id])) { - $updatedVector[$id] = $value; - } - } - $required = $updatedVector; - } - - if (count($required) == 0) { - // Empty result set, we don't need to check other terms - break; - } - } - - - if ($required !== null) { - $this->_resVector = &$required; - } else { - $this->_resVector = &$optional; - } - - ksort($this->_resVector, SORT_NUMERIC); - } - - - /** - * Score calculator for conjunction queries (all subqueries are required) - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function _conjunctionScore($docId, Zend_Search_Lucene_Interface $reader) - { - if ($this->_coord === null) { - $this->_coord = $reader->getSimilarity()->coord(count($this->_subqueries), - count($this->_subqueries) ); - } - - $score = 0; - - foreach ($this->_subqueries as $subquery) { - $subscore = $subquery->score($docId, $reader); - - if ($subscore == 0) { - return 0; - } - - $score += $subquery->score($docId, $reader) * $this->_coord; - } - - return $score * $this->_coord * $this->getBoost(); - } - - - /** - * Score calculator for non conjunction queries (not all subqueries are required) - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function _nonConjunctionScore($docId, Zend_Search_Lucene_Interface $reader) - { - if ($this->_coord === null) { - $this->_coord = array(); - - $maxCoord = 0; - foreach ($this->_signs as $sign) { - if ($sign !== false /* not prohibited */) { - $maxCoord++; - } - } - - for ($count = 0; $count <= $maxCoord; $count++) { - $this->_coord[$count] = $reader->getSimilarity()->coord($count, $maxCoord); - } - } - - $score = 0; - $matchedSubqueries = 0; - foreach ($this->_subqueries as $subqueryId => $subquery) { - $subscore = $subquery->score($docId, $reader); - - // Prohibited - if ($this->_signs[$subqueryId] === false && $subscore != 0) { - return 0; - } - - // is required, but doen't match - if ($this->_signs[$subqueryId] === true && $subscore == 0) { - return 0; - } - - if ($subscore != 0) { - $matchedSubqueries++; - $score += $subscore; - } - } - - return $score * $this->_coord[$matchedSubqueries] * $this->getBoost(); - } - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - // Initialize weight if it's not done yet - $this->_initWeight($reader); - - foreach ($this->_subqueries as $subquery) { - $subquery->execute($reader); - } - - if ($this->_signs === null) { - $this->_calculateConjunctionResult(); - } else { - $this->_calculateNonConjunctionResult(); - } - } - - - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - */ - public function matchedDocs() - { - return $this->_resVector; - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - if (isset($this->_resVector[$docId])) { - if ($this->_signs === null) { - return $this->_conjunctionScore($docId, $reader); - } else { - return $this->_nonConjunctionScore($docId, $reader); - } - } else { - return 0; - } - } - - /** - * Return query terms - * - * @return array - */ - public function getQueryTerms() - { - $terms = array(); - - foreach ($this->_subqueries as $id => $subquery) { - if ($this->_signs === null || $this->_signs[$id] !== false) { - $terms = array_merge($terms, $subquery->getQueryTerms()); - } - } - - return $terms; - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - foreach ($this->_subqueries as $id => $subquery) { - if ($this->_signs === null || $this->_signs[$id] !== false) { - $subquery->highlightMatchesDOM($doc, $colorIndex); - } - } - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - - $query = ''; - - foreach ($this->_subqueries as $id => $subquery) { - if ($id != 0) { - $query .= ' '; - } - - if ($this->_signs === null || $this->_signs[$id] === true) { - $query .= '+'; - } else if ($this->_signs[$id] === false) { - $query .= '-'; - } - - $query .= '(' . $subquery->__toString() . ')'; - - if ($subquery->getBoost() != 1) { - $query .= '^' . round($subquery->getBoost(), 4); - } - } - - return $query; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Empty.php b/search/Zend/Search/Lucene/Search/Query/Empty.php deleted file mode 100644 index 2b67d1bfb25..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Empty.php +++ /dev/null @@ -1,139 +0,0 @@ -'; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Fuzzy.php b/search/Zend/Search/Lucene/Search/Query/Fuzzy.php deleted file mode 100644 index 5171d191b32..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Fuzzy.php +++ /dev/null @@ -1,390 +0,0 @@ -= 1) { - throw new Zend_Search_Lucene_Exception('minimumSimilarity cannot be greater than or equal to 1'); - } - if ($prefixLength < 0) { - throw new Zend_Search_Lucene_Exception('prefixLength cannot be less than 0'); - } - - $this->_term = $term; - $this->_minimumSimilarity = $minimumSimilarity; - $this->_prefixLength = $prefixLength; - } - - /** - * Calculate maximum distance for specified word length - * - * @param integer $prefixLength - * @param integer $termLength - * @param integer $length - * @return integer - */ - private function _calculateMaxDistance($prefixLength, $termLength, $length) - { - $this->_maxDistances[$length] = (int) ((1 - $this->_minimumSimilarity)*(min($termLength, $length) + $prefixLength)); - return $this->_maxDistances[$length]; - } - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - $this->_matches = array(); - $this->_scores = array(); - $this->_termKeys = array(); - - if ($this->_term->field === null) { - // Search through all fields - $fields = $index->getFieldNames(true /* indexed fields list */); - } else { - $fields = array($this->_term->field); - } - - $prefix = Zend_Search_Lucene_Index_Term::getPrefix($this->_term->text, $this->_prefixLength); - $prefixByteLength = strlen($prefix); - $prefixUtf8Length = Zend_Search_Lucene_Index_Term::getLength($prefix); - - $termLength = Zend_Search_Lucene_Index_Term::getLength($this->_term->text); - - $termRest = substr($this->_term->text, $prefixByteLength); - // we calculate length of the rest in bytes since levenshtein() is not UTF-8 compatible - $termRestLength = strlen($termRest); - - $scaleFactor = 1/(1 - $this->_minimumSimilarity); - - foreach ($fields as $field) { - $index->resetTermsStream(); - - if ($prefix != '') { - $index->skipTo(new Zend_Search_Lucene_Index_Term($prefix, $field)); - - while ($index->currentTerm() !== null && - $index->currentTerm()->field == $field && - substr($index->currentTerm()->text, 0, $prefixByteLength) == $prefix) { - // Calculate similarity - $target = substr($index->currentTerm()->text, $prefixByteLength); - - $maxDistance = isset($this->_maxDistances[strlen($target)])? - $this->_maxDistances[strlen($target)] : - $this->_calculateMaxDistance($prefixUtf8Length, $termRestLength, strlen($target)); - - if ($termRestLength == 0) { - // we don't have anything to compare. That means if we just add - // the letters for current term we get the new word - $similarity = (($prefixUtf8Length == 0)? 0 : 1 - strlen($target)/$prefixUtf8Length); - } else if (strlen($target) == 0) { - $similarity = (($prefixUtf8Length == 0)? 0 : 1 - $termRestLength/$prefixUtf8Length); - } else if ($maxDistance < abs($termRestLength - strlen($target))){ - //just adding the characters of term to target or vice-versa results in too many edits - //for example "pre" length is 3 and "prefixes" length is 8. We can see that - //given this optimal circumstance, the edit distance cannot be less than 5. - //which is 8-3 or more precisesly abs(3-8). - //if our maximum edit distance is 4, then we can discard this word - //without looking at it. - $similarity = 0; - } else { - $similarity = 1 - levenshtein($termRest, $target)/($prefixUtf8Length + min($termRestLength, strlen($target))); - } - - if ($similarity > $this->_minimumSimilarity) { - $this->_matches[] = $index->currentTerm(); - $this->_termKeys[] = $index->currentTerm()->key(); - $this->_scores[] = ($similarity - $this->_minimumSimilarity)*$scaleFactor; - } - - $index->nextTerm(); - } - } else { - $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); - - while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { - // Calculate similarity - $target = $index->currentTerm()->text; - - $maxDistance = isset($this->_maxDistances[strlen($target)])? - $this->_maxDistances[strlen($target)] : - $this->_calculateMaxDistance(0, $termRestLength, strlen($target)); - - if ($maxDistance < abs($termRestLength - strlen($target))){ - //just adding the characters of term to target or vice-versa results in too many edits - //for example "pre" length is 3 and "prefixes" length is 8. We can see that - //given this optimal circumstance, the edit distance cannot be less than 5. - //which is 8-3 or more precisesly abs(3-8). - //if our maximum edit distance is 4, then we can discard this word - //without looking at it. - $similarity = 0; - } else { - $similarity = 1 - levenshtein($termRest, $target)/min($termRestLength, strlen($target)); - } - - if ($similarity > $this->_minimumSimilarity) { - $this->_matches[] = $index->currentTerm(); - $this->_termKeys[] = $index->currentTerm()->key(); - $this->_scores[] = ($similarity - $this->_minimumSimilarity)*$scaleFactor; - } - - $index->nextTerm(); - } - } - - $index->closeTermsStream(); - } - - if (count($this->_matches) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } else if (count($this->_matches) == 1) { - return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); - } else { - $rewrittenQuery = new Zend_Search_Lucene_Search_Query_Boolean(); - - array_multisort($this->_scores, SORT_DESC, SORT_NUMERIC, - $this->_termKeys, SORT_ASC, SORT_STRING, - $this->_matches); - - $termCount = 0; - foreach ($this->_matches as $id => $matchedTerm) { - $subquery = new Zend_Search_Lucene_Search_Query_Term($matchedTerm); - $subquery->setBoost($this->_scores[$id]); - - $rewrittenQuery->addSubquery($subquery); - - $termCount++; - if ($termCount >= self::MAX_CLAUSE_COUNT) { - break; - } - } - - return $rewrittenQuery; - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Return query terms - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function getQueryTerms() - { - if ($this->_matches === null) { - throw new Zend_Search_Lucene_Exception('Search has to be performed first to get matched terms'); - } - - return $this->_matches; - } - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - * @throws Zend_Search_Lucene_Exception - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - * @throws Zend_Search_Lucene_Exception - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function matchedDocs() - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - * @throws Zend_Search_Lucene_Exception - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $words = array(); - - foreach ($this->_matches as $term) { - $words[] = $term->text; - } - - $doc->highlight($words, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - return (($this->_term->field === null)? '' : $this->_term->field . ':') - . $this->_term->text . '~' - . (($this->_minimumSimilarity != self::DEFAULT_MIN_SIMILARITY)? round($this->_minimumSimilarity, 4) : ''); - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Insignificant.php b/search/Zend/Search/Lucene/Search/Query/Insignificant.php deleted file mode 100644 index b61955db2f7..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Insignificant.php +++ /dev/null @@ -1,140 +0,0 @@ -'; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/MultiTerm.php b/search/Zend/Search/Lucene/Search/Query/MultiTerm.php deleted file mode 100644 index e3f79acedd1..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/MultiTerm.php +++ /dev/null @@ -1,671 +0,0 @@ - (docId => freq, ...) - * term2Id => (docId => freq, ...) - * - * @var array - */ - private $_termsFreqs = array(); - - - /** - * A score factor based on the fraction of all query terms - * that a document contains. - * float for conjunction queries - * array of float for non conjunction queries - * - * @var mixed - */ - private $_coord = null; - - - /** - * Terms weights - * array of Zend_Search_Lucene_Search_Weight - * - * @var array - */ - private $_weights = array(); - - - /** - * Class constructor. Create a new multi-term query object. - * - * if $signs array is omitted then all terms are required - * it differs from addTerm() behavior, but should never be used - * - * @param array $terms Array of Zend_Search_Lucene_Index_Term objects - * @param array $signs Array of signs. Sign is boolean|null. - */ - public function __construct($terms = null, $signs = null) - { - if (is_array($terms)) { - $this->_terms = $terms; - - $this->_signs = null; - // Check if all terms are required - if (is_array($signs)) { - foreach ($signs as $sign ) { - if ($sign !== true) { - $this->_signs = $signs; - break; - } - } - } - } - } - - - /** - * Add a $term (Zend_Search_Lucene_Index_Term) to this query. - * - * The sign is specified as: - * TRUE - term is required - * FALSE - term is prohibited - * NULL - term is neither prohibited, nor required - * - * @param Zend_Search_Lucene_Index_Term $term - * @param boolean|null $sign - * @return void - */ - public function addTerm(Zend_Search_Lucene_Index_Term $term, $sign = null) { - if ($sign !== true || $this->_signs !== null) { // Skip, if all terms are required - if ($this->_signs === null) { // Check, If all previous terms are required - $this->_signs = array(); - foreach ($this->_terms as $prevTerm) { - $this->_signs[] = true; - } - } - $this->_signs[] = $sign; - } - - $this->_terms[] = $term; - } - - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - if (count($this->_terms) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - // Check, that all fields are qualified - $allQualified = true; - foreach ($this->_terms as $term) { - if ($term->field === null) { - $allQualified = false; - break; - } - } - - if ($allQualified) { - return $this; - } else { - /** transform multiterm query to boolean and apply rewrite() method to subqueries. */ - $query = new Zend_Search_Lucene_Search_Query_Boolean(); - $query->setBoost($this->getBoost()); - - foreach ($this->_terms as $termId => $term) { - $subquery = new Zend_Search_Lucene_Search_Query_Term($term); - - $query->addSubquery($subquery->rewrite($index), - ($this->_signs === null)? true : $this->_signs[$termId]); - } - - return $query; - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - $terms = $this->_terms; - $signs = $this->_signs; - - foreach ($terms as $id => $term) { - if (!$index->hasTerm($term)) { - if ($signs === null || $signs[$id] === true) { - // Term is required - return new Zend_Search_Lucene_Search_Query_Empty(); - } else { - // Term is optional or prohibited - // Remove it from terms and signs list - unset($terms[$id]); - unset($signs[$id]); - } - } - } - - // Check if all presented terms are prohibited - $allProhibited = true; - if ($signs === null) { - $allProhibited = false; - } else { - foreach ($signs as $sign) { - if ($sign !== false) { - $allProhibited = false; - break; - } - } - } - if ($allProhibited) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - /** - * @todo make an optimization for repeated terms - * (they may have different signs) - */ - - if (count($terms) == 1) { - // It's already checked, that it's not a prohibited term - - // It's one term query with one required or optional element - $optimizedQuery = new Zend_Search_Lucene_Search_Query_Term(reset($terms)); - $optimizedQuery->setBoost($this->getBoost()); - - return $optimizedQuery; - } - - if (count($terms) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - $optimizedQuery = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $signs); - $optimizedQuery->setBoost($this->getBoost()); - return $optimizedQuery; - } - - - /** - * Returns query term - * - * @return array - */ - public function getTerms() - { - return $this->_terms; - } - - - /** - * Return terms signs - * - * @return array - */ - public function getSigns() - { - return $this->_signs; - } - - - /** - * Set weight for specified term - * - * @param integer $num - * @param Zend_Search_Lucene_Search_Weight_Term $weight - */ - public function setWeight($num, $weight) - { - $this->_weights[$num] = $weight; - } - - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - $this->_weight = new Zend_Search_Lucene_Search_Weight_MultiTerm($this, $reader); - return $this->_weight; - } - - - /** - * Calculate result vector for Conjunction query - * (like '+something +another') - * - * @param Zend_Search_Lucene_Interface $reader - */ - private function _calculateConjunctionResult(Zend_Search_Lucene_Interface $reader) - { - $this->_resVector = null; - - if (count($this->_terms) == 0) { - $this->_resVector = array(); - } - - $resVectors = array(); - $resVectorsSizes = array(); - $resVectorsIds = array(); // is used to prevent arrays comparison - foreach ($this->_terms as $termId => $term) { - $resVectors[] = array_flip($reader->termDocs($term)); - $resVectorsSizes[] = count(end($resVectors)); - $resVectorsIds[] = $termId; - - $this->_termsFreqs[$termId] = $reader->termFreqs($term); - } - // sort resvectors in order of subquery cardinality increasing - array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC, - $resVectorsIds, SORT_ASC, SORT_NUMERIC, - $resVectors); - - foreach ($resVectors as $nextResVector) { - if($this->_resVector === null) { - $this->_resVector = $nextResVector; - } else { - //$this->_resVector = array_intersect_key($this->_resVector, $nextResVector); - - /** - * This code is used as workaround for array_intersect_key() slowness problem. - */ - $updatedVector = array(); - foreach ($this->_resVector as $id => $value) { - if (isset($nextResVector[$id])) { - $updatedVector[$id] = $value; - } - } - $this->_resVector = $updatedVector; - } - - if (count($this->_resVector) == 0) { - // Empty result set, we don't need to check other terms - break; - } - } - - // ksort($this->_resVector, SORT_NUMERIC); - // Docs are returned ordered. Used algorithm doesn't change elements order. - } - - - /** - * Calculate result vector for non Conjunction query - * (like '+something -another') - * - * @param Zend_Search_Lucene_Interface $reader - */ - private function _calculateNonConjunctionResult(Zend_Search_Lucene_Interface $reader) - { - $requiredVectors = array(); - $requiredVectorsSizes = array(); - $requiredVectorsIds = array(); // is used to prevent arrays comparison - - $optional = array(); - $prohibited = array(); - - foreach ($this->_terms as $termId => $term) { - $termDocs = array_flip($reader->termDocs($term)); - - if ($this->_signs[$termId] === true) { - // required - $requiredVectors[] = $termDocs; - $requiredVectorsSizes[] = count($termDocs); - $requiredVectorsIds[] = $termId; - } elseif ($this->_signs[$termId] === false) { - // prohibited - // array union - $prohibited += $termDocs; - } else { - // neither required, nor prohibited - // array union - $optional += $termDocs; - } - - $this->_termsFreqs[$termId] = $reader->termFreqs($term); - } - - // sort resvectors in order of subquery cardinality increasing - array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC, - $requiredVectorsIds, SORT_ASC, SORT_NUMERIC, - $requiredVectors); - - $required = null; - foreach ($requiredVectors as $nextResVector) { - if($required === null) { - $required = $nextResVector; - } else { - //$required = array_intersect_key($required, $nextResVector); - - /** - * This code is used as workaround for array_intersect_key() slowness problem. - */ - $updatedVector = array(); - foreach ($required as $id => $value) { - if (isset($nextResVector[$id])) { - $updatedVector[$id] = $value; - } - } - $required = $updatedVector; - } - - if (count($required) == 0) { - // Empty result set, we don't need to check other terms - break; - } - } - - if ($required !== null) { - $this->_resVector = $required; - } else { - $this->_resVector = $optional; - } - - if (count($prohibited) != 0) { - // $this->_resVector = array_diff_key($this->_resVector, $prohibited); - - /** - * This code is used as workaround for array_diff_key() slowness problem. - */ - if (count($this->_resVector) < count($prohibited)) { - $updatedVector = $this->_resVector; - foreach ($this->_resVector as $id => $value) { - if (isset($prohibited[$id])) { - unset($updatedVector[$id]); - } - } - $this->_resVector = $updatedVector; - } else { - $updatedVector = $this->_resVector; - foreach ($prohibited as $id => $value) { - unset($updatedVector[$id]); - } - $this->_resVector = $updatedVector; - } - } - - ksort($this->_resVector, SORT_NUMERIC); - } - - - /** - * Score calculator for conjunction queries (all terms are required) - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function _conjunctionScore($docId, Zend_Search_Lucene_Interface $reader) - { - if ($this->_coord === null) { - $this->_coord = $reader->getSimilarity()->coord(count($this->_terms), - count($this->_terms) ); - } - - $score = 0.0; - - foreach ($this->_terms as $termId=>$term) { - /** - * We don't need to check that term freq is not 0 - * Score calculation is performed only for matched docs - */ - $score += $reader->getSimilarity()->tf($this->_termsFreqs[$termId][$docId]) * - $this->_weights[$termId]->getValue() * - $reader->norm($docId, $term->field); - } - - return $score * $this->_coord * $this->getBoost(); - } - - - /** - * Score calculator for non conjunction queries (not all terms are required) - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function _nonConjunctionScore($docId, $reader) - { - if ($this->_coord === null) { - $this->_coord = array(); - - $maxCoord = 0; - foreach ($this->_signs as $sign) { - if ($sign !== false /* not prohibited */) { - $maxCoord++; - } - } - - for ($count = 0; $count <= $maxCoord; $count++) { - $this->_coord[$count] = $reader->getSimilarity()->coord($count, $maxCoord); - } - } - - $score = 0.0; - $matchedTerms = 0; - foreach ($this->_terms as $termId=>$term) { - // Check if term is - if ($this->_signs[$termId] !== false && // not prohibited - isset($this->_termsFreqs[$termId][$docId]) // matched - ) { - $matchedTerms++; - - /** - * We don't need to check that term freq is not 0 - * Score calculation is performed only for matched docs - */ - $score += - $reader->getSimilarity()->tf($this->_termsFreqs[$termId][$docId]) * - $this->_weights[$termId]->getValue() * - $reader->norm($docId, $term->field); - } - } - - return $score * $this->_coord[$matchedTerms] * $this->getBoost(); - } - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - if ($this->_signs === null) { - $this->_calculateConjunctionResult($reader); - } else { - $this->_calculateNonConjunctionResult($reader); - } - - // Initialize weight if it's not done yet - $this->_initWeight($reader); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - */ - public function matchedDocs() - { - return $this->_resVector; - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - if (isset($this->_resVector[$docId])) { - if ($this->_signs === null) { - return $this->_conjunctionScore($docId, $reader); - } else { - return $this->_nonConjunctionScore($docId, $reader); - } - } else { - return 0; - } - } - - /** - * Return query terms - * - * @return array - */ - public function getQueryTerms() - { - if ($this->_signs === null) { - return $this->_terms; - } - - $terms = array(); - - foreach ($this->_signs as $id => $sign) { - if ($sign !== false) { - $terms[] = $this->_terms[$id]; - } - } - - return $terms; - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $words = array(); - - if ($this->_signs === null) { - foreach ($this->_terms as $term) { - $words[] = $term->text; - } - } else { - foreach ($this->_signs as $id => $sign) { - if ($sign !== false) { - $words[] = $this->_terms[$id]->text; - } - } - } - - $doc->highlight($words, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - - $query = ''; - - foreach ($this->_terms as $id => $term) { - if ($id != 0) { - $query .= ' '; - } - - if ($this->_signs === null || $this->_signs[$id] === true) { - $query .= '+'; - } else if ($this->_signs[$id] === false) { - $query .= '-'; - } - - if ($term->field !== null) { - $query .= $term->field . ':'; - } - $query .= $term->text; - } - - if ($this->getBoost() != 1) { - $query = '(' . $query . ')^' . $this->getBoost(); - } - - return $query; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Phrase.php b/search/Zend/Search/Lucene/Search/Query/Phrase.php deleted file mode 100644 index d275fe37f1f..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Phrase.php +++ /dev/null @@ -1,567 +0,0 @@ - (docId => array( pos1, pos2, ... ), ...) - * term2Id => (docId => array( pos1, pos2, ... ), ...) - * - * @var array - */ - private $_termsPositions = array(); - - /** - * Class constructor. Create a new prase query. - * - * @param string $field Field to search. - * @param array $terms Terms to search Array of strings. - * @param array $offsets Relative term positions. Array of integers. - * @throws Zend_Search_Lucene_Exception - */ - public function __construct($terms = null, $offsets = null, $field = null) - { - $this->_slop = 0; - - if (is_array($terms)) { - $this->_terms = array(); - foreach ($terms as $termId => $termText) { - $this->_terms[$termId] = ($field !== null)? new Zend_Search_Lucene_Index_Term($termText, $field): - new Zend_Search_Lucene_Index_Term($termText); - } - } else if ($terms === null) { - $this->_terms = array(); - } else { - throw new Zend_Search_Lucene_Exception('terms argument must be array of strings or null'); - } - - if (is_array($offsets)) { - if (count($this->_terms) != count($offsets)) { - throw new Zend_Search_Lucene_Exception('terms and offsets arguments must have the same size.'); - } - $this->_offsets = $offsets; - } else if ($offsets === null) { - $this->_offsets = array(); - foreach ($this->_terms as $termId => $term) { - $position = count($this->_offsets); - $this->_offsets[$termId] = $position; - } - } else { - throw new Zend_Search_Lucene_Exception('offsets argument must be array of strings or null'); - } - } - - /** - * Set slop - * - * @param integer $slop - */ - public function setSlop($slop) - { - $this->_slop = $slop; - } - - - /** - * Get slop - * - * @return integer - */ - public function getSlop() - { - return $this->_slop; - } - - - /** - * Adds a term to the end of the query phrase. - * The relative position of the term is specified explicitly or the one immediately - * after the last term added. - * - * @param Zend_Search_Lucene_Index_Term $term - * @param integer $position - */ - public function addTerm(Zend_Search_Lucene_Index_Term $term, $position = null) { - if ((count($this->_terms) != 0)&&(end($this->_terms)->field != $term->field)) { - throw new Zend_Search_Lucene_Exception('All phrase terms must be in the same field: ' . - $term->field . ':' . $term->text); - } - - $this->_terms[] = $term; - if ($position !== null) { - $this->_offsets[] = $position; - } else if (count($this->_offsets) != 0) { - $this->_offsets[] = end($this->_offsets) + 1; - } else { - $this->_offsets[] = 0; - } - } - - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - if (count($this->_terms) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } else if ($this->_terms[0]->field !== null) { - return $this; - } else { - $query = new Zend_Search_Lucene_Search_Query_Boolean(); - $query->setBoost($this->getBoost()); - - foreach ($index->getFieldNames(true) as $fieldName) { - $subquery = new Zend_Search_Lucene_Search_Query_Phrase(); - $subquery->setSlop($this->getSlop()); - - foreach ($this->_terms as $termId => $term) { - $qualifiedTerm = new Zend_Search_Lucene_Index_Term($term->text, $fieldName); - - $subquery->addTerm($qualifiedTerm, $this->_offsets[$termId]); - } - - $query->addSubquery($subquery); - } - - return $query; - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - // Check, that index contains all phrase terms - foreach ($this->_terms as $term) { - if (!$index->hasTerm($term)) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - } - - if (count($this->_terms) == 1) { - // It's one term query - $optimizedQuery = new Zend_Search_Lucene_Search_Query_Term(reset($this->_terms)); - $optimizedQuery->setBoost($this->getBoost()); - - return $optimizedQuery; - } - - if (count($this->_terms) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - - return $this; - } - - /** - * Returns query term - * - * @return array - */ - public function getTerms() - { - return $this->_terms; - } - - - /** - * Set weight for specified term - * - * @param integer $num - * @param Zend_Search_Lucene_Search_Weight_Term $weight - */ - public function setWeight($num, $weight) - { - $this->_weights[$num] = $weight; - } - - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - $this->_weight = new Zend_Search_Lucene_Search_Weight_Phrase($this, $reader); - return $this->_weight; - } - - - /** - * Score calculator for exact phrase queries (terms sequence is fixed) - * - * @param integer $docId - * @return float - */ - public function _exactPhraseFreq($docId) - { - $freq = 0; - - // Term Id with lowest cardinality - $lowCardTermId = null; - - // Calculate $lowCardTermId - foreach ($this->_terms as $termId => $term) { - if ($lowCardTermId === null || - count($this->_termsPositions[$termId][$docId]) < - count($this->_termsPositions[$lowCardTermId][$docId]) ) { - $lowCardTermId = $termId; - } - } - - // Walk through positions of the term with lowest cardinality - foreach ($this->_termsPositions[$lowCardTermId][$docId] as $lowCardPos) { - // We expect phrase to be found - $freq++; - - // Walk through other terms - foreach ($this->_terms as $termId => $term) { - if ($termId != $lowCardTermId) { - $expectedPosition = $lowCardPos + - ($this->_offsets[$termId] - - $this->_offsets[$lowCardTermId]); - - if (!in_array($expectedPosition, $this->_termsPositions[$termId][$docId])) { - $freq--; // Phrase wasn't found. - break; - } - } - } - } - - return $freq; - } - - /** - * Score calculator for sloppy phrase queries (terms sequence is fixed) - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function _sloppyPhraseFreq($docId, Zend_Search_Lucene_Interface $reader) - { - $freq = 0; - - $phraseQueue = array(); - $phraseQueue[0] = array(); // empty phrase - $lastTerm = null; - - // Walk through the terms to create phrases. - foreach ($this->_terms as $termId => $term) { - $queueSize = count($phraseQueue); - $firstPass = true; - - // Walk through the term positions. - // Each term position produces a set of phrases. - foreach ($this->_termsPositions[$termId][$docId] as $termPosition ) { - if ($firstPass) { - for ($count = 0; $count < $queueSize; $count++) { - $phraseQueue[$count][$termId] = $termPosition; - } - } else { - for ($count = 0; $count < $queueSize; $count++) { - if ($lastTerm !== null && - abs( $termPosition - $phraseQueue[$count][$lastTerm] - - ($this->_offsets[$termId] - $this->_offsets[$lastTerm])) > $this->_slop) { - continue; - } - - $newPhraseId = count($phraseQueue); - $phraseQueue[$newPhraseId] = $phraseQueue[$count]; - $phraseQueue[$newPhraseId][$termId] = $termPosition; - } - - } - - $firstPass = false; - } - $lastTerm = $termId; - } - - - foreach ($phraseQueue as $phrasePos) { - $minDistance = null; - - for ($shift = -$this->_slop; $shift <= $this->_slop; $shift++) { - $distance = 0; - $start = reset($phrasePos) - reset($this->_offsets) + $shift; - - foreach ($this->_terms as $termId => $term) { - $distance += abs($phrasePos[$termId] - $this->_offsets[$termId] - $start); - - if($distance > $this->_slop) { - break; - } - } - - if ($minDistance === null || $distance < $minDistance) { - $minDistance = $distance; - } - } - - if ($minDistance <= $this->_slop) { - $freq += $reader->getSimilarity()->sloppyFreq($minDistance); - } - } - - return $freq; - } - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - $this->_resVector = null; - - if (count($this->_terms) == 0) { - $this->_resVector = array(); - } - - $resVectors = array(); - $resVectorsSizes = array(); - $resVectorsIds = array(); // is used to prevent arrays comparison - foreach ($this->_terms as $termId => $term) { - $resVectors[] = array_flip($reader->termDocs($term)); - $resVectorsSizes[] = count(end($resVectors)); - $resVectorsIds[] = $termId; - - $this->_termsPositions[$termId] = $reader->termPositions($term); - } - // sort resvectors in order of subquery cardinality increasing - array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC, - $resVectorsIds, SORT_ASC, SORT_NUMERIC, - $resVectors); - - foreach ($resVectors as $nextResVector) { - if($this->_resVector === null) { - $this->_resVector = $nextResVector; - } else { - //$this->_resVector = array_intersect_key($this->_resVector, $nextResVector); - - /** - * This code is used as workaround for array_intersect_key() slowness problem. - */ - $updatedVector = array(); - foreach ($this->_resVector as $id => $value) { - if (isset($nextResVector[$id])) { - $updatedVector[$id] = $value; - } - } - $this->_resVector = $updatedVector; - } - - if (count($this->_resVector) == 0) { - // Empty result set, we don't need to check other terms - break; - } - } - - // ksort($this->_resVector, SORT_NUMERIC); - // Docs are returned ordered. Used algorithm doesn't change elements order. - - // Initialize weight if it's not done yet - $this->_initWeight($reader); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - */ - public function matchedDocs() - { - return $this->_resVector; - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - if (isset($this->_resVector[$docId])) { - if ($this->_slop == 0) { - $freq = $this->_exactPhraseFreq($docId); - } else { - $freq = $this->_sloppyPhraseFreq($docId, $reader); - } - - if ($freq != 0) { - $tf = $reader->getSimilarity()->tf($freq); - $weight = $this->_weight->getValue(); - $norm = $reader->norm($docId, reset($this->_terms)->field); - - return $tf * $weight * $norm * $this->getBoost(); - } - - // Included in result, but culculated freq is zero - return 0; - } else { - return 0; - } - } - - /** - * Return query terms - * - * @return array - */ - public function getQueryTerms() - { - return $this->_terms; - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $words = array(); - foreach ($this->_terms as $term) { - $words[] = $term->text; - } - - $doc->highlight($words, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - - $query = ''; - - if (isset($this->_terms[0]) && $this->_terms[0]->field !== null) { - $query .= $this->_terms[0]->field . ':'; - } - - $query .= '"'; - - foreach ($this->_terms as $id => $term) { - if ($id != 0) { - $query .= ' '; - } - $query .= $term->text; - } - - $query .= '"'; - - if ($this->_slop != 0) { - $query .= '~' . $this->_slop; - } - - return $query; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Range.php b/search/Zend/Search/Lucene/Search/Query/Range.php deleted file mode 100644 index 4e8c6383e8c..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Range.php +++ /dev/null @@ -1,331 +0,0 @@ -field != $upperTerm->field) { - throw new Zend_Search_Lucene_Exception('Both terms must be for the same field'); - } - - $this->_field = ($lowerTerm !== null)? $lowerTerm->field : $upperTerm->field; - $this->_lowerTerm = $lowerTerm; - $this->_upperTerm = $upperTerm; - $this->_inclusive = $inclusive; - } - - /** - * Get query field name - * - * @return string|null - */ - public function getField() - { - return $this->_field; - } - - /** - * Get lower term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function getLowerTerm() - { - return $this->_lowerTerm; - } - - /** - * Get upper term - * - * @return Zend_Search_Lucene_Index_Term|null - */ - public function getUpperTerm() - { - return $this->_upperTerm; - } - - /** - * Get upper term - * - * @return boolean - */ - public function isInclusive() - { - return $this->_inclusive; - } - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - $this->_matches = array(); - - if ($this->_field === null) { - // Search through all fields - $fields = $index->getFieldNames(true /* indexed fields list */); - } else { - $fields = array($this->_field); - } - - foreach ($fields as $field) { - $index->resetTermsStream(); - - if ($this->_lowerTerm !== null) { - $lowerTerm = new Zend_Search_Lucene_Index_Term($this->_lowerTerm->text, $field); - - $index->skipTo($lowerTerm); - - if (!$this->_inclusive && - $index->currentTerm() == $lowerTerm) { - // Skip lower term - $index->nextTerm(); - } - } else { - $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); - } - - - if ($this->_upperTerm !== null) { - // Walk up to the upper term - $upperTerm = new Zend_Search_Lucene_Index_Term($this->_upperTerm->text, $field); - - while ($index->currentTerm() !== null && - $index->currentTerm()->field == $field && - $index->currentTerm()->text < $upperTerm->text) { - $this->_matches[] = $index->currentTerm(); - $index->nextTerm(); - } - - if ($this->_inclusive && $index->currentTerm() == $upperTerm) { - // Include upper term into result - $this->_matches[] = $upperTerm; - } - } else { - // Walk up to the end of field data - while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { - $this->_matches[] = $index->currentTerm(); - $index->nextTerm(); - } - } - - $index->closeTermsStream(); - } - - if (count($this->_matches) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } else if (count($this->_matches) == 1) { - return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); - } else { - $rewrittenQuery = new Zend_Search_Lucene_Search_Query_MultiTerm(); - - foreach ($this->_matches as $matchedTerm) { - $rewrittenQuery->addTerm($matchedTerm); - } - - return $rewrittenQuery; - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Return query terms - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function getQueryTerms() - { - if ($this->_matches === null) { - throw new Zend_Search_Lucene_Exception('Search has to be performed first to get matched terms'); - } - - return $this->_matches; - } - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - * @throws Zend_Search_Lucene_Exception - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); - } - - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - * @throws Zend_Search_Lucene_Exception - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function matchedDocs() - { - throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - * @throws Zend_Search_Lucene_Exception - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $words = array(); - - foreach ($this->_matches as $term) { - $words[] = $term->text; - } - - $doc->highlight($words, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - return (($this->_field === null)? '' : $this->_field . ':') - . (($this->_inclusive)? '[' : '{') - . (($this->_lowerTerm !== null)? $this->_lowerTerm->text : 'null') - . ' TO ' - . (($this->_upperTerm !== null)? $this->_upperTerm->text : 'null') - . (($this->_inclusive)? ']' : '}'); - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Term.php b/search/Zend/Search/Lucene/Search/Query/Term.php deleted file mode 100644 index f9aa071b8ec..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Term.php +++ /dev/null @@ -1,224 +0,0 @@ -dirroot}/search/Zend/Search/Lucene/Search/Query.php"; - -/** Zend_Search_Lucene_Search_Weight_Term */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Weight/Term.php"; - - -/** - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Search - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ -class Zend_Search_Lucene_Search_Query_Term extends Zend_Search_Lucene_Search_Query -{ - /** - * Term to find. - * - * @var Zend_Search_Lucene_Index_Term - */ - private $_term; - - /** - * Documents vector. - * - * @var array - */ - private $_docVector = null; - - /** - * Term freqs vector. - * array(docId => freq, ...) - * - * @var array - */ - private $_termFreqs; - - - /** - * Zend_Search_Lucene_Search_Query_Term constructor - * - * @param Zend_Search_Lucene_Index_Term $term - * @param boolean $sign - */ - public function __construct(Zend_Search_Lucene_Index_Term $term) - { - $this->_term = $term; - } - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - if ($this->_term->field != null) { - return $this; - } else { - $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); - $query->setBoost($this->getBoost()); - - foreach ($index->getFieldNames(true) as $fieldName) { - $term = new Zend_Search_Lucene_Index_Term($this->_term->text, $fieldName); - - $query->addTerm($term); - } - - return $query->rewrite($index); - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - // Check, that index contains specified term - if (!$index->hasTerm($this->_term)) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } - - return $this; - } - - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - $this->_weight = new Zend_Search_Lucene_Search_Weight_Term($this->_term, $this, $reader); - return $this->_weight; - } - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - $this->_docVector = array_flip($reader->termDocs($this->_term)); - $this->_termFreqs = $reader->termFreqs($this->_term); - - // Initialize weight if it's not done yet - $this->_initWeight($reader); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - */ - public function matchedDocs() - { - return $this->_docVector; - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - if (isset($this->_docVector[$docId])) { - return $reader->getSimilarity()->tf($this->_termFreqs[$docId]) * - $this->_weight->getValue() * - $reader->norm($docId, $this->_term->field) * - $this->getBoost(); - } else { - return 0; - } - } - - /** - * Return query terms - * - * @return array - */ - public function getQueryTerms() - { - return array($this->_term); - } - - /** - * Return query term - * - * @return Zend_Search_Lucene_Index_Term - */ - public function getTerm() - { - return $this->_term; - } - - /** - * Returns query term - * - * @return array - */ - public function getTerms() - { - return $this->_terms; - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $doc->highlight($this->_term->text, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - return (($this->_term->field === null)? '':$this->_term->field . ':') . $this->_term->text; - } -} - diff --git a/search/Zend/Search/Lucene/Search/Query/Wildcard.php b/search/Zend/Search/Lucene/Search/Query/Wildcard.php deleted file mode 100644 index 5ca692df514..00000000000 --- a/search/Zend/Search/Lucene/Search/Query/Wildcard.php +++ /dev/null @@ -1,297 +0,0 @@ -_pattern = $pattern; - } - - /** - * Get terms prefix - * - * @param string $word - * @return string - */ - private static function _getPrefix($word) - { - $questionMarkPosition = strpos($word, '?'); - $astrericPosition = strpos($word, '*'); - - if ($questionMarkPosition !== false) { - if ($astrericPosition !== false) { - return substr($word, 0, min($questionMarkPosition, $astrericPosition)); - } - - return substr($word, 0, $questionMarkPosition); - } else if ($astrericPosition !== false) { - return substr($word, 0, $astrericPosition); - } - - return $word; - } - - /** - * Re-write query into primitive queries in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function rewrite(Zend_Search_Lucene_Interface $index) - { - $this->_matches = array(); - - if ($this->_pattern->field === null) { - // Search through all fields - $fields = $index->getFieldNames(true /* indexed fields list */); - } else { - $fields = array($this->_pattern->field); - } - - $prefix = self::_getPrefix($this->_pattern->text); - $prefixLength = strlen($prefix); - $matchExpression = '/^' . str_replace(array('\\?', '\\*'), array('.', '.*') , preg_quote($this->_pattern->text, '/')) . '$/'; - - /** @todo check for PCRE unicode support may be performed through Zend_Environment in some future */ - if (@preg_match('/\pL/u', 'a') == 1) { - // PCRE unicode support is turned on - // add Unicode modifier to the match expression - $matchExpression .= 'u'; - } - - - foreach ($fields as $field) { - $index->resetTermsStream(); - - if ($prefix != '') { - $index->skipTo(new Zend_Search_Lucene_Index_Term($prefix, $field)); - - while ($index->currentTerm() !== null && - $index->currentTerm()->field == $field && - substr($index->currentTerm()->text, 0, $prefixLength) == $prefix) { - if (preg_match($matchExpression, $index->currentTerm()->text) === 1) { - $this->_matches[] = $index->currentTerm(); - } - - $index->nextTerm(); - } - } else { - $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); - - while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { - if (preg_match($matchExpression, $index->currentTerm()->text) === 1) { - $this->_matches[] = $index->currentTerm(); - } - - $index->nextTerm(); - } - } - - $index->closeTermsStream(); - } - - if (count($this->_matches) == 0) { - return new Zend_Search_Lucene_Search_Query_Empty(); - } else if (count($this->_matches) == 1) { - return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); - } else { - $rewrittenQuery = new Zend_Search_Lucene_Search_Query_MultiTerm(); - - foreach ($this->_matches as $matchedTerm) { - $rewrittenQuery->addTerm($matchedTerm); - } - - return $rewrittenQuery; - } - } - - /** - * Optimize query in the context of specified index - * - * @param Zend_Search_Lucene_Interface $index - * @return Zend_Search_Lucene_Search_Query - */ - public function optimize(Zend_Search_Lucene_Interface $index) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - - /** - * Returns query pattern - * - * @return Zend_Search_Lucene_Index_Term - */ - public function getPattern() - { - return $this->_pattern; - } - - - /** - * Return query terms - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function getQueryTerms() - { - if ($this->_matches === null) { - throw new Zend_Search_Lucene_Exception('Search has to be performed first to get matched terms'); - } - - return $this->_matches; - } - - /** - * Constructs an appropriate Weight implementation for this query. - * - * @param Zend_Search_Lucene_Interface $reader - * @return Zend_Search_Lucene_Search_Weight - * @throws Zend_Search_Lucene_Exception - */ - public function createWeight(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - - /** - * Execute query in context of index reader - * It also initializes necessary internal structures - * - * @param Zend_Search_Lucene_Interface $reader - * @throws Zend_Search_Lucene_Exception - */ - public function execute(Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Get document ids likely matching the query - * - * It's an array with document ids as keys (performance considerations) - * - * @return array - * @throws Zend_Search_Lucene_Exception - */ - public function matchedDocs() - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Score specified document - * - * @param integer $docId - * @param Zend_Search_Lucene_Interface $reader - * @return float - * @throws Zend_Search_Lucene_Exception - */ - public function score($docId, Zend_Search_Lucene_Interface $reader) - { - throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); - } - - /** - * Highlight query terms - * - * @param integer &$colorIndex - * @param Zend_Search_Lucene_Document_Html $doc - */ - public function highlightMatchesDOM(Zend_Search_Lucene_Document_Html $doc, &$colorIndex) - { - $words = array(); - - $matchExpression = '/^' . str_replace(array('\\?', '\\*'), array('.', '.*') , preg_quote($this->_pattern->text, '/')) . '$/'; - if (@preg_match('/\pL/u', 'a') == 1) { - // PCRE unicode support is turned on - // add Unicode modifier to the match expression - $matchExpression .= 'u'; - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($doc->getFieldUtf8Value('body'), 'UTF-8'); - foreach ($tokens as $token) { - if (preg_match($matchExpression, $token->getTermText()) === 1) { - $words[] = $token->getTermText(); - } - } - - $doc->highlight($words, $this->_getHighlightColor($colorIndex)); - } - - /** - * Print a query - * - * @return string - */ - public function __toString() - { - // It's used only for query visualisation, so we don't care about characters escaping - return (($this->_pattern->field === null)? '' : $this->_pattern->field . ':') . $this->_pattern->text; - } -} - diff --git a/search/Zend/Search/Lucene/Search/QueryEntry.php b/search/Zend/Search/Lucene/Search/QueryEntry.php deleted file mode 100644 index b5ea48317e9..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryEntry.php +++ /dev/null @@ -1,87 +0,0 @@ -_boost *= $boostFactor; - } - - -} diff --git a/search/Zend/Search/Lucene/Search/QueryEntry/Phrase.php b/search/Zend/Search/Lucene/Search/QueryEntry/Phrase.php deleted file mode 100644 index 0f0090ab4f4..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryEntry/Phrase.php +++ /dev/null @@ -1,149 +0,0 @@ -_phrase = $phrase; - $this->_field = $field; - } - - /** - * Process modifier ('~') - * - * @param mixed $parameter - */ - public function processFuzzyProximityModifier($parameter = null) - { - $this->_proximityQuery = true; - - if ($parameter !== null) { - $this->_wordsDistance = $parameter; - } - } - - /** - * Transform entry to a subquery - * - * @param string $encoding - * @return Zend_Search_Lucene_Search_Query - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function getQuery($encoding) - { - if (strpos($this->_phrase, '?') !== false || strpos($this->_phrase, '*') !== false) { - throw new Zend_Search_Lucene_Search_QueryParserException('Wildcards are only allowed in a single terms.'); - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_phrase, $encoding); - - if (count($tokens) == 0) { - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - - if (count($tokens) == 1) { - $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field); - $query = new Zend_Search_Lucene_Search_Query_Term($term); - $query->setBoost($this->_boost); - - return $query; - } - - //It's not empty or one term query - $position = -1; - $query = new Zend_Search_Lucene_Search_Query_Phrase(); - foreach ($tokens as $token) { - $position += $token->getPositionIncrement(); - $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $this->_field); - $query->addTerm($term, $position); - } - - if ($this->_proximityQuery) { - $query->setSlop($this->_wordsDistance); - } - - $query->setBoost($this->_boost); - - return $query; - } -} diff --git a/search/Zend/Search/Lucene/Search/QueryEntry/Subquery.php b/search/Zend/Search/Lucene/Search/QueryEntry/Subquery.php deleted file mode 100644 index de15ba81df2..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryEntry/Subquery.php +++ /dev/null @@ -1,86 +0,0 @@ -_query = $query; - } - - /** - * Process modifier ('~') - * - * @param mixed $parameter - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function processFuzzyProximityModifier($parameter = null) - { - throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' sign must follow term or phrase'); - } - - - /** - * Transform entry to a subquery - * - * @param string $encoding - * @return Zend_Search_Lucene_Search_Query - */ - public function getQuery($encoding) - { - $this->_query->setBoost($this->_boost); - - return $this->_query; - } -} diff --git a/search/Zend/Search/Lucene/Search/QueryEntry/Term.php b/search/Zend/Search/Lucene/Search/QueryEntry/Term.php deleted file mode 100644 index 9b81e84dcfd..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryEntry/Term.php +++ /dev/null @@ -1,203 +0,0 @@ -_term = $term; - $this->_field = $field; - } - - /** - * Process modifier ('~') - * - * @param mixed $parameter - */ - public function processFuzzyProximityModifier($parameter = null) - { - $this->_fuzzyQuery = true; - - if ($parameter !== null) { - $this->_similarity = $parameter; - } else { - $this->_similarity = Zend_Search_Lucene_Search_Query_Fuzzy::DEFAULT_MIN_SIMILARITY; - } - } - - /** - * Transform entry to a subquery - * - * @param string $encoding - * @return Zend_Search_Lucene_Search_Query - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function getQuery($encoding) - { - if (strpos($this->_term, '?') !== false || strpos($this->_term, '*') !== false) { - if ($this->_fuzzyQuery) { - throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is not supported for terms with wildcards.'); - } - - $pattern = ''; - - $subPatterns = explode('*', $this->_term); - - $astericFirstPass = true; - foreach ($subPatterns as $subPattern) { - if (!$astericFirstPass) { - $pattern .= '*'; - } else { - $astericFirstPass = false; - } - - $subPatternsL2 = explode('?', $subPattern); - - $qMarkFirstPass = true; - foreach ($subPatternsL2 as $subPatternL2) { - if (!$qMarkFirstPass) { - $pattern .= '?'; - } else { - $qMarkFirstPass = false; - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($subPatternL2, $encoding); - if (count($tokens) > 1) { - throw new Zend_Search_Lucene_Search_QueryParserException('Wildcard search is supported only for non-multiple word terms'); - } - - foreach ($tokens as $token) { - $pattern .= $token->getTermText(); - } - } - } - - $term = new Zend_Search_Lucene_Index_Term($pattern, $this->_field); - $query = new Zend_Search_Lucene_Search_Query_Wildcard($term); - $query->setBoost($this->_boost); - - return $query; - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_term, $encoding); - - if (count($tokens) == 0) { - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - - if (count($tokens) == 1 && !$this->_fuzzyQuery) { - $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field); - $query = new Zend_Search_Lucene_Search_Query_Term($term); - $query->setBoost($this->_boost); - - return $query; - } - - if (count($tokens) == 1 && $this->_fuzzyQuery) { - $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field); - $query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, $this->_similarity); - $query->setBoost($this->_boost); - - return $query; - } - - if ($this->_fuzzyQuery) { - throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is supported only for non-multiple word terms'); - } - - //It's not empty or one term query - $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); - - /** - * @todo Process $token->getPositionIncrement() to support stemming, synonyms and other - * analizer design features - */ - foreach ($tokens as $token) { - $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $this->_field); - $query->addTerm($term, true); // all subterms are required - } - - $query->setBoost($this->_boost); - - return $query; - } -} diff --git a/search/Zend/Search/Lucene/Search/QueryHit.php b/search/Zend/Search/Lucene/Search/QueryHit.php deleted file mode 100644 index 2a281979b73..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryHit.php +++ /dev/null @@ -1,108 +0,0 @@ -_index = new Zend_Search_Lucene_Proxy($index); - } - - - /** - * Convenience function for getting fields from the document - * associated with this hit. - * - * @param string $offset - * @return string - */ - public function __get($offset) - { - return $this->getDocument()->getFieldValue($offset); - } - - - /** - * Return the document object for this hit - * - * @return Zend_Search_Lucene_Document - */ - public function getDocument() - { - if (!$this->_document instanceof Zend_Search_Lucene_Document) { - $this->_document = $this->_index->getDocument($this->id); - } - - return $this->_document; - } - - - /** - * Return the index object for this hit - * - * @return Zend_Search_Lucene_Interface - */ - public function getIndex() - { - return $this->_index; - } -} - diff --git a/search/Zend/Search/Lucene/Search/QueryLexer.php b/search/Zend/Search/Lucene/Search/QueryLexer.php deleted file mode 100644 index 206e7a66b77..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryLexer.php +++ /dev/null @@ -1,508 +0,0 @@ -addRules(array( array(self::ST_WHITE_SPACE, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_WHITE_SPACE, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_WHITE_SPACE, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_WHITE_SPACE, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - array(self::ST_WHITE_SPACE, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), - array(self::ST_WHITE_SPACE, self::IN_QUOTE, self::ST_QUOTED_LEXEME), - array(self::ST_WHITE_SPACE, self::IN_DECIMAL_POINT, self::ST_LEXEME), - array(self::ST_WHITE_SPACE, self::IN_ASCII_DIGIT, self::ST_LEXEME), - array(self::ST_WHITE_SPACE, self::IN_CHAR, self::ST_LEXEME) - )); - $this->addRules(array( array(self::ST_SYNT_LEXEME, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_SYNT_LEXEME, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_SYNT_LEXEME, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_SYNT_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - array(self::ST_SYNT_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), - array(self::ST_SYNT_LEXEME, self::IN_QUOTE, self::ST_QUOTED_LEXEME), - array(self::ST_SYNT_LEXEME, self::IN_DECIMAL_POINT, self::ST_LEXEME), - array(self::ST_SYNT_LEXEME, self::IN_ASCII_DIGIT, self::ST_LEXEME), - array(self::ST_SYNT_LEXEME, self::IN_CHAR, self::ST_LEXEME) - )); - $this->addRules(array( array(self::ST_LEXEME, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_LEXEME, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_LEXEME, self::IN_MUTABLE_CHAR, self::ST_LEXEME), - array(self::ST_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - array(self::ST_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), - - // IN_QUOTE not allowed - array(self::ST_LEXEME, self::IN_QUOTE, self::ST_ERROR, $quoteWithinLexemeErrorAction), - - array(self::ST_LEXEME, self::IN_DECIMAL_POINT, self::ST_LEXEME), - array(self::ST_LEXEME, self::IN_ASCII_DIGIT, self::ST_LEXEME), - array(self::ST_LEXEME, self::IN_CHAR, self::ST_LEXEME) - )); - $this->addRules(array( array(self::ST_QUOTED_LEXEME, self::IN_WHITE_SPACE, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_SYNT_CHAR, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_MUTABLE_CHAR, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_QCHAR), - array(self::ST_QUOTED_LEXEME, self::IN_QUOTE, self::ST_WHITE_SPACE), - array(self::ST_QUOTED_LEXEME, self::IN_DECIMAL_POINT, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_ASCII_DIGIT, self::ST_QUOTED_LEXEME), - array(self::ST_QUOTED_LEXEME, self::IN_CHAR, self::ST_QUOTED_LEXEME) - )); - $this->addRules(array( array(self::ST_ESCAPED_CHAR, self::IN_WHITE_SPACE, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_SYNT_CHAR, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_MUTABLE_CHAR, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_LEXEME_MODIFIER, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_ESCAPE_CHAR, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_QUOTE, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_DECIMAL_POINT, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_ASCII_DIGIT, self::ST_LEXEME), - array(self::ST_ESCAPED_CHAR, self::IN_CHAR, self::ST_LEXEME) - )); - $this->addRules(array( array(self::ST_ESCAPED_QCHAR, self::IN_WHITE_SPACE, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_SYNT_CHAR, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_MUTABLE_CHAR, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_LEXEME_MODIFIER, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_ESCAPE_CHAR, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_QUOTE, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_DECIMAL_POINT, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_ASCII_DIGIT, self::ST_QUOTED_LEXEME), - array(self::ST_ESCAPED_QCHAR, self::IN_CHAR, self::ST_QUOTED_LEXEME) - )); - $this->addRules(array( array(self::ST_LEXEME_MODIFIER, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_LEXEME_MODIFIER, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_LEXEME_MODIFIER, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_LEXEME_MODIFIER, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - - // IN_ESCAPE_CHAR not allowed - array(self::ST_LEXEME_MODIFIER, self::IN_ESCAPE_CHAR, self::ST_ERROR, $lexemeModifierErrorAction), - - // IN_QUOTE not allowed - array(self::ST_LEXEME_MODIFIER, self::IN_QUOTE, self::ST_ERROR, $lexemeModifierErrorAction), - - - array(self::ST_LEXEME_MODIFIER, self::IN_DECIMAL_POINT, self::ST_MANTISSA), - array(self::ST_LEXEME_MODIFIER, self::IN_ASCII_DIGIT, self::ST_NUMBER), - - // IN_CHAR not allowed - array(self::ST_LEXEME_MODIFIER, self::IN_CHAR, self::ST_ERROR, $lexemeModifierErrorAction), - )); - $this->addRules(array( array(self::ST_NUMBER, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_NUMBER, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_NUMBER, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_NUMBER, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - - // IN_ESCAPE_CHAR not allowed - array(self::ST_NUMBER, self::IN_ESCAPE_CHAR, self::ST_ERROR, $wrongNumberErrorAction), - - // IN_QUOTE not allowed - array(self::ST_NUMBER, self::IN_QUOTE, self::ST_ERROR, $wrongNumberErrorAction), - - array(self::ST_NUMBER, self::IN_DECIMAL_POINT, self::ST_MANTISSA), - array(self::ST_NUMBER, self::IN_ASCII_DIGIT, self::ST_NUMBER), - - // IN_CHAR not allowed - array(self::ST_NUMBER, self::IN_CHAR, self::ST_ERROR, $wrongNumberErrorAction), - )); - $this->addRules(array( array(self::ST_MANTISSA, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), - array(self::ST_MANTISSA, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_MANTISSA, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), - array(self::ST_MANTISSA, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), - - // IN_ESCAPE_CHAR not allowed - array(self::ST_MANTISSA, self::IN_ESCAPE_CHAR, self::ST_ERROR, $wrongNumberErrorAction), - - // IN_QUOTE not allowed - array(self::ST_MANTISSA, self::IN_QUOTE, self::ST_ERROR, $wrongNumberErrorAction), - - // IN_DECIMAL_POINT not allowed - array(self::ST_MANTISSA, self::IN_DECIMAL_POINT, self::ST_ERROR, $wrongNumberErrorAction), - - array(self::ST_MANTISSA, self::IN_ASCII_DIGIT, self::ST_MANTISSA), - - // IN_CHAR not allowed - array(self::ST_MANTISSA, self::IN_CHAR, self::ST_ERROR, $wrongNumberErrorAction), - )); - - - /** Actions */ - $syntaxLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addQuerySyntaxLexeme'); - $lexemeModifierAction = new Zend_Search_Lucene_FSMAction($this, 'addLexemeModifier'); - $addLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addLexeme'); - $addQuotedLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addQuotedLexeme'); - $addNumberLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addNumberLexeme'); - $addLexemeCharAction = new Zend_Search_Lucene_FSMAction($this, 'addLexemeChar'); - - - /** Syntax lexeme */ - $this->addEntryAction(self::ST_SYNT_LEXEME, $syntaxLexemeAction); - // Two lexemes in succession - $this->addTransitionAction(self::ST_SYNT_LEXEME, self::ST_SYNT_LEXEME, $syntaxLexemeAction); - - - /** Lexeme */ - $this->addEntryAction(self::ST_LEXEME, $addLexemeCharAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_LEXEME, $addLexemeCharAction); - // ST_ESCAPED_CHAR => ST_LEXEME transition is covered by ST_LEXEME entry action - - $this->addTransitionAction(self::ST_LEXEME, self::ST_WHITE_SPACE, $addLexemeAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_SYNT_LEXEME, $addLexemeAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_QUOTED_LEXEME, $addLexemeAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_LEXEME_MODIFIER, $addLexemeAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_NUMBER, $addLexemeAction); - $this->addTransitionAction(self::ST_LEXEME, self::ST_MANTISSA, $addLexemeAction); - - - /** Quoted lexeme */ - // We don't need entry action (skeep quote) - $this->addTransitionAction(self::ST_QUOTED_LEXEME, self::ST_QUOTED_LEXEME, $addLexemeCharAction); - $this->addTransitionAction(self::ST_ESCAPED_QCHAR, self::ST_QUOTED_LEXEME, $addLexemeCharAction); - // Closing quote changes state to the ST_WHITE_SPACE other states are not used - $this->addTransitionAction(self::ST_QUOTED_LEXEME, self::ST_WHITE_SPACE, $addQuotedLexemeAction); - - - /** Lexeme modifier */ - $this->addEntryAction(self::ST_LEXEME_MODIFIER, $lexemeModifierAction); - - - /** Number */ - $this->addEntryAction(self::ST_NUMBER, $addLexemeCharAction); - $this->addEntryAction(self::ST_MANTISSA, $addLexemeCharAction); - $this->addTransitionAction(self::ST_NUMBER, self::ST_NUMBER, $addLexemeCharAction); - // ST_NUMBER => ST_MANTISSA transition is covered by ST_MANTISSA entry action - $this->addTransitionAction(self::ST_MANTISSA, self::ST_MANTISSA, $addLexemeCharAction); - - $this->addTransitionAction(self::ST_NUMBER, self::ST_WHITE_SPACE, $addNumberLexemeAction); - $this->addTransitionAction(self::ST_NUMBER, self::ST_SYNT_LEXEME, $addNumberLexemeAction); - $this->addTransitionAction(self::ST_NUMBER, self::ST_LEXEME_MODIFIER, $addNumberLexemeAction); - $this->addTransitionAction(self::ST_MANTISSA, self::ST_WHITE_SPACE, $addNumberLexemeAction); - $this->addTransitionAction(self::ST_MANTISSA, self::ST_SYNT_LEXEME, $addNumberLexemeAction); - $this->addTransitionAction(self::ST_MANTISSA, self::ST_LEXEME_MODIFIER, $addNumberLexemeAction); - } - - - - - /** - * Translate input char to an input symbol of state machine - * - * @param string $char - * @return integer - */ - private function _translateInput($char) - { - if (strpos(self::QUERY_WHITE_SPACE_CHARS, $char) !== false) { return self::IN_WHITE_SPACE; - } else if (strpos(self::QUERY_SYNT_CHARS, $char) !== false) { return self::IN_SYNT_CHAR; - } else if (strpos(self::QUERY_MUTABLE_CHARS, $char) !== false) { return self::IN_MUTABLE_CHAR; - } else if (strpos(self::QUERY_LEXEMEMODIFIER_CHARS, $char) !== false) { return self::IN_LEXEME_MODIFIER; - } else if (strpos(self::QUERY_ASCIIDIGITS_CHARS, $char) !== false) { return self::IN_ASCII_DIGIT; - } else if ($char === '"' ) { return self::IN_QUOTE; - } else if ($char === '.' ) { return self::IN_DECIMAL_POINT; - } else if ($char === '\\') { return self::IN_ESCAPE_CHAR; - } else { return self::IN_CHAR; - } - } - - - /** - * This method is used to tokenize query string into lexemes - * - * @param string $inputString - * @param string $encoding - * @return array - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function tokenize($inputString, $encoding) - { - $this->reset(); - - $this->_lexemes = array(); - $this->_queryString = array(); - - $strLength = iconv_strlen($inputString, $encoding); - - // Workaround for iconv_substr bug - $inputString .= ' '; - - for ($count = 0; $count < $strLength; $count++) { - $this->_queryString[$count] = iconv_substr($inputString, $count, 1, $encoding); - } - - for ($this->_queryStringPosition = 0; - $this->_queryStringPosition < count($this->_queryString); - $this->_queryStringPosition++) { - $this->process($this->_translateInput($this->_queryString[$this->_queryStringPosition])); - } - - $this->process(self::IN_WHITE_SPACE); - - if ($this->getState() != self::ST_WHITE_SPACE) { - throw new Zend_Search_Lucene_Search_QueryParserException('Unexpected end of query'); - } - - $this->_queryString = null; - - return $this->_lexemes; - } - - - - /********************************************************************* - * Actions implementation - * - * Actions affect on recognized lexemes list - *********************************************************************/ - - /** - * Add query syntax lexeme - * - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function addQuerySyntaxLexeme() - { - $lexeme = $this->_queryString[$this->_queryStringPosition]; - - // Process two char lexemes - if (strpos(self::QUERY_DOUBLECHARLEXEME_CHARS, $lexeme) !== false) { - // increase current position in a query string - $this->_queryStringPosition++; - - // check, - if ($this->_queryStringPosition == count($this->_queryString) || - $this->_queryString[$this->_queryStringPosition] != $lexeme) { - throw new Zend_Search_Lucene_Search_QueryParserException('Two chars lexeme expected. ' . $this->_positionMsg()); - } - - // duplicate character - $lexeme .= $lexeme; - } - - $token = new Zend_Search_Lucene_Search_QueryToken( - Zend_Search_Lucene_Search_QueryToken::TC_SYNTAX_ELEMENT, - $lexeme, - $this->_queryStringPosition); - - // Skip this lexeme if it's a field indicator ':' and treat previous as 'field' instead of 'word' - if ($token->type == Zend_Search_Lucene_Search_QueryToken::TT_FIELD_INDICATOR) { - $token = array_pop($this->_lexemes); - if ($token === null || $token->type != Zend_Search_Lucene_Search_QueryToken::TT_WORD) { - throw new Zend_Search_Lucene_Search_QueryParserException('Field mark \':\' must follow field name. ' . $this->_positionMsg()); - } - - $token->type = Zend_Search_Lucene_Search_QueryToken::TT_FIELD; - } - - $this->_lexemes[] = $token; - } - - /** - * Add lexeme modifier - */ - public function addLexemeModifier() - { - $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( - Zend_Search_Lucene_Search_QueryToken::TC_SYNTAX_ELEMENT, - $this->_queryString[$this->_queryStringPosition], - $this->_queryStringPosition); - } - - - /** - * Add lexeme - */ - public function addLexeme() - { - $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( - Zend_Search_Lucene_Search_QueryToken::TC_WORD, - $this->_currentLexeme, - $this->_queryStringPosition - 1); - - $this->_currentLexeme = ''; - } - - /** - * Add quoted lexeme - */ - public function addQuotedLexeme() - { - $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( - Zend_Search_Lucene_Search_QueryToken::TC_PHRASE, - $this->_currentLexeme, - $this->_queryStringPosition); - - $this->_currentLexeme = ''; - } - - /** - * Add number lexeme - */ - public function addNumberLexeme() - { - $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( - Zend_Search_Lucene_Search_QueryToken::TC_NUMBER, - $this->_currentLexeme, - $this->_queryStringPosition - 1); - $this->_currentLexeme = ''; - } - - /** - * Extend lexeme by one char - */ - public function addLexemeChar() - { - $this->_currentLexeme .= $this->_queryString[$this->_queryStringPosition]; - } - - - /** - * Position message - * - * @return string - */ - private function _positionMsg() - { - return 'Position is ' . $this->_queryStringPosition . '.'; - } - - - /********************************************************************* - * Syntax errors actions - *********************************************************************/ - public function lexModifierErrException() - { - throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier character can be followed only by number, white space or query syntax element. ' . $this->_positionMsg()); - } - public function quoteWithinLexemeErrException() - { - throw new Zend_Search_Lucene_Search_QueryParserException('Quote within lexeme must be escaped by \'\\\' char. ' . $this->_positionMsg()); - } - public function wrongNumberErrException() - { - throw new Zend_Search_Lucene_Search_QueryParserException('Wrong number syntax.' . $this->_positionMsg()); - } -} - diff --git a/search/Zend/Search/Lucene/Search/QueryParser.php b/search/Zend/Search/Lucene/Search/QueryParser.php deleted file mode 100644 index b1092a5af65..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryParser.php +++ /dev/null @@ -1,630 +0,0 @@ -dirroot}/search/Zend/Search/Lucene/Index/Term.php"; - -/** Zend_Search_Lucene_Search_Query_Term */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Term.php"; - -/** Zend_Search_Lucene_Search_Query_MultiTerm */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/MultiTerm.php"; - -/** Zend_Search_Lucene_Search_Query_Boolean */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Boolean.php"; - -/** Zend_Search_Lucene_Search_Query_Phrase */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Phrase.php"; - -/** Zend_Search_Lucene_Search_Query_Wildcard */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Wildcard.php"; - -/** Zend_Search_Lucene_Search_Query_Range */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Range.php"; - -/** Zend_Search_Lucene_Search_Query_Fuzzy */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Fuzzy.php"; - -/** Zend_Search_Lucene_Search_Query_Empty */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Empty.php"; - -/** Zend_Search_Lucene_Search_Query_Insignificant */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Insignificant.php"; - - -/** Zend_Search_Lucene_Search_QueryLexer */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryLexer.php"; - -/** Zend_Search_Lucene_Search_QueryParserContext */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryParserContext.php"; - - -/** Zend_Search_Lucene_FSM */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/FSM.php"; - -/** Zend_Search_Lucene_Exception */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Exception.php"; - -/** Zend_Search_Lucene_Search_QueryParserException */ -require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryParserException.php"; - - -/** - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Search - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ -class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM -{ - /** - * Parser instance - * - * @var Zend_Search_Lucene_Search_QueryParser - */ - private static $_instance = null; - - - /** - * Query lexer - * - * @var Zend_Search_Lucene_Search_QueryLexer - */ - private $_lexer; - - /** - * Tokens list - * Array of Zend_Search_Lucene_Search_QueryToken objects - * - * @var array - */ - private $_tokens; - - /** - * Current token - * - * @var integer|string - */ - private $_currentToken; - - /** - * Last token - * - * It can be processed within FSM states, but this addirional state simplifies FSM - * - * @var Zend_Search_Lucene_Search_QueryToken - */ - private $_lastToken = null; - - /** - * Range query first term - * - * @var string - */ - private $_rqFirstTerm = null; - - /** - * Current query parser context - * - * @var Zend_Search_Lucene_Search_QueryParserContext - */ - private $_context; - - /** - * Context stack - * - * @var array - */ - private $_contextStack; - - /** - * Query string encoding - * - * @var string - */ - private $_encoding; - - /** - * Query string default encoding - * - * @var string - */ - private $_defaultEncoding = ''; - - /** - * Defines query parsing mode. - * - * If this option is turned on, then query parser suppress query parser exceptions - * and constructs multi-term query using all words from a query. - * - * That helps to avoid exceptions caused by queries, which don't conform to query language, - * but limits possibilities to check, that query entered by user has some inconsistencies. - * - * - * Default is true. - * - * Use {@link Zend_Search_Lucene::suppressQueryParsingExceptions()}, - * {@link Zend_Search_Lucene::dontSuppressQueryParsingExceptions()} and - * {@link Zend_Search_Lucene::checkQueryParsingExceptionsSuppressMode()} to operate - * with this setting. - * - * @var boolean - */ - private $_suppressQueryParsingExceptions = true; - - /** - * Boolean operators constants - */ - const B_OR = 0; - const B_AND = 1; - - /** - * Default boolean queries operator - * - * @var integer - */ - private $_defaultOperator = self::B_OR; - - - /** Query parser State Machine states */ - const ST_COMMON_QUERY_ELEMENT = 0; // Terms, phrases, operators - const ST_CLOSEDINT_RQ_START = 1; // Range query start (closed interval) - '[' - const ST_CLOSEDINT_RQ_FIRST_TERM = 2; // First term in '[term1 to term2]' construction - const ST_CLOSEDINT_RQ_TO_TERM = 3; // 'TO' lexeme in '[term1 to term2]' construction - const ST_CLOSEDINT_RQ_LAST_TERM = 4; // Second term in '[term1 to term2]' construction - const ST_CLOSEDINT_RQ_END = 5; // Range query end (closed interval) - ']' - const ST_OPENEDINT_RQ_START = 6; // Range query start (opened interval) - '{' - const ST_OPENEDINT_RQ_FIRST_TERM = 7; // First term in '{term1 to term2}' construction - const ST_OPENEDINT_RQ_TO_TERM = 8; // 'TO' lexeme in '{term1 to term2}' construction - const ST_OPENEDINT_RQ_LAST_TERM = 9; // Second term in '{term1 to term2}' construction - const ST_OPENEDINT_RQ_END = 10; // Range query end (opened interval) - '}' - - /** - * Parser constructor - */ - public function __construct() - { - parent::__construct(array(self::ST_COMMON_QUERY_ELEMENT, - self::ST_CLOSEDINT_RQ_START, - self::ST_CLOSEDINT_RQ_FIRST_TERM, - self::ST_CLOSEDINT_RQ_TO_TERM, - self::ST_CLOSEDINT_RQ_LAST_TERM, - self::ST_CLOSEDINT_RQ_END, - self::ST_OPENEDINT_RQ_START, - self::ST_OPENEDINT_RQ_FIRST_TERM, - self::ST_OPENEDINT_RQ_TO_TERM, - self::ST_OPENEDINT_RQ_LAST_TERM, - self::ST_OPENEDINT_RQ_END - ), - Zend_Search_Lucene_Search_QueryToken::getTypes()); - - $this->addRules( - array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT), - array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT) - )); - $this->addRules( - array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM), - array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM), - array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM), - array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT) - )); - $this->addRules( - array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM), - array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM), - array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM), - array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT) - )); - - - - $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry'); - $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry'); - $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField'); - $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign'); - $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier'); - $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter'); - $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart'); - $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd'); - $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator'); - $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm'); - $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm'); - $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm'); - $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm'); - - - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction); - $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction); - - $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction); - $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction); - $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction); - $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction); - - - - $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer(); - } - - /** - * Get query parser instance - * - * @return Zend_Search_Lucene_Search_QueryParser - */ - private static function _getInstance() - { - if (self::$_instance === null) { - self::$_instance = new self(); - } - return self::$_instance; - } - - /** - * Set query string default encoding - * - * @param string $encoding - */ - public static function setDefaultEncoding($encoding) - { - self::_getInstance()->_defaultEncoding = $encoding; - } - - /** - * Get query string default encoding - * - * @return string - */ - public static function getDefaultEncoding() - { - return self::_getInstance()->_defaultEncoding; - } - - /** - * Set default boolean operator - * - * @param integer $operator - */ - public static function setDefaultOperator($operator) - { - self::_getInstance()->_defaultOperator = $operator; - } - - /** - * Get default boolean operator - * - * @return integer - */ - public static function getDefaultOperator() - { - return self::_getInstance()->_defaultOperator; - } - - /** - * Turn on 'suppress query parser exceptions' mode. - */ - public static function suppressQueryParsingExceptions() - { - self::_getInstance()->_suppressQueryParsingExceptions = true; - } - /** - * Turn off 'suppress query parser exceptions' mode. - */ - public static function dontSuppressQueryParsingExceptions() - { - self::_getInstance()->_suppressQueryParsingExceptions = false; - } - /** - * Check 'suppress query parser exceptions' mode. - * @return boolean - */ - public static function queryParsingExceptionsSuppressed() - { - return self::_getInstance()->_suppressQueryParsingExceptions; - } - - - - /** - * Parses a query string - * - * @param string $strQuery - * @param string $encoding - * @return Zend_Search_Lucene_Search_Query - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public static function parse($strQuery, $encoding = null) - { - self::_getInstance(); - - // Reset FSM if previous parse operation didn't return it into a correct state - self::$_instance->reset(); - - try { - self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding; - self::$_instance->_lastToken = null; - self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding); - self::$_instance->_contextStack = array(); - self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding); - - // Empty query - if (count(self::$_instance->_tokens) == 0) { - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - - - foreach (self::$_instance->_tokens as $token) { - try { - self::$_instance->_currentToken = $token; - self::$_instance->process($token->type); - - self::$_instance->_lastToken = $token; - } catch (Exception $e) { - if (strpos($e->getMessage(), 'There is no any rule for') !== false) { - throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.' ); - } - - throw $e; - } - } - - if (count(self::$_instance->_contextStack) != 0) { - throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' ); - } - - return self::$_instance->_context->getQuery(); - } catch (Zend_Search_Lucene_Search_QueryParserException $e) { - if (self::$_instance->_suppressQueryParsingExceptions) { - $queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding); - - $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); - $termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true /* required term */ : - null /* optional term */; - - foreach ($queryTokens as $token) { - $query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign); - } - - - return $query; - } else { - throw $e; - } - } - } - - - /********************************************************************* - * Actions implementation - * - * Actions affect on recognized lexemes list - *********************************************************************/ - - /** - * Add term to a query - */ - public function addTermEntry() - { - $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField()); - $this->_context->addEntry($entry); - } - - /** - * Add phrase to a query - */ - public function addPhraseEntry() - { - $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField()); - $this->_context->addEntry($entry); - } - - /** - * Set entry field - */ - public function setField() - { - $this->_context->setNextEntryField($this->_currentToken->text); - } - - /** - * Set entry sign - */ - public function setSign() - { - $this->_context->setNextEntrySign($this->_currentToken->type); - } - - - /** - * Process fuzzy search/proximity modifier - '~' - */ - public function processFuzzyProximityModifier() - { - $this->_context->processFuzzyProximityModifier(); - } - - /** - * Process modifier parameter - * - * @throws Zend_Search_Lucene_Exception - */ - public function processModifierParameter() - { - if ($this->_lastToken === null) { - throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); - } - - switch ($this->_lastToken->type) { - case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK: - $this->_context->processFuzzyProximityModifier($this->_currentToken->text); - break; - - case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK: - $this->_context->boost($this->_currentToken->text); - break; - - default: - // It's not a user input exception - throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); - } - } - - - /** - * Start subquery - */ - public function subqueryStart() - { - $this->_contextStack[] = $this->_context; - $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField()); - } - - /** - * End subquery - */ - public function subqueryEnd() - { - if (count($this->_contextStack) == 0) { - throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' ); - } - - $query = $this->_context->getQuery(); - $this->_context = array_pop($this->_contextStack); - - $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query)); - } - - /** - * Process logical operator - */ - public function logicalOperator() - { - $this->_context->addLogicalOperator($this->_currentToken->type); - } - - /** - * Process first range query term (opened interval) - */ - public function openedRQFirstTerm() - { - $this->_rqFirstTerm = $this->_currentToken->text; - } - - /** - * Process last range query term (opened interval) - * - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function openedRQLastTerm() - { - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); - if (count($tokens) > 1) { - throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); - } else if (count($tokens) == 1) { - $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); - } else { - $from = null; - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); - if (count($tokens) > 1) { - throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); - } else if (count($tokens) == 1) { - $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); - } else { - $to = null; - } - - if ($from === null && $to === null) { - throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); - } - - $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false); - $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); - $this->_context->addEntry($entry); - } - - /** - * Process first range query term (closed interval) - */ - public function closedRQFirstTerm() - { - $this->_rqFirstTerm = $this->_currentToken->text; - } - - /** - * Process last range query term (closed interval) - * - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function closedRQLastTerm() - { - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); - if (count($tokens) > 1) { - throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); - } else if (count($tokens) == 1) { - $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); - } else { - $from = null; - } - - $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); - if (count($tokens) > 1) { - throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); - } else if (count($tokens) == 1) { - $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); - } else { - $to = null; - } - - if ($from === null && $to === null) { - throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); - } - - $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true); - $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); - $this->_context->addEntry($entry); - } -} - diff --git a/search/Zend/Search/Lucene/Search/QueryParserContext.php b/search/Zend/Search/Lucene/Search/QueryParserContext.php deleted file mode 100644 index f63914ee2e8..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryParserContext.php +++ /dev/null @@ -1,416 +0,0 @@ -_encoding = $encoding; - $this->_defaultField = $defaultField; - } - - - /** - * Get context default field - * - * @return string|null - */ - public function getField() - { - return ($this->_nextEntryField !== null) ? $this->_nextEntryField : $this->_defaultField; - } - - /** - * Set field for next entry - * - * @param string $field - */ - public function setNextEntryField($field) - { - $this->_nextEntryField = $field; - } - - - /** - * Set sign for next entry - * - * @param integer $sign - * @throws Zend_Search_Lucene_Exception - */ - public function setNextEntrySign($sign) - { - if ($this->_mode === self::GM_BOOLEAN) { - throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.'); - } - - $this->_mode = self::GM_SIGNS; - - if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED) { - $this->_nextEntrySign = true; - } else if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED) { - $this->_nextEntrySign = false; - } else { - throw new Zend_Search_Lucene_Exception('Unrecognized sign type.'); - } - } - - - /** - * Add entry to a query - * - * @param Zend_Search_Lucene_Search_QueryEntry $entry - */ - public function addEntry(Zend_Search_Lucene_Search_QueryEntry $entry) - { - if ($this->_mode !== self::GM_BOOLEAN) { - $this->_signs[] = $this->_nextEntrySign; - } - - $this->_entries[] = $entry; - - $this->_nextEntryField = null; - $this->_nextEntrySign = null; - } - - - /** - * Process fuzzy search or proximity search modifier - * - * @throws Zend_Search_Lucene_Search_QueryParserException - */ - public function processFuzzyProximityModifier($parameter = null) - { - // Check, that modifier has came just after word or phrase - if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) { - throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.'); - } - - $lastEntry = array_pop($this->_entries); - - if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) { - // there are no entries or last entry is boolean operator - throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.'); - } - - $lastEntry->processFuzzyProximityModifier($parameter); - - $this->_entries[] = $lastEntry; - } - - /** - * Set boost factor to the entry - * - * @param float $boostFactor - */ - public function boost($boostFactor) - { - // Check, that modifier has came just after word or phrase - if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) { - throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.'); - } - - $lastEntry = array_pop($this->_entries); - - if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) { - // there are no entries or last entry is boolean operator - throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.'); - } - - $lastEntry->boost($boostFactor); - - $this->_entries[] = $lastEntry; - } - - /** - * Process logical operator - * - * @param integer $operator - */ - public function addLogicalOperator($operator) - { - if ($this->_mode === self::GM_SIGNS) { - throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.'); - } - - $this->_mode = self::GM_BOOLEAN; - - $this->_entries[] = $operator; - } - - - /** - * Generate 'signs style' query from the context - * '+term1 term2 -term3 +() ...' - * - * @return Zend_Search_Lucene_Search_Query - */ - public function _signStyleExpressionQuery() - { - $query = new Zend_Search_Lucene_Search_Query_Boolean(); - - if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { - $defaultSign = true; // required - } else { - // Zend_Search_Lucene_Search_QueryParser::B_OR - $defaultSign = null; // optional - } - - foreach ($this->_entries as $entryId => $entry) { - $sign = ($this->_signs[$entryId] !== null) ? $this->_signs[$entryId] : $defaultSign; - $query->addSubquery($entry->getQuery($this->_encoding), $sign); - } - - return $query; - } - - - /** - * Generate 'boolean style' query from the context - * 'term1 and term2 or term3 and () and not ()' - * - * @return Zend_Search_Lucene_Search_Query - * @throws Zend_Search_Lucene - */ - private function _booleanExpressionQuery() - { - /** - * We treat each level of an expression as a boolean expression in - * a Disjunctive Normal Form - * - * AND operator has higher precedence than OR - * - * Thus logical query is a disjunction of one or more conjunctions of - * one or more query entries - */ - - $expressionRecognizer = new Zend_Search_Lucene_Search_BooleanExpressionRecognizer(); - - try { - foreach ($this->_entries as $entry) { - if ($entry instanceof Zend_Search_Lucene_Search_QueryEntry) { - $expressionRecognizer->processLiteral($entry); - } else { - switch ($entry) { - case Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME: - $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_AND_OPERATOR); - break; - - case Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME: - $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_OR_OPERATOR); - break; - - case Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME: - $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_NOT_OPERATOR); - break; - - default: - throw new Zend_Search_Lucene('Boolean expression error. Unknown operator type.'); - } - } - } - - $conjuctions = $expressionRecognizer->finishExpression(); - } catch (Zend_Search_Exception $e) { - // throw new Zend_Search_Lucene_Search_QueryParserException('Boolean expression error. Error message: \'' . - // $e->getMessage() . '\'.' ); - // It's query syntax error message and it should be user friendly. So FSM message is omitted - throw new Zend_Search_Lucene_Search_QueryParserException('Boolean expression error.'); - } - - // Remove 'only negative' conjunctions - foreach ($conjuctions as $conjuctionId => $conjuction) { - $nonNegativeEntryFound = false; - - foreach ($conjuction as $conjuctionEntry) { - if ($conjuctionEntry[1]) { - $nonNegativeEntryFound = true; - break; - } - } - - if (!$nonNegativeEntryFound) { - unset($conjuctions[$conjuctionId]); - } - } - - - $subqueries = array(); - foreach ($conjuctions as $conjuction) { - // Check, if it's a one term conjuction - if (count($conjuction) == 1) { - $subqueries[] = $conjuction[0][0]->getQuery($this->_encoding); - } else { - $subquery = new Zend_Search_Lucene_Search_Query_Boolean(); - - foreach ($conjuction as $conjuctionEntry) { - $subquery->addSubquery($conjuctionEntry[0]->getQuery($this->_encoding), $conjuctionEntry[1]); - } - - $subqueries[] = $subquery; - } - } - - if (count($subqueries) == 0) { - return new Zend_Search_Lucene_Search_Query_Insignificant(); - } - - if (count($subqueries) == 1) { - return $subqueries[0]; - } - - - $query = new Zend_Search_Lucene_Search_Query_Boolean(); - - foreach ($subqueries as $subquery) { - // Non-requirered entry/subquery - $query->addSubquery($subquery); - } - - return $query; - } - - /** - * Generate query from current context - * - * @return Zend_Search_Lucene_Search_Query - */ - public function getQuery() - { - if ($this->_mode === self::GM_BOOLEAN) { - return $this->_booleanExpressionQuery(); - } else { - return $this->_signStyleExpressionQuery(); - } - } -} diff --git a/search/Zend/Search/Lucene/Search/QueryParserException.php b/search/Zend/Search/Lucene/Search/QueryParserException.php deleted file mode 100644 index 52f6fb7bf58..00000000000 --- a/search/Zend/Search/Lucene/Search/QueryParserException.php +++ /dev/null @@ -1,40 +0,0 @@ - or field:() pairs - const TT_FIELD_INDICATOR = 3; // ':' - const TT_REQUIRED = 4; // '+' - const TT_PROHIBITED = 5; // '-' - const TT_FUZZY_PROX_MARK = 6; // '~' - const TT_BOOSTING_MARK = 7; // '^' - const TT_RANGE_INCL_START = 8; // '[' - const TT_RANGE_INCL_END = 9; // ']' - const TT_RANGE_EXCL_START = 10; // '{' - const TT_RANGE_EXCL_END = 11; // '}' - const TT_SUBQUERY_START = 12; // '(' - const TT_SUBQUERY_END = 13; // ')' - const TT_AND_LEXEME = 14; // 'AND' or 'and' - const TT_OR_LEXEME = 15; // 'OR' or 'or' - const TT_NOT_LEXEME = 16; // 'NOT' or 'not' - const TT_TO_LEXEME = 17; // 'TO' or 'to' - const TT_NUMBER = 18; // Number, like: 10, 0.8, .64, .... - - - /** - * Returns all possible lexeme types. - * It's used for syntax analyzer state machine initialization - * - * @return array - */ - public static function getTypes() - { - return array( self::TT_WORD, - self::TT_PHRASE, - self::TT_FIELD, - self::TT_FIELD_INDICATOR, - self::TT_REQUIRED, - self::TT_PROHIBITED, - self::TT_FUZZY_PROX_MARK, - self::TT_BOOSTING_MARK, - self::TT_RANGE_INCL_START, - self::TT_RANGE_INCL_END, - self::TT_RANGE_EXCL_START, - self::TT_RANGE_EXCL_END, - self::TT_SUBQUERY_START, - self::TT_SUBQUERY_END, - self::TT_AND_LEXEME, - self::TT_OR_LEXEME, - self::TT_NOT_LEXEME, - self::TT_TO_LEXEME, - self::TT_NUMBER - ); - } - - - /** - * TokenCategories - */ - const TC_WORD = 0; // Word - const TC_PHRASE = 1; // Phrase (one or several quoted words) - const TC_NUMBER = 2; // Nubers, which are used with syntax elements. Ex. roam~0.8 - const TC_SYNTAX_ELEMENT = 3; // + - ( ) [ ] { } ! || && ~ ^ - - - /** - * Token type. - * - * @var integer - */ - public $type; - - /** - * Token text. - * - * @var integer - */ - public $text; - - /** - * Token position within query. - * - * @var integer - */ - public $position; - - - /** - * IndexReader constructor needs token type and token text as a parameters. - * - * @param integer $tokenCategory - * @param string $tokText - * @param integer $position - */ - public function __construct($tokenCategory, $tokenText, $position) - { - $this->text = $tokenText; - $this->position = $position + 1; // Start from 1 - - switch ($tokenCategory) { - case self::TC_WORD: - if ( strtolower($tokenText) == 'and') { - $this->type = self::TT_AND_LEXEME; - } else if (strtolower($tokenText) == 'or') { - $this->type = self::TT_OR_LEXEME; - } else if (strtolower($tokenText) == 'not') { - $this->type = self::TT_NOT_LEXEME; - } else if (strtolower($tokenText) == 'to') { - $this->type = self::TT_TO_LEXEME; - } else { - $this->type = self::TT_WORD; - } - break; - - case self::TC_PHRASE: - $this->type = self::TT_PHRASE; - break; - - case self::TC_NUMBER: - $this->type = self::TT_NUMBER; - break; - - case self::TC_SYNTAX_ELEMENT: - switch ($tokenText) { - case ':': - $this->type = self::TT_FIELD_INDICATOR; - break; - - case '+': - $this->type = self::TT_REQUIRED; - break; - - case '-': - $this->type = self::TT_PROHIBITED; - break; - - case '~': - $this->type = self::TT_FUZZY_PROX_MARK; - break; - - case '^': - $this->type = self::TT_BOOSTING_MARK; - break; - - case '[': - $this->type = self::TT_RANGE_INCL_START; - break; - - case ']': - $this->type = self::TT_RANGE_INCL_END; - break; - - case '{': - $this->type = self::TT_RANGE_EXCL_START; - break; - - case '}': - $this->type = self::TT_RANGE_EXCL_END; - break; - - case '(': - $this->type = self::TT_SUBQUERY_START; - break; - - case ')': - $this->type = self::TT_SUBQUERY_END; - break; - - case '!': - $this->type = self::TT_NOT_LEXEME; - break; - - case '&&': - $this->type = self::TT_AND_LEXEME; - break; - - case '||': - $this->type = self::TT_OR_LEXEME; - break; - - default: - throw new Zend_Search_Lucene_Exception('Unrecognized query syntax lexeme: \'' . $tokenText . '\''); - } - break; - - case self::TC_NUMBER: - $this->type = self::TT_NUMBER; - - default: - throw new Zend_Search_Lucene_Exception('Unrecognized lexeme type: \'' . $tokenCategory . '\''); - } - } -} - diff --git a/search/Zend/Search/Lucene/Search/Similarity.php b/search/Zend/Search/Lucene/Search/Similarity.php deleted file mode 100644 index 95b05656560..00000000000 --- a/search/Zend/Search/Lucene/Search/Similarity.php +++ /dev/null @@ -1,553 +0,0 @@ - 0.0, - 1 => 5.820766E-10, - 2 => 6.9849193E-10, - 3 => 8.1490725E-10, - 4 => 9.313226E-10, - 5 => 1.1641532E-9, - 6 => 1.3969839E-9, - 7 => 1.6298145E-9, - 8 => 1.8626451E-9, - 9 => 2.3283064E-9, - 10 => 2.7939677E-9, - 11 => 3.259629E-9, - 12 => 3.7252903E-9, - 13 => 4.656613E-9, - 14 => 5.5879354E-9, - 15 => 6.519258E-9, - 16 => 7.4505806E-9, - 17 => 9.313226E-9, - 18 => 1.1175871E-8, - 19 => 1.3038516E-8, - 20 => 1.4901161E-8, - 21 => 1.8626451E-8, - 22 => 2.2351742E-8, - 23 => 2.6077032E-8, - 24 => 2.9802322E-8, - 25 => 3.7252903E-8, - 26 => 4.4703484E-8, - 27 => 5.2154064E-8, - 28 => 5.9604645E-8, - 29 => 7.4505806E-8, - 30 => 8.940697E-8, - 31 => 1.0430813E-7, - 32 => 1.1920929E-7, - 33 => 1.4901161E-7, - 34 => 1.7881393E-7, - 35 => 2.0861626E-7, - 36 => 2.3841858E-7, - 37 => 2.9802322E-7, - 38 => 3.5762787E-7, - 39 => 4.172325E-7, - 40 => 4.7683716E-7, - 41 => 5.9604645E-7, - 42 => 7.1525574E-7, - 43 => 8.34465E-7, - 44 => 9.536743E-7, - 45 => 1.1920929E-6, - 46 => 1.4305115E-6, - 47 => 1.66893E-6, - 48 => 1.9073486E-6, - 49 => 2.3841858E-6, - 50 => 2.861023E-6, - 51 => 3.33786E-6, - 52 => 3.8146973E-6, - 53 => 4.7683716E-6, - 54 => 5.722046E-6, - 55 => 6.67572E-6, - 56 => 7.6293945E-6, - 57 => 9.536743E-6, - 58 => 1.1444092E-5, - 59 => 1.335144E-5, - 60 => 1.5258789E-5, - 61 => 1.9073486E-5, - 62 => 2.2888184E-5, - 63 => 2.670288E-5, - 64 => 3.0517578E-5, - 65 => 3.8146973E-5, - 66 => 4.5776367E-5, - 67 => 5.340576E-5, - 68 => 6.1035156E-5, - 69 => 7.6293945E-5, - 70 => 9.1552734E-5, - 71 => 1.0681152E-4, - 72 => 1.2207031E-4, - 73 => 1.5258789E-4, - 74 => 1.8310547E-4, - 75 => 2.1362305E-4, - 76 => 2.4414062E-4, - 77 => 3.0517578E-4, - 78 => 3.6621094E-4, - 79 => 4.272461E-4, - 80 => 4.8828125E-4, - 81 => 6.1035156E-4, - 82 => 7.324219E-4, - 83 => 8.544922E-4, - 84 => 9.765625E-4, - 85 => 0.0012207031, - 86 => 0.0014648438, - 87 => 0.0017089844, - 88 => 0.001953125, - 89 => 0.0024414062, - 90 => 0.0029296875, - 91 => 0.0034179688, - 92 => 0.00390625, - 93 => 0.0048828125, - 94 => 0.005859375, - 95 => 0.0068359375, - 96 => 0.0078125, - 97 => 0.009765625, - 98 => 0.01171875, - 99 => 0.013671875, - 100 => 0.015625, - 101 => 0.01953125, - 102 => 0.0234375, - 103 => 0.02734375, - 104 => 0.03125, - 105 => 0.0390625, - 106 => 0.046875, - 107 => 0.0546875, - 108 => 0.0625, - 109 => 0.078125, - 110 => 0.09375, - 111 => 0.109375, - 112 => 0.125, - 113 => 0.15625, - 114 => 0.1875, - 115 => 0.21875, - 116 => 0.25, - 117 => 0.3125, - 118 => 0.375, - 119 => 0.4375, - 120 => 0.5, - 121 => 0.625, - 122 => 0.75, - 123 => 0.875, - 124 => 1.0, - 125 => 1.25, - 126 => 1.5, - 127 => 1.75, - 128 => 2.0, - 129 => 2.5, - 130 => 3.0, - 131 => 3.5, - 132 => 4.0, - 133 => 5.0, - 134 => 6.0, - 135 => 7.0, - 136 => 8.0, - 137 => 10.0, - 138 => 12.0, - 139 => 14.0, - 140 => 16.0, - 141 => 20.0, - 142 => 24.0, - 143 => 28.0, - 144 => 32.0, - 145 => 40.0, - 146 => 48.0, - 147 => 56.0, - 148 => 64.0, - 149 => 80.0, - 150 => 96.0, - 151 => 112.0, - 152 => 128.0, - 153 => 160.0, - 154 => 192.0, - 155 => 224.0, - 156 => 256.0, - 157 => 320.0, - 158 => 384.0, - 159 => 448.0, - 160 => 512.0, - 161 => 640.0, - 162 => 768.0, - 163 => 896.0, - 164 => 1024.0, - 165 => 1280.0, - 166 => 1536.0, - 167 => 1792.0, - 168 => 2048.0, - 169 => 2560.0, - 170 => 3072.0, - 171 => 3584.0, - 172 => 4096.0, - 173 => 5120.0, - 174 => 6144.0, - 175 => 7168.0, - 176 => 8192.0, - 177 => 10240.0, - 178 => 12288.0, - 179 => 14336.0, - 180 => 16384.0, - 181 => 20480.0, - 182 => 24576.0, - 183 => 28672.0, - 184 => 32768.0, - 185 => 40960.0, - 186 => 49152.0, - 187 => 57344.0, - 188 => 65536.0, - 189 => 81920.0, - 190 => 98304.0, - 191 => 114688.0, - 192 => 131072.0, - 193 => 163840.0, - 194 => 196608.0, - 195 => 229376.0, - 196 => 262144.0, - 197 => 327680.0, - 198 => 393216.0, - 199 => 458752.0, - 200 => 524288.0, - 201 => 655360.0, - 202 => 786432.0, - 203 => 917504.0, - 204 => 1048576.0, - 205 => 1310720.0, - 206 => 1572864.0, - 207 => 1835008.0, - 208 => 2097152.0, - 209 => 2621440.0, - 210 => 3145728.0, - 211 => 3670016.0, - 212 => 4194304.0, - 213 => 5242880.0, - 214 => 6291456.0, - 215 => 7340032.0, - 216 => 8388608.0, - 217 => 1.048576E7, - 218 => 1.2582912E7, - 219 => 1.4680064E7, - 220 => 1.6777216E7, - 221 => 2.097152E7, - 222 => 2.5165824E7, - 223 => 2.9360128E7, - 224 => 3.3554432E7, - 225 => 4.194304E7, - 226 => 5.0331648E7, - 227 => 5.8720256E7, - 228 => 6.7108864E7, - 229 => 8.388608E7, - 230 => 1.00663296E8, - 231 => 1.17440512E8, - 232 => 1.34217728E8, - 233 => 1.6777216E8, - 234 => 2.01326592E8, - 235 => 2.34881024E8, - 236 => 2.68435456E8, - 237 => 3.3554432E8, - 238 => 4.02653184E8, - 239 => 4.69762048E8, - 240 => 5.3687091E8, - 241 => 6.7108864E8, - 242 => 8.0530637E8, - 243 => 9.395241E8, - 244 => 1.07374182E9, - 245 => 1.34217728E9, - 246 => 1.61061274E9, - 247 => 1.87904819E9, - 248 => 2.14748365E9, - 249 => 2.68435456E9, - 250 => 3.22122547E9, - 251 => 3.75809638E9, - 252 => 4.2949673E9, - 253 => 5.3687091E9, - 254 => 6.4424509E9, - 255 => 7.5161928E9 ); - - - /** - * Set the default Similarity implementation used by indexing and search - * code. - * - * @param Zend_Search_Lucene_Search_Similarity $similarity - */ - public static function setDefault(Zend_Search_Lucene_Search_Similarity $similarity) - { - self::$_defaultImpl = $similarity; - } - - - /** - * Return the default Similarity implementation used by indexing and search - * code. - * - * @return Zend_Search_Lucene_Search_Similarity - */ - public static function getDefault() - { - if (!self::$_defaultImpl instanceof Zend_Search_Lucene_Search_Similarity) { - self::$_defaultImpl = new Zend_Search_Lucene_Search_Similarity_Default(); - } - - return self::$_defaultImpl; - } - - - /** - * Computes the normalization value for a field given the total number of - * terms contained in a field. These values, together with field boosts, are - * stored in an index and multipled into scores for hits on each field by the - * search code. - * - * Matches in longer fields are less precise, so implemenations of this - * method usually return smaller values when 'numTokens' is large, - * and larger values when 'numTokens' is small. - * - * That these values are computed under - * IndexWriter::addDocument(Document) and stored then using - * encodeNorm(float). Thus they have limited precision, and documents - * must be re-indexed if this method is altered. - * - * fieldName - name of field - * numTokens - the total number of tokens contained in fields named - * 'fieldName' of 'doc'. - * Returns a normalization factor for hits on this field of this document - * - * @param string $fieldName - * @param integer $numTokens - * @return float - */ - abstract public function lengthNorm($fieldName, $numTokens); - - /** - * Computes the normalization value for a query given the sum of the squared - * weights of each of the query terms. This value is then multipled into the - * weight of each query term. - * - * This does not affect ranking, but rather just attempts to make scores - * from different queries comparable. - * - * sumOfSquaredWeights - the sum of the squares of query term weights - * Returns a normalization factor for query weights - * - * @param float $sumOfSquaredWeights - * @return float - */ - abstract public function queryNorm($sumOfSquaredWeights); - - - /** - * Decodes a normalization factor stored in an index. - * - * @param integer $byte - * @return float - */ - public static function decodeNorm($byte) - { - return self::$_normTable[$byte & 0xFF]; - } - - - /** - * Encodes a normalization factor for storage in an index. - * - * The encoding uses a five-bit exponent and three-bit mantissa, thus - * representing values from around 7x10^9 to 2x10^-9 with about one - * significant decimal digit of accuracy. Zero is also represented. - * Negative numbers are rounded up to zero. Values too large to represent - * are rounded down to the largest representable value. Positive values too - * small to represent are rounded up to the smallest positive representable - * value. - * - * @param float $f - * @return integer - */ - static function encodeNorm($f) - { - return self::_floatToByte($f); - } - - /** - * Float to byte conversion - * - * @param integer $b - * @return float - */ - private static function _floatToByte($f) - { - // round negatives up to zero - if ($f <= 0.0) { - return 0; - } - - // search for appropriate value - $lowIndex = 0; - $highIndex = 255; - while ($highIndex >= $lowIndex) { - // $mid = ($highIndex - $lowIndex)/2; - $mid = ($highIndex + $lowIndex) >> 1; - $delta = $f - self::$_normTable[$mid]; - - if ($delta < 0) { - $highIndex = $mid-1; - } elseif ($delta > 0) { - $lowIndex = $mid+1; - } else { - return $mid; // We got it! - } - } - - // round to closest value - if ($highIndex != 255 && - $f - self::$_normTable[$highIndex] > self::$_normTable[$highIndex+1] - $f ) { - return $highIndex + 1; - } else { - return $highIndex; - } - } - - - /** - * Computes a score factor based on a term or phrase's frequency in a - * document. This value is multiplied by the idf(Term, Searcher) - * factor for each term in the query and these products are then summed to - * form the initial score for a document. - * - * Terms and phrases repeated in a document indicate the topic of the - * document, so implementations of this method usually return larger values - * when 'freq' is large, and smaller values when 'freq' - * is small. - * - * freq - the frequency of a term within a document - * Returns a score factor based on a term's within-document frequency - * - * @param float $freq - * @return float - */ - abstract public function tf($freq); - - /** - * Computes the amount of a sloppy phrase match, based on an edit distance. - * This value is summed for each sloppy phrase match in a document to form - * the frequency that is passed to tf(float). - * - * A phrase match with a small edit distance to a document passage more - * closely matches the document, so implementations of this method usually - * return larger values when the edit distance is small and smaller values - * when it is large. - * - * distance - the edit distance of this sloppy phrase match - * Returns the frequency increment for this match - * - * @param integer $distance - * @return float - */ - abstract public function sloppyFreq($distance); - - - /** - * Computes a score factor for a simple term or a phrase. - * - * The default implementation is: - * return idfFreq(searcher.docFreq(term), searcher.maxDoc()); - * - * input - the term in question or array of terms - * reader - reader the document collection being searched - * Returns a score factor for the term - * - * @param mixed $input - * @param Zend_Search_Lucene_Interface $reader - * @return a score factor for the term - */ - public function idf($input, Zend_Search_Lucene_Interface $reader) - { - if (!is_array($input)) { - return $this->idfFreq($reader->docFreq($input), $reader->count()); - } else { - $idf = 0.0; - foreach ($input as $term) { - $idf += $this->idfFreq($reader->docFreq($term), $reader->count()); - } - return $idf; - } - } - - /** - * Computes a score factor based on a term's document frequency (the number - * of documents which contain the term). This value is multiplied by the - * tf(int) factor for each term in the query and these products are - * then summed to form the initial score for a document. - * - * Terms that occur in fewer documents are better indicators of topic, so - * implemenations of this method usually return larger values for rare terms, - * and smaller values for common terms. - * - * docFreq - the number of documents which contain the term - * numDocs - the total number of documents in the collection - * Returns a score factor based on the term's document frequency - * - * @param integer $docFreq - * @param integer $numDocs - * @return float - */ - abstract public function idfFreq($docFreq, $numDocs); - - /** - * Computes a score factor based on the fraction of all query terms that a - * document contains. This value is multiplied into scores. - * - * The presence of a large portion of the query terms indicates a better - * match with the query, so implemenations of this method usually return - * larger values when the ratio between these parameters is large and smaller - * values when the ratio between them is small. - * - * overlap - the number of query terms matched in the document - * maxOverlap - the total number of terms in the query - * Returns a score factor based on term overlap with the query - * - * @param integer $overlap - * @param integer $maxOverlap - * @return float - */ - abstract public function coord($overlap, $maxOverlap); -} - diff --git a/search/Zend/Search/Lucene/Search/Similarity/Default.php b/search/Zend/Search/Lucene/Search/Similarity/Default.php deleted file mode 100644 index 7b8d6ef7c75..00000000000 --- a/search/Zend/Search/Lucene/Search/Similarity/Default.php +++ /dev/null @@ -1,109 +0,0 @@ -createWeight(). - * The sumOfSquaredWeights() method is then called on the top-level - * query to compute the query normalization factor Similarity->queryNorm(float). - * This factor is then passed to normalize(float). At this point the weighting - * is complete. - * - * @category Zend - * @package Zend_Search_Lucene - * @subpackage Search - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - */ -abstract class Zend_Search_Lucene_Search_Weight -{ - /** - * Normalization factor. - * This value is stored only for query expanation purpose and not used in any other place - * - * @var float - */ - protected $_queryNorm; - - /** - * Weight value - * - * Weight value may be initialized in sumOfSquaredWeights() or normalize() - * because they both are invoked either in Query::_initWeight (for top-level query) or - * in corresponding methods of parent query's weights - * - * @var float - */ - protected $_value; - - - /** - * The weight for this query. - * - * @return float - */ - public function getValue() - { - return $this->_value; - } - - /** - * The sum of squared weights of contained query clauses. - * - * @return float - */ - abstract public function sumOfSquaredWeights(); - - /** - * Assigns the query normalization factor to this. - * - * @param $norm - */ - abstract public function normalize($norm); -} - diff --git a/search/Zend/Search/Lucene/Search/Weight/Boolean.php b/search/Zend/Search/Lucene/Search/Weight/Boolean.php deleted file mode 100644 index 08385b79713..00000000000 --- a/search/Zend/Search/Lucene/Search/Weight/Boolean.php +++ /dev/null @@ -1,136 +0,0 @@ -_query = $query; - $this->_reader = $reader; - $this->_weights = array(); - - $signs = $query->getSigns(); - - foreach ($query->getSubqueries() as $num => $subquery) { - if ($signs === null || $signs[$num] === null || $signs[$num]) { - $this->_weights[$num] = $subquery->createWeight($reader); - } - } - } - - - /** - * The weight for this query - * Standard Weight::$_value is not used for boolean queries - * - * @return float - */ - public function getValue() - { - return $this->_query->getBoost(); - } - - - /** - * The sum of squared weights of contained query clauses. - * - * @return float - */ - public function sumOfSquaredWeights() - { - $sum = 0; - foreach ($this->_weights as $weight) { - // sum sub weights - $sum += $weight->sumOfSquaredWeights(); - } - - // boost each sub-weight - $sum *= $this->_query->getBoost() * $this->_query->getBoost(); - - // check for empty query (like '-something -another') - if ($sum == 0) { - $sum = 1.0; - } - return $sum; - } - - - /** - * Assigns the query normalization factor to this. - * - * @param float $queryNorm - */ - public function normalize($queryNorm) - { - // incorporate boost - $queryNorm *= $this->_query->getBoost(); - - foreach ($this->_weights as $weight) { - $weight->normalize($queryNorm); - } - } -} - - diff --git a/search/Zend/Search/Lucene/Search/Weight/Empty.php b/search/Zend/Search/Lucene/Search/Weight/Empty.php deleted file mode 100644 index 0b1702ae096..00000000000 --- a/search/Zend/Search/Lucene/Search/Weight/Empty.php +++ /dev/null @@ -1,56 +0,0 @@ -_query = $query; - $this->_reader = $reader; - $this->_weights = array(); - - $signs = $query->getSigns(); - - foreach ($query->getTerms() as $id => $term) { - if ($signs === null || $signs[$id] === null || $signs[$id]) { - $this->_weights[$id] = new Zend_Search_Lucene_Search_Weight_Term($term, $query, $reader); - $query->setWeight($id, $this->_weights[$id]); - } - } - } - - - /** - * The weight for this query - * Standard Weight::$_value is not used for boolean queries - * - * @return float - */ - public function getValue() - { - return $this->_query->getBoost(); - } - - - /** - * The sum of squared weights of contained query clauses. - * - * @return float - */ - public function sumOfSquaredWeights() - { - $sum = 0; - foreach ($this->_weights as $weight) { - // sum sub weights - $sum += $weight->sumOfSquaredWeights(); - } - - // boost each sub-weight - $sum *= $this->_query->getBoost() * $this->_query->getBoost(); - - // check for empty query (like '-something -another') - if ($sum == 0) { - $sum = 1.0; - } - return $sum; - } - - - /** - * Assigns the query normalization factor to this. - * - * @param float $queryNorm - */ - public function normalize($queryNorm) - { - // incorporate boost - $queryNorm *= $this->_query->getBoost(); - - foreach ($this->_weights as $weight) { - $weight->normalize($queryNorm); - } - } -} - - diff --git a/search/Zend/Search/Lucene/Search/Weight/Phrase.php b/search/Zend/Search/Lucene/Search/Weight/Phrase.php deleted file mode 100644 index 873e44c3039..00000000000 --- a/search/Zend/Search/Lucene/Search/Weight/Phrase.php +++ /dev/null @@ -1,107 +0,0 @@ -_query = $query; - $this->_reader = $reader; - } - - /** - * The sum of squared weights of contained query clauses. - * - * @return float - */ - public function sumOfSquaredWeights() - { - // compute idf - $this->_idf = $this->_reader->getSimilarity()->idf($this->_query->getTerms(), $this->_reader); - - // compute query weight - $this->_queryWeight = $this->_idf * $this->_query->getBoost(); - - // square it - return $this->_queryWeight * $this->_queryWeight; - } - - - /** - * Assigns the query normalization factor to this. - * - * @param float $queryNorm - */ - public function normalize($queryNorm) - { - $this->_queryNorm = $queryNorm; - - // normalize query weight - $this->_queryWeight *= $queryNorm; - - // idf for documents - $this->_value = $this->_queryWeight * $this->_idf; - } -} - - diff --git a/search/Zend/Search/Lucene/Search/Weight/Term.php b/search/Zend/Search/Lucene/Search/Weight/Term.php deleted file mode 100644 index 1d880b2db00..00000000000 --- a/search/Zend/Search/Lucene/Search/Weight/Term.php +++ /dev/null @@ -1,124 +0,0 @@ -_term = $term; - $this->_query = $query; - $this->_reader = $reader; - } - - - /** - * The sum of squared weights of contained query clauses. - * - * @return float - */ - public function sumOfSquaredWeights() - { - // compute idf - $this->_idf = $this->_reader->getSimilarity()->idf($this->_term, $this->_reader); - - // compute query weight - $this->_queryWeight = $this->_idf * $this->_query->getBoost(); - - // square it - return $this->_queryWeight * $this->_queryWeight; - } - - - /** - * Assigns the query normalization factor to this. - * - * @param float $queryNorm - */ - public function normalize($queryNorm) - { - $this->_queryNorm = $queryNorm; - - // normalize query weight - $this->_queryWeight *= $queryNorm; - - // idf for documents - $this->_value = $this->_queryWeight * $this->_idf; - } -} - diff --git a/search/Zend/Search/Lucene/Storage/Directory.php b/search/Zend/Search/Lucene/Storage/Directory.php deleted file mode 100644 index 011734efa5e..00000000000 --- a/search/Zend/Search/Lucene/Storage/Directory.php +++ /dev/null @@ -1,135 +0,0 @@ - Zend_Search_Lucene_Storage_File object - * - * @var array - * @throws Zend_Search_Lucene_Exception - */ - protected $_fileHandlers; - - /** - * Default file permissions - * - * @var integer - */ - protected static $_defaultFilePermissions = 0666; - - - /** - * Get default file permissions - * - * @return integer - */ - public static function getDefaultFilePermissions() - { - return self::$_defaultFilePermissions; - } - - /** - * Set default file permissions - * - * @param integer $mode - */ - public static function setDefaultFilePermissions($mode) - { - self::$_defaultFilePermissions = $mode; - } - - - /** - * Utility function to recursive directory creation - * - * @param string $dir - * @param integer $mode - * @param boolean $recursive - * @return boolean - */ - - public static function mkdirs($dir, $mode = 0777, $recursive = true) - { - if (is_null($dir) || $dir === '') { - return false; - } - if (is_dir($dir) || $dir === '/') { - return true; - } - if (self::mkdirs(dirname($dir), $mode, $recursive)) { - return mkdir($dir, $mode); - } - return false; - } - - - /** - * Object constructor - * Checks if $path is a directory or tries to create it. - * - * @param string $path - * @throws Zend_Search_Lucene_Exception - */ - public function __construct($path) - { - if (!is_dir($path)) { - if (file_exists($path)) { - throw new Zend_Search_Lucene_Exception('Path exists, but it\'s not a directory'); - } else { - if (!self::mkdirs($path)) { - throw new Zend_Search_Lucene_Exception("Can't create directory '$path'."); - } - } - } - $this->_dirPath = $path; - $this->_fileHandlers = array(); - } - - - /** - * Closes the store. - * - * @return void - */ - public function close() - { - foreach ($this->_fileHandlers as $fileObject) { - $fileObject->close(); - } - - $this->_fileHandlers = array(); - } - - - /** - * Returns an array of strings, one for each file in the directory. - * - * @return array - */ - public function fileList() - { - $result = array(); - - $dirContent = opendir( $this->_dirPath ); - while (($file = readdir($dirContent)) !== false) { - if (($file == '..')||($file == '.')) continue; - - if( !is_dir($this->_dirPath . '/' . $file) ) { - $result[] = $file; - } - } - closedir($dirContent); - - return $result; - } - - /** - * Creates a new, empty file in the directory with the given $filename. - * - * @param string $filename - * @return Zend_Search_Lucene_Storage_File - * @throws Zend_Search_Lucene_Exception - */ - public function createFile($filename) - { - if (isset($this->_fileHandlers[$filename])) { - $this->_fileHandlers[$filename]->close(); - } - unset($this->_fileHandlers[$filename]); - $this->_fileHandlers[$filename] = new Zend_Search_Lucene_Storage_File_Filesystem($this->_dirPath . '/' . $filename, 'w+b'); - - global $php_errormsg; - $trackErrors = ini_get('track_errors'); ini_set('track_errors', '1'); - if (!@chmod($this->_dirPath . '/' . $filename, self::$_defaultFilePermissions)) { - ini_set('track_errors', $trackErrors); - throw new Zend_Search_Lucene_Exception($php_errormsg); - } - ini_set('track_errors', $trackErrors); - - return $this->_fileHandlers[$filename]; - } - - - /** - * Removes an existing $filename in the directory. - * - * @param string $filename - * @return void - * @throws Zend_Search_Lucene_Exception - */ - public function deleteFile($filename) - { - if (isset($this->_fileHandlers[$filename])) { - $this->_fileHandlers[$filename]->close(); - } - unset($this->_fileHandlers[$filename]); - - global $php_errormsg; - $trackErrors = ini_get('track_errors'); ini_set('track_errors', '1'); - if (!@unlink($this->_dirPath . '/' . $filename)) { - ini_set('track_errors', $trackErrors); - throw $e; - - throw new Zend_Search_Lucene_Exception('Can\'t delete file: ' . $php_errormsg); - } - ini_set('track_errors', $trackErrors); - } - - /** - * Purge file if it's cached by directory object - * - * Method is used to prevent 'too many open files' error - * - * @param string $filename - * @return void - */ - public function purgeFile($filename) - { - if (isset($this->_fileHandlers[$filename])) { - $this->_fileHandlers[$filename]->close(); - } - unset($this->_fileHandlers[$filename]); - } - - - /** - * Returns true if a file with the given $filename exists. - * - * @param string $filename - * @return boolean - */ - public function fileExists($filename) - { - return isset($this->_fileHandlers[$filename]) || - file_exists($this->_dirPath . '/' . $filename); - } - - - /** - * Returns the length of a $filename in the directory. - * - * @param string $filename - * @return integer - */ - public function fileLength($filename) - { - if (isset( $this->_fileHandlers[$filename] )) { - return $this->_fileHandlers[$filename]->size(); - } - return filesize($this->_dirPath .'/'. $filename); - } - - - /** - * Returns the UNIX timestamp $filename was last modified. - * - * @param string $filename - * @return integer - */ - public function fileModified($filename) - { - return filemtime($this->_dirPath .'/'. $filename); - } - - - /** - * Renames an existing file in the directory. - * - * @param string $from - * @param string $to - * @return void - * @throws Zend_Search_Lucene_Exception - */ - public function renameFile($from, $to) - { - global $php_errormsg; - - if (isset($this->_fileHandlers[$from])) { - $this->_fileHandlers[$from]->close(); - } - unset($this->_fileHandlers[$from]); - - if (isset($this->_fileHandlers[$to])) { - $this->_fileHandlers[$to]->close(); - } - unset($this->_fileHandlers[$to]); - - if (file_exists($this->_dirPath . '/' . $to)) { - if (!unlink($this->_dirPath . '/' . $to)) { - throw new Zend_Search_Lucene_Exception('Delete operation failed'); - } - } - - $trackErrors = ini_get('track_errors'); - ini_set('track_errors', '1'); - - $success = @rename($this->_dirPath . '/' . $from, $this->_dirPath . '/' . $to); - if (!$success) { - ini_set('track_errors', $trackErrors); - throw new Zend_Search_Lucene_Exception($php_errormsg); - } - - ini_set('track_errors', $trackErrors); - - return $success; - } - - - /** - * Sets the modified time of $filename to now. - * - * @param string $filename - * @return void - */ - public function touchFile($filename) - { - return touch($this->_dirPath .'/'. $filename); - } - - - /** - * Returns a Zend_Search_Lucene_Storage_File object for a given $filename in the directory. - * - * If $shareHandler option is true, then file handler can be shared between File Object - * requests. It speed-ups performance, but makes problems with file position. - * Shared handler are good for short atomic requests. - * Non-shared handlers are useful for stream file reading (especial for compound files). - * - * @param string $filename - * @param boolean $shareHandler - * @return Zend_Search_Lucene_Storage_File - */ - public function getFileObject($filename, $shareHandler = true) - { - $fullFilename = $this->_dirPath . '/' . $filename; - - if (!$shareHandler) { - return new Zend_Search_Lucene_Storage_File_Filesystem($fullFilename); - } - - if (isset( $this->_fileHandlers[$filename] )) { - $this->_fileHandlers[$filename]->seek(0); - return $this->_fileHandlers[$filename]; - } - - $this->_fileHandlers[$filename] = new Zend_Search_Lucene_Storage_File_Filesystem($fullFilename); - return $this->_fileHandlers[$filename]; - } -} - diff --git a/search/Zend/Search/Lucene/Storage/File.php b/search/Zend/Search/Lucene/Storage/File.php deleted file mode 100644 index 8a4fab5a188..00000000000 --- a/search/Zend/Search/Lucene/Storage/File.php +++ /dev/null @@ -1,427 +0,0 @@ -_fread(1)); - } - - /** - * Writes a byte to the end of the file. - * - * @param integer $byte - */ - public function writeByte($byte) - { - return $this->_fwrite(chr($byte), 1); - } - - /** - * Read num bytes from the current position in the file - * and advances the file pointer. - * - * @param integer $num - * @return string - */ - public function readBytes($num) - { - return $this->_fread($num); - } - - /** - * Writes num bytes of data (all, if $num===null) to the end - * of the string. - * - * @param string $data - * @param integer $num - */ - public function writeBytes($data, $num=null) - { - $this->_fwrite($data, $num); - } - - - /** - * Reads an integer from the current position in the file - * and advances the file pointer. - * - * @return integer - */ - public function readInt() - { - $str = $this->_fread(4); - - return ord($str{0}) << 24 | - ord($str{1}) << 16 | - ord($str{2}) << 8 | - ord($str{3}); - } - - - /** - * Writes an integer to the end of file. - * - * @param integer $value - */ - public function writeInt($value) - { - settype($value, 'integer'); - $this->_fwrite( chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF), 4 ); - } - - - /** - * Returns a long integer from the current position in the file - * and advances the file pointer. - * - * @return integer - * @throws Zend_Search_Lucene_Exception - */ - public function readLong() - { - $str = $this->_fread(8); - - /** - * Check, that we work in 64-bit mode. - * fseek() uses long for offset. Thus, largest index segment file size in 32bit mode is 2Gb - */ - if (PHP_INT_SIZE > 4) { - return ord($str{0}) << 56 | - ord($str{1}) << 48 | - ord($str{2}) << 40 | - ord($str{3}) << 32 | - ord($str{4}) << 24 | - ord($str{5}) << 16 | - ord($str{6}) << 8 | - ord($str{7}); - } else { - if ((ord($str{0}) != 0) || - (ord($str{1}) != 0) || - (ord($str{2}) != 0) || - (ord($str{3}) != 0) || - ((ord($str{0}) & 0x80) != 0)) { - throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); - } - - return ord($str{4}) << 24 | - ord($str{5}) << 16 | - ord($str{6}) << 8 | - ord($str{7}); - } - } - - /** - * Writes long integer to the end of file - * - * @param integer $value - * @throws Zend_Search_Lucene_Exception - */ - public function writeLong($value) - { - /** - * Check, that we work in 64-bit mode. - * fseek() and ftell() use long for offset. Thus, largest index segment file size in 32bit mode is 2Gb - */ - if (PHP_INT_SIZE > 4) { - settype($value, 'integer'); - $this->_fwrite( chr($value>>56 & 0xFF) . - chr($value>>48 & 0xFF) . - chr($value>>40 & 0xFF) . - chr($value>>32 & 0xFF) . - chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF), 8 ); - } else { - if ($value > 0x7FFFFFFF) { - throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); - } - - $this->_fwrite( "\x00\x00\x00\x00" . - chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF), 8 ); - } - } - - - - /** - * Returns a variable-length integer from the current - * position in the file and advances the file pointer. - * - * @return integer - */ - public function readVInt() - { - $nextByte = ord($this->_fread(1)); - $val = $nextByte & 0x7F; - - for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) { - $nextByte = ord($this->_fread(1)); - $val |= ($nextByte & 0x7F) << $shift; - } - return $val; - } - - /** - * Writes a variable-length integer to the end of file. - * - * @param integer $value - */ - public function writeVInt($value) - { - settype($value, 'integer'); - while ($value > 0x7F) { - $this->_fwrite(chr( ($value & 0x7F)|0x80 )); - $value >>= 7; - } - $this->_fwrite(chr($value)); - } - - - /** - * Reads a string from the current position in the file - * and advances the file pointer. - * - * @return string - */ - public function readString() - { - $strlen = $this->readVInt(); - if ($strlen == 0) { - return ''; - } else { - /** - * This implementation supports only Basic Multilingual Plane - * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support - * "supplementary characters" (characters whose code points are - * greater than 0xFFFF) - * Java 2 represents these characters as a pair of char (16-bit) - * values, the first from the high-surrogates range (0xD800-0xDBFF), - * the second from the low-surrogates range (0xDC00-0xDFFF). Then - * they are encoded as usual UTF-8 characters in six bytes. - * Standard UTF-8 representation uses four bytes for supplementary - * characters. - */ - - $str_val = $this->_fread($strlen); - - for ($count = 0; $count < $strlen; $count++ ) { - if (( ord($str_val{$count}) & 0xC0 ) == 0xC0) { - $addBytes = 1; - if (ord($str_val{$count}) & 0x20 ) { - $addBytes++; - - // Never used. Java2 doesn't encode strings in four bytes - if (ord($str_val{$count}) & 0x10 ) { - $addBytes++; - } - } - $str_val .= $this->_fread($addBytes); - $strlen += $addBytes; - - // Check for null character. Java2 encodes null character - // in two bytes. - if (ord($str_val{$count}) == 0xC0 && - ord($str_val{$count+1}) == 0x80 ) { - $str_val{$count} = 0; - $str_val = substr($str_val,0,$count+1) - . substr($str_val,$count+2); - } - $count += $addBytes; - } - } - - return $str_val; - } - } - - /** - * Writes a string to the end of file. - * - * @param string $str - * @throws Zend_Search_Lucene_Exception - */ - public function writeString($str) - { - /** - * This implementation supports only Basic Multilingual Plane - * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support - * "supplementary characters" (characters whose code points are - * greater than 0xFFFF) - * Java 2 represents these characters as a pair of char (16-bit) - * values, the first from the high-surrogates range (0xD800-0xDBFF), - * the second from the low-surrogates range (0xDC00-0xDFFF). Then - * they are encoded as usual UTF-8 characters in six bytes. - * Standard UTF-8 representation uses four bytes for supplementary - * characters. - */ - - // convert input to a string before iterating string characters - settype($str, 'string'); - - $chars = $strlen = strlen($str); - $containNullChars = false; - - for ($count = 0; $count < $strlen; $count++ ) { - /** - * String is already in Java 2 representation. - * We should only calculate actual string length and replace - * \x00 by \xC0\x80 - */ - if ((ord($str{$count}) & 0xC0) == 0xC0) { - $addBytes = 1; - if (ord($str{$count}) & 0x20 ) { - $addBytes++; - - // Never used. Java2 doesn't encode strings in four bytes - // and we dont't support non-BMP characters - if (ord($str{$count}) & 0x10 ) { - $addBytes++; - } - } - $chars -= $addBytes; - - if (ord($str{$count}) == 0 ) { - $containNullChars = true; - } - $count += $addBytes; - } - } - - if ($chars < 0) { - throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string'); - } - - $this->writeVInt($chars); - if ($containNullChars) { - $this->_fwrite(str_replace($str, "\x00", "\xC0\x80")); - } else { - $this->_fwrite($str); - } - } - - - /** - * Reads binary data from the current position in the file - * and advances the file pointer. - * - * @return string - */ - public function readBinary() - { - return $this->_fread($this->readVInt()); - } -} diff --git a/search/Zend/Search/Lucene/Storage/File/Filesystem.php b/search/Zend/Search/Lucene/Storage/File/Filesystem.php deleted file mode 100644 index d508ce9dcff..00000000000 --- a/search/Zend/Search/Lucene/Storage/File/Filesystem.php +++ /dev/null @@ -1,222 +0,0 @@ -_fileHandle = @fopen($filename, $mode); - - if ($this->_fileHandle === false) { - ini_set('track_errors', $trackErrors); - throw new Zend_Search_Lucene_Exception($php_errormsg); - } - - ini_set('track_errors', $trackErrors); - } - - /** - * Sets the file position indicator and advances the file pointer. - * The new position, measured in bytes from the beginning of the file, - * is obtained by adding offset to the position specified by whence, - * whose values are defined as follows: - * SEEK_SET - Set position equal to offset bytes. - * SEEK_CUR - Set position to current location plus offset. - * SEEK_END - Set position to end-of-file plus offset. (To move to - * a position before the end-of-file, you need to pass a negative value - * in offset.) - * SEEK_CUR is the only supported offset type for compound files - * - * Upon success, returns 0; otherwise, returns -1 - * - * @param integer $offset - * @param integer $whence - * @return integer - */ - public function seek($offset, $whence=SEEK_SET) - { - return fseek($this->_fileHandle, $offset, $whence); - } - - - /** - * Get file position. - * - * @return integer - */ - public function tell() - { - return ftell($this->_fileHandle); - } - - /** - * Flush output. - * - * Returns true on success or false on failure. - * - * @return boolean - */ - public function flush() - { - return fflush($this->_fileHandle); - } - - /** - * Close File object - */ - public function close() - { - if ($this->_fileHandle !== null ) { - @fclose($this->_fileHandle); - $this->_fileHandle = null; - } - } - - /** - * Get the size of the already opened file - * - * @return integer - */ - public function size() - { - $position = ftell($this->_fileHandle); - fseek($this->_fileHandle, 0, SEEK_END); - $size = ftell($this->_fileHandle); - fseek($this->_fileHandle,$position); - - return $size; - } - - /** - * Read a $length bytes from the file and advance the file pointer. - * - * @param integer $length - * @return string - */ - protected function _fread($length=1) - { - if ($length == 0) { - return ''; - } - - if ($length < 1024) { - return fread($this->_fileHandle, $length); - } - - $data = ''; - while ( $length > 0 && ($nextBlock = fread($this->_fileHandle, $length)) != false ) { - $data .= $nextBlock; - $length -= strlen($nextBlock); - } - return $data; - } - - - /** - * Writes $length number of bytes (all, if $length===null) to the end - * of the file. - * - * @param string $data - * @param integer $length - */ - protected function _fwrite($data, $length=null) - { - if ($length === null ) { - fwrite($this->_fileHandle, $data); - } else { - fwrite($this->_fileHandle, $data, $length); - } - } - - /** - * Lock file - * - * Lock type may be a LOCK_SH (shared lock) or a LOCK_EX (exclusive lock) - * - * @param integer $lockType - * @param boolean $nonBlockingLock - * @return boolean - */ - public function lock($lockType, $nonBlockingLock = false) - { - if ($nonBlockingLock) { - return flock($this->_fileHandle, $lockType | LOCK_NB); - } else { - return flock($this->_fileHandle, $lockType); - } - } - - /** - * Unlock file - * - * Returns true on success - * - * @return boolean - */ - public function unlock() - { - if ($this->_fileHandle !== null ) { - return flock($this->_fileHandle, LOCK_UN); - } else { - return true; - } - } -} - diff --git a/search/Zend/Search/Lucene/Storage/File/Memory.php b/search/Zend/Search/Lucene/Storage/File/Memory.php deleted file mode 100644 index e830bcea703..00000000000 --- a/search/Zend/Search/Lucene/Storage/File/Memory.php +++ /dev/null @@ -1,555 +0,0 @@ -_data = $data; - } - - /** - * Reads $length number of bytes at the current position in the - * file and advances the file pointer. - * - * @param integer $length - * @return string - */ - protected function _fread($length = 1) - { - $returnValue = substr($this->_data, $this->_position, $length); - $this->_position += $length; - return $returnValue; - } - - - /** - * Sets the file position indicator and advances the file pointer. - * The new position, measured in bytes from the beginning of the file, - * is obtained by adding offset to the position specified by whence, - * whose values are defined as follows: - * SEEK_SET - Set position equal to offset bytes. - * SEEK_CUR - Set position to current location plus offset. - * SEEK_END - Set position to end-of-file plus offset. (To move to - * a position before the end-of-file, you need to pass a negative value - * in offset.) - * Upon success, returns 0; otherwise, returns -1 - * - * @param integer $offset - * @param integer $whence - * @return integer - */ - public function seek($offset, $whence=SEEK_SET) - { - switch ($whence) { - case SEEK_SET: - $this->_position = $offset; - break; - - case SEEK_CUR: - $this->_position += $offset; - break; - - case SEEK_END: - $this->_position = strlen($this->_data); - $this->_position += $offset; - break; - - default: - break; - } - } - - /** - * Get file position. - * - * @return integer - */ - public function tell() - { - return $this->_position; - } - - /** - * Flush output. - * - * Returns true on success or false on failure. - * - * @return boolean - */ - public function flush() - { - // Do nothing - - return true; - } - - /** - * Writes $length number of bytes (all, if $length===null) to the end - * of the file. - * - * @param string $data - * @param integer $length - */ - protected function _fwrite($data, $length=null) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - if ($length !== null) { - $this->_data .= substr($data, 0, $length); - } else { - $this->_data .= $data; - } - - $this->_position = strlen($this->_data); - } - - /** - * Lock file - * - * Lock type may be a LOCK_SH (shared lock) or a LOCK_EX (exclusive lock) - * - * @param integer $lockType - * @return boolean - */ - public function lock($lockType, $nonBlockinLock = false) - { - // Memory files can't be shared - // do nothing - - return true; - } - - /** - * Unlock file - */ - public function unlock() - { - // Memory files can't be shared - // do nothing - } - - /** - * Reads a byte from the current position in the file - * and advances the file pointer. - * - * @return integer - */ - public function readByte() - { - return ord($this->_data[$this->_position++]); - } - - /** - * Writes a byte to the end of the file. - * - * @param integer $byte - */ - public function writeByte($byte) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - $this->_data .= chr($byte); - $this->_position = strlen($this->_data); - - return 1; - } - - /** - * Read num bytes from the current position in the file - * and advances the file pointer. - * - * @param integer $num - * @return string - */ - public function readBytes($num) - { - $returnValue = substr($this->_data, $this->_position, $num); - $this->_position += $num; - - return $returnValue; - } - - /** - * Writes num bytes of data (all, if $num===null) to the end - * of the string. - * - * @param string $data - * @param integer $num - */ - public function writeBytes($data, $num=null) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - if ($num !== null) { - $this->_data .= substr($data, 0, $num); - } else { - $this->_data .= $data; - } - - $this->_position = strlen($this->_data); - } - - - /** - * Reads an integer from the current position in the file - * and advances the file pointer. - * - * @return integer - */ - public function readInt() - { - $str = substr($this->_data, $this->_position, 4); - $this->_position += 4; - - return ord($str{0}) << 24 | - ord($str{1}) << 16 | - ord($str{2}) << 8 | - ord($str{3}); - } - - - /** - * Writes an integer to the end of file. - * - * @param integer $value - */ - public function writeInt($value) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - settype($value, 'integer'); - $this->_data .= chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF); - - $this->_position = strlen($this->_data); - } - - - /** - * Returns a long integer from the current position in the file - * and advances the file pointer. - * - * @return integer - * @throws Zend_Search_Lucene_Exception - */ - public function readLong() - { - $str = substr($this->_data, $this->_position, 8); - $this->_position += 8; - - /** - * Check, that we work in 64-bit mode. - * fseek() uses long for offset. Thus, largest index segment file size in 32bit mode is 2Gb - */ - if (PHP_INT_SIZE > 4) { - return ord($str{0}) << 56 | - ord($str{1}) << 48 | - ord($str{2}) << 40 | - ord($str{3}) << 32 | - ord($str{4}) << 24 | - ord($str{5}) << 16 | - ord($str{6}) << 8 | - ord($str{7}); - } else { - if ((ord($str{0}) != 0) || - (ord($str{1}) != 0) || - (ord($str{2}) != 0) || - (ord($str{3}) != 0) || - ((ord($str{0}) & 0x80) != 0)) { - throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); - } - - return ord($str{4}) << 24 | - ord($str{5}) << 16 | - ord($str{6}) << 8 | - ord($str{7}); - } - } - - /** - * Writes long integer to the end of file - * - * @param integer $value - * @throws Zend_Search_Lucene_Exception - */ - public function writeLong($value) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - /** - * Check, that we work in 64-bit mode. - * fseek() and ftell() use long for offset. Thus, largest index segment file size in 32bit mode is 2Gb - */ - if (PHP_INT_SIZE > 4) { - settype($value, 'integer'); - $this->_data .= chr($value>>56 & 0xFF) . - chr($value>>48 & 0xFF) . - chr($value>>40 & 0xFF) . - chr($value>>32 & 0xFF) . - chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF); - } else { - if ($value > 0x7FFFFFFF) { - throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); - } - - $this->_data .= chr(0) . chr(0) . chr(0) . chr(0) . - chr($value>>24 & 0xFF) . - chr($value>>16 & 0xFF) . - chr($value>>8 & 0xFF) . - chr($value & 0xFF); - } - - $this->_position = strlen($this->_data); - } - - - - /** - * Returns a variable-length integer from the current - * position in the file and advances the file pointer. - * - * @return integer - */ - public function readVInt() - { - $nextByte = ord($this->_data[$this->_position++]); - $val = $nextByte & 0x7F; - - for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) { - $nextByte = ord($this->_data[$this->_position++]); - $val |= ($nextByte & 0x7F) << $shift; - } - return $val; - } - - /** - * Writes a variable-length integer to the end of file. - * - * @param integer $value - */ - public function writeVInt($value) - { - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - settype($value, 'integer'); - while ($value > 0x7F) { - $this->_data .= chr( ($value & 0x7F)|0x80 ); - $value >>= 7; - } - $this->_data .= chr($value); - - $this->_position = strlen($this->_data); - } - - - /** - * Reads a string from the current position in the file - * and advances the file pointer. - * - * @return string - */ - public function readString() - { - $strlen = $this->readVInt(); - if ($strlen == 0) { - return ''; - } else { - /** - * This implementation supports only Basic Multilingual Plane - * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support - * "supplementary characters" (characters whose code points are - * greater than 0xFFFF) - * Java 2 represents these characters as a pair of char (16-bit) - * values, the first from the high-surrogates range (0xD800-0xDBFF), - * the second from the low-surrogates range (0xDC00-0xDFFF). Then - * they are encoded as usual UTF-8 characters in six bytes. - * Standard UTF-8 representation uses four bytes for supplementary - * characters. - */ - - $str_val = substr($this->_data, $this->_position, $strlen); - $this->_position += $strlen; - - for ($count = 0; $count < $strlen; $count++ ) { - if (( ord($str_val{$count}) & 0xC0 ) == 0xC0) { - $addBytes = 1; - if (ord($str_val{$count}) & 0x20 ) { - $addBytes++; - - // Never used. Java2 doesn't encode strings in four bytes - if (ord($str_val{$count}) & 0x10 ) { - $addBytes++; - } - } - $str_val .= substr($this->_data, $this->_position, $addBytes); - $this->_position += $addBytes; - $strlen += $addBytes; - - // Check for null character. Java2 encodes null character - // in two bytes. - if (ord($str_val{$count}) == 0xC0 && - ord($str_val{$count+1}) == 0x80 ) { - $str_val{$count} = 0; - $str_val = substr($str_val,0,$count+1) - . substr($str_val,$count+2); - } - $count += $addBytes; - } - } - - return $str_val; - } - } - - /** - * Writes a string to the end of file. - * - * @param string $str - * @throws Zend_Search_Lucene_Exception - */ - public function writeString($str) - { - /** - * This implementation supports only Basic Multilingual Plane - * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support - * "supplementary characters" (characters whose code points are - * greater than 0xFFFF) - * Java 2 represents these characters as a pair of char (16-bit) - * values, the first from the high-surrogates range (0xD800-0xDBFF), - * the second from the low-surrogates range (0xDC00-0xDFFF). Then - * they are encoded as usual UTF-8 characters in six bytes. - * Standard UTF-8 representation uses four bytes for supplementary - * characters. - */ - - // We do not need to check if file position points to the end of "file". - // Only append operation is supported now - - // convert input to a string before iterating string characters - settype($str, 'string'); - - $chars = $strlen = strlen($str); - $containNullChars = false; - - for ($count = 0; $count < $strlen; $count++ ) { - /** - * String is already in Java 2 representation. - * We should only calculate actual string length and replace - * \x00 by \xC0\x80 - */ - if ((ord($str{$count}) & 0xC0) == 0xC0) { - $addBytes = 1; - if (ord($str{$count}) & 0x20 ) { - $addBytes++; - - // Never used. Java2 doesn't encode strings in four bytes - // and we dont't support non-BMP characters - if (ord($str{$count}) & 0x10 ) { - $addBytes++; - } - } - $chars -= $addBytes; - - if (ord($str{$count}) == 0 ) { - $containNullChars = true; - } - $count += $addBytes; - } - } - - if ($chars < 0) { - throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string'); - } - - $this->writeVInt($chars); - if ($containNullChars) { - $this->_data .= str_replace($str, "\x00", "\xC0\x80"); - - } else { - $this->_data .= $str; - } - - $this->_position = strlen($this->_data); - } - - - /** - * Reads binary data from the current position in the file - * and advances the file pointer. - * - * @return string - */ - public function readBinary() - { - $length = $this->readVInt(); - $returnValue = substr($this->_data, $this->_position, $length); - $this->_position += $length; - return $returnValue; - } -} - diff --git a/search/Zend/Search/TODO.txt b/search/Zend/Search/TODO.txt deleted file mode 100644 index 799a19e9607..00000000000 --- a/search/Zend/Search/TODO.txt +++ /dev/null @@ -1,7 +0,0 @@ -@todo - -- Additional queries: wildcard, proximity, and range - -- Better class-level docblocks (most functions okay) - - diff --git a/search/add.php b/search/add.php deleted file mode 100644 index 8543215a569..00000000000 --- a/search/add.php +++ /dev/null @@ -1,198 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @version prepared for 2.0 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * - * Asynchronous adder for new indexable contents - * - * Major chages in this review is passing the xxxx_db_names return to - * multiple arity to handle multiple document types modules - * - * changes are in implementing new $DB access - */ - - /** - * includes and requires - */ - require_once('../config.php'); - - if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); /// It must be included from the cron script - } - - global $DB; - -/// makes inclusions of the Zend Engine more reliable - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - - require_once($CFG->dirroot.'/search/lib.php'); - require_once($CFG->dirroot.'/search/indexlib.php'); - - -/// checks global search activation - - // require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - /* - Obsolete with the MOODLE INTERNAL check - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('beadmin', 'search', get_login_url()); - } - */ - -/// check index - - try { - $index = new Zend_Search_Lucene(SEARCH_INDEX_PATH); - } catch(LuceneException $e) { - mtrace("Could not construct a valid index. Maybe the first indexation was never made, or files might be corrupted. Run complete indexation again."); - return; - } - $dbcontrol = new IndexDBControl(); - $addition_count = 0; - $mainstartindextime = time(); - - mtrace('Starting index update (additions)...'); - mtrace('Index size before: '.$CFG->search_index_size."\n"); - -/// get all modules - if ($mods = search_collect_searchables(false, true)){ - -/// append virtual modules onto array - - foreach ($mods as $mod) { - - $indexdate = 0; - $indexdatestring = 'search_indexer_run_date_'.$mod->name; - $startrundate = time(); - if (isset($CFG->$indexdatestring)) { - $indexdate = $CFG->$indexdatestring; - } - - //build include file and function names - $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php'; - $db_names_function = $mod->name.'_db_names'; - $get_document_function = $mod->name.'_single_document'; - $get_newrecords_function = $mod->name.'_new_records'; - $additions = array(); - - if (file_exists($class_file)) { - require_once($class_file); - - //if both required functions exist - if (function_exists($db_names_function) and function_exists($get_document_function)) { - mtrace("Checking $mod->name module for additions."); - $valuesArray = $db_names_function(); - if ($valuesArray){ - foreach($valuesArray as $values){ - $where = (isset($values[5]) and $values[5]!='') ? 'AND ('.$values[5].')' : ''; - $itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " AND itemtype = '{$values[4]}' " : '' ; - - //select records in MODULE table, but not in SEARCH_DATABASE_TABLE - $table = SEARCH_DATABASE_TABLE; - $query = " - SELECT - docid, - itemtype - FROM - {{$table}} - WHERE - doctype = ? - $itemtypes - "; - $docIds = $DB->get_records_sql_menu($query, array($mod->name)); - - if (!empty($docIds)){ - list($usql, $params) = $DB->get_in_or_equal(array_keys($docIds), SQL_PARAMS_QM, 'param', false); // negative IN - $query = " - SELECT id, - $values[0] as docid - FROM - {{$values[1]}} - WHERE - id $usql AND - $values[2] > $indexdate - $where - "; - $records = $DB->get_records_sql($query, $params); - } else { - $records = array(); - } - - // foreach record, build a module specific search document using the get_document function - if (is_array($records)) { - foreach($records as $record) { - $add = $get_document_function($record->docid, $values[4]); - // some documents may not be indexable - if ($add) - $additions[] = $add; - } - } - } - - // foreach document, add it to the index and database table - foreach ($additions as $add) { - ++$addition_count; - // try the addDocument() so possible dml_write_exception don't block other modules running. - // also we can list all the new documents that are failing. - try { - // object to insert into db - $dbid = $dbcontrol->addDocument($add); - - // synchronise db with index - $add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid)); - - $index->addDocument($add); - - mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)"); - } - - catch (dml_write_exception $e) { - mtrace(" Add: FAILED adding '$add->title' , moodle instance id = $add->docid , Error: $e->error "); - mtrace($e); - } - - } - } - else{ - mtrace("No types to add.\n"); - } - - //commit changes - $index->commit(); - - //update index date - set_config($indexdatestring, $startrundate); - - mtrace("Finished $mod->name.\n"); - } - } - } - } - -/// commit changes - - $index->commit(); - -/// update index date and size - - set_config('search_indexer_run_date', $mainstartindextime); - set_config('search_index_size', (int)$CFG->search_index_size + (int)$addition_count); - -/// print some additional info - - mtrace("Added $addition_count documents."); - mtrace('Index size after: '.$index->count()); - -?> diff --git a/search/cron.php b/search/cron.php deleted file mode 100644 index dd04ae260a5..00000000000 --- a/search/cron.php +++ /dev/null @@ -1,27 +0,0 @@ -dirroot/search/lib.php"); - - if (empty($CFG->enableglobalsearch)) { - mtrace('Global searching is not enabled. Nothing performed by search.'); - } - else{ - include("{$CFG->dirroot}/search/cron_php5.php"); - } -?> \ No newline at end of file diff --git a/search/cron_php5.php b/search/cron_php5.php deleted file mode 100644 index fa53cc17408..00000000000 --- a/search/cron_php5.php +++ /dev/null @@ -1,33 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -*/ - -try{ - ini_set('max_execution_time', 300); - raise_memory_limit(MEMORY_EXTRA); - - mtrace("\n--DELETE----"); - require_once($CFG->dirroot.'/search/delete.php'); - mtrace("--UPDATE----"); - require_once($CFG->dirroot.'/search/update.php'); - mtrace("--ADD-------"); - require_once($CFG->dirroot.'/search/add.php'); - mtrace("------------"); - //mtrace("cron finished."); - mtrace('done'); -} -catch(Exception $ex){ - mtrace('Fatal exception from Lucene subsystem. Search engine may not have been updated.'); - mtrace($ex); -} -?> diff --git a/search/delete.php b/search/delete.php deleted file mode 100644 index 972a96122b8..00000000000 --- a/search/delete.php +++ /dev/null @@ -1,158 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @version prepared for 2.0 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * - * Asynchronous index cleaner - * - * Major chages in this review is passing the xxxx_db_names return to - * multiple arity to handle multiple document types modules - */ - - /** - * includes and requires - */ - require_once('../config.php'); - - if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); /// It must be included from the cron script - } - - global $DB; - -/// makes inclusions of the Zend Engine more reliable - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - - require_once($CFG->dirroot.'/search/lib.php'); - require_once($CFG->dirroot.'/search/indexlib.php'); - -/// checks global search activation - - // require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - /* - Obsolete with the MOODLE INTERNAL check - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('beadmin', 'search', get_login_url()); - } - */ - - try { - $index = new Zend_Search_Lucene(SEARCH_INDEX_PATH); - } catch(LuceneException $e) { - mtrace("Could not construct a valid index. Maybe the first indexation was never made, or files might be corrupted. Run complete indexation again."); - return; - } - $dbcontrol = new IndexDBControl(); - $deletion_count = 0; - $startcleantime = time(); - - mtrace('Starting clean-up of removed records...'); - mtrace('Index size before: '.$CFG->search_index_size."\n"); - -/// check all modules - if ($mods = search_collect_searchables(false, true)){ - - foreach ($mods as $mod) { - //build function names - $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php'; - $delete_function = $mod->name.'_delete'; - $db_names_function = $mod->name.'_db_names'; - $deletions = array(); - - if (file_exists($class_file)) { - require_once($class_file); - - //if both required functions exist - if (function_exists($delete_function) and function_exists($db_names_function)) { - mtrace("Checking $mod->name module for deletions."); - $valuesArray = $db_names_function(); - if ($valuesArray){ - foreach($valuesArray as $values){ - $where = (!empty($values[5])) ? 'WHERE '.$values[5] : ''; - $itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " itemtype = '{$values[4]}' AND " : '' ; - $query = " - SELECT - id, - {$values[0]} - FROM - {{$values[1]}} - $where - "; - $docIds = $DB->get_records_sql($query, array()); - - if (!empty($docIds)){ - $table = SEARCH_DATABASE_TABLE; - list($usql, $params) = $DB->get_in_or_equal(array_keys($docIds), SQL_PARAMS_QM, 'param', false); // negative IN - $query = " - SELECT - id, - docid - FROM - {{$table}} - WHERE - doctype = '{$mod->name}' AND - $itemtypes - docid $usql - "; - $records = $DB->get_records_sql($query, $params); - } else { - $records = array(); - } - - // build an array of all the deleted records - foreach($records as $record) { - $deletions[] = $delete_function($record->docid, $values[4]); - } - } - - foreach ($deletions as $delete) { - // find the specific document in the index, using it's docid and doctype as keys - // change from default text only search to include numerals for this search. - Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive()); - $doc = $index->find("+docid:{$delete->id} +doctype:$mod->name +itemtype:{$delete->itemtype}"); - - // get the record, should only be one - foreach ($doc as $thisdoc) { - ++$deletion_count; - mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)"); - - //remove it from index and database table - $dbcontrol->delDocument($thisdoc); - $index->delete($thisdoc->id); - } - } - } - else{ - mtrace("No types to delete.\n"); - } - mtrace("Finished $mod->name.\n"); - } - } - } - } - -/// commit changes - - $index->commit(); - -/// update index date and index size - - set_config('search_indexer_cleanup_date', $startcleantime); - set_config('search_index_size', (int)$CFG->search_index_size - (int)$deletion_count); - - mtrace("Finished $deletion_count removals."); - mtrace('Index size after: '.$index->count()); - -?> \ No newline at end of file diff --git a/search/documents/assignment_document.php b/search/documents/assignment_document.php deleted file mode 100644 index 9b5c365fc55..00000000000 --- a/search/documents/assignment_document.php +++ /dev/null @@ -1,409 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for assignment activity module -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/assignment/lib.php'); - -/** -* a class for representing searchable information -* -*/ -class AssignmentSearchDocument extends SearchDocument { - - /** - * constructor - */ - public function __construct(&$assignmentitem, $assignment_module_id, $itemtype, $course_id, $owner_id, $context_id , $submissionoffset = null) { - // generic information; required - $doc->docid = $assignmentitem['id']; - $doc->documenttype = SEARCH_TYPE_ASSIGNMENT; - $doc->itemtype = $itemtype; - $doc->contextid = $context_id; - - // we cannot call userdate with relevant locale at indexing time. - $doc->title = "{$itemtype}: {$assignmentitem['name']}"; - $doc->date = $assignmentitem['date']; - - //remove '(ip.ip.ip.ip)' from chat author list - $doc->author = $assignmentitem['authors']; - if ($itemtype == 'intro') { - $doc->contents = $assignmentitem['intro']; - $doc->url = assignment_make_link($assignment_module_id, $itemtype, $owner_id); - } else { - $doc->contents = $assignmentitem['data1']; - $doc->url = assignment_make_link($assignment_module_id, $itemtype, $owner_id, $submissionoffset); - } - - // module specific information; optional - $data->assignment = $assignment_module_id; - $data->assignmenttype = $assignmentitem['assignmenttype']; - - // construct the parent class - parent::__construct($doc, $data, $course_id, 0, 0, 'mod/'.SEARCH_TYPE_ASSIGNMENT); - } -} - - -/** -* constructs a valid link to a chat content -* @param cm_id the chat course module -* @param start the start time of the session -* @param end th end time of the session -* @uses CFG -* @return a well formed link to session display -*/ -function assignment_make_link($cm_id, $itemtype, $owner, $submissionoffset=null) { - global $CFG; - - if ($itemtype == 'intro') { - return $CFG->wwwroot.'/mod/assignment/view.php?id='.$cm_id; - } else { - return $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$cm_id.'&userid='.$owner.'&mode=single&offset='.$submissionoffset; - //?id=80&userid=4&mode=single&filter=0&offset=1 - } -} - -/** -* part of search engine API -* @uses $DB -* -*/ -function assignment_iterator() { - global $DB; - - if ($assignments = $DB->get_records('assignment')) - return $assignments; - else - return array(); -} - -/** -* part of search engine API -* @uses $CFG, $DB -* -*/ -function assignment_get_content_for_index(&$assignment) { - global $CFG, $DB; - - $documents = array(); - $course = $DB->get_record('course', array('id' => $assignment->course)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'assignment')); - $cm = $DB->get_record('course_modules', array('course' => $assignment->course, 'module' => $coursemodule, 'instance' => $assignment->id)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - $assignment = assignment_add_document_fields($assignment); - $documents[] = new AssignmentSearchDocument(get_object_vars($assignment), $cm->id, 'intro', $assignment->course, null, $context->id); - - $submissions = assignment_get_all_submissions($assignment); - if ($submissions){ - $submissionoffset=-1; - foreach($submissions as $submission){ - $submissionoffset++; - $submission = assignment_submission_add_document_fields($assignment, $submission); - if (file_exists("{$CFG->dirroot}/mod/assignment/type/{$assignment->assignmenttype}/searchlib.php")){ - include_once("{$CFG->dirroot}/mod/assignment/type/{$assignment->assignmenttype}/searchlib.php"); - if (function_exists('assignment_get_submission_location')){ - $submitted = assignment_get_submission_location($assignment, $submission); - } - } - if (empty($submitted)){ - // this is for moodle legacy types that would need not to be patched for searchlib.php - switch($assignment->assignmenttype){ - case 'online' : { - $submitted->source = 'text'; - $submitted->data = $submission->data1; - } - break; - case 'uploadsingle' : - case 'upload' : { - $submitted->source = 'files'; - $submitted->data = "{$assignment->course}/moddata/assignment/{$assignment->id}/{$submission->userid}"; - } - break; - case 'offline' : continue; // cannot index, no content in Moodle !! - } - } - if (empty($submitted)) continue; // ignoring - - if ($submitted->source = 'text'){ - $submission->description = $submitted->data; - $submission->description = preg_replace("/<[^>]*>/", '', $submission->description); // stip all tags - $documents[] = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submission', $assignment->course, $submission->userid, $context->id, $submissionoffset); - mtrace("finished online submission for {$submission->authors} in assignment {$assignment->name}"); - } elseif ($submitted->source = 'files'){ - $SUBMITTED = opendir($submitted->path); - while($entry = readdir($SUBMITTED)){ - if (preg_match("/^\./", $entry)) continue; // exclude hidden and dirs . and .. - $path = "{$submitted->path}/{$entry}"; - $documents[] = assignment_get_physical_file($submission, $assignment, $cm, $path, $context_id, $documents); - mtrace("finished attachement $path for {$submission->authors} in assignment {$assignment->name}"); - } - closedir($submission->path); - } - } - } - mtrace("finished assignment {$assignment->name}"); - return $documents; - } - return array(); -} - -/** -* get text from a physical file in an assignment submission -* @uses $CFG, $DB -* @param object $submission a submission for which to fetch some representative text -* @param object $assignment the relevant assignment as a context -* @param object $cm the corresponding coursemodule -* @param string $path a file from which to fetch some representative text -* @param int $contextid the moodle context if needed -* @param array $documents the array of documents, by ref, where to add the new document. -* @return a search document when unique or false. -*/ -function assignment_get_physical_file(&$submission, &$assignment, &$cm, $path, $context_id, &$documents = null){ - global $CFG, $DB; - - $fileparts = pathinfo($path); - // cannot index unknown or masked types - if (empty($fileparts['extension'])) { - mtrace("Cannot index without explicit extension."); - return false; - } - - $ext = strtolower($fileparts['extension']); - - // cannot index unallowed or unhandled types - if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) { - mtrace($fileparts['extension'] . ' is not an allowed extension for indexing'); - return false; - } - if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){ - include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php'); - $function_name = 'get_text_for_indexing_'.$ext; - $submission->description = $function_name(null, $path); - - // get authors - $user = $DB->get_record('user', array('id' => $submission->userid)); - $submission->authors = fullname($user); - - // we need a real id on file - $submission->id = "{$submission->id}/{$path}"; - - if (!empty($submission->description)){ - if ($getsingle){ - $single = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submitted', $assignment->course, $submission->userid, $context_id); - mtrace("finished submission file from {$submission->authors}"); - return $single; - } else { - $documents[] = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submitted', $assignment->course, $submission->userid, $context_id); - } - mtrace("finished submission file from {$submission->authors}"); - } - } else { - mtrace("fulltext handler not found for $ext type"); - } - return false; -} - -/** -* returns a single data search document based on an assignment -* @uses $DB -* @param string $id the id of the searchable item -* @param string $itemtype the type of information -*/ -function assignment_single_document($id, $itemtype) { - global $DB; - - if ($itemtype == 'intro') { - if (!$assignment = $DB->get_record('assignment', array('id' => $id))) { - return null; - } - } elseif ($itemtype == 'submission') { - if ($submission = $DB->get_record('assignment_submissions', array('id' => $id))) { - if (!$assignment = $DB->get_record('assignment', array('id' => $submission->assignment))) { - return null; - } - } else { - return null; - } - } - $course = $DB->get_record('course', array('id' => $assignment->course)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'assignment')); - $cm = $DB->get_record('course_modules', array('course' => $course->id, 'module' => $coursemodule, 'instance' => $assignment->id)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - // should be only one - if ($itemtype == 'intro') { - $assignment = assignment_add_document_fields($assignment); - $document = new AssignmentSearchDocument(get_object_vars($assignment), $cm->id, 'intro', $assignment->course, null, $context->id); - return $document; - } - if ($itemtype == 'submission') { - $submission = assignment_submission_add_document_fields($assignment, $submission); - $document = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submission', $assignment->course, null, $context->id); - return $document; - } - } - return null; -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function assignment_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* // TODO chat indexable records are virtual. Should proceed in a special way -*/ -function assignment_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql]] - return array( - array('id', 'assignment', 'timemodified', 'timemodified', 'intro'), - array('id', 'assignment_submissions', 'timecreated', 'timemodified', 'submission') - ); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @uses $CFG, $USER, $DB -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by entry_type. In chats, this id -* points out a session history which is a close sequence of messages. -* @param int $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @return true if access is allowed, false elsewhere -*/ -function assignment_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $USER, $DB; - - include_once("{$CFG->dirroot}/{$path}/lib.php"); - - // get the chat session and all related stuff - if ($itemtype == 'description'){ - $assignment = $DB->get_record('assignment', array('id' => $this_id)); - } elseif ($itemtype == 'submitted'){ - $submission = $DB->get_record('assignment_submissions', array('id' => $this_id)); - $assignment = $DB->get_record('assignment', array('id' => $submission->assignment)); - } - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : hidden assignment "; - return false; - } - - /* - group consistency check : checks the following situations about groups - // trap if user is not same group and groups are separated - $current_group = get_current_group($course->id); - $course = get_record('course', 'id', $assignment->course); - if ((groupmode($course, $cm) == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : assignment element is in separated group "; - return false; - } - */ - - //user ownership check : - // trap if user is not owner of the resource and the ressource is a submission/attachement - if ($itemtype == 'submitted' && $USER->id != $submission->userid && !has_capability('mod/assignment:view', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : i'm not owner of this assignment "; - return false; - } - - //date check : no submission may be viewed before timedue - if ($itemtype == 'submitted' && $assignment->timedue < time()){ - if (!empty($CFG->search_access_debug)) echo "search reject : cannot read submissions before end of assignment "; - return false; - } - - //ownership check : checks the following situations about user - // trap if user is not owner and cannot see other's entries - // TODO : typically may be stored into indexing cache - if (!has_capability('mod/assignment:view', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : cannot read past sessions "; - return false; - } - - return true; -} - -/** -* this call back is called when displaying the link for some last post processing -* -*/ -function assignment_link_post_processing($title){ - global $CFG; - - if (!function_exists('search_assignment_getstring')){ - function search_assignment_getstring($matches){ - return get_string($matches[1], 'assignment'); - } - } - - $title = preg_replace_callback('/^(description|submitted)/', 'search_assignment_getstring', $title); - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} -/** - * This adds properties to a records from the submissions table to be a search document - * @global $DB - * @param $assignment - * @param $submission - * @return - */ -function assignment_submission_add_document_fields($assignment, $submission) { - global $DB; - - $owner = $DB->get_record('user', array('id' => $submission->userid)); - $submission->authors = fullname($owner); - $submission->assignmenttype = $assignment->assignmenttype; - $submission->date = $submission->timemodified; - $submission->name = "submission:"; - - return $submission; -} - -function assignment_add_document_fields($assignment) { - $assignment->authors = ''; - $assignment->date = $assignment->timemodified; - - return $assignment; -} -?> diff --git a/search/documents/chat_document.php b/search/documents/chat_document.php deleted file mode 100644 index e4cf354e8d0..00000000000 --- a/search/documents/chat_document.php +++ /dev/null @@ -1,327 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for chat activity module -* This file contains the mapping between a chat history and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/chat/lib.php -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/chat/lib.php'); - -/** -* a class for representing searchable information -* -*/ -class ChatTrackSearchDocument extends SearchDocument { - - /** - * constructor - */ - public function __construct(&$chatsession, $chat_id, $chat_module_id, $course_id, $group_id, $context_id) { - // generic information; required - $doc->docid = $chat_id.'-'.$chatsession['sessionstart'].'-'.$chatsession['sessionend']; - $doc->documenttype = SEARCH_TYPE_CHAT; - $doc->itemtype = 'session'; - $doc->contextid = $context_id; - - $duration = $chatsession['sessionend'] - $chatsession['sessionstart']; - // we cannot call userdate with relevant locale at indexing time. - $doc->title = get_string('chatreport', 'chat').' '.get_string('openedon', 'search').' TT_'.$chatsession['sessionstart'].'_TT ('.get_string('duration', 'search').' : '.get_string('numseconds', '', $duration).')'; - $doc->date = $chatsession['sessionend']; - - //remove '(ip.ip.ip.ip)' from chat author list - $doc->author = preg_replace('/\(.*?\)/', '', $chatsession['authors']); - $doc->contents = $chatsession['content']; - $doc->url = chat_make_link($chat_module_id, $chatsession['sessionstart'], $chatsession['sessionend']); - - // module specific information; optional - $data->chat = $chat_id; - - // construct the parent class - parent::__construct($doc, $data, $course_id, $group_id, 0, 'mod/'.SEARCH_TYPE_CHAT); - } -} - - -/** -* constructs a valid link to a chat content -* @param cm_id the chat course module -* @param int $start the start time of the session -* @param int $end th end time of the session -* @uses $CFG -* @return a well formed link to session display -*/ -function chat_make_link($cm_id, $start, $end) { - global $CFG; - - return $CFG->wwwroot.'/mod/chat/report.php?id='.$cm_id.'&start='.$start.'&end='.$end; -} - -/** -* fetches all the records for a given session and assemble them as a unique track -* we revamped here the code of report.php for making sessions, but without any output. -* note that we should collect sessions "by groups" if $groupmode is SEPARATEGROUPS. -* @param int $chat_id the database -* @param int $fromtime -* @param int $totime -* @uses $CFG, $DB -* @return an array of objects representing the chat sessions. -*/ -function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) { - global $CFG, $DB; - - $chat = $DB->get_record('chat', array('id' => $chat_id)); - $course = $DB->get_record('course', array('id' => $chat->course)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'data')); - $cm = $DB->get_record('course_modules', array('course' => $course->id, 'module' => $coursemodule, 'instance' => $chat->id)); - if (isset($cm->groupmode) && empty($course->groupmodeforce)) { - $groupmode = $cm->groupmode; - } else { - $groupmode = $course->groupmode; - } - - $fromtimeclause = ($fromtime) ? "AND timestamp >= {$fromtime}" : ''; - $totimeclause = ($totime) ? "AND timestamp <= {$totime}" : ''; - $tracks = array(); - $messages = $DB->get_records_select('chat_messages', "chatid = :chatid :from :to", array('chatid' => $chat_id, 'from' => $fromtimeclause, 'to' => $totimeclause), 'timestamp DESC'); - if ($messages){ - // splits discussions against groups - $groupedMessages = array(); - if ($groupmode != SEPARATEGROUPS){ - foreach($messages as $aMessage){ - $groupedMessages[$aMessage->groupid][] = $aMessage; - } - } else { - $groupedMessages[-1] = &$messages; - } - $sessiongap = 5 * 60; // 5 minutes silence means a new session - $sessionend = 0; - $sessionstart = 0; - $sessionusers = array(); - $lasttime = time(); - - foreach ($groupedMessages as $groupId => $messages) { // We are walking BACKWARDS through the messages - $messagesleft = count($messages); - foreach ($messages as $message) { // We are walking BACKWARDS through the messages - $messagesleft --; // Countdown - - if ($message->system) { - continue; - } - // we are within a session track - if ((($lasttime - $message->timestamp) < $sessiongap) and $messagesleft) { // Same session - if (count($tracks) > 0){ - if ($message->userid) { // Remember user and count messages - $tracks[count($tracks) - 1]->sessionusers[$message->userid] = $message->userid; - // update last track (if exists) record appending content (remember : we go backwards) - } - $tracks[count($tracks) - 1]->content .= ' '.$message->message; - $tracks[count($tracks) - 1]->sessionstart = $message->timestamp; - } - } else { - // we initiate a new session track (backwards) - $track = new stdClass(); - $track->sessionend = $message->timestamp; - $track->sessionstart = $message->timestamp; - $track->content = $message->message; - // reset the accumulator of users - $track->sessionusers = array(); - $track->sessionusers[$message->userid] = $message->userid; - $track->groupid = $groupId; - $tracks[] = $track; - } - $lasttime = $message->timestamp; - } - } - } - return $tracks; -} - -/** -* part of search engine API -* @uses $DB -* -*/ -function chat_iterator() { - global $DB; - - $chatrooms = $DB->get_records('chat'); - return $chatrooms; -} - -/** -* part of search engine API -* @uses $DB -* @param reference $chat -* -*/ -function chat_get_content_for_index(&$chat) { - global $DB; - - $documents = array(); - $course = $DB->get_record('course', array('id' => $chat->course)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'chat')); - $cm = $DB->get_record('course_modules', array('course' => $chat->course, 'module' => $coursemodule, 'instance' => $chat->id)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - // getting records for indexing - $sessionTracks = chat_get_session_tracks($chat->id); - if ($sessionTracks){ - foreach($sessionTracks as $aTrackId => $aTrack) { - foreach($aTrack->sessionusers as $aUserId){ - $user = $DB->get_record('user', array('id' => $aUserId)); - $aTrack->authors = ($user) ? fullname($user) : '' ; - $documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat->id, $cm->id, $chat->course, $aTrack->groupid, $context->id); - } - } - } - return $documents; - } - return array(); -} - -/** -* returns a single data search document based on a chat_session id -* chat session id is a text composite identifier made of : -* - the chat id -* - the timestamp when the session starts -* - the timestamp when the session ends -* @uses $DB -* @param id the multipart chat session id -* @param itemtype the type of information (session is the only type) -*/ -function chat_single_document($id, $itemtype) { - global $DB; - - list($chat_id, $sessionstart, $sessionend) = explode('-', $id); - $chat = $DB->get_record('chat', array('id' => $chat_id)); - $course = $DB->get_record('course', array('id' => $chat->course)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'chat')); - $cm = $DB->get_record('course_modules', array('course' => $course->id, 'module' => $coursemodule, 'instance' => $chat->id)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - // should be only one - $tracks = chat_get_session_tracks($chat->id, $sessionstart, $sessionstart); - if ($tracks){ - $aTrack = $tracks[0]; - $document = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat_id, $cm->id, $chat->course, $aTrack->groupid, $context->id); - return $document; - } - } - return null; -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function chat_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* // TODO chat indexable records are virtual. Should proceed in a special way -*/ -function chat_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql] - return null; -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by entry_type. In chats, this id -* points out a session history which is a close sequence of messages. -* @param int $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @uses $CFG, $DB -* @return true if access is allowed, false elsewhere -*/ -function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - include_once("{$CFG->dirroot}/{$path}/lib.php"); - - list($chat_id, $sessionstart, $sessionend) = explode('-', $this_id); - // get the chat session and all related stuff - $chat = $DB->get_record('chat', array('id' => $chat_id)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : hidden chat "; - return false; - } - - //group consistency check : checks the following situations about groups - // trap if user is not same group and groups are separated - $course = $DB->get_record('course', array('id' => $chat->course)); - if (isset($cm->groupmode) && empty($course->groupmodeforce)) { - $groupmode = $cm->groupmode; - } else { - $groupmode = $course->groupmode; - } - if (($groupmode == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : chat element is in separated group "; - return false; - } - - //ownership check : checks the following situations about user - // trap if user is not owner and has cannot see other's entries - // TODO : typically may be stored into indexing cache - if (!has_capability('mod/chat:readlog', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : cannot read past sessions "; - return false; - } - - return true; -} - -/** -* this call back is called when displaying the link for some last post processing -* @uses $CFG -* @param string $title -* -*/ -function chat_link_post_processing($title){ - global $CFG; - setLocale(LC_TIME, substr(current_language(), 0, 2)); - $title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title); - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} -?> diff --git a/search/documents/data_document.php b/search/documents/data_document.php deleted file mode 100644 index 499a922aa30..00000000000 --- a/search/documents/data_document.php +++ /dev/null @@ -1,441 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for data activity module -* This file contains the mapping between a database object and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/data/lib.php -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/data/lib.php'); - -/** -* a class for representing searchable information (data records) -* -*/ -class DataSearchDocument extends SearchDocument { - - /** - * constructor - */ - public function __construct(&$record, $course_id, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $record['id']; - $doc->documenttype = SEARCH_TYPE_DATA; - $doc->itemtype = 'record'; - $doc->contextid = $context_id; - - $doc->title = $record['title']; - $doc->date = $record['timemodified']; - //remove '(ip.ip.ip.ip)' from data record author field - if ($record['userid']){ - $user = $DB->get_record('user', array('id' => $record['userid'])); - } - $doc->author = (isset($user)) ? $user->firstname.' '.$user->lastname : '' ; - $doc->contents = $record['content']; - $doc->url = data_make_link($record['dataid'], $record['id']); - - // module specific information; optional - // $data->params = serialize(@$record['params']); may be useful - $data->database = $record['dataid']; - - // construct the parent class - parent::__construct($doc, $data, $course_id, $record['groupid'], $record['userid'], 'mod/'.SEARCH_TYPE_DATA); - } -} - -/** -* a class for representing searchable information (comments on data records) -* -*/ -class DataCommentSearchDocument extends SearchDocument { - - /** - * constructor - */ - public function __construct(&$comment, $course_id, $context_id) { - // generic information; required - $doc->docid = $comment['id']; - $doc->documenttype = SEARCH_TYPE_DATA; - $doc->itemtype = 'comment'; - $doc->contextid = $context_id; - - $doc->title = get_string('commenton', 'search').' '.$comment['title']; - $doc->date = $comment['modified']; - //remove '(ip.ip.ip.ip)' from data record author field - $doc->author = preg_replace('/\(.*?\)/', '', $comment['author']); - $doc->contents = $comment['content']; - $doc->url = data_make_link($comment['dataid'], $comment['recordid']); - - // module specific information; optional - $data->database = $comment['dataid']; - - // construct the parent class - parent::__construct($doc, $data, $course_id, $comment['groupid'], $comment['userid'], 'mod/'.SEARCH_TYPE_DATA); - } -} - -/** -* constructs a valid link to a data record content -* @param int $database_id the database reference -* @param int $record_id the record reference -* @uses $CFG -* @return a valid url top access the information as a string -*/ -function data_make_link($database_id, $record_id) { - global $CFG; - - return $CFG->wwwroot.'/mod/data/view.php?d='.$database_id.'&rid='.$record_id; -} - -/** -* fetches all the records for a given database -* @param int $database_id the database -* @param string $typematch a comma separated list of types that should be considered for searching or * -* @uses $CFG, $DB -* @return an array of objects representing the data records. -*/ -function data_get_records($database_id, $typematch = '*', $recordid = 0) { - global $CFG, $DB; - - $fieldset = $DB->get_records('data_fields', array('dataid' => $database_id)); - $uniquerecordclause = ($recordid > 0) ? " AND c.recordid = $recordid " : '' ; - $query = " - SELECT - c.* - FROM - {data_content} as c, - {data_records} as r - WHERE - c.recordid = r.id AND - r.dataid = ? - $uniquerecordclause - ORDER BY - c.fieldid - "; - $data = $DB->get_records_sql($query, array($database_id)); - $records = array(); - if ($data){ - foreach($data as $aDatum){ - if($typematch == '*' || preg_match("/\\b{$fieldset[$aDatum->fieldid]->type}\\b/", $typematch)){ - if (!isset($records[$aDatum->recordid])){ - $records[$aDatum->recordid]['_first'] = $aDatum->content.' '.$aDatum->content1.' '.$aDatum->content2.' '.$aDatum->content3.' '.$aDatum->content4.' '; - } else { - $records[$aDatum->recordid][$fieldset[$aDatum->fieldid]->name] = $aDatum->content.' '.$aDatum->content1.' '.$aDatum->content2.' '.$aDatum->content3.' '.$aDatum->content4.' '; - } - } - } - } - return $records; -} - -/** -* fetches all the comments for a given database -* @param int $database_id the database -* @uses $CFG, $DB -* @return an array of objects representing the data record comments. -*/ -function data_get_comments($database_id) { - global $CFG, $DB; - - $query = " - SELECT - c.id, - r.groupid, - c.userid, - c.itemid, - c.content, - c.timecreated, - r.dataid - FROM - {data_records} as r - JOIN - {comments} as c ON c.contextid = r.id - WHERE - r.dataid = ? - "; - $comments = $DB->get_records_sql($query, array($database_id)); - return $comments; -} - - -/** -* part of search engine API -* @uses $DB -* -*/ -function data_iterator() { - global $DB; - - $databases = $DB->get_records('data'); - return $databases; -} - -/** -* part of search engine API -* @uses $DB -* @param reference $database the database instance -* @return an array of searchable documents -*/ -function data_get_content_for_index(&$database) { - global $DB; - - $documents = array(); - $recordTitles = array(); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'data')); - $cm = $DB->get_record('course_modules', array('course' => $database->course, 'module' => $coursemodule, 'instance' => $database->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - // getting records for indexing - $records_content = data_get_records($database->id, 'text,textarea'); - if ($records_content){ - foreach(array_keys($records_content) as $arecordid) { - - // extract title as first record in order - $first = $records_content[$arecordid]['_first']; - unset($records_content[$arecordid]['_first']); - - // concatenates all other texts - $content = ''; - foreach($records_content[$arecordid] as $afield){ - $content = @$content.' '.$afield; - } - unset($recordMetaData); - $recordMetaData = $DB->get_record('data_records', array('id' => $arecordid)); - $recordMetaData->title = $first; - $recordTitles[$arecordid] = $first; - $recordMetaData->content = $content; - $documents[] = new DataSearchDocument(get_object_vars($recordMetaData), $database->course, $context->id); - } - } - - // getting comments for indexing - $records_comments = data_get_comments($database->id); - if ($records_comments){ - foreach($records_comments as $aComment){ - $aComment->title = $recordsTitle[$aComment->itemid]; - $authoruser = $DB->get_record('user', array('id' => $aComment->userid)); - $aComment->author = fullname($authoruser); - $documents[] = new DataCommentSearchDocument(get_object_vars($aComment), $database->course, $context->id); - } - } - return $documents; -} - -/** -* returns a single data search document based on a data entry id -* @uses $DB -* @param in $id the id of the record -* @param string $itemtype the type of the information -* @return a single searchable document -*/ -function data_single_document($id, $itemtype) { - global $DB; - - if ($itemtype == 'record'){ - // get main record - $recordMetaData = $DB->get_record('data_records', array('id' => $id)); - // get context - $record_course = $DB->get_field('data', 'course', array('id' => $recordMetaData->dataid)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'data')); - $cm = $DB->get_record('course_modules', array('course' => $record_course, 'module' => $coursemodule, 'instance' => $recordMetaData->dataid)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - // compute text - $recordData = data_get_records($recordMetaData->dataid, 'text,textarea', $id); - if ($recordData){ - $dataArray = array_values($recordData); - $record_content = $dataArray[0]; // We cannot have more than one record here - - // extract title as first record in order - $first = $record_content['_first']; - unset($record_content['_first']); - - // concatenates all other texts - $content = ''; - foreach($record_content as $aField){ - $content = @$content.' '.$aField; - } - unset($recordMetaData); - $recordMetaData = $DB->get_record('data_records', array('id' => $id)); - $recordMetaData->title = $first; - $recordMetaData->content = $content; - return new DataSearchDocument(get_object_vars($recordMetaData), $record_course, $context->id); - } - } elseif($itemtype == 'comment') { - // get main records - $comment = $DB->get_record('data_comments', array('id' => $id)); - $record = $DB->get_record('data_records', array('id' => $comment->recordid)); - // get context - $record_course = $DB->get_field('data', 'course', array('id' => $record->dataid)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'data')); - $cm = $DB->get_record('course_modules', array('course' => $record_course, 'module' => $coursemodule, 'instance' => $recordMetaData->dataid)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - // add extra fields - $comment->title = $DB->get_field('search_document', 'title', array('docid' => $record->id, 'itemtype' => 'record')); - $comment->dataid = $record->dataid; - $comment->groupid = $record->groupid; - $authoruser = $DB->get_record('user', array('id' => $comment->userid)); - $comment->author = fullname($authoruser); - // make document - return new DataCommentSearchDocument(get_object_vars($comment), $record_course, $context->id); - } else { - mtrace('Error : bad or missing item type'); - return NULL; - } -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function data_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function data_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql] - return array( - array('id', 'data_records', 'timecreated', 'timemodified', 'record'), - array('id', 'comments', 'timecreated', 'timecreated', 'comment') - ); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In databases, this id -* points out an indexed data record page. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @uses $CFG, $DB -* @return true if access is allowed, false elsewhere -*/ -function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - // get the database object and all related stuff - if ($itemtype == 'record'){ - $record = $DB->get_record('data_records', array('id' => $this_id)); - } - elseif($itemtype == 'comment'){ - $comment = $DB->get_record('data_comments', array('id' => $this_id)); - $record = $DB->get_record('data_records', array('id' => $comment->recordid)); - } - else{ - // we do not know what type of information is required - return false; - } - $data = $DB->get_record('data', array('id' => $record->dataid)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : hidden database "; - return false; - } - - //group consistency check : checks the following situations about groups - // trap if user is not same group and groups are separated - $course = $DB->get_record('course', 'id', $data->course); - if (isset($cm->groupmode) && empty($course->groupmodeforce)) { - $groupmode = $cm->groupmode; - } else { - $groupmode = $course->groupmode; - } - if (($groupmode == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : separated group owned resource "; - return false; - } - - //ownership check : checks the following situations about user - // trap if user is not owner and has cannot see other's entries - if ($itemtype == 'record'){ - if ($user->id != $record->userid && !has_capability('mod/data:viewentry', $context) && !has_capability('mod/data:manageentries', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : not owned resource "; - return false; - } - } - - //approval check - // trap if unapproved and has not approval capabilities - // TODO : report a potential capability lack of : mod/data:approve - $approval = $DB->get_field('data_records', 'approved', array('id' => $record->id)); - if (!$approval && !has_capability('mod/data:manageentries', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : unapproved resource "; - return false; - } - - //minimum records to view check - // trap if too few records - // TODO : report a potential capability lack of : mod/data:viewhiddenentries - $recordsAmount = $DB->count_records('data_records', array('dataid' => $data->id)); - if ($data->requiredentriestoview > $recordsAmount && !has_capability('mod/data:manageentries', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : not enough records to view "; - return false; - } - - //opening periods check - // trap if user has not capability to see hidden records and date is out of opening range - // TODO : report a potential capability lack of : mod/data:viewhiddenentries - $now = usertime(time()); - if ($data->timeviewfrom > 0) - if ($now < $data->timeviewfrom && !has_capability('mod/data:manageentries', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : still not open activity "; - return false; - } - if ($data->timeviewto > 0) - if ($now > $data->timeviewto && !has_capability('mod/data:manageentries', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : closed activity "; - return false; - } - - return true; -} - -/** -* post processes the url for cleaner output. -* @param string $title -*/ -function data_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} - -?> \ No newline at end of file diff --git a/search/documents/document.php b/search/documents/document.php deleted file mode 100644 index ae3f46c7a4f..00000000000 --- a/search/documents/document.php +++ /dev/null @@ -1,75 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* Base search document from which other module/block types can -* extend. -*/ - -/** -* -*/ -abstract class SearchDocument extends Zend_Search_Lucene_Document { - public function __construct(&$doc, &$data, $course_id, $group_id, $user_id, $path, $additional_keyset = null) { - //document identification and indexing - $this->addField(Zend_Search_Lucene_Field::Keyword('docid', $doc->docid)); - //document type : the name of the Moodle element that manages it - $this->addField(Zend_Search_Lucene_Field::Keyword('doctype', $doc->documenttype)); - //allows subclassing information from complex modules. - $this->addField(Zend_Search_Lucene_Field::Keyword('itemtype', $doc->itemtype)); - //caches the course context. - $this->addField(Zend_Search_Lucene_Field::Keyword('course_id', $course_id)); - //caches the originator's group. - $this->addField(Zend_Search_Lucene_Field::Keyword('group_id', $group_id)); - //caches the originator if any - $this->addField(Zend_Search_Lucene_Field::Keyword('user_id', $user_id)); - // caches the context of this information. i-e, the context in which this information - // is being produced/attached. Speeds up the "check for access" process as context in - // which the information resides (a course, a module, a block, the site) is stable. - $this->addField(Zend_Search_Lucene_Field::UnIndexed('context_id', $doc->contextid)); - - //data for document - $this->addField(Zend_Search_Lucene_Field::Text('title', $doc->title)); - $this->addField(Zend_Search_Lucene_Field::Text('author', $doc->author)); - $this->addField(Zend_Search_Lucene_Field::UnStored('contents', $doc->contents)); - $this->addField(Zend_Search_Lucene_Field::UnIndexed('url', $doc->url)); - $this->addField(Zend_Search_Lucene_Field::UnIndexed('date', $doc->date)); - - //additional data added on a per-module basis - $this->addField(Zend_Search_Lucene_Field::Binary('data', serialize($data))); - - // adding a path allows the document to know where to find specific library calls - // for checking access to a module or block content. The Lucene records should only - // be responsible to bring back to that call sufficient and consistent information - // in order to perform the check. - $this->addField(Zend_Search_Lucene_Field::UnIndexed('path', $path)); - /* - // adding a capability set required for viewing. -1 if no capability required. - // the capability required for viewing is depending on the local situation - // of the document. each module should provide this information when pushing - // out search document structure. Although capability model should be kept flat - // there is no exclusion some module or block developpers use logical combinations - // of multiple capabilities in their code. This possibility should be left open here. - $this->addField(Zend_Search_Lucene_Field::UnIndexed('capabilities', $caps)); - */ - - /* - // Additional key set allows a module to ask for extensible criteria based search - // depending on the module internal needs. - */ - if (!empty($additional_keyset)){ - foreach($additional_keyset as $keyname => $keyvalue){ - $this->addField(Zend_Search_Lucene_Field::Keyword($keyname, $keyvalue)); - } - } - } -} - -?> \ No newline at end of file diff --git a/search/documents/forum_document.php b/search/documents/forum_document.php deleted file mode 100644 index 819704d7eac..00000000000 --- a/search/documents/forum_document.php +++ /dev/null @@ -1,394 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for forum activity module -* This file contains the mapping between a forum post and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/forum/lib.php -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/forum/lib.php'); - -/** -* a class for representing searchable information -* -*/ -class ForumSearchDocument extends SearchDocument { - - /** - * constructor - * @uses $DB; - */ - public function __construct(&$post, $forum_id, $course_id, $itemtype, $context_id) { - global $DB; - - // generic information - $doc->docid = $post['id']; - $doc->documenttype = SEARCH_TYPE_FORUM; - $doc->itemtype = $itemtype; - $doc->contextid = $context_id; - - $doc->title = $post['subject']; - - $user = $DB->get_record('user', array('id' => $post['userid'])); - $doc->author = fullname($user); - $doc->contents = $post['message']; - $doc->date = $post['created']; - $doc->url = forum_make_link($post['discussion'], $post['id']); - - // module specific information - $data->forum = $forum_id; - $data->discussion = $post['discussion']; - - //temporary fix until MDL-24822 resolved - if (!isset($post['groupid']) || $post['groupid'] < 0) { - $post['groupid'] = 0; - } - - parent::__construct($doc, $data, $course_id, $post['groupid'], $post['userid'], 'mod/'.SEARCH_TYPE_FORUM); - } -} - -/** -* constructs a valid link to a chat content -* @uses $CFG -* @param int $discussion_id the discussion -* @param int $post_id the id of a single post -* @return a well formed link to forum message display -*/ -function forum_make_link($discussion_id, $post_id) { - global $CFG; - - return $CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion_id.'#p'.$post_id; -} - -/** -* search standard API -* @uses $DB; -* -*/ -function forum_iterator() { - global $DB; - - $forums = $DB->get_records('forum'); - return $forums; -} - -/** -* search standard API -* @uses $DB -* @param reference $forum a forum instance -* @return an array of searchable documents -*/ -function forum_get_content_for_index(&$forum) { - global $DB; - - $documents = array(); - if (!$forum) return $documents; - - $posts = forum_get_discussions_fast($forum->id); - mtrace("Found ".count($posts)." discussions to analyse in forum ".$forum->name); - if (!$posts) return $documents; - - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'forum')); - $cm = $DB->get_record('course_modules', array('course' => $forum->course, 'module' => $coursemodule, 'instance' => $forum->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - foreach($posts as $aPost) { - $aPost->itemtype = 'head'; - if ($aPost) { - if (!empty($aPost->message)) { - echo "*"; - $documents[] = new ForumSearchDocument(get_object_vars($aPost), $forum->id, $forum->course, 'head', $context->id); - } - if ($children = forum_get_child_posts_fast_recurse($aPost->id, $forum->id)) { - foreach($children as $aChild) { - echo "."; - $aChild->itemtype = 'post'; - if (strlen($aChild->message) > 0) { - $documents[] = new ForumSearchDocument(get_object_vars($aChild), $forum->id, $forum->course, 'post', $context->id); - } - } - } - } - } - mtrace("Finished discussion"); - return $documents; -} - -/** -* returns a single forum search document based on a forum entry id -* @uses $DB -* @param int $id an id for a single information stub -* @param string $itemtype the type of information -*/ -function forum_single_document($id, $itemtype) { - global $DB; - - // both known item types are posts so get them the same way - $post = $DB->get_record('forum_posts', array('id' => $id)); - $discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'forum')); - $cm = $DB->get_record('course_modules', array('course' => $discussion->course, 'module' => $coursemodule, 'instance' => $discussion->forum)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - $post->groupid = $discussion->groupid; - // temporary fix until MDL-24822 is resolved. - if ($post->groupid == -1) { - $post->groupid = 0; - } - return new ForumSearchDocument(get_object_vars($post), $discussion->forum, $discussion->course, $itemtype, $context->id); - } - return null; -} - -/** -* dummy delete function that aggregates id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function forum_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function forum_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql] - return array( - array('id', 'forum_posts', 'created', 'modified', 'head', 'parent = 0'), - array('id', 'forum_posts', 'created', 'modified', 'post', 'parent != 0') - ); -} - -/** -* reworked faster version from /mod/forum/lib.php -* @param int $forum_id a forum identifier -* @uses $CFG, $USER, $DB -* @return an array of posts -*/ -function forum_get_discussions_fast($forum_id) { - global $CFG, $USER, $DB; - - $timelimit=''; - if (!empty($CFG->forum_enabletimedposts)) { - - $courseid = $DB->get_field('forum', 'course', array('id'=>$forum_id)); - - if ($courseid) { - $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid); - $systemcontext = get_context_instance(CONTEXT_SYSTEM); - } else { - $coursecontext = get_context_instance(CONTEXT_SYSTEM); - $systemcontext = $coursecontext; - } - - if (true) { - // TODO: can not test teachers and admins here, use proper capability and enrolment test - $now = time(); - $timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')"; - if (isloggedin()) { - $timelimit .= " OR d.userid = '$USER->id'"; - } - $timelimit .= ')'; - } - } - - $query = " - SELECT - p.id, - p.subject, - p.discussion, - p.message, - p.created, - d.groupid, - p.userid, - u.firstname, - u.lastname - FROM - {forum_discussions} d - JOIN - {forum_posts} p - ON - p.discussion = d.id - JOIN - {user} u - ON - p.userid = u.id - WHERE - d.forum = ? AND - p.parent = 0 - $timelimit - ORDER BY - d.timemodified DESC - "; - return $DB->get_records_sql($query, array($forum_id)); -} - -/** - * recursively calls forum_get_child_posts_fast() - * @return array of whole generation of descendants of a parent post. - * - */ -function forum_get_child_posts_fast_recurse($parent_id, $forum_id, $recursing=false) { - - $children = forum_get_child_posts_fast($parent_id, $forum_id); - - // we have children to return, but - if (count($children) > 0) { - // first lets check if there are any children under them. - $foundchildren = array(); - foreach($children as $child) { - $subchildren = forum_get_child_posts_fast_recurse($child->id, $forum_id , true); - $foundchildren = array_merge($foundchildren,$subchildren); - } - // merge found children into their parents. - $allchildren = array_merge($children, $foundchildren); - return $allchildren; - } else { - return array(); - } -} - -/** -* reworked faster version from /mod/forum/lib.php -* @param int $parent the id of the first post within the discussion -* @param int $forum_id the forum identifier -* @uses $CFG, $DB -* @return an array of posts -*/ -function forum_get_child_posts_fast($parent, $forum_id) { - global $CFG, $DB; - - $query = " - SELECT - p.id, - p.subject, - p.discussion, - p.message, - p.created, - ? AS forum, - p.userid, - d.groupid, - u.firstname, - u.lastname - FROM - {forum_discussions} d - JOIN - {forum_posts} p - ON - p.discussion = d.id - JOIN - {user} u - ON - p.userid = u.id - WHERE - p.parent = ? - ORDER BY - p.created ASC - "; - return $DB->get_records_sql($query, array($forum_id, $parent)); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In forums, this id -* points out the individual post. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @uses $CFG, $USER, $DB -* @return true if access is allowed, false elsewhere -*/ -function forum_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $USER, $DB, $SESSION; - - include_once("{$CFG->dirroot}/{$path}/lib.php"); - - // get the forum post and all related stuff - $post = $DB->get_record('forum_posts', array('id' => $this_id)); - $discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : hidden forum resource "; - return false; - } - - // approval check : entries should be approved for being viewed, or belongs to the user - if (($post->userid != $USER->id) && !$post->mailed && !has_capability('mod/forum:viewhiddentimeposts', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : time hidden forum item"; - return false; - } - - // group check : entries should be in accessible groups - if (isset($SESSION->currentgroup[$discussion->course])) { - $current_group = $SESSION->currentgroup[$discussion->course]; - } else { - $current_group = groups_get_all_groups($discussion->course, $USER->id); - if (is_array($current_group)) { - $current_group = array_shift(array_keys($current_group)); - $SESSION->currentgroup[$discussion->course] = $current_group; - } else { - $current_group = 0; - } - } - - $course = $DB->get_record('course', array('id' => $discussion->course)); - if (isset($cm->groupmode) && empty($course->groupmodeforce)) { - $groupmode = $cm->groupmode; - } else { - $groupmode = $course->groupmode; - } - if ($group_id >= 0 && ($groupmode == SEPARATEGROUPS) && ($group_id != $current_group) && !has_capability('mod/forum:viewdiscussionsfromallgroups', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : separated grouped forum item"; - return false; - } - - return true; -} - -/** -* post processes the url for cleaner output. -* @uses $CFG -* @param string $title -*/ -function forum_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} - -?> \ No newline at end of file diff --git a/search/documents/glossary_document.php b/search/documents/glossary_document.php deleted file mode 100644 index ac04e9b8d83..00000000000 --- a/search/documents/glossary_document.php +++ /dev/null @@ -1,287 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for glossary activity module -* This file contains a mapping between a glossary entry and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/glossary/lib.php -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); - -/** -* a class for representing searchable information -* -*/ -class GlossarySearchDocument extends SearchDocument { - - /** - * document constructor - * - */ - public function __construct(&$entry, $course_id, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $entry['id']; - $doc->documenttype = SEARCH_TYPE_GLOSSARY; - $doc->itemtype = 'standard'; - $doc->contextid = $context_id; - - $doc->title = $entry['concept']; - $doc->date = $entry['timecreated']; - - if ($entry['userid']) - $user = $DB->get_record('user', array('id' => $entry['userid'])); - $doc->author = ($user ) ? $user->firstname.' '.$user->lastname : '' ; - $doc->contents = strip_tags($entry['definition']); - $doc->url = glossary_make_link($entry['id']); - - // module specific information; optional - $data->glossary = $entry['glossaryid']; - - // construct the parent class - parent::__construct($doc, $data, $course_id, -1, $entry['userid'], 'mod/'.SEARCH_TYPE_GLOSSARY); - } -} - -/** -* a class for representing searchable information -* -*/ -class GlossaryCommentSearchDocument extends SearchDocument { - - /** - * document constructor - * @uses $DB - */ - public function __construct(&$entry, $glossary_id, $course_id, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $entry['itemid']; - $doc->documenttype = SEARCH_TYPE_GLOSSARY; - $doc->itemtype = 'comment'; - $doc->contextid = $context_id; - - $doc->title = get_string('commenton', 'search') . ' ' . $entry['concept']; - $doc->date = $entry['timecreated']; - - if ($entry['userid']) - $user = $DB->get_record('user', array('id' => $entry['userid'])); - $doc->author = ($user ) ? $user->firstname.' '.$user->lastname : '' ; - $doc->contents = strip_tags($entry['content']); - $doc->url = glossary_make_link($entry['itemid']); - - // module specific information; optional - $data->glossary = $glossary_id; - - // construct the parent class - parent::__construct($doc, $data, $course_id, -1, $entry['userid'], 'mod/'.SEARCH_TYPE_GLOSSARY); - } -} - -/** -* constructs valid access links to information -* @uses $CFG -* @param int $entry_id the id of the glossary entry -* @return a full featured link element as a string -*/ -function glossary_make_link($entry_id) { - global $CFG; - require_once($CFG->dirroot.'/search/querylib.php'); - - //links directly to entry - // return $CFG->wwwroot.'/mod/glossary/showentry.php?eid='.$entry_id; - - // TOO LONG URL - // Suggestion : bounce on popup within the glossarie's showentry page - // preserve glossary pop-up, be careful where you place your ' and "s - //this function is meant to return a url that is placed between href='[url here]' - $jsondata = array('url'=>'/mod/glossary/showentry.php?eid='.$entry_id,'name'=>'entry','options'=>DEFAULT_POPUP_SETTINGS); - $jsondata = json_encode($jsondata); - return "$CFG->wwwroot/mod/glossary/showentry.php?eid=$entry_id' onclick='return openpopup(null, $jsondata);"; -} - -/** -* part of search engine API -* -*/ -function glossary_iterator() { - global $DB; - - $glossaries = $DB->get_records('glossary'); - return $glossaries; -} - -/** -* part of search engine API -* @uses $DB -* @param object $glossary a glossary instance -* @return an array of searchable documents -*/ -function glossary_get_content_for_index(&$glossary) { - global $DB; - - // get context - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'glossary')); - $cm = $DB->get_record('course_modules', array('course' => $glossary->course, 'module' => $coursemodule, 'instance' => $glossary->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - $documents = array(); - $entryIds = array(); - // index entries - $entries = $DB->get_records('glossary_entries', array('glossaryid' => $glossary->id)); - if ($entries){ - foreach($entries as $entry) { - $concepts[$entry->id] = $entry->concept; - if (strlen($entry->definition) > 0) { - $entryIds[] = $entry->id; - $documents[] = new GlossarySearchDocument(get_object_vars($entry), $glossary->course, $context->id); - } - } - } - - // index comments - if (count($entryIds)){ - list($entryidssql, $params) = $DB->get_in_or_equal($entryIds, SQL_PARAMS_NAMED); - $params['ctxid'] = $context->id; - $sql = "SELECT * - FROM {comments} - WHERE contextid = :ctxid - AND itemid $entryidssql"; - $comments = $DB->get_recordset_sql($sql, $params); - - if ($comments){ - foreach($comments as $comment) { - if (strlen($comment->entrycomment) > 0) { - $comment->concept = $concepts[$comment->entryid]; - $documents[] = new GlossaryCommentSearchDocument(get_object_vars($comment), $glossary->id, $glossary->course, $context->id); - } - } - } - } - return $documents; -} - -/** -* part of search engine API -* @uses $DB -* @param int $id the glossary entry identifier -* @param string $itemtype the type of information -* @return a single search document based on a glossary entry -*/ -function glossary_single_document($id, $itemtype) { - global $DB; - - if ($itemtype == 'standard'){ - $entry = $DB->get_record('glossary_entries', array('id' => $id)); - } - elseif ($itemtype == 'comment'){ - $comment = $DB->get_record('glossary_comments', array('id' => $id)); - $entry = $DB->get_record('glossary_entries', array('id' => $comment->entryid)); - } - $glossary_course = $DB->get_field('glossary', 'course', array('id' => $entry->glossaryid)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'glossary')); - $cm = $DB->get_record('course_modules', array('course' => $glossary_course, 'module' => $coursemodule, 'instance' => $entry->glossaryid)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - if ($itemtype == 'standard'){ - return new GlossarySearchDocument(get_object_vars($entry), $glossary_course, $context->id); - } - elseif ($itemtype == 'comment'){ - return new GlossaryCommentSearchDocument(get_object_vars($comment), $entry->glossaryid, $glossary_course, $context->id); - } -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function glossary_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function glossary_db_names() { - //[primary id], [table name], [time created field name], [time modified field name] - return array( - array('id', 'glossary_entries', 'timecreated', 'timemodified', 'standard'), - array('id', 'comments', 'timecreated', 'timecreated', 'comment') - ); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @uses $CFG, $DB -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In glossaries, this id -* points out the indexed glossary item. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @param int $context_id the current group used by the user when searching -* @return true if access is allowed, false elsewhere -*/ -function glossary_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - // get the glossary object and all related stuff - $entry = $DB->get_record('glossary_entries', array('id' => $this_id)); - $glossary = $DB->get_record('glossary', array('id' => $entry->glossaryid)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $context)) { - return false; - } - - //approval check : entries should be approved for being viewed, or belongs to the user unless the viewer can approve them or manage them - if (!$entry->approved && $user != $entry->userid && !has_capability('mod/glossary:approve', $context) && !has_capability('mod/glossary:manageentries', $context)) { - return false; - } - - return true; -} - -/** -* post processes the url for cleaner output. -* @param string $title -*/ -function glossary_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} - -?> \ No newline at end of file diff --git a/search/documents/label_document.php b/search/documents/label_document.php deleted file mode 100644 index e57c1d8a985..00000000000 --- a/search/documents/label_document.php +++ /dev/null @@ -1,192 +0,0 @@ - 1.9 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for all resources -* This file contains the mapping between a resource and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/resource/lib.php -*/ - -/** -* requires and includes -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/resource/lib.php'); - -/* * -* a class for representing searchable information -* -*/ -class LabelSearchDocument extends SearchDocument { - public function __construct(&$label, $context_id) { - // generic information; required - $doc->docid = $label['id']; - $doc->documenttype = SEARCH_TYPE_LABEL; - $doc->itemtype = 'label'; - $doc->contextid = $context_id; - - $doc->title = strip_tags($label['name']); - $doc->date = $label['timemodified']; - $doc->author = ''; - $doc->contents = strip_tags($label['intro']); - $doc->url = label_make_link($label['course']); - - // module specific information; optional - $data = array(); - - // construct the parent class - parent::__construct($doc, $data, $label['course'], 0, 0, 'mod/'.SEARCH_TYPE_LABEL); - } //constructor -} - -/** -* constructs valid access links to information -* @param int $resourceId the of the resource -* @return a full featured link element as a string -*/ -function label_make_link($course_id) { - global $CFG; - - return $CFG->wwwroot.'/course/view.php?id='.$course_id; -} - -/** -* part of standard API -* -*/ -function label_iterator() { - global $DB; - - //trick to leave search indexer functionality intact, but allow - //this document to only use the below function to return info - //to be searched - $labels = $DB->get_records('label'); - return $labels; -} - -/** -* part of standard API -* this function does not need a content iterator, returns all the info -* itself; -* @param $label notneeded to comply API, remember to fake the iterator array though -* @uses $CFG, $DB -* @return an array of searchable documents -*/ -function label_get_content_for_index(&$label) { - global $CFG, $DB; - - // starting with Moodle native resources - $documents = array(); - - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'label')); - $cm = $DB->get_record('course_modules', array('course' => $label->course, 'module' => $coursemodule, 'instance' => $label->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - - $documents[] = new LabelSearchDocument(get_object_vars($label), $context->id); - - mtrace("finished label {$label->id}"); - return $documents; -} - -/** -* part of standard API. -* returns a single resource search document based on a label id -* @uses $CFG, $DB -* @param int $id the id of the accessible document -* @param string $itemtype the nature of the information making the document -* @return a searchable object or null if failure -*/ -function label_single_document($id, $itemtype) { - global $CFG, $DB; - - $label = $DB->get_record('label', array('id' => $id)); - - if ($label){ - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'label')); - $cm = $DB->get_record('course_modules', array('id' => $label->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - return new LabelSearchDocument(get_object_vars($label), $context->id); - } - return null; -} - -/** -* dummy delete function that aggregates id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function label_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} //resource_delete - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function label_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql] - return array(array('id', 'label', 'timemodified', 'timemodified', 'label', '')); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* @uses $CFG, $DB -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In resources, this id -* points to the resource record and not to the module that shows it. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @return true if access is allowed, false elsewhere -*/ -function label_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - $r = $DB->get_record('label', array('id' => $this_id)); - $module_context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $module_context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - $course_context = get_context_instance(CONTEXT_COURSE, $r->course); - - //check if englobing course is visible - if (!is_enrolled($course_context) and !is_viewing($course_context)) { - return false; - } - - //check if found course module is visible - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $module_context)){ - return false; - } - - return true; -} - -/** -* post processes the url for cleaner output. -* @param string $title -*/ -function label_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding("(".shorten_text(clean_text($title), 60)."...) ", 'UTF-8', 'auto'); - } - return mb_convert_encoding("(".shorten_text(clean_text($title), 60)."...) ", 'auto', 'UTF-8'); -} -?> \ No newline at end of file diff --git a/search/documents/lesson_document.php b/search/documents/lesson_document.php deleted file mode 100644 index f1c105bbcd7..00000000000 --- a/search/documents/lesson_document.php +++ /dev/null @@ -1,234 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for lesson activity module -* This file contains the mapping between a lesson page and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/lesson/lib.php -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/lesson/lib.php'); - -/** -* a class for representing searchable information -* -*/ -class LessonPageSearchDocument extends SearchDocument { - - /** - * constructor - * - */ - public function __construct(&$page, $lessonmodule_id, $course_id, $itemtype, $context_id) { - // generic information - $doc->docid = $page['id']; - $doc->documenttype = SEARCH_TYPE_LESSON; - $doc->itemtype = $itemtype; - $doc->contextid = $context_id; - - $doc->title = $page['title']; - - $doc->author = ''; - $doc->contents = $page['contents']; - $doc->date = $page['timecreated']; - $doc->url = lesson_make_link($lessonmodule_id, $page['id'], $itemtype); - - // module specific information - $data->lesson = $page['lessonid']; - - parent::__construct($doc, $data, $course_id, 0, 0, 'mod/'.SEARCH_TYPE_LESSON); - } -} - -/** -* constructs a valid link to a chat content -* @param int $lessonid the lesson module -* @param int $itemid the id of a single page -* @param string $itemtype the nature of the indexed object -* @return a well formed link to lesson page -*/ -function lesson_make_link($lessonmoduleid, $itemid, $itemtype) { - global $CFG; - - if ($itemtype == 'page'){ - return $CFG->wwwroot."/mod/lesson/view.php?id={$lessonmoduleid}&pageid={$itemid}"; - } - return $CFG->wwwroot.'/mod/lesson/view.php?id='.$lessonmoduleid; -} - -/** -* search standard API -* @uses $DB -* -*/ -function lesson_iterator() { - global $DB; - - if ($lessons = $DB->get_records('lesson')){ - return $lessons; - } else { - return array(); - } -} - -/** -* search standard API -* @uses $DB -* @param reference $lesson a lesson instance (by ref) -* @return an array of searchable documents -*/ -function lesson_get_content_for_index(&$lesson) { - global $DB; - - $documents = array(); - if (!$lesson) return $documents; - - $pages = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id)); - if ($pages){ - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'lesson')); - $cm = $DB->get_record('course_modules', array('course' => $lesson->course, 'module' => $coursemodule, 'instance' => $lesson->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - foreach($pages as $aPage){ - $documents[] = new LessonPageSearchDocument(get_object_vars($aPage), $cm->id, $lesson->course, 'page', $context->id); - } - } - - return $documents; -} - -/** -* returns a single lesson search document based on a lesson page id -* @uses $DB -* @param int $id an id for a single information item -* @param string $itemtype the type of information -*/ -function lesson_single_document($id, $itemtype) { - global $DB; - - // only page is known yet - $page = $DB->get_record('lesson_pages', array('id' => $id)); - $lesson = $DB->get_record('lesson', array('id' => $page->lessonid)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'lesson')); - $cm = $DB->get_record('course_modules', array('course' => $lesson->course, 'module' => $coursemodule, 'instance' => $page->lessonid)); - if ($cm){ - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - $lesson->groupid = 0; - return new LessonPageSearchDocument(get_object_vars($page), $cm->id, $lesson->course, $itemtype, $context->id); - } - return null; -} - -/** -* dummy delete function that aggregates id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function lesson_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function lesson_db_names() { - //[primary id], [table name], [time created field name], [time modified field name] [itemtype] [select for getting itemtype] - return array( - array('id', 'lesson_pages', 'timecreated', 'timemodified', 'page') - ); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In lessons, this id -* points out the individual page. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @param int $context_id the id of the context used when indexing -* @uses $CFG, $USER, $DB -* @return true if access is allowed, false elsewhere -*/ -function lesson_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $USER, $DB; - - include_once("{$CFG->dirroot}/{$path}/lib.php"); - - // get the lesson page - $page = $DB->get_record('lesson_pages', array('id' => $this_id)); - $lesson = $DB->get_record('lesson', array('id' => $page->lessonid)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){ - if (!empty($CFG->search_access_debug)) echo "search reject : hidden lesson "; - return false; - } - - $lessonsuperuser = has_capability('mod/lesson:edit', $context) or has_capability('mod/lesson:manage', $context); - // approval check : entries should be approved for being viewed, or belongs to the user - if (time() < $lesson->available && !$lessonsuperuser ){ - if (!empty($CFG->search_access_debug)) echo "search reject : lesson is not available "; - return false; - } - - if ($lesson->usepassword && !$lessonsuperuser){ - if (!empty($CFG->search_access_debug)) echo "search reject : password required, cannot output in searches "; - return false; - } - - // the user have it seen yet ? did he tried one time at least - $attempt = $DB->get_record('lesson_attempts', array('lessonid'=>$lesson->id,'pageid'=>$page->id, 'userid'=>$USER->id)); - - if (!$attempt && !$lessonsuperuser){ - if (!empty($CFG->search_access_debug)) echo "search reject : never tried this lesson "; - return false; - } - - if ($attempt && !$attempt->correct && !$lessonsuperuser && !$lesson->retake){ - if (!empty($CFG->search_access_debug)) echo "search reject : one try only, still not good "; - return false; - } - - return true; -} - -/** -* this call back is called when displaying the link for some last post processing -* -*/ -function lesson_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} - -?> \ No newline at end of file diff --git a/search/documents/physical_doc.php b/search/documents/physical_doc.php deleted file mode 100644 index a6beb18600e..00000000000 --- a/search/documents/physical_doc.php +++ /dev/null @@ -1,65 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* MS Word extractor -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_doc(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // adds moodle root switch if none was defined - if (!isset($CFG->block_search_usemoodleroot)){ - set_config('block_search_usemoodleroot', 1); - } - - $moodleroot = ($CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ; - - // just call pdftotext over stdout and capture the output - if (!empty($CFG->block_search_word_to_text_cmd)){ - if (!file_exists("{$moodleroot}{$CFG->block_search_word_to_text_cmd}")){ - mtrace('Error with MSWord to text converter command : executable not found at '.$moodleroot.$CFG->block_search_word_to_text_cmd); - } else { - if ($directfile == ''){ - $file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"); - } else { - $file = escapeshellarg("{$CFG->dataroot}/{$directfile}"); - } - $command = trim($CFG->block_search_word_to_text_cmd); - $text_converter_cmd = "{$moodleroot}{$command} -m UTF-8.txt $file"; - if ($CFG->block_search_word_to_text_env){ - putenv($CFG->block_search_word_to_text_env); - } - mtrace("Executing : $text_converter_cmd"); - $result = shell_exec($text_converter_cmd); - if ($result){ - return mb_convert_encoding($result, 'UTF-8', 'auto'); - } else { - mtrace('Error with MSWord to text converter command : execution failed. '); - return ''; - } - } - } else { - mtrace('Error with MSWord to text converter command : command not set up. Execute once search block configuration.'); - return ''; - } -} -?> \ No newline at end of file diff --git a/search/documents/physical_htm.php b/search/documents/physical_htm.php deleted file mode 100644 index e96e066f6d6..00000000000 --- a/search/documents/physical_htm.php +++ /dev/null @@ -1,65 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_htm(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // just get text - if ($directfile == ''){ - $text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}")); - } else { - $text = implode('', file("{$CFG->dataroot}/{$directfile}")); - } - - // extract keywords and other interesting meta information and put it back as real content for indexing - if (preg_match('/(.*)]*)>(.*)/is', $text, $matches)){ - $prefix = $matches[1]; - $meta_attributes = $matches[2]; - $suffix = $matches[3]; - if (preg_match('/name="(keywords|description)"/i', $meta_attributes)){ - preg_match('/content="([^"]+)"/i', $meta_attributes, $matches); - $text = $prefix.' '.$matches[1].' '.$suffix; - } - } - // brutally filters all html tags - $text = preg_replace("/<[^>]*>/", '', $text); - $text = preg_replace("//", '', $text); - $text = html_entity_decode($text, ENT_COMPAT, 'UTF-8'); - $text = mb_convert_encoding($text, 'UTF-8', 'auto'); - - /* - * debug code for tracing input - echo "
"; - $FILE = fopen("filetrace.log", 'w'); - fwrite($FILE, $text); - fclose($FILE); - echo "
"; - */ - - if (!empty($CFG->block_search_limit_index_body)){ - $text = shorten_text($text, $CFG->block_search_limit_index_body); - } - return $text; -} -?> \ No newline at end of file diff --git a/search/documents/physical_html.php b/search/documents/physical_html.php deleted file mode 100644 index 9054776edd8..00000000000 --- a/search/documents/physical_html.php +++ /dev/null @@ -1,26 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a standard html format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -*/ -function get_text_for_indexing_html(&$resource, $directfile = ''){ - - // wraps to htm handler - include_once 'physical_htm.php'; - return get_text_for_indexing_htm($resource, $directfile); -} -?> \ No newline at end of file diff --git a/search/documents/physical_odt.php b/search/documents/physical_odt.php deleted file mode 100644 index 289ed251964..00000000000 --- a/search/documents/physical_odt.php +++ /dev/null @@ -1,62 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of the opensource ODT binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* OpenOffice Odt extractor -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_odt(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // adds moodle root switch if none was defined - if (!isset($CFG->block_search_usemoodleroot)){ - set_config('block_search_usemoodleroot', 1); - } - - $moodleroot = ($CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ; - - // just call pdftotext over stdout and capture the output - if (!empty($CFG->block_search_odt_to_text_cmd)){ - if (!file_exists("{$moodleroot}{$CFG->block_search_odt_to_text_cmd}")){ - mtrace('Error with OpenOffice ODT to text converter command : exectuable not found at '.$moodleroot.$CFG->block_search_odt_to_text_cmd); - } else { - if ($directfile == ''){ - $file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"); - } else { - $file = escapeshellarg("{$CFG->dataroot}/{$directfile}"); - } - $command = trim($CFG->block_search_odt_to_text_cmd); - $text_converter_cmd = "{$moodleroot}{$command} --encoding=UTF-8 $file"; - mtrace("Executing : $text_converter_cmd"); - $result = shell_exec($text_converter_cmd); - if ($result){ - return $result; - } else { - mtrace('Error with OpenOffice ODT to text converter command : execution failed. '); - return ''; - } - } - } else { - mtrace('Error with OpenOffice ODT to text converter command : command not set up. Execute once search block configuration.'); - return ''; - } -} -?> \ No newline at end of file diff --git a/search/documents/physical_pdf.php b/search/documents/physical_pdf.php deleted file mode 100644 index e6f7864a311..00000000000 --- a/search/documents/physical_pdf.php +++ /dev/null @@ -1,61 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_pdf(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // adds moodle root switch if none was defined - if (!isset($CFG->block_search_usemoodleroot)){ - set_config('block_search_usemoodleroot', 1); - } - - $moodleroot = ($CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ; - - // just call pdftotext over stdout and capture the output - if (!empty($CFG->block_search_pdf_to_text_cmd)){ - preg_match("/^\S+/", $CFG->block_search_pdf_to_text_cmd, $matches); - if (!file_exists("{$moodleroot}{$matches[0]}")){ - mtrace('Error with pdf to text converter command : executable not found at '.$moodleroot.$matches[0]); - } else { - if ($directfile == ''){ - $file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"); - } else { - $file = escapeshellarg("{$CFG->dataroot}/{$directfile}"); - } - $command = trim($CFG->block_search_pdf_to_text_cmd); - $text_converter_cmd = "{$moodleroot}{$command} $file -"; - $result = shell_exec($text_converter_cmd); - if ($result){ - return $result; - } else { - mtrace('Error with pdf to text converter command : execution failed for '.$text_converter_cmd.'. Check for execution permission on pdf converter executable.'); - return ''; - } - } - } else { - mtrace('Error with pdf to text converter command : command not set up. Execute once search block configuration.'); - return ''; - } -} -?> \ No newline at end of file diff --git a/search/documents/physical_ppt.php b/search/documents/physical_ppt.php deleted file mode 100644 index b91628a2f0c..00000000000 --- a/search/documents/physical_ppt.php +++ /dev/null @@ -1,96 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/* -* first implementation is a trivial heuristic based on ppt character stream : -* text sequence always starts with a 00 9F 0F 04 sequence followed by a 15 bytes -* sequence -* In this sequence is a A8 0F or A0 0F or AA 0F followed by a little-indian encoding of text buffer size -* A8 0F denotes for ASCII text (local system monobyte encoding) -* A0 0F denotes for UTF-16 encoding -* AA 0F are non textual sequences -* texts are either in ASCII or UTF-16 -* text ends on a new sequence start, or on a 00 00 NULL UTF-16 end of stream -* -* based on these following rules, here is a little empiric texte extractor for PPT -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_ppt(&$resource, $directfile = ''){ - global $CFG; - - $indextext = null; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - if ($directfile == ''){ - $text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}")); - } else { - $text = implode('', file("{$CFG->dataroot}/{$directfile}")); - } - - $remains = $text; - $fragments = array(); - while (preg_match('/\x00\x9F\x0F\x04.{9}(......)(.*)/s', $remains, $matches)){ - $unpacked = unpack("ncode/Llength", $matches[1]); - $sequencecode = $unpacked['code']; - $length = $unpacked['length']; - // print "length : ".$length." ; segment type : ".sprintf("%x", $sequencecode)."
"; - $followup = $matches[2]; - // local system encoding sequence - if ($sequencecode == 0xA80F){ - $aFragment = substr($followup, 0, $length); - $remains = substr($followup, $length); - $fragments[] = $aFragment; - } - // denotes unicode encoded sequence - elseif ($sequencecode == 0xA00F){ - $aFragment = substr($followup, 0, $length); - // $aFragment = mb_convert_encoding($aFragment, 'UTF-16', 'UTF-8'); - $aFragment = preg_replace('/\xA0\x00\x19\x20/s', "'", $aFragment); // some quotes - $aFragment = preg_replace('/\x00/s', "", $aFragment); - $remains = substr($followup, $length); - $fragments[] = $aFragment; - } - else{ - $remains = $followup; - } - } - $indextext = implode(' ', $fragments); - $indextext = preg_replace('/\x19\x20/', "'", $indextext); // some quotes - $indextext = preg_replace('/\x09/', '', $indextext); // some extra chars - $indextext = preg_replace('/\x0D/', "\n", $indextext); // some quotes - $indextext = preg_replace('/\x0A/', "\n", $indextext); // some quotes - $indextextprint = implode('
', $fragments); - - // debug code - // $logppt = fopen("C:/php5/logs/pptlog", "w"); - // fwrite($logppt, $indextext); - // fclose($logppt); - - if (!empty($CFG->block_search_limit_index_body)){ - $indextext = shorten_text($text, $CFG->block_search_limit_index_body); - } - - $indextext = mb_convert_encoding($indextext, 'UTF-8', 'auto'); - return $indextext; -} -?> \ No newline at end of file diff --git a/search/documents/physical_swf.php b/search/documents/physical_swf.php deleted file mode 100644 index 2e027b0ba21..00000000000 --- a/search/documents/physical_swf.php +++ /dev/null @@ -1,71 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* @note : The Adobe SWF Converters library is not GPL, although it can be of free use in some -* situations. This file is provided for convenience, but should use having a glance at -* {@link http://www.adobe.com/licensing/developer/} -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_swf(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // adds moodle root switch if none was defined - if (!isset($CFG->block_search_usemoodleroot)){ - set_config('block_search_usemoodleroot', 1); - } - - $moodleroot = ($CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ; - - // just call pdftotext over stdout and capture the output - if (!empty($CFG->block_search_pdf_to_text_cmd)){ - $command = trim($CFG->block_search_swf_to_text_cmd); - if (!file_exists("{$moodleroot}{$command}")){ - mtrace('Error with swf to text converter command : executable not found as '.$moodleroot.$command); - } else { - if ($directfile == ''){ - $file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"); - } else { - $file = escapeshellarg("{$CFG->dataroot}/{$directfile}"); - } - $text_converter_cmd = "{$moodleroot}{$command} -t $file"; - $result = shell_exec($text_converter_cmd); - - // result is in html. We must strip it off - $result = preg_replace("/<[^>]*>/", '', $result); - $result = preg_replace("//", '', $result); - $result = html_entity_decode($result, ENT_COMPAT, 'UTF-8'); - $result = mb_convert_encoding($result, 'UTF-8', 'auto'); - - if ($result){ - return $result; - } else { - mtrace('Error with swf to text converter command : execution failed for '.$text_converter_cmd.'. Check for execution permission on swf converter executable.'); - return ''; - } - } - } else { - mtrace('Error with swf to text converter command : command not set up. Execute once search block configuration.'); - return ''; - } -} -?> \ No newline at end of file diff --git a/search/documents/physical_txt.php b/search/documents/physical_txt.php deleted file mode 100644 index 1f4d7857469..00000000000 --- a/search/documents/physical_txt.php +++ /dev/null @@ -1,40 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_txt(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // just try to get text empirically from ppt binary flow - if ($directfile == ''){ - $text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}")); - } else { - $text = implode('', file("{$CFG->dataroot}/{$directfile}")); - } - - if (!empty($CFG->block_search_limit_index_body)){ - $text = shorten_text($text, $CFG->block_search_limit_index_body); - } - return $text; -} -?> \ No newline at end of file diff --git a/search/documents/physical_xml.php b/search/documents/physical_xml.php deleted file mode 100644 index db4178275b5..00000000000 --- a/search/documents/physical_xml.php +++ /dev/null @@ -1,43 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version revised for Moodle 2.0 -* -* this is a format handler for getting text out of a proprietary binary format -* so it can be indexed by Lucene search engine -*/ - -/** -* @param object $resource -* @param string $directfile if the resource is given as a direct file path, use it as reference to the file -* @uses $CFG -*/ -function get_text_for_indexing_xml(&$resource, $directfile = ''){ - global $CFG; - - // SECURITY : do not allow non admin execute anything on system !! - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) return; - - // just get text - if ($directfile == ''){ - $text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}")); - } else { - $text = implode('', file("{$CFG->dataroot}/{$directfile}")); - } - - // filter out all xml tags - $text = preg_replace("/<[^>]*>/", ' ', $text); - - if (!empty($CFG->block_search_limit_index_body)){ - $text = shorten_text($text, $CFG->block_search_limit_index_body); - } - return $text; -} -?> \ No newline at end of file diff --git a/search/documents/resource_document.php b/search/documents/resource_document.php deleted file mode 100644 index 529d76243e9..00000000000 --- a/search/documents/resource_document.php +++ /dev/null @@ -1,363 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for all resources -* This file contains the mapping between a resource and it's indexable counterpart, -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/resource/lib.php -*/ - -/** -* requires and includes -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/resource/lib.php'); - -/* * -* a class for representing searchable information -* -*/ -class ResourceSearchDocument extends SearchDocument { - public function __construct(&$resource, $context_id) { - // generic information; required - $doc->docid = $resource['trueid']; - $doc->documenttype = SEARCH_TYPE_RESOURCE; - $doc->itemtype = $resource['type']; - $doc->contextid = $context_id; - - $doc->title = strip_tags($resource['name']); - $doc->date = $resource['timemodified']; - $doc->author = ''; - $doc->contents = strip_tags($resource['summary']).' '.strip_tags($resource['alltext']); - $doc->url = resource_make_link($resource['id']); - - // module specific information; optional - $data = array(); - - // construct the parent class - parent::__construct($doc, $data, $resource['course'], 0, 0, 'mod/'.SEARCH_TYPE_RESOURCE); - } -} - -/** -* constructs valid access links to information -* @param resourceId the of the resource -* @return a full featured link element as a string -*/ -function resource_make_link($resource_id) { - global $CFG; - - return $CFG->wwwroot.'/mod/resource/view.php?id='.$resource_id; -} - -/** -* part of standard API -* -*/ -function resource_iterator() { - //trick to leave search indexer functionality intact, but allow - //this document to only use the below function to return info - //to be searched - return array(true); - } - -/** -* part of standard API -* this function does not need a content iterator, returns all the info -* itself; -* @param void $notneeded to comply API, remember to fake the iterator array though -* @uses $CFG, $DB -* @return an array of searchable documents -*/ -function resource_get_content_for_index(&$notneeded) { - global $CFG, $DB; - - - // starting with Moodle native resources - $documents = array(); - - $dbman = $DB->get_manager(); - if (!$dbman->table_exists('resource_old')) { - return $documents; - } - - // the resources have been moved into modules of their own. indexing need to be created for these. - // for a temporary fix (until MDL-24856 is fixed) pointing this query to a table that is copy of the old resource table schema. - $query = " - SELECT - id as trueid, - r.* - FROM - {resource_old} as r - WHERE - alltext != '' AND - alltext != ' ' AND - alltext != ' ' AND - type != 'file' - "; - if ($resources = $DB->get_records_sql($query)){ - foreach($resources as $aResource){ - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource')); - $cm = $DB->get_record('course_modules', array('course' => $aResource->course, 'module' => $coursemodule, 'instance' => $aResource->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - $aResource->id = $cm->id; - $documents[] = new ResourceSearchDocument(get_object_vars($aResource), $context->id); - mtrace("finished $aResource->name"); - } - } - - // special physical files handling - /** - * this sequence searches for a compatible physical stream handler for getting a text - * equivalence for the content. - * - */ - if (@$CFG->block_search_enable_file_indexing){ - $query = " - SELECT - r.id as trueid, - cm.id as id, - r.course as course, - r.name as name, - r.summary as summary, - r.alltext as alltext, - r.reference as reference, - r.type as type, - r.timemodified as timemodified - FROM - {resource_old} as r, - {course_modules} as cm, - {modules} as m - WHERE - r.type = 'file' AND - cm.instance = r.id AND - cm.course = r.course AND - cm.module = m.id AND - m.name = 'resource' - "; - if ($resources = $DB->get_records_sql($query)){ - // invokes external content extractor if exists. - foreach($resources as $aResource){ - // fetches a physical indexable document and adds it to documents passed by ref - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource')); - $cm = $DB->get_record('course_modules', array('id' => $aResource->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - resource_get_physical_file($aResource, $context->id, false, $documents); - } - } - } - return $documents; -} - -/** -* get text from a physical file -* @uses $CFG -* @param reference $resource a resource for which to fetch some representative text -* @param int $context_id the context associated with the resource -* @param bool $getsingle if true, returns a single search document, elsewhere return the array -* given as documents increased by one -* @param array $documents the array of documents, by ref, where to add the new document. -* @return a search document when unique or false. -*/ -function resource_get_physical_file(&$resource, $context_id, $getsingle, &$documents = null){ - global $CFG; - - // cannot index empty references - if (empty($resource->reference)){ - mtrace("Cannot index, empty reference."); - return false; - } - - // cannot index remote resources - if (resource_is_url($resource->reference)){ - mtrace("Cannot index remote URLs."); - return false; - } - - $fileparts = pathinfo($resource->reference); - // cannot index unknown or masked types - if (empty($fileparts['extension'])) { - mtrace("Cannot index without explicit extension."); - return false; - } - - // cannot index non existent file - $file = "{$CFG->dataroot}/{$resource->course}/{$resource->reference}"; - if (!file_exists($file)){ - mtrace("Missing resource file $file : will not be indexed."); - return false; - } - - $ext = strtolower($fileparts['extension']); - - // cannot index unallowed or unhandled types - if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) { - mtrace($fileparts['extension'] . ' is not an allowed extension for indexing'); - return false; - } - if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){ - include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php'); - $function_name = 'get_text_for_indexing_'.$ext; - $resource->alltext = $function_name($resource); - if (!empty($resource->alltext)){ - if ($getsingle){ - $single = new ResourceSearchDocument(get_object_vars($resource), $context_id); - mtrace("finished file $resource->name as {$resource->reference}"); - return $single; - } else { - $documents[] = new ResourceSearchDocument(get_object_vars($resource), $context_id); - } - mtrace("finished file $resource->name as {$resource->reference}"); - } - } else { - mtrace("fulltext handler not found for $ext type"); - } - return false; -} - -/** -* part of standard API. -* returns a single resource search document based on a resource_entry id -* @uses $CFG, $DB -* @param id the id of the accessible document -* @return a searchable object or null if failure -*/ -function resource_single_document($id, $itemtype) { - global $CFG, $DB; - - // rewriting with legacy moodle databse API - $query = " - SELECT - r.id as trueid, - cm.id as id, - r.course as course, - r.name as name, - r.summary as summary, - r.alltext as alltext, - r.reference as reference, - r.type as type, - r.timemodified as timemodified - FROM - {resource} as r, - {course_modules} as cm, - {modules} as m - WHERE - cm.instance = r.id AND - cm.course = r.course AND - cm.module = m.id AND - m.name = 'resource' AND - ((r.type != 'file' AND - r.alltext != '' AND - r.alltext != ' ' AND - r.alltext != ' ') OR - r.type = 'file') AND - r.id = '?' - "; - $resource = $DB->get_record_sql($query, array($id)); - - if ($resource){ - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'resource')); - $cm = $DB->get_record('course_modules', array('id' => $resource->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - if ($resource->type == 'file' && @$CFG->block_search_enable_file_indexing){ - $document = resource_get_physical_file($resource, true, $context->id); - if (!$document) mtrace("Warning : this document {$resource->name} will not be indexed"); - return $document; - } else { - return new ResourceSearchDocument(get_object_vars($resource), $context->id); - } - } - mtrace('null resource'); - return null; -} - -/** -* dummy delete function that aggregates id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function resource_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* -*/ -function resource_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [additional where conditions for sql] - return array(array('id', 'resource_old', 'timemodified', 'timemodified', 'any', " (alltext != '' AND alltext != ' ' AND alltext != ' ' AND TYPE != 'file') OR TYPE = 'file' ")); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* @uses $CFG, $DB -* @param path the access path to the module script code -* @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param this_id the item id within the information class denoted by itemtype. In resources, this id -* points to the resource record and not to the module that shows it. -* @param user the user record denoting the user who searches -* @param group_id the current group used by the user when searching -* @return true if access is allowed, false elsewhere -*/ -function resource_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - // include_once("{$CFG->dirroot}/{$path}/lib.php"); - - $r = $DB->get_record('resource', array('id' => $this_id)); - $module_context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $module_context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - $course = $DB->get_record('course', array('id' => $r->course)); - $course_context = get_context_instance(CONTEXT_COURSE, $r->course); - $course = $DB->get_record('course', array('id' => $r->course)); - - //check if course is visible - if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $course_context)) { - return false; - } - - //check if user is registered in course or course is open to guests - if (!is_enrolled($course_context) and !is_viewing($course_context)) { //TODO: guest course access is gone, this needs a different solution - return false; - } - - - //check if found course module is visible - if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $module_context)){ - return false; - } - - return true; -} - -/** -* post processes the url for cleaner output. -* @param string $title -*/ -function resource_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} -?> \ No newline at end of file diff --git a/search/documents/user_document.php b/search/documents/user_document.php deleted file mode 100644 index 418193e798f..00000000000 --- a/search/documents/user_document.php +++ /dev/null @@ -1,385 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* special (EXTRA) document handling for user related data -* -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/blog/lib.php'); - -/** -* a class for representing searchable information in user metadata -* -*/ -class UserSearchDocument extends SearchDocument { - - /** - * constructor - * @uses $DB - */ - public function __construct(&$userhash, $user_id, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $userhash['id']; - $doc->documenttype = SEARCH_TYPE_USER; - $doc->itemtype = 'user'; - $doc->contextid = $context_id; - - $user = $DB->get_record('user', array('id' => $user_id)); - $doc->title = get_string('user').': '.fullname($user); - $doc->date = ($userhash['lastaccess']) ? $userhash['lastaccess'] : time() ; - - //remove '(ip.ip.ip.ip)' from chat author list - $doc->author = $user->id; - $doc->contents = $userhash['description']; - $doc->url = user_make_link($user_id, 'user'); - - // module specific information; optional - - // construct the parent class - parent::__construct($doc, $data, 0, 0, $user_id, PATH_FOR_SEARCH_TYPE_USER); - } -} - -/** -* a class for representing searchable information in user metadata -* -*/ -class UserPostSearchDocument extends SearchDocument { - - /** - * constructor - * @uses $DB - */ - public function __construct(&$post, $user_id, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $post['id']; - $doc->documenttype = SEARCH_TYPE_USER; - $doc->itemtype = 'post'; - $doc->contextid = $context_id; - - $user = $DB->get_record('user', array('id' => $user_id)); - - // we cannot call userdate with relevant locale at indexing time. - //$doc->title = get_string('post').': '.fullname($user); - $doc->title = $post['subject']; - $doc->date = $post['created']; - - //remove '(ip.ip.ip.ip)' from chat author list - $doc->author = fullname($user); - $doc->contents = $post['description']; - // $doc->url = user_make_link($user_id, 'post'); - $doc->url = user_make_link($post['id'], 'post'); - - // module specific information; optional - - // construct the parent class - parent::__construct($doc, $data, 0, 0, $user_id, PATH_FOR_SEARCH_TYPE_USER); - } -} - -/** -* a class for representing searchable information in user metadata -* -*/ -class UserBlogAttachmentSearchDocument extends SearchDocument { - - /** - * constructor - * @uses $DB - */ - public function __construct(&$post, $context_id) { - global $DB; - - // generic information; required - $doc->docid = $post['id']; - $doc->documenttype = SEARCH_TYPE_USER; - $doc->itemtype = 'attachment'; - $doc->contextid = $context_id; - - $user = $DB->get_record('user', 'id', $post['userid']); - - // we cannot call userdate with relevant locale at indexing time. - $doc->title = get_string('file').' : '.$post['subject']; - $doc->date = $post['created']; - - //remove '(ip.ip.ip.ip)' from chat author list - $doc->author = fullname($user); - $doc->contents = $post['alltext']; - $doc->url = user_make_link($post['id'], 'attachment'); - - // module specific information; optional - - // construct the parent class - parent::__construct($doc, $data, 0, 0, $post['userid'], PATH_FOR_SEARCH_TYPE_USER); - } -} - - -/** -* constructs a valid link to a user record -* @param int $userid the user -* @param string $itemtype -* @uses $CFG, $DB -* @return a well formed link to user information -*/ -function user_make_link($itemid, $itemtype) { - global $CFG, $DB; - - if ($itemtype == 'user'){ - return $CFG->wwwroot.'/user/view.php?id='.$itemid; - } elseif ($itemtype == 'post') { - return $CFG->wwwroot.'/blog/index.php?postid='.$itemid; - } elseif ($itemtype == 'attachment') { - $post = $DB->get_record('post', array('id' => $itemid)); - if (!$CFG->slasharguments){ - return $CFG->wwwroot."/file.php?file=/blog/attachments/{$post->id}/{$post->attachment}"; - } else { - return $CFG->wwwroot."/file.php/blog/attachments/{$post->id}/{$post->attachment}"; - } - } else { - return null; - } -} - -/** -* part of search engine API -* @uses $DB -* -*/ -function user_iterator() { - global $DB; - - $users = $DB->get_records('user'); - return $users; -} - -/** -* part of search engine API -* @uses $CFG, $DB -* @param reference $user a user record -* @return an array of documents generated from data -*/ -function user_get_content_for_index(&$user) { - global $CFG, $DB; - - $documents = array(); - - $userhash = get_object_vars($user); - $documents[] = new UserSearchDocument($userhash, $user->id, null); - - if ($posts = $DB->get_records('post', array('userid' => $user->id), 'created')){ - foreach($posts as $post){ - $texts = array(); - $texts[] = $post->subject; - $texts[] = $post->summary; - $texts[] = $post->content; - $post->description = implode(' ', $texts); - - // record the attachment if any and physical files can be indexed - if (@$CFG->block_search_enable_file_indexing){ - if ($post->attachment){ - user_get_physical_file($post, null, false, $documents); - } - } - - $posthash = get_object_vars($post); - $documents[] = new UserPostSearchDocument($posthash, $user->id, null); - } - } - return $documents; -} - -/** -* get text from a physical file -* @uses $CFG -* @param object $post a post to whech the file is attached to -* @param boolean $context_id if in future we need recording a context along with the search document, pass it here -* @param boolean $getsingle if true, returns a single search document, elsewhere return the array -* given as documents increased by one -* @param array $documents the array of documents, by ref, where to add the new document. -* @return a search document when unique or false. -*/ -function user_get_physical_file(&$post, $context_id, $getsingle, &$documents = null){ - global $CFG; - - // cannot index empty references - if (empty($post->attachment)){ - mtrace("Cannot index, empty reference."); - return false; - } - - $fileparts = pathinfo($post->attachment); - // cannot index unknown or masked types - if (empty($fileparts['extension'])) { - mtrace("Cannot index without explicit extension."); - return false; - } - - // cannot index non existent file - $file = "{$CFG->dataroot}/blog/attachments/{$post->id}/{$post->attachment}"; - if (!file_exists($file)){ - mtrace("Missing attachment file $file : will not be indexed."); - return false; - } - - $ext = strtolower($fileparts['extension']); - - // cannot index unallowed or unhandled types - if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) { - mtrace($fileparts['extension'] . ' is not an allowed extension for indexing'); - return false; - } - if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){ - include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php'); - $function_name = 'get_text_for_indexing_'.$ext; - $directfile = "blog/attachments/{$post->id}/{$post->attachment}"; - $post->alltext = $function_name($post, $directfile); - if (!empty($post->alltext)){ - if ($getsingle){ - $posthash = get_object_vars($post); - $single = new UserBlogAttachmentSearchDocument($posthash, $context_id); - mtrace("finished attachment {$post->attachment} in {$post->title}"); - return $single; - } else { - $posthash = get_object_vars($post); - $documents[] = new UserBlogAttachmentSearchDocument($posthash, $context_id); - } - mtrace("finished attachment {$post->attachment} in {$post->subject}"); - } - } else { - mtrace("fulltext handler not found for $ext type"); - } - return false; -} - -/** -* returns a single user search document -* @uses $DB -* @param composite $id a unique document id made with -* @param itemtype the type of information (session is the only type) -*/ -function user_single_document($id, $itemtype) { - global $DB; - - if ($itemtype == 'user'){ - if ($user = $DB->get_record('user', array('id' => $id))){ - $userhash = get_object_vars($user); - return new UserSearchDocument($userhash, $user->id, 'user', null); - } - } elseif ($itemtype == 'post') { - if ($post = $DB->get_record('post', array('id' => $id))){ - $texts = array(); - $texts[] = $post->subject; - $texts[] = $post->summary; - $texts[] = $post->content; - $post->description = implode(" ", $texts); - $posthash = get_object_vars($post); - return new UserPostSearchDocument($posthash, $post->userid, 'post', null); - } - } elseif ($itemtype == 'attachment' && @$CFG->block_search_enable_file_indexing) { - if ($post = $DB->get_records('post', array('id' => $id))){ - if ($post->attachment){ - return user_get_physical_file($post, null, true); - } - } - } - return null; -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function user_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -/** -* returns the var names needed to build a sql query for addition/deletions -* attachments are indirect records, linked to its post -*/ -function user_db_names() { - //[primary id], [table name], [time created field name], [time modified field name] [itemtype] [select restriction clause] - return array( - array('id', 'user', 'firstaccess', 'timemodified', 'user'), - array('id', 'post', 'created', 'lastmodified', 'post'), - array('id', 'post', 'created', 'lastmodified', 'attachment') - ); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by entry_type. In chats, this id -* points out a session history which is a close sequence of messages. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @uses $CFG, $DB -* @return true if access is allowed, false elsewhere -*/ -function user_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB; - - include_once("{$CFG->dirroot}/{$path}/lib.php"); - - if ($itemtype == 'user'){ - // get the user - $userrecord = $DB->get_record('user', array('id' => $this_id)); - - // we cannot see nothing from unconfirmed users - if (!$userrecord->confirmed and !has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))){ - if (!empty($CFG->search_access_debug)) echo "search reject : unconfirmed user "; - return false; - } - } elseif ($itemtype == 'post' || $itemtype == 'attachment'){ - // get the post - $post = $DB->get_record('post', array('id' => $this_id)); - $userrecord = $DB->get_record('user', array('id' => $post->userid)); - - // we can try using blog visibility check - return blog_user_can_view_user_post($user->id, $post); - } - $context = $DB->get_record('context', array('id' => $context_id)); - - return true; -} - -/** -* this call back is called when displaying the link for some last post processing -* -*/ -function user_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} -?> \ No newline at end of file diff --git a/search/documents/wiki_document.php b/search/documents/wiki_document.php deleted file mode 100644 index 0643c0a021f..00000000000 --- a/search/documents/wiki_document.php +++ /dev/null @@ -1,324 +0,0 @@ - 1.8 -* @contributor Tatsuva Shirai 20090530 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* @version Moodle 2.0 -* -* document handling for wiki activity module -* This file contains the mapping between a wiki page and it's indexable counterpart, -* e.g. searchdocument->title = wikipage->pagename -* -* Functions for iterating and retrieving the necessary records are now also included -* in this file, rather than mod/wiki/lib.php -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/documents/document.php'); -require_once($CFG->dirroot.'/mod/wiki/lib.php'); - -/** -* All the $doc->___ fields are required by the base document class! -* Each and every module that requires search functionality must correctly -* map their internal fields to the five $doc fields (id, title, author, contents -* and url). Any module specific data can be added to the $data object, which is -* serialised into a binary field in the index. -*/ -class WikiSearchDocument extends SearchDocument { - public function __construct(&$page, $wiki_id, $course_id, $group_id, $user_id, $context_id) { - // generic information; required - $doc->docid = $page['id']; - $doc->documenttype = SEARCH_TYPE_WIKI; - $doc->itemtype = 'standard'; - $doc->contextid = $context_id; - - $doc->title = $page['title']; - $doc->date = $page['timemodified']; - //remove '(ip.ip.ip.ip)' from wiki author field - $doc->author = $page['author']; - $doc->contents = $page['cachedcontent']; - $doc->url = wiki_make_link($page['id']); - - // module specific information; optional - //$data->version = $page['version']; - $data->wiki = $wiki_id; - - // construct the parent class - parent::__construct($doc, $data, $course_id, $group_id, $user_id, 'mod/'.SEARCH_TYPE_WIKI); - } -} - -/** -* converts a page name to cope Wiki constraints. Transforms spaces in plus. -* @param str the name to convert -* @return the converted name -*/ -function wiki_name_convert($str) { - return str_replace(' ', '+', $str); -} - -/** -* constructs a valid link to a wiki content -* @param int $wikiId -* @param string $title -* @param int $version -* @uses $CFG -*/ -function wiki_make_link($pageid) { - global $CFG; - - return $CFG->wwwroot.'/mod/wiki/view.php?pageid='.$pageid; -} - -/** -* rescued and converted from ewikimoodlelib.php -* retrieves latest version of a page -* @uses $DB -* @param object $entry the wiki object as a reference -* @param string $pagename the name of the page known by the wiki engine -* @param int $version -*/ -function wiki_get_latest_page(&$entry, $pagename, $version = 0) { - global $DB; - - $params = array('title' => $pagename, 'subwikiid' => $entry->id); - - if ($version > 0 && is_int($version)) { - $versionclause = "AND ( version = :version )"; - $sort = 'version DESC'; - $params['version'] = $version; - } else { - $versionclause = ''; - $sort = ''; - } - - $select = "( title = :title ) AND subwikiid = :subwikiid $versionclause "; - - //change this to recordset_select, as per http://docs.moodle.org/en/Datalib_Notes - if ($result_arr = $DB->get_records_select('wiki_pages', $select, $params, $sort, '*', 0, 1)) { - foreach ($result_arr as $obj) { - $result_obj = $obj; - } - } - - if (isset($result_obj)) { - $result_obj->meta = @unserialize($result_obj->meta); - return $result_obj; - } else { - return false; - } -} - -/** -* fetches all pages, including old versions -* @uses $DB -* @param object $entry the wiki object as a reference -* @return an array of record objects that represents pages of this wiki object -*/ -function wiki_get_pages(&$entry) { - global $DB; - - return $DB->get_records('wiki_pages', array('wiki', $entry->id)); -} - -/** -* fetches all the latest versions of all the pages -* @uses $DB -* @param reference $entry -*/ -function wiki_get_latest_pages(&$entry) { - global $DB; - - //== (My)SQL for this - /* select * from wiki_pages - inner join - (select wiki_pages.pagename, max(wiki_pages.version) as ver - from wiki_pages group by pagename) as a - on ((wiki_pages.version = a.ver) and - (wiki_pages.pagename like a.pagename)) */ - - $pages = array(); - - //http://moodle.org/bugs/bug.php?op=show&bugid=5877&pos=0 - if ($ids = $DB->get_records('wiki_pages', array('subwikiid' => $entry->id), '', 'distinct title')) { - if ($pagesets = $DB->get_records('wiki_pages', array('subwikiid' => $entry->id), '', 'distinct title')) { - foreach ($pagesets as $aPageset) { - $pages[] = wiki_get_latest_page($entry, $aPageset->title); - } - } else { - return false; - } - } - return $pages; -} - -/** -* part of search engine API -* @uses $DB; -* -*/ -function wiki_iterator() { - global $DB; - - $wikis = $DB->get_records('wiki'); - return $wikis; -} - -/** -* part of search engine API -* @uses $DB -* @param reference $wiki a wiki instance -* @return an array of searchable deocuments -*/ -function wiki_get_content_for_index(&$wiki) { - global $CFG, $DB; - require_once($CFG->dirroot . '/mod/wiki/locallib.php'); - - $documents = array(); - $entries = wiki_get_subwikis($wiki->id); - if ($entries){ - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'wiki')); - $cm = $DB->get_record('course_modules', array('course' => $wiki->course, 'module' => $coursemodule, 'instance' => $wiki->id)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - foreach($entries as $entry) { - - //all pages - //$pages = wiki_get_pages($entry); - - //latest pages - $pages = wiki_get_latest_pages($entry); - if (is_array($pages)) { - foreach($pages as $page) { - if (strlen($page->title) > 0) { - $owner = $DB->get_record('user', array('id' => $page->userid)); - $page->author = fullname($owner); - $documents[] = new WikiSearchDocument(get_object_vars($page), $entry->wikiid, $wiki->course, $entry->groupid, $page->userid, $context->id); - } - } - } - } - } - return $documents; -} - -/** -* returns a single wiki search document based on a wiki_entry id -* @uses $DB; -* @param int $id the id of the wiki -* @param string $itemtype the type of information (standard) -* @return a searchable document -*/ -function wiki_single_document($id, $itemtype) { - global $DB; - - $page = $DB->get_record('wiki_pages', array('id' => $id)); - $entry = $DB->get_record('wiki_subwikis', array('id' => $page->subwikiid)); - $wiki = $DB->get_record('wiki', array('id' => $entry->wikiid)); - $coursemodule = $DB->get_field('modules', 'id', array('name' => 'wiki')); - $cm = $DB->get_record('course_modules', array('course' => $wiki->course, 'module' => $coursemodule, 'instance' => $entry->wikiid)); - $context = get_context_instance(CONTEXT_MODULE, $cm->id); - $user = $DB->get_record('user', array('id' => $page->userid)); - $page->author = fullname($user); - return new WikiSearchDocument(get_object_vars($page), $entry->wikiid, $wiki->course, $entry->groupid, $page->userid, $context->id); -} - -/** -* dummy delete function that packs id with itemtype. -* this was here for a reason, but I can't remember it at the moment. -* -*/ -function wiki_delete($info, $itemtype) { - $object->id = $info; - $object->itemtype = $itemtype; - return $object; -} - -//returns the var names needed to build a sql query for addition/deletions -function wiki_db_names() { - //[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql] - return array(array('id', 'wiki_pages', 'timecreated', 'timemodified', 'standard')); -} - -/** -* this function handles the access policy to contents indexed as searchable documents. If this -* function does not exist, the search engine assumes access is allowed. -* When this point is reached, we already know that : -* - user is legitimate in the surrounding context -* - user may be guest and guest access is allowed to the module -* - the function may perform local checks within the module information logic -* @param string $path the access path to the module script code -* @param string $itemtype the information subclassing (usefull for complex modules, defaults to 'standard') -* @param int $this_id the item id within the information class denoted by itemtype. In wikies, this id -* points out the indexed wiki page. -* @param object $user the user record denoting the user who searches -* @param int $group_id the current group used by the user when searching -* @param int $context_id a context that eventually comes with the object -* @uses $CFG, $DB -* @return true if access is allowed, false elsewhere -*/ -function wiki_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){ - global $CFG, $DB, $SESSION; - - // get the wiki object and all related stuff - $page = $DB->get_record('wiki_pages', array('id' => $this_id)); - $wiki = $DB->get_record('wiki', array('id' => $page->wiki)); - $course = $DB->get_record('course', array('id' => $wiki->course)); - $context = $DB->get_record('context', array('id' => $context_id)); - $cm = $DB->get_record('course_modules', array('id' => $context->instanceid)); - - if (empty($cm)) return false; // Shirai 20090530 - MDL19342 - course module might have been delete - - if (!$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : hidden wiki "; - return false; - } - - //group consistency check : checks the following situations about groups - // trap if user is not same group and groups are separated - if (isset($SESSION->currentgroup[$course->id])) { - $current_group = $SESSION->currentgroup[$course->id]; - } else { - $current_group = groups_get_all_groups($course->id, $USER->id); - if (is_array($current_group)) { - $current_group = array_shift(array_keys($current_group)); - $SESSION->currentgroup[$course->id] = $current_group; - } else { - $current_group = 0; - } - } - - if (isset($cm->groupmode) && empty($course->groupmodeforce)) { - $groupmode = $cm->groupmode; - } else { - $groupmode = $course->groupmode; - } - if (($groupmode == SEPARATEGROUPS) && $group_id != $current_group && !has_capability('moodle/site:accessallgroups', $context)) { - if (!empty($CFG->search_access_debug)) echo "search reject : separated group owner wiki "; - return false; - } - - return true; -} - -/** -* this call back is called when displaying the link for some last post processing -* -*/ -function wiki_link_post_processing($title){ - global $CFG; - - if ($CFG->block_search_utf8dir){ - return mb_convert_encoding($title, 'UTF-8', 'auto'); - } - return mb_convert_encoding($title, 'auto', 'UTF-8'); -} - -?> \ No newline at end of file diff --git a/search/index.php b/search/index.php deleted file mode 100644 index 089688c9659..00000000000 --- a/search/index.php +++ /dev/null @@ -1,18 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* Entry page for /search -* Redirects to query.php, because that is the most likely place a -* user intended to go to when typing moodle.site/search -*/ - -header("Location: query.php"); -?> \ No newline at end of file diff --git a/search/indexer.php b/search/indexer.php deleted file mode 100644 index 8f2b9e31c4d..00000000000 --- a/search/indexer.php +++ /dev/null @@ -1,225 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for Moodle 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* The indexer logic - -* -* Look through each installed module's or block's search document class file (/search/documents) -* for necessary search functions, and if they're present add the content to the index. -* Repeat this for blocks. -* -* Because the iterator/retrieval functions are now stored in /search/documents/_document.php, -* /mod/mod/lib.php doesn't have to be modified - and thus the search module becomes quite -* self-sufficient. URL's are now stored in the index, stopping us from needing to require -* the class files to generate a results page. -* -* Along with the index data, each document's summary gets stored in the database -* and synchronised to the index (flat file) via the primary key ('id') which is mapped -* to the 'dbid' field in the index -* */ - - -/** -* includes and requires -*/ - -define('NO_OUTPUT_BUFFERING', true); - -require_once('../config.php'); -require_once($CFG->dirroot.'/search/lib.php'); - -//this'll take some time, set up the environment -@set_time_limit(0); - - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - -/// only administrators can index the moodle installation, because access to all pages is required - - require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('beadmin', 'search', get_login_url()); - } - -/// confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point) - - $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA)); - - if ($sure != 'yes') { - mtrace("
Sorry, you need to confirm indexing via indexersplash.php"
-              .". (Back to query page).
"); - - exit(0); - } - -/// check for php5 (lib.php) - - //php5 found, continue including php5-only files - //require_once("$CFG->dirroot/search/Zend/Search/Lucene.php"); - require_once($CFG->dirroot.'/search/indexlib.php'); - - mtrace(''); - mtrace('
Server Time: '.date('r',time())."\n");
-
-    if (isset($CFG->search_indexer_busy) && $CFG->search_indexer_busy == '1') {
-        //means indexing was not finished previously
-        mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
-    }
-
-/// turn on busy flag
-
-    set_config('search_indexer_busy', '1');
-
-    //paths
-    $index_path = SEARCH_INDEX_PATH;
-    $index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
-    $dbcontrol = new IndexDBControl();
-
-/// setup directory in data root
-
-    if (!file_exists($index_path)) {
-        mtrace("Data directory ($index_path) does not exist, attempting to create.");
-        if (!mkdir($index_path, $CFG->directorypermissions)) {
-            search_pexit("Error creating data directory at: $index_path. Please correct.");
-        }
-        else {
-            mtrace("Directory successfully created.");
-        }
-    }
-    else {
-        mtrace("Using {$index_path} as data directory.");
-    }
-
-    Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());
-    $index = new Zend_Search_Lucene($index_path, true);
-
-/// New regeneration
-
-    mtrace('Deleting old index entries.');
-    $DB->delete_records(SEARCH_DATABASE_TABLE);
-
-/// begin timer
-
-    search_stopwatch();
-    mtrace("Starting activity modules\n");
-
-    //the presence of the required search functions -
-    // * mod_iterator
-    // * mod_get_content_for_index
-    //are the sole basis for including a module in the index at the moment.
-
-    $searchables = search_collect_searchables();
-
-/// start indexation
-
-    if ($searchables){
-        foreach ($searchables as $mod) {
-
-            //mark last update times for mods to now.
-            $indexdatestring = 'search_indexer_update_date_'.$mod->name;
-            set_config($indexdatestring, time());
-            $indexdatestring = 'search_indexer_run_date_'.$mod->name;
-            set_config($indexdatestring, time());
-
-            mtrace("starting indexing {$mod->name}\n");
-
-            $key = 'search_in_'.$mod->name;
-            if (isset($CFG->$key) && !$CFG->$key) {
-                mtrace("module $key has been administratively disabled. Skipping...\n");
-                continue;
-            }
-
-            if ($mod->location == 'internal'){
-                $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
-            } else {
-                $class_file = $CFG->dirroot.'/'.$mod->location.'/'.$mod->name.'/search_document.php';
-            }
-
-            if (file_exists($class_file)) {
-                include_once($class_file);
-
-                //build function names
-                $iter_function = $mod->name.'_iterator';
-                $index_function = $mod->name.'_get_content_for_index';
-                $counter = 0;
-                if (function_exists($index_function) && function_exists($iter_function)) {
-                    mtrace("Processing module function $index_function ...");
-                    $sources = $iter_function();
-                    if ($sources){
-                        foreach ($sources as $i) {
-                            $documents = $index_function($i);
-
-                            //begin transaction
-                            if ($documents){
-                                foreach($documents as $document) {
-                                    $counter++;
-
-                                    // temporary fix until MDL-24822 is resolved
-                                    if ($document->group_id == -1 and $mod->name ='forum') {
-                                        $document->group_id = 0;
-                                    }
-                                    //object to insert into db
-                                    $dbid = $dbcontrol->addDocument($document);
-
-                                    //synchronise db with index
-                                    $document->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
-
-                                    //add document to index
-                                    $index->addDocument($document);
-
-                                    //commit every x new documents, and print a status message
-                                    if (($counter % 2000) == 0) {
-                                        $index->commit();
-                                        mtrace(".. $counter");
-                                    }
-                                }
-                            }
-                            //end transaction
-                        }
-                    }
-
-                    //commit left over documents, and finish up
-                    $index->commit();
-
-                    mtrace("-- $counter documents indexed");
-                    mtrace("done.\n");
-                }
-            } else {
-               mtrace ("No search document found for plugin {$mod->name}. Ignoring.");
-            }
-        }
-    }
-
-/// finished modules
-
-    mtrace('Finished activity modules');
-    search_stopwatch();
-
-    mtrace(".
Back to query page."); - mtrace('
'); - -/// finished, turn busy flag off - - set_config('search_indexer_busy', '0'); - -/// mark the time we last updated - - set_config('search_indexer_run_date', time()); - -/// and the index size - - set_config('search_index_size', (int)$index->count()); - -?> \ No newline at end of file diff --git a/search/indexersplash.php b/search/indexersplash.php deleted file mode 100644 index 78ac128d71f..00000000000 --- a/search/indexersplash.php +++ /dev/null @@ -1,77 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @version prepared for 2.0 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * - * This file serves as a splash-screen (entry page) to the indexer script - - * it is in place to prevent accidental reindexing which can lead to a loss - * of time, amongst other things. - */ - - /** - * includes and requires - */ - require_once('../config.php'); - - /// makes inclusions of the Zend Engine more reliable - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - - require_once($CFG->dirroot.'/search/lib.php'); - - /// check global search is enabled - - require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('beadmin', 'search', get_login_url()); - } - - require_once("$CFG->dirroot/search/indexlib.php"); - $indexinfo = new IndexInfo(); - - if ($indexinfo->valid()) { - $strsearch = get_string('search', 'search'); - $strquery = get_string('stats'); - - // print page header - $site = get_site(); - - $PAGE->set_url('/search/indexersplash.php'); - $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); - $PAGE->navbar->add($strsearch, new moodle_url('/search/index.php')); - $PAGE->navbar->add($strquery, new moodle_url('/search/stats.php')); - $PAGE->navbar->add(get_string('runindexer','search')); - $PAGE->set_title($strsearch); - $PAGE->set_heading($site->fullname); - echo $OUTPUT->header(); - - mtrace("
The data directory ($indexinfo->path) contains $indexinfo->filecount files, and\n"
-              ."there are ".$indexinfo->dbcount." records in the block_search_documents table.\n"
-              ."\n"
-              ."This indicates that you have already succesfully indexed this site. Follow the link\n"
-              ."if you are sure that you want to continue indexing - this will replace any existing\n"
-              ."index data (no Moodle data is affected).\n"
-              ."\n"
-              ."You are encouraged to use the 'Test indexing' script before continuing onto\n"
-              ."indexing - this will check if the modules are set up correctly. Please correct\n"
-              ."any errors before proceeding.\n"
-              ."\n"
-              ."Test indexing or "
-              ."Continue indexing or Back to query page."
-              ."
"); - echo $OUTPUT->footer(); - } else { - header('Location: indexer.php?areyousure=yes'); - } -?> diff --git a/search/indexlib.php b/search/indexlib.php deleted file mode 100644 index 3c2075ef291..00000000000 --- a/search/indexlib.php +++ /dev/null @@ -1,262 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* Index info class -* -* Used to retrieve information about an index. -* Has methods to check for valid database and data directory, -* and the index itself. -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/lib.php'); -require_once($CFG->dirroot.'/search/Zend/Search/Lucene.php'); - -/** -* main class for searchable information in the Lucene index -*/ -class IndexInfo { - - private $path, //index data directory - $size, //size of directory (i.e. the whole index) - $filecount, //number of files - $indexcount, //number of docs in index - $dbcount, //number of docs in db - $types, //array of [document types => count] - $complete, //is index completely formed? - $time; //date index was generated - - public function __construct($path = SEARCH_INDEX_PATH) { - global $CFG, $DB; - - $this->path = $path; - - //test to see if there is a valid index on disk, at the specified path - try { - $test_index = new Zend_Search_Lucene($this->path, false); - $validindex = true; - } catch(Exception $e) { - $validindex = false; - } - - //retrieve file system info about the index if it is valid - if ($validindex) { - $this->size = display_size(get_directory_size($this->path)); - $index_dir = get_directory_list($this->path, '', false, false); - $this->filecount = count($index_dir); - $this->indexcount = $test_index->count(); - } - else { - $this->size = 0; - $this->filecount = 0; - $this->indexcount = 0; - } - - $db_exists = false; //for now - - //get all the current tables in moodle - $admin_tables = $DB->get_tables(); - - //check if our search table exists - if (in_array(SEARCH_DATABASE_TABLE, $admin_tables)) { - //retrieve database information if it does - $db_exists = true; - - //total documents - $this->dbcount = $DB->count_records(SEARCH_DATABASE_TABLE); - - //individual document types - $types = search_collect_searchables(false, false); - asort($types); - - foreach(array_keys($types) as $type) { - $c = $DB->count_records(SEARCH_DATABASE_TABLE, array('doctype' => $type)); - $types[$type]->records = (int)$c; - } - $this->types = $types; - } else { - $this->dbcount = 0; - $this->types = array(); - } - - //check if the busy flag is set - if (isset($CFG->search_indexer_busy) && $CFG->search_indexer_busy == '1') { - $this->complete = false; - } else { - $this->complete = true; - } - - //get the last run date for the indexer - if ($this->valid() && $CFG->search_indexer_run_date) { - $this->time = $CFG->search_indexer_run_date; - } else { - $this->time = 0; - } - } - - /** - * returns false on error, and the error message via referenced variable $err - * @param array $err array of errors - */ - public function valid(&$err = null) { - $err = array(); - $ret = true; - - if (!$this->is_valid_dir()) { - $err['dir'] = get_string('invalidindexerror', 'search'); - $ret = false; - } - - if (!$this->is_valid_db()) { - $err['db'] = get_string('emptydatabaseerror', 'search'); - $ret = false; - } - - if (!$this->complete) { - $err['index'] = get_string('uncompleteindexingerror','search'); - $ret = false; - } - - return $ret; - } - - /** - * is the index dir valid - * - */ - public function is_valid_dir() { - if ($this->filecount > 0) { - return true; - } else { - return false; - } - } - - /** - * is the db table valid - * - */ - public function is_valid_db() { - if ($this->dbcount > 0) { - return true; - } else { - return false; - } - } - - /** - * shorthand get method for the class variables - * @param object $var - */ - public function __get($var) { - if (in_array($var, array_keys(get_class_vars(get_class($this))))) { - return $this->$var; - } - } -} - - -/** -* DB Index control class -* -* Used to control the search index database table -*/ -class IndexDBControl { - - /** - * does the table exist? - * @deprecated - * @uses $CFG, $DB - */ - public function checkTableExists() { - global $CFG, $DB; - - $tables = $DB->get_tables(); - if (in_array(SEARCH_DATABASE_TABLE, $tables)) { - return true; - } - else { - return false; - } - } //checkTableExists - - /** - * NEVER USED - * - * is our database setup valid? - * @uses db, CFG - * @deprecated Database is installed at install and should not be dropped out - * - public function checkDB() { - global $CFG, $db; - - $sqlfile = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql"; - $ret = false; - if ($this->checkTableExists()) { - execute_sql('drop table '.SEARCH_DATABASE_TABLE, false); - } - - //turn output buffering on - to hide modify_database() output - ob_start(); - $ret = modify_database($sqlfile, '', false); - - //chuck the buffer and resume normal operation - ob_end_clean(); - return $ret; - } //checkDB */ - - /** - * add a document record to the table - * @param document must be a Lucene SearchDocument instance - * @uses $CFG, $DB - */ - public function addDocument($document=null) { - global $DB, $CFG; - - if ($document == null) { - return false; - } - - // object to insert into db - $doc->doctype = $document->doctype; - $doc->docid = $document->docid; - $doc->itemtype = $document->itemtype; - $doc->title = $document->title; - $doc->url = $document->url; - $doc->updated = time(); - $doc->docdate = $document->date; - $doc->courseid = $document->course_id; - $doc->groupid = $document->group_id; - - //insert summary into db - $table = SEARCH_DATABASE_TABLE; - $id = $DB->insert_record($table, $doc); - - return $id; - } - - /** - * remove a document record from the index - * @param document must be a Lucene document instance, or at least a dbid enveloppe - * @uses $DB - */ - public function delDocument($document) { - global $DB; - - $table = SEARCH_DATABASE_TABLE; - $DB->delete_records($table, array('id' => $document->dbid)); - } -} - -?> \ No newline at end of file diff --git a/search/lib.php b/search/lib.php deleted file mode 100644 index d93a633f810..00000000000 --- a/search/lib.php +++ /dev/null @@ -1,197 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* General function library -* -* This file must not contain any PHP 5, because it is used to test for PHP 5 -* itself, and needs to be able to be executed on PHP 4 installations. -* -*/ - -/** -* Constants -*/ -define('SEARCH_INDEX_PATH', $CFG->dataroot.'/search'); -define('SEARCH_DATABASE_TABLE', 'block_search_documents'); - -// get document types -include_once $CFG->dirroot.'/search/searchtypes.php'; - -/** -* collects all searchable items identities -* @param boolean $namelist if true, only returns list of names of searchable items -* @param boolean $verbose if true, prints a discovering status -* @return an array of names or an array of type descriptors -*/ -function search_collect_searchables($namelist=false, $verbose=true){ - global $CFG, $DB; - - $searchables = array(); - $searchables_names = array(); - -/// get all installed modules - if ($mods = $DB->get_records('modules', null, 'name', 'id,name')){ - - $searchabletypes = array_values(search_get_document_types()); - - foreach($mods as $mod){ - $plugin = new StdClass(); - $plugin->name = $mod->name; - $plugin->type = 'mod'; - if (in_array($mod->name, $searchabletypes)){ - $plugin->location = 'internal'; - $searchables[$plugin->name] = $plugin; - $searchables_names[] = $mod->name; - } else { - $documentfile = $CFG->dirroot."/mod/{$mod->name}/search_document.php"; - $plugin->location = 'mod'; - if (file_exists($documentfile)){ - $searchables[$plugin->name] = $plugin; - $searchables_names[] = $mod->name; - } - } - } - if ($verbose) mtrace(count($searchables).' modules to search in / '.count($mods).' modules found.'); - } - -/// collects blocks as indexable information may be found in blocks either - if ($blocks = $DB->get_records('block', null, 'name', 'id,name')) { - $blocks_searchables = array(); - // prepend the "block_" prefix to discriminate document type plugins - foreach($blocks as $block){ - $plugin = new StdClass(); - $plugin->dirname = $block->name; - $plugin->name = 'block_'.$block->name; - if (in_array('SEARCH_TYPE_'.strtoupper($block->name), $searchabletypes)){ - $plugin->location = 'internal'; - $plugin->type = 'block'; - $blocks_searchables[$plugin->name] = $plugin; - $searchables_names[] = $plugin->name; - } else { - $documentfile = $CFG->dirroot."/blocks/{$plugin->dirname}/search_document.php"; - if (file_exists($documentfile)){ - $plugin->location = 'blocks'; - $plugin->type = 'block'; - $blocks_searchables[$plugin->name] = $plugin; - $searchables_names[] = $plugin->name; - } - } - } - if ($verbose) mtrace(count($blocks_searchables).' blocks to search in / '.count($blocks).' blocks found.'); - $searchables = array_merge($searchables, $blocks_searchables); - } - -/// add virtual modules onto the back of the array - - $additional = search_get_additional_modules($searchables_names); - if (!empty($additional)){ - if ($verbose) mtrace(count($additional).' additional to search in.'); - $searchables = array_merge($searchables, $additional); - } - - if ($namelist) - return $searchables_names; - return $searchables; -} - -/** -* returns all the document type constants that are known in core implementation -* @param prefix a pattern for recognizing constants -* @return an array of type labels -*/ -function search_get_document_types($prefix = 'SEARCH_TYPE_') { - $ret = array(); - foreach (get_defined_constants() as $key => $value) { - if (preg_match("/^{$prefix}/", $key)){ - $ret[$key] = $value; - } - } - sort($ret); - return $ret; -} - -/** -* additional virtual modules to index -* -* By adding 'moo' to the extras array, an additional document type -* documents/moo_document.php will be indexed - this allows for -* virtual modules to be added to the index, i.e. non-module specific -* information. -*/ -function search_get_additional_modules(&$searchables_names) { - $extras = array(/* additional keywords go here */); - if (defined('SEARCH_EXTRAS')){ - $extras = explode(',', SEARCH_EXTRAS); - } - - $ret = array(); - $temp = new StdClass; - foreach($extras as $extra) { - $plugin = new StdClass(); - $plugin->name = $extra; - $plugin->location = 'internal'; - eval('$plugin->type = TYPE_FOR_SEARCH_TYPE_'.strtoupper($extra).';'); - $ret[$plugin->name] = $plugin; - $searchables_names[] = $extra; - } - - return $ret; -} - -/** -* shortens a url so it can fit on the results page -* @param url the url -* @param length the size limit we want -*/ -function search_shorten_url($url, $length=30) { - return substr($url, 0, $length)."..."; -} - -/** -* simple timer function, on first call, records a current microtime stamp, outputs result on 2nd call -* @param cli an output formatting switch -* @return void -*/ -function search_stopwatch($cli = false) { - if (!empty($GLOBALS['search_script_start_time'])) { - if (!$cli) print ''; - print round(microtime(true) - $GLOBALS['search_script_start_time'], 6).' '.get_string('seconds', 'search'); - if (!$cli) print ''; - unset($GLOBALS['search_script_start_time']); - } else { - $GLOBALS['search_script_start_time'] = microtime(true); - } -} - -/** -* print and exit (for debugging) -* @param str a variable to explore -* @return void -*/ -function search_pexit($str = "") { - if (is_array($str) or is_object($str)) { - print_r($str); - } else if ($str) { - print $str."
"; - } - exit(0); -} - -function search_updatedcallback($name) { - global $CFG, $DB; - // set block to hidden when global search is disabled. - if ($CFG->enableglobalsearch != 1) { - $DB->set_field('block', 'visible', 0, array('name'=>'search')); // Hide block - } -} - -?> diff --git a/search/query.php b/search/query.php deleted file mode 100644 index 2af22bd2b12..00000000000 --- a/search/query.php +++ /dev/null @@ -1,414 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * - * The query page - accepts a user-entered query string and returns results. - * - * Queries are boolean-aware, e.g.: - * - * '+' term required - * '-' term must not be present - * '' (no modifier) term's presence increases rank, but isn't required - * 'field:' search this field - * - * Examples: - * - * 'earthquake +author:michael' - * Searches for documents written by 'michael' that contain 'earthquake' - * - * 'earthquake +doctype:wiki' - * Search all wiki pages for 'earthquake' - * - * '+author:helen +author:foster' - * All articles written by Helen Foster - * - */ - - /** - * includes and requires - */ - require_once('../config.php'); - require_once($CFG->dirroot.'/search/lib.php'); - - $block_instanceid = required_param('block_instanceid', PARAM_INT);// Block Instance ID - - if ($CFG->forcelogin) { - require_login(); - } - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - //Check user's permissions against the block instance from which the user came - if (empty($block_instanceid)) { - print_error('searchnotpermitted', 'search'); - } - if (!$DB->record_exists('block_instances', array('id' => $block_instanceid, 'blockname' => 'search'))) { - print_error('searchnotpermitted', 'search'); - } - $contextblock = get_context_instance(CONTEXT_BLOCK, $block_instanceid); - require_capability('moodle/block:view', $contextblock); - - $adv = new stdClass(); - -/// check for php5, but don't die yet (see line 52) - - require_once($CFG->dirroot.'/search/querylib.php'); - - $page_number = optional_param('page', -1, PARAM_INT); - $pages = ($page_number == -1) ? false : true; - $advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false; - $query_string = optional_param('query_string', '', PARAM_CLEAN); - - $url = new moodle_url('/search/query.php'); - if ($page_number !== -1) { - $url->param('page', $page_number); - } - if ($advanced) { - $url->param('a', '1'); - } - $url->param('block_instanceid', $block_instanceid); - $PAGE->set_url($url); - -/// discard harmfull searches - - if (!isset($CFG->block_search_utf8dir)){ - set_config('block_search_utf8dir', 1); - } - -/// discard harmfull searches - - if (preg_match("/^[\*\?]+$/", $query_string)){ - $query_string = ''; - $error = get_string('fullwildcardquery','search'); - } - - - if ($pages && isset($_SESSION['search_advanced_query'])) { - // if both are set, then we are busy browsing through the result pages of an advanced query - $adv = unserialize($_SESSION['search_advanced_query']); - } elseif ($advanced) { - // otherwise we are dealing with a new advanced query - unset($_SESSION['search_advanced_query']); - session_unregister('search_advanced_query'); - - // chars to strip from strings (whitespace) - $chars = " \t\n\r\0\x0B,-+"; - - // retrieve advanced query variables - $adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars); - $adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars); - $adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars); - $adv->module = optional_param('module', '', PARAM_CLEAN); - $adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars); - $adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars); - } - - if ($advanced) { - //parse the advanced variables into a query string - //TODO: move out to external query class (QueryParse?) - - $query_string = ''; - - // get all available module types adding third party modules - $module_types = array_merge(array('all'), array_values(search_get_document_types())); - $module_types = array_merge($module_types, array_values(search_get_document_types('X_SEARCH_TYPE'))); - $adv->module = in_array($adv->module, $module_types) ? $adv->module : 'all'; - - // convert '1 2' into '+1 +2' for required words field - if (strlen(trim($adv->mustappear)) > 0) { - $query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear)); - } - - // convert '1 2' into '-1 -2' for not wanted words field - if (strlen(trim($adv->notappear)) > 0) { - $query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear)); - } - - // this field is left untouched, apart from whitespace being stripped - if (strlen(trim($adv->canappear)) > 0) { - $query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear)); - } - - // add module restriction - $doctypestr = 'doctype'; - $titlestr = 'title'; - $authorstr = 'author'; - if ($adv->module != 'all') { - $query_string .= " +{$doctypestr}:".$adv->module; - } - - // create title search string - if (strlen(trim($adv->title)) > 0) { - $query_string .= " +{$titlestr}:".implode(" +{$titlestr}:", preg_split("/[\s,;]+/", $adv->title)); - } - - // create author search string - if (strlen(trim($adv->author)) > 0) { - $query_string .= " +{$authorstr}:".implode(" +{$authorstr}:", preg_split("/[\s,;]+/", $adv->author)); - } - - // save our options if the query is valid - if (!empty($query_string)) { - $_SESSION['search_advanced_query'] = serialize($adv); - } - } - - // normalise page number - if ($page_number < 1) { - $page_number = 1; - } - - //run the query against the index ensuring internal coding works in UTF-8 - Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive()); - $sq = new SearchQuery($query_string, $page_number, 10, false); - - $site = get_site(); - - $strsearch = get_string('search', 'search'); - $strquery = get_string('enteryoursearchquery', 'search'); - - // print the header - $site = get_site(); - $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); - $PAGE->navbar->add($strsearch, new moodle_url('/search/query.php?block_instanceid=' . $block_instanceid)); - $PAGE->navbar->add($strquery, new moodle_url('/search/stats.php?block_instanceid=' . $block_instanceid)); - $PAGE->set_title($strsearch); - $PAGE->set_heading($site->fullname); - echo $OUTPUT->header(); - - if (!empty($error)){ - notice ($error); - } - - echo $OUTPUT->box_start(); - echo $OUTPUT->heading($strquery); - - echo $OUTPUT->box_start(); - - $vars = get_object_vars($adv); - - if (isset($vars)) { - foreach ($vars as $key => $value) { - // htmlentities breaks non-ascii chars ?? - $adv->key = $value; - //$adv->$key = htmlentities($value); - } - } - ?> -
- -   -   -   - | - - box_start(); - ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
:
:
:
: - -
:
:

- - - - - -
| 
-
- box_end(); - } - ?> -
-
- -
- is_valid_index()) { - //use cached variable to show up-to-date index size (takes deletions into account) - print $CFG->search_index_size; - } - else { - print "0"; - } - - print ' '; - print_string('documents', 'search'); - print '.'; - - if (!$sq->is_valid_index() and has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print '

' . get_string('noindexmessage', 'search') . '' . get_string('createanindex', 'search')."

\n"; - } - - ?> -
- box_end(); - -/// prints all the results in a box - - if ($sq->is_valid()) { - echo $OUTPUT->box_start(); - - search_stopwatch(); - $hit_count = $sq->count(); - - print "
"; - - print $hit_count.' '.get_string('resultsreturnedfor', 'search') . " '".s($query_string)."'."; - print "
"; - - if ($hit_count > 0) { - $page_links = $sq->page_numbers(); - $hits = $sq->results(); - - if ($advanced) { - // if in advanced mode, search options are saved in the session, so - // we can remove the query string var from the page links, and replace - // it with a=1 (Advanced = on) instead - $page_links = preg_replace("/query_string=[^&]+/", 'a=1', $page_links); - } - - print "
    "; - - $typestr = get_string('type', 'search'); - $scorestr = get_string('score', 'search'); - $authorstr = get_string('author', 'search'); - - $searchables = search_collect_searchables(false, false); - - //build a list of distinct user objects needed for results listing. - $hitusers = array(); - foreach ($hits as $listing) { - if ($listing->doctype == 'user' and !isset($hitusers[$listing->userid])) { - $hitusers[$listing->userid] = $DB->get_record('user', array('id' => $listing->userid)); - } - } - - foreach ($hits as $listing) { - - if ($listing->doctype == 'user') { // A special handle for users - $icon = $OUTPUT->user_picture($hitusers[$listing->userid]); - } else { - $iconpath = $OUTPUT->pix_url('icon', $listing->doctype); - $icon = "\"\"/"; - } - $coursename = $DB->get_field('course', 'fullname', array('id' => $listing->courseid)); - $courseword = mb_convert_case(get_string('course', 'moodle'), MB_CASE_LOWER, 'UTF-8'); - $course = ($listing->doctype != 'user') ? ' ('.$courseword.': \''.$coursename.'\')' : '' ; - - $title_post_processing_function = $listing->doctype.'_link_post_processing'; - $searchable_instance = $searchables[$listing->doctype]; - if ($searchable_instance->location == 'internal'){ - require_once "{$CFG->dirroot}/search/documents/{$listing->doctype}_document.php"; - } else { - require_once "{$CFG->dirroot}/{$searchable_instance->location}/{$listing->doctype}/search_document.php"; - } - if (function_exists($title_post_processing_function)) { - $listing->title = $title_post_processing_function($listing->title); - } - - echo "
  1. url) - ."'>$icon $listing->title $course
    \n"; - echo "{$typestr}: " . $listing->doctype . ", {$scorestr}: " . round($listing->score, 3); - if (!empty($listing->author) && !is_numeric($listing->author)){ - echo ", {$authorstr}: ".$listing->author."\n" - ."
  2. \n"; - } - } - echo "
"; - echo $page_links; - } - echo $OUTPUT->box_end(); - ?> -
- . -
- - box_end(); - echo $OUTPUT->footer(); -?> diff --git a/search/querylib.php b/search/querylib.php deleted file mode 100644 index 6f91f92dd4b..00000000000 --- a/search/querylib.php +++ /dev/null @@ -1,495 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -*/ - -/** -* includes and requires -*/ -require_once($CFG->dirroot.'/search/Zend/Search/Lucene.php'); - -define('DEFAULT_POPUP_SETTINGS', "\"menubar=0,location=0,scrollbars,resizable,width=600,height=450\""); - -/** -* a class that represents a single result record of the search engine -*/ -class SearchResult { -public $url, - $title, - $doctype, - $author, - $score, - $number, - $courseid; -} - - -/** -* split this into Cache class and extend to SearchCache? -*/ -class SearchCache { -private $mode, - $valid; - - // foresees other caching locations - public function __construct($mode = 'session') { - $accepted_modes = array('session'); - - if (in_array($mode, $accepted_modes)) { - $this->mode = $mode; - } else { - $this->mode = 'session'; - } //else - - $this->valid = true; - } - - /** - * returns the search cache status - * @return boolean - */ - public function can_cache() { - return $this->valid; - } - - /** - * - * - */ - public function cache($id = false, $object = false) { - //see if there was a previous query - $last_term = $this->fetch('search_last_term'); - - //if this query is different from the last, clear out the last one - if ($id != false && $last_term != $id) { - $this->clear($last_term); - } - - //store the new query if id and object are passed in - if ($object && $id) { - $this->store('search_last_term', $id); - $this->store($id, $object); - return true; - //otherwise return the stored results - } else if ($id && $this->exists($id)) { - return $this->fetch($id); - } - } - - /** - * do key exist in cache ? - * @param id the object key - * @return boolean - */ - private function exists($id) { - switch ($this->mode) { - case 'session' : - return isset($_SESSION[$id]); - } - } - - /** - * clears a cached object in cache - * @param the object key to clear - * @return void - */ - private function clear($id) { - switch ($this->mode) { - case 'session' : - unset($_SESSION[$id]); - session_unregister($id); - return; - } - } - - /** - * fetches a cached object - * @param id the object identifier - * @return the object cached - */ - private function fetch($id) { - switch ($this->mode) { - case 'session' : - return ($this->exists($id)) ? unserialize($_SESSION[$id]) : false; - } - } - - /** - * put an object in cache - * @param id the key for that object - * @param object the object to cache as a serialized value - * @return void - */ - private function store($id, $object) { - switch ($this->mode) { - case 'session' : - $_SESSION[$id] = serialize($object); - return; - } - } -} - -/** -* Represents a single query with results -* -*/ -class SearchQuery { - private $index, - $term, - $pagenumber, - $cache, - $validquery, - $validindex, - $results, - $results_per_page, - $total_results; - - /** - * constructor records query parameters - * - */ - public function __construct($term = '', $page = 1, $results_per_page = 10, $cache = false) { - global $CFG; - - $this->term = $term; - $this->pagenumber = $page; - $this->cache = $cache; - $this->validquery = true; - $this->validindex = true; - $this->results_per_page = $results_per_page; - - $index_path = SEARCH_INDEX_PATH; - - try { - $this->index = new Zend_Search_Lucene($index_path, false); - } catch(Exception $e) { - $this->validindex = false; - return; - } - - if (empty($this->term)) { - $this->validquery = false; - } else { - $this->set_query($this->term); - } - } - - /** - * determines state of query object depending on query entry and - * tries to lauch search if all is OK - * @return void (this is only a state changing trigger). - */ - public function set_query($term = '') { - if (!empty($term)) { - $this->term = $term; - } - - if (empty($this->term)) { - $this->validquery = false; - } else { - $this->validquery = true; - } - - if ($this->validquery and $this->validindex) { - $this->results = $this->get_results(); - } else { - $this->results = array(); - } - } - - /** - * accessor to the result table. - * @return an array of result records - */ - public function results() { - return $this->results; - } - - /** - * do the effective collection of results - * @param boolean $all - * @uses USER - */ - private function process_results($all=false) { - global $USER; - - // unneeded since changing the default Zend Lexer - // $term = mb_convert_case($this->term, MB_CASE_LOWER, 'UTF-8'); - $term = $this->term; - $page = optional_param('page', 1, PARAM_INT); - - //experimental - return more results - // $strip_arr = array('author:', 'title:', '+', '-', 'doctype:'); - // $stripped_term = str_replace($strip_arr, '', $term); - - // $search_string = $term." title:".$stripped_term." author:".$stripped_term; - $search_string = $term; - $hits = $this->index->find($search_string); - //-- - - $hitcount = count($hits); - $this->total_results = $hitcount; - - if ($hitcount == 0) return array(); - - $resultdoc = new SearchResult(); - $resultdocs = array(); - $searchables = search_collect_searchables(false, false); - - $realindex = 0; - - /** - if (!$all) { - if ($finalresults < $this->results_per_page) { - $this->pagenumber = 1; - } elseif ($this->pagenumber > $totalpages) { - $this->pagenumber = $totalpages; - } - - $start = ($this->pagenumber - 1) * $this->results_per_page; - $end = $start + $this->results_per_page; - - if ($end > $finalresults) { - $end = $finalresults; - } - } else { - $start = 0; - $end = $finalresults; - } */ - - for ($i = 0; $i < min($hitcount, ($page) * $this->results_per_page); $i++) { - $hit = $hits[$i]; - - //check permissions on each result - if ($this->can_display($USER, $hit->docid, $hit->doctype, $hit->course_id, $hit->group_id, $hit->path, $hit->itemtype, $hit->context_id, $searchables )) { - if ($i >= ($page - 1) * $this->results_per_page){ - $resultdoc->number = $realindex; - $resultdoc->url = $hit->url; - $resultdoc->title = $hit->title; - $resultdoc->score = $hit->score; - $resultdoc->doctype = $hit->doctype; - $resultdoc->author = $hit->author; - $resultdoc->courseid = $hit->course_id; - $resultdoc->userid = $hit->user_id; - - //and store it - $resultdocs[] = clone($resultdoc); - } - $realindex++; - } else { - // lowers total_results one unit - $this->total_results--; - } - } - - $totalpages = ceil($this->total_results/$this->results_per_page); - - - return $resultdocs; - } - - /** - * get results of a search query using a caching strategy if available - * @return the result documents as an array of search objects - */ - private function get_results() { - $cache = new SearchCache(); - - if ($this->cache && $cache->can_cache()) { - if (!($resultdocs = $cache->cache($this->term))) { - $resultdocs = $this->process_results(); - //cache the results so we don't have to compute this on every page-load - $cache->cache($this->term, $resultdocs); - //print "Using new results."; - } else { - //There was something in the cache, so we're using that to save time - //print "Using cached results."; - } - } else { - //no caching :( - // print "Caching disabled!"; - $resultdocs = $this->process_results(); - } - return $resultdocs; - } - - /** - * constructs the results paging links on results. - * @return string the results paging links - */ - public function page_numbers() { - $pages = $this->total_pages(); - $query = htmlentities($this->term,ENT_NOQUOTES,'utf-8'); - $page = $this->pagenumber; - $next = get_string('next', 'search'); - $back = get_string('back', 'search'); - - $ret = ""; - - //shorten really long page lists, to stop table distorting width-ways - if (strlen($ret) > 70) { - $start = 4; - $end = $page - 5; - $ret = preg_replace("/$start<\/a>.*?$end<\/a>/", '...', $ret); - - $start = $page + 5; - $end = $pages - 3; - $ret = preg_replace("/$start<\/a>.*?$end<\/a>/", '...', $ret); - } - - return $ret; - } - - /** - * can the user see this result ? - * @param user a reference upon the user to be checked for access - * @param this_id the item identifier - * @param doctype the search document type. MAtches the module or block or - * extra search source definition - * @param course_id the course reference of the searched result - * @param group_id the group identity attached to the found resource - * @param path the path that routes to the local lib.php of the searched - * surrounding object fot that document - * @param item_type a subclassing information for complex module data models - * @uses CFG - * // TODO reorder parameters more consistently - */ - private function can_display(&$user, $this_id, $doctype, $course_id, $group_id, $path, $item_type, $context_id, &$searchables) { - global $CFG, $DB; - - /** - * course related checks - */ - // admins can see everything, anyway. - if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))){ - return true; - } - - // first check course compatibility against user : enrolled users to that course can see. - $myCourses = enrol_get_users_courses($user->id, true); - $unenroled = !in_array($course_id, array_keys($myCourses)); - - // if guests are allowed, logged guest can see - $isallowedguest = false; //TODO: this will be harder to do now because we do not have guest field in course table any more - - if ($unenroled && !$isallowedguest){ - return false; - } - - // if user is enrolled or is allowed user and course is hidden, can he see it ? - $visibility = $DB->get_field('course', 'visible', array('id' => $course_id)); - if ($visibility <= 0){ - if (!has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course_id))){ - return false; - } - } - - /** - * prerecorded capabilities - */ - // get context caching information and tries to discard unwanted records here - - - /** - * final checks - */ - // then give back indexing data to the module for local check - $searchable_instance = $searchables[$doctype]; - if ($searchable_instance->location == 'internal'){ - include_once "{$CFG->dirroot}/search/documents/{$doctype}_document.php"; - } else { - include_once "{$CFG->dirroot}/{$searchable_instance->location}/{$doctype}/search_document.php"; - } - $access_check_function = "{$doctype}_check_text_access"; - - if (function_exists($access_check_function)){ - $modulecheck = $access_check_function($path, $item_type, $this_id, $user, $group_id, $context_id); - // echo "module said $modulecheck for item $doctype/$item_type/$this_id"; - return($modulecheck); - } - - return true; - } - - /** - * - */ - public function count() { - return $this->total_results; - } //count - - /** - * - */ - public function is_valid() { - return ($this->validquery and $this->validindex); - } - - /** - * - */ - public function is_valid_query() { - return $this->validquery; - } - - /** - * - */ - public function is_valid_index() { - return $this->validindex; - } - - /** - * - */ - public function total_pages() { - return ceil($this->count()/$this->results_per_page); - } - - /** - * - */ - public function get_pagenumber() { - return $this->pagenumber; - } - - /** - * - */ - public function get_results_per_page() { - return $this->results_per_page; - } -} -?> \ No newline at end of file diff --git a/search/searchtypes.php b/search/searchtypes.php deleted file mode 100644 index 029126269e6..00000000000 --- a/search/searchtypes.php +++ /dev/null @@ -1,36 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* Searcheable types -* to disable a type, just comment the two declaration lines for that type -* -*/ - -//document types that can be searched -//define('SEARCH_TYPE_NONE', 'none'); -define('SEARCH_TYPE_WIKI', 'wiki'); -define('SEARCH_TYPE_FORUM', 'forum'); -define('SEARCH_TYPE_GLOSSARY', 'glossary'); -define('SEARCH_TYPE_RESOURCE', 'resource'); -define('SEARCH_TYPE_DATA', 'data'); -define('SEARCH_TYPE_CHAT', 'chat'); -define('SEARCH_TYPE_LESSON', 'lesson'); -define('SEARCH_TYPE_ASSIGNMENT', 'assignment'); -define('SEARCH_TYPE_LABEL', 'label'); - -define('SEARCH_EXTRAS', 'user'); -define('SEARCH_TYPE_USER', 'user'); -define('PATH_FOR_SEARCH_TYPE_USER', 'user'); -define('TYPE_FOR_SEARCH_TYPE_USER', 'core'); - -?> \ No newline at end of file diff --git a/search/stats.php b/search/stats.php deleted file mode 100644 index 8ecb097f6f0..00000000000 --- a/search/stats.php +++ /dev/null @@ -1,185 +0,0 @@ - 1.8 -* @date 2008/03/31 -* @version prepared for 2.0 -* @license http://www.gnu.org/copyleft/gpl.html GNU Public License -* -* Prints some basic statistics about the current index. -* Does some diagnostics if you are logged in as an administrator. -* -*/ - -/** -* includes and requires -*/ -require_once('../config.php'); -require_once($CFG->dirroot.'/search/lib.php'); - -$block_instanceid = required_param('block_instanceid', PARAM_INT);// Block Instance ID - -/// checks global search is enabled - - if ($CFG->forcelogin) { - require_login(); - } - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - //Check user's permissions against the block instance from which the user came - if (empty($block_instanceid)) { - print_error('searchnotpermitted', 'search'); - } - if (!$DB->record_exists('block_instances', array('id' => $block_instanceid, 'blockname' => 'search'))) { - print_error('searchnotpermitted', 'search'); - } - $contextblock = get_context_instance(CONTEXT_BLOCK, $block_instanceid); - require_capability('moodle/block:view', $contextblock); - -/// check for php5, but don't die yet - - require_once($CFG->dirroot.'/search/indexlib.php'); - - $indexinfo = new IndexInfo(); - - $site = get_site(); - - $strsearch = get_string('search', 'search'); - $strquery = get_string('statistics', 'search'); - - $site = get_site(); - - $url = new moodle_url('/search/stats.php'); - $url->param('block_instanceid', $block_instanceid); - $PAGE->set_url($url); - - $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); - $PAGE->navbar->add($strsearch, new moodle_url('/search/query.php?block_instanceid=' . $block_instanceid)); - $PAGE->navbar->add($strquery, new moodle_url('/search/stats.php?block_instanceid=' . $block_instanceid)); - $PAGE->set_title($strsearch); - $PAGE->set_heading($site->fullname); - echo $OUTPUT->header(); - -/// keep things pretty, even if php5 isn't available - - echo $OUTPUT->box_start(); - echo $OUTPUT->heading($strquery); - - echo $OUTPUT->box_start(); - - $databasestr = get_string('database', 'search'); - $documentsinindexstr = get_string('documentsinindex', 'search'); - $deletionsinindexstr = get_string('deletionsinindex', 'search'); - $documentsindatabasestr = get_string('documentsindatabase', 'search'); - $databasestatestr = get_string('databasestate', 'search'); - -/// this table is only for admins, shows index directory size and location - - if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - $datadirectorystr = get_string('datadirectory', 'search'); - $inindexdirectorystr = get_string('filesinindexdirectory', 'search'); - $totalsizestr = get_string('totalsize', 'search'); - $errorsstr = get_string('errors', 'search'); - $solutionsstr = get_string('solutions', 'search'); - $checkdirstr = get_string('checkdir', 'search'); - $checkdbstr = get_string('checkdb', 'search'); - $checkdiradvicestr = get_string('checkdiradvice', 'search'); - $checkdbadvicestr = get_string('checkdbadvice', 'search'); - $runindexerteststr = get_string('runindexertest', 'search'); - $runindexerstr = get_string('runindexer', 'search'); - - $admin_table = new html_table(); - $admin_table->tablealign = 'center'; - $admin_table->align = array ('right', 'left'); - $admin_table->wrap = array ('nowrap', 'nowrap'); - $admin_table->cellpadding = 5; - $admin_table->cellspacing = 0; - $admin_table->width = '500'; - - $admin_table->data[] = array("{$datadirectorystr}", ''.$indexinfo->path.''); - $admin_table->data[] = array($inindexdirectorystr, $indexinfo->filecount); - $admin_table->data[] = array($totalsizestr, $indexinfo->size); - - if ($indexinfo->time > 0) { - $admin_table->data[] = array(get_string('createdon', 'search'), date('r', $indexinfo->time)); - } - else { - $admin_table->data[] = array(get_string('createdon', 'search'), '-'); - } - - if (!$indexinfo->valid($errors)) { - $admin_table->data[] = array("{$errorsstr}", ' '); - foreach ($errors as $key => $value) { - $admin_table->data[] = array($key.' ... ', $value); - } - } - - echo html_writer::table($admin_table); - $spacer = array('height'=>20, 'br'=>true); - echo $OUTPUT->spacer($spacer); // should be done with CSS instead - echo $OUTPUT->heading($solutionsstr); - - unset($admin_table->data); - if (isset($errors['dir'])) { - $admin_table->data[] = array($checkdirstr, $checkdiradvicestr); - } - if (isset($errors['db'])) { - $admin_table->data[] = array($checkdbstr, $checkdbadvicestr); - } - - $admin_table->data[] = array($runindexerteststr, 'tests/index.php'); - $admin_table->data[] = array($runindexerstr, 'indexersplash.php'); - - echo html_writer::table($admin_table); - echo $OUTPUT->spacer($spacer) . '
'; - } - -/// this is the standard summary table for normal users, shows document counts - - $table = new html_table(); - $table->tablealign = 'center'; - $table->align = array ('right', 'left'); - $table->wrap = array ('nowrap', 'nowrap'); - $table->cellpadding = 5; - $table->cellspacing = 0; - $table->width = '500'; - - $table->data[] = array("{$databasestr}", "{$CFG->prefix}".SEARCH_DATABASE_TABLE.''); - -/// add extra fields if we're admin - - if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - //don't want to confuse users if the two totals don't match (hint: they should) - $table->data[] = array($documentsinindexstr, $indexinfo->indexcount); - - //*cough* they should match if deletions were actually removed from the index, - //as it turns out, they're only marked as deleted and not returned in search results - $table->data[] = array($deletionsinindexstr, (int)$indexinfo->indexcount - (int)$indexinfo->dbcount); - } - - $table->data[] = array($documentsindatabasestr, $indexinfo->dbcount); - - foreach($indexinfo->types as $type) { - if ($type->type == 'mod'){ - $table->data[] = array(get_string('documentsfor', 'search') . " '".get_string('modulenameplural', $type->name)."'", $type->records); - } else if ($type->type == 'block') { - $table->data[] = array(get_string('documentsfor', 'search') . " '".get_string('pluginname', $type->name)."'", $type->records); - } else { - $table->data[] = array(get_string('documentsfor', 'search') . " '".get_string($type->name)."'", $type->records); - } - - } - - echo $OUTPUT->heading($databasestatestr); - echo html_writer::table($table); - - echo $OUTPUT->box_end(); - echo $OUTPUT->box_end(); - echo $OUTPUT->footer(); -?> diff --git a/search/tests/index.php b/search/tests/index.php deleted file mode 100644 index 594fd6330b3..00000000000 --- a/search/tests/index.php +++ /dev/null @@ -1,152 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * @version Moodle 2.0 - **/ - - define('NO_OUTPUT_BUFFERING', true); - - require_once('../../config.php'); - - @set_time_limit(0); -/// makes inclusions of the Zend Engine more reliable - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - - require_once($CFG->dirroot.'/search/lib.php'); - - require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('onlyadmins', 'error', get_login_url()); - } - - mtrace('
Server Time: '.date('r',time()));
-    mtrace("Testing global search capabilities:\n");
-
-    //fix paths for testing
-    set_include_path(get_include_path().":../");
-    require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
-
-    mtrace("Checking activity modules:\n");
-
-    //the presence of the required search functions -
-    // * mod_iterator
-    // * mod_get_content_for_index
-    //are the sole basis for including a module in the index at the moment.
-
-/// get all installed modules
-    if ($mods = $DB->get_records('modules', null, 'name', 'id, name')){
-
-        $searchabletypes = array_values(search_get_document_types());
-
-        foreach($mods as $mod){
-            if (in_array($mod->name, $searchabletypes)){
-                $mod->location = 'internal';
-                $searchables[] = $mod;
-            } else {
-                $documentfile = $CFG->dirroot."/mod/{$mod->name}/search_document.php";
-                $mod->location = 'mod';
-                if (file_exists($documentfile)){
-                    $searchables[] = $mod;
-                }
-            }
-        }
-        mtrace(count($searchables).' modules to search in / '.count($mods).' modules found.');
-    }
-
-/// collects blocks as indexable information may be found in blocks either
-    if ($blocks = $DB->get_records('block', null, 'name', 'id,name')) {
-        $blocks_searchables = array();
-        // prepend the "block_" prefix to discriminate document type plugins
-        foreach($blocks as $block){
-            $block->dirname = $block->name;
-            $block->name = 'block_'.$block->name;
-            if (in_array('SEARCH_TYPE_'.strtoupper($block->name), $searchabletypes)){
-                $mod->location = 'internal';
-                $blocks_searchables[] = $block;
-            } else {
-                $documentfile = $CFG->dirroot."/blocks/{$block->dirname}/search_document.php";
-                if (file_exists($documentfile)){
-                    $mod->location = 'blocks';
-                    $blocks_searchables[] = $block;
-                }
-            }
-        }
-        mtrace(count($blocks_searchables).' blocks to search in / '.count($blocks).' blocks found.');
-        $searchables = array_merge($searchables, $blocks_searchables);
-    }
-
-/// add virtual modules onto the back of the array
-
-    $additional = search_get_additional_modules();
-    mtrace(count($additional).' additional to search in.');
-    $searchables = array_merge($searchables, $additional);
-
-    foreach ($searchables as $mod) {
-
-        $key = 'search_in_'.$mod->name;
-        if (isset($CFG->$key) && !$CFG->$key) {
-            mtrace("module $key has been administratively disabled. Skipping...\n");
-            continue;
-        }
-
-        if ($mod->location == 'internal'){
-            $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
-        } else {
-            $class_file = $CFG->dirroot.'/'.$mod->location.'/'.$mod->name.'/search_document.php';
-        }
-
-        if (file_exists($class_file)) {
-            include_once($class_file);
-
-            if ($mod->location != 'internal' && !defined('X_SEARCH_TYPE_'.strtoupper($mod->name))) {
-                mtrace("ERROR: Constant 'X_SEARCH_TYPE_".strtoupper($mod->name)."' is not defined in search/searchtypes.php or in module");
-                continue;
-            }
-
-            $iter_function = $mod->name.'_iterator';
-            $index_function = $mod->name.'_get_content_for_index';
-
-            if (function_exists($index_function) && function_exists($iter_function)) {
-                $entries = $iter_function();
-                if (!empty($entries)) {
-                    $documents = $index_function(array_pop($entries));
-
-                    if (is_array($documents)) {
-                        mtrace("Success: '$mod->name' module seems to be ready for indexing.");
-                    } else {
-                        mtrace("ERROR: $index_function() doesn't seem to be returning an array.");
-                    }
-                } else {
-                    mtrace("Success : '$mod->name' has nothing to index.");
-                }
-            } else {
-                mtrace("ERROR: $iter_function() and/or $index_function() does not exist in $class_file");
-            }
-        } else {
-            mtrace("Notice: $class_file does not exist, this module will not be indexed.");
-        }
-    }
-
-    mtrace("\nFinished checking for searcheable items.");
-
-    mtrace("
Back to query page or Start indexing."); - mtrace('
'); -?> \ No newline at end of file diff --git a/search/update.php b/search/update.php deleted file mode 100644 index eb75f555ad6..00000000000 --- a/search/update.php +++ /dev/null @@ -1,200 +0,0 @@ - 1.8 - * @date 2008/03/31 - * @version prepared for 2.0 - * @license http://www.gnu.org/copyleft/gpl.html GNU Public License - * - * Index asynchronous updator - * - * Major chages in this review is passing the xxxx_db_names return to - * multiple arity to handle multiple document types modules - */ - - /** - * includes and requires - */ - require_once('../config.php'); - - if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); /// It must be included from the cron script - } - - global $DB; - -/// makes inclusions of the Zend Engine more reliable - ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path')); - - require_once($CFG->dirroot.'/search/lib.php'); - require_once($CFG->dirroot.'/search/indexlib.php'); - -/// checks global search activation - - // require_login(); - - if (empty($CFG->enableglobalsearch)) { - print_error('globalsearchdisabled', 'search'); - } - - /* - Obsolete with the MOODLE INTERNAL check - if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) { - print_error('beadmin', 'search', get_login_url()); - } - */ - - try { - $index = new Zend_Search_Lucene(SEARCH_INDEX_PATH); - } catch(LuceneException $e) { - mtrace("Could not construct a valid index. Maybe the first indexation was never made, or files might be corrupted. Run complete indexation again."); - return; - } - $dbcontrol = new IndexDBControl(); - $update_count = 0; - $mainstartupdatedate = time(); - -/// indexing changed resources - - mtrace("Starting index update (updates)...\n"); - - if ($mods = search_collect_searchables(false, true)){ - - foreach ($mods as $mod) { - $indexdate = 0; - $indexdatestring = 'search_indexer_update_date_'.$mod->name; - $startupdatedate = time(); - if (isset($CFG->$indexdatestring)) { - $indexdate = $CFG->$indexdatestring; - } - - $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php'; - $get_document_function = $mod->name.'_single_document'; - $delete_function = $mod->name.'_delete'; - $db_names_function = $mod->name.'_db_names'; - $updates = array(); - - if (file_exists($class_file)) { - require_once($class_file); - - //if both required functions exist - if (function_exists($delete_function) and function_exists($db_names_function) and function_exists($get_document_function)) { - mtrace("Checking $mod->name module for updates."); - $valuesArray = $db_names_function(); - if ($valuesArray){ - foreach($valuesArray as $values){ - $where = (isset($values[5]) and $values[5]!='') ? 'AND ('.$values[5].')' : ''; - $itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " AND itemtype = '{$values[4]}' " : '' ; - - //TODO: check 'in' syntax with other RDBMS' (add and update.php as well) - $table = SEARCH_DATABASE_TABLE; - $query = " - SELECT - docid, - itemtype - FROM - {{$table}} - WHERE - doctype = ? - $itemtypes - "; - $docIds = $DB->get_records_sql_menu($query, array($mod->name)); - if (!empty($docIds)){ - list($usql, $params) = $DB->get_in_or_equal(array_keys($docIds)); - $query = " - SELECT - id, - $values[0] as docid - FROM - {{$values[1]}} - WHERE - $values[3] > $indexdate AND - id $usql - $where - "; - $records = $DB->get_records_sql($query, $params); - } else { - $records = array(); - } - - foreach($records as $record) { - $updates[] = $delete_function($record->docid, $docIds[$record->docid]); - } - } - - foreach ($updates as $update) { - ++$update_count; - $added_doc = false; - - //get old document for deletion later - // change from default text only search to include numerals for this search. - Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive()); - $doc = $index->find("+docid:{$update->id} +doctype:{$mod->name} +itemtype:{$update->itemtype}"); - - try { - //add new modified document back into index - $add = $get_document_function($update->id, $update->itemtype); - - //object to insert into db - $dbid = $dbcontrol->addDocument($add); - - //synchronise db with index - $add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid)); - mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)"); - $index->addDocument($add); - $added_doc = true; - } - - catch (dml_write_exception $e) { - mtrace(" Add: FAILED adding '$add->title' , moodle instance id = $add->docid , Error: $e->error "); - mtrace($e); - $added_doc = false; - } - - if ($added_doc) { - // ok we've successfully added the new document so far - // delete single previous old document - try { - //get the record, should only be one - foreach ($doc as $thisdoc) { - mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)"); - $dbcontrol->delDocument($thisdoc); - $index->delete($thisdoc->id); - } - } - - catch (dml_write_exception $e) { - mtrace(" Delete: FAILED deleting '$thisdoc->title' , moodle instance id = $thisdoc->docid , Error: $e->error "); - mtrace($e); - } - } - } - } - else{ - mtrace("No types to update.\n"); - } - //commit changes - $index->commit(); - - //update index date - set_config($indexdatestring, $startupdatedate); - - mtrace("Finished $mod->name.\n"); - } - } - } - } - - //commit changes - $index->commit(); - - //update index date - set_config('search_indexer_update_date', $mainstartupdatedate); - - mtrace("Finished $update_count updates"); - -?> \ No newline at end of file diff --git a/version.php b/version.php index 6bcc026af5b..a8ec5fc4c2b 100644 --- a/version.php +++ b/version.php @@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2011102700.00; // YYYYMMDD = weekly release date of this DEV branch +$version = 2011102700.01; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes