- <?php
-
- * @file
- * Integration with the Apache Solr search application.
- */
-
- define('APACHESOLR_READ_WRITE', 0);
- define('APACHESOLR_READ_ONLY', 1);
-
- include_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.d6.inc');
-
- if (arg(0) == 'admin' && (arg(1) == 'settings' || arg(1) == 'logs') && arg(2) == 'apachesolr') {
- include_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.admin.inc');
- }
-
- * Implementation of hook_menu().
- */
- function apachesolr_menu($may_cache) {
- $items = array();
- if ($may_cache) {
- $items[] = array(
- 'path' => 'admin/settings/apachesolr',
- 'title' => t('Apache Solr'),
- 'description' => t('Administer Apache Solr.'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'apachesolr_settings',
- 'access' => user_access('administer search'),
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/settings',
- 'title' => t('Settings'),
- 'weight' => -10,
- 'access' => user_access('administer search'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/enabled-filters',
- 'title' => t('Enabled filters'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'apachesolr_enabled_facets_form',
- 'weight' => -7,
- 'access' => user_access('administer search'),
- 'type' => MENU_LOCAL_TASK,
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/index',
- 'title' => t('Search index'),
- 'callback' => 'apachesolr_index_page',
- 'access' => user_access('administer search'),
- 'weight' => -8,
- 'type' => MENU_LOCAL_TASK,
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/index/clear/confirm',
- 'title' => t('Confirm the re-indexing of all content'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'apachesolr_clear_index_confirm',
- 'access' => user_access('administer search'),
- 'type' => MENU_CALLBACK,
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/index/delete/confirm',
- 'title' => t('Confirm index deletion'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'apachesolr_delete_index_confirm',
- 'access' => user_access('administer search'),
- 'type' => MENU_CALLBACK,
- );
- $items[] = array(
- 'path' => 'admin/logs/apachesolr',
- 'title' => t('Apache Solr search index'),
- 'callback' => 'apachesolr_index_report',
- 'access' => user_access('access site reports'),
- );
- $items[] = array(
- 'path' => 'admin/logs/apachesolr/index',
- 'title' => t('Search index'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/mlt/add_block',
- 'callback' => 'drupal_get_form',
- 'callback arguments' => 'apachesolr_mlt_add_block_form',
- 'access' => user_access('administer search'),
- 'type' => MENU_CALLBACK,
- );
- }
- else {
- if (arg(0) == 'admin' && arg(1) == 'settings' && arg(2) == 'apachesolr' && arg(3) == 'mlt' && arg(4) == 'delete_block' && arg(5)) {
- $items[] = array(
- 'path' => 'admin/settings/apachesolr/mlt/delete_block/'. arg(5),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => array('apachesolr_mlt_delete_block_form', arg(5)),
- 'access' => user_access('administer search'),
- 'type' => MENU_CALLBACK,
- );
- }
- }
- return $items;
- }
-
- * Determines Apache Solr's behavior when searching causes an exception (e.g. Solr isn't available.)
- * Depending on the admin settings, possibly redirect to Drupal's core search.
- *
- * @param $search_name
- * The name of the search implementation.
- *
- * @param $querystring
- * The search query that was issued at the time of failure.
- */
- function apachesolr_failure($search_name, $querystring) {
- $fail_rule = variable_get('apachesolr_failure', 'show_error');
-
- switch ($fail_rule) {
- case 'show_error':
- drupal_set_message(t('The Apache Solr search engine is not available. Please contact your site administrator.'), 'error');
- break;
- case 'show_drupal_results':
- drupal_set_message(t("%search_name is not available. Your search is being redirected.", array('%search_name' => $search_name)));
- drupal_goto('search/node/' . drupal_urlencode($querystring));
- break;
- case 'show_no_results':
- return;
- }
- }
-
- * Like $site_key in _update_refresh() - returns a site-specific hash.
- */
- function apachesolr_site_hash() {
- if (!($hash = variable_get('apachesolr_site_hash', FALSE))) {
- global $base_url;
-
- $hash = substr(base_convert(sha1(uniqid($base_url, TRUE)), 16, 36), 0, 6);
- variable_set('apachesolr_site_hash', $hash);
- }
- return $hash;
- }
-
- * Generate a unique ID for an entity being indexed.
- *
- * @param $id
- * An id number (or string) unique to this site, such as a node ID.
- * @param $entity
- * A string like 'node', 'file', 'user', or some other Drupal object type.
- *
- * @return
- * A string combining the parameters with the site hash.
- */
- function apachesolr_document_id($id, $entity = 'node') {
- return apachesolr_site_hash() . "/$entity/" . $id;
- }
-
- * Implementation of hook_user().
- *
- * Mark nodes as needing re-indexing if the author name changes.
- */
- function apachesolr_user($op, &$edit, &$account) {
- switch ($op) {
- case 'update':
- if (isset($edit['name']) && $account->name != $edit['name']) {
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- db_query("UPDATE {apachesolr_search_node} asn INNER JOIN {node} n ON asn.nid = n.nid SET asn.changed = %d WHERE n.uid = %d", time(), $account->uid);
- break;
- default:
- db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid IN (SELECT nid FROM {node} WHERE uid = %d)", time(), $account->uid);
- break;
- }
- }
- break;
- }
- }
-
- * Implementation of hook_taxonomy().
- *
- * Mark nodes as needing re-indexing if a term name changes.
- */
- function apachesolr_taxonomy($op, $type, $edit) {
- if ($type == 'term' && ($op == 'update')) {
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- db_query("UPDATE {apachesolr_search_node} asn INNER JOIN {term_node} tn ON asn.nid = tn.nid SET asn.changed = %d WHERE tn.tid = %d", time(), $edit['tid']);
- break;
- default:
- db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid IN (SELECT nid FROM {term_node} WHERE tid = %d)", time(), $edit['tid']);
- break;
- }
- }
-
- }
-
- * Implementation of hook_comment().
- *
- * Mark nodes as needing re-indexing if comments are added or changed.
- * Like search_comment().
- */
- function apachesolr_comment($edit, $op) {
- $edit = (array) $edit;
- switch ($op) {
-
- case 'insert':
- case 'update':
- case 'delete':
- case 'publish':
- case 'unpublish':
-
-
- apachesolr_mark_node($edit['nid']);
- break;
- }
- }
-
- * Mark one node as needing re-indexing.
- */
- function apachesolr_mark_node($nid) {
- db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid = %d", time(), $nid);
- }
-
- * Implementation of hook_node_type().
- *
- * Mark nodes as needing re-indexing if a node type name changes.
- */
- function apachesolr_node_type($op, $info) {
- if ($op != 'delete' && !empty($info->old_type) && $info->old_type != $info->type) {
-
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- db_query("UPDATE {apachesolr_search_node} asn INNER JOIN {node} n ON asn.nid = n.nid SET asn.changed = %d WHERE (n.type = '%s' OR n.type = '%s')", time(), $info->old_type, $info->type);
- break;
- default:
- db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE nid IN (SELECT nid FROM {node} WHERE type = '%s' OR type = '%s')", time(), $info->old_type, $info->type);
- break;
- }
- }
- }
-
- * Helper function for modules implementing hook_search's 'status' op.
- */
- function apachesolr_index_status($namespace) {
- list($excluded_types, $args, $join_sql, $exclude_sql) = _apachesolr_exclude_types($namespace);
- $total = db_result(db_query("SELECT COUNT(asn.nid) FROM {apachesolr_search_node} asn ". $join_sql ."WHERE asn.status = 1 " . $exclude_sql, $excluded_types));
- $remaining = db_result(db_query("SELECT COUNT(asn.nid) FROM {apachesolr_search_node} asn ". $join_sql ."WHERE (asn.changed > %d OR (asn.changed = %d AND asn.nid > %d)) AND asn.status = 1 " . $exclude_sql, $args));
- return array('remaining' => $remaining, 'total' => $total);
- }
-
- * Returns last changed and last nid for an indexing namespace.
- */
- function apachesolr_get_last_index($namespace) {
- $stored = variable_get('apachesolr_index_last', array());
- return isset($stored[$namespace]) ? $stored[$namespace] : array('last_change' => 0, 'last_nid' => 0);
- }
-
- * Clear a specific namespace's last changed and nid, or clear all.
- */
- function apachesolr_clear_last_index($namespace = '') {
- if ($namespace) {
- $stored = variable_get('apachesolr_index_last', array());
- unset($stored[$namespace]);
- variable_set('apachesolr_index_last', $stored);
- }
- else {
- variable_del('apachesolr_index_last');
- }
- }
-
- * Truncate and rebuild the apachesolr_search_node table, reset the apachesolr_index_last variable.
- * This is the most complete way to force reindexing, or to build the indexing table for the
- * first time.
- *
- * @param $type
- * A single content type to be reindexed, leaving the others unaltered.
- */
- function apachesolr_rebuild_index_table($type = NULL) {
-
- if (isset($type)) {
- switch ($GLOBALS['db_type']) {
- case 'mysql':
- case 'mysqli':
- db_query("DELETE FROM {apachesolr_search_node} USING {apachesolr_search_node} asn INNER JOIN {node} n ON asn.nid = n.nid WHERE n.type = '%s'", $type);
- break;
- default:
- db_query("DELETE FROM {apachesolr_search_node} WHERE nid IN (SELECT nid FROM {node} WHERE type = '%s')", $type);
- break;
- }
-
- db_query("INSERT INTO {apachesolr_search_node} (nid, status, changed)
- SELECT n.nid, n.status, %d AS changed
- FROM {node} n WHERE n.type = '%s'", time(), $type);
- }
- else {
- db_query("DELETE FROM {apachesolr_search_node}");
-
- if (module_exists('comment')) {
-
- db_query("INSERT INTO {apachesolr_search_node} (nid, status, changed)
- SELECT n.nid, n.status, GREATEST(n.created, n.changed, COALESCE(c.last_comment_timestamp, 0)) AS changed
- FROM {node} n
- LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid");
- }
- else {
- db_query("INSERT INTO {apachesolr_search_node} (nid, status, changed)
- SELECT n.nid, n.status, GREATEST(n.created, n.changed) AS changed
- FROM {node} n");
- }
-
- $time = time();
- db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE changed > %d", $time, $time);
- apachesolr_clear_last_index();
- }
- }
-
- function _apachesolr_exclude_types($namespace) {
- extract(apachesolr_get_last_index($namespace));
- $excluded_types = module_invoke_all('apachesolr_types_exclude', $namespace);
- $args = array($last_change, $last_change, $last_nid);
- $join_sql = '';
- $exclude_sql = '';
- if ($excluded_types) {
- $excluded_types = array_unique($excluded_types);
- $join_sql = "INNER JOIN {node} n ON n.nid = asn.nid ";
- $exclude_sql = "AND n.type NOT IN(". db_placeholders($excluded_types, 'varchar') .") ";
- $args = array_merge($args, $excluded_types);
- }
- return array($excluded_types, $args, $join_sql, $exclude_sql);
- }
-
- * Returns an array of rows from a query based on an indexing namespace.
- */
- function apachesolr_get_nodes_to_index($namespace, $limit) {
- $rows = array();
- if (variable_get('apachesolr_read_only', APACHESOLR_READ_WRITE)) {
- return $rows;
- }
- list($excluded_types, $args, $join_sql, $exclude_sql) = _apachesolr_exclude_types($namespace);
- $result = db_query_range("SELECT asn.nid, asn.changed FROM {apachesolr_search_node} asn ". $join_sql ."WHERE (asn.changed > %d OR (asn.changed = %d AND asn.nid > %d)) AND asn.status = 1 ". $exclude_sql ."ORDER BY asn.changed ASC, asn.nid ASC", $args, 0, $limit);
- while ($row = db_fetch_object($result)) {
- $rows[] = $row;
- }
- return $rows;
- }
-
- * Function to handle the indexing of nodes.
- *
- * The calling function must supply a name space or track/store
- * the timestamp and nid returned.
- * Returns FALSE if no nodes were indexed (none found or error).
- */
- function apachesolr_index_nodes($rows, $namespace = '', $callback = 'apachesolr_add_node_document') {
- if (!$rows) {
-
- return FALSE;
- }
-
- try {
-
- $solr = apachesolr_get_solr();
-
- if (!$solr->ping(variable_get('apachesolr_ping_timeout', 4))) {
- throw new Exception(t('No Solr instance available during indexing.'));
- }
- }
- catch (Exception $e) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), WATCHDOG_ERROR);
- return FALSE;
- }
- include_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.index.inc');
- $documents = array();
- $old_position = apachesolr_get_last_index($namespace);
- $position = $old_position;
-
-
- global $user;
- session_save_session(FALSE);
- $saved_user = $user;
- $user = drupal_anonymous_user();
-
- foreach ($rows as $row) {
- try {
- $callback($documents, $row->nid, $namespace);
-
- $position['last_change'] = $row->changed;
- $position['last_nid'] = $row->nid;
- }
- catch (Exception $e) {
-
- watchdog('Apache Solr', t('Error constructing documents to index: <br /> !message', array('!message' => nl2br(strip_tags($e->getMessage())))), WATCHDOG_ERROR);
- break;
- }
- }
-
- $user = $saved_user;
- session_save_session(TRUE);
-
- if (count($documents)) {
- try {
- watchdog('Apache Solr', t('Adding @count documents.', array('@count' => count($documents))));
-
- $docs_chunk = array_chunk($documents, 20);
- foreach ($docs_chunk as $docs) {
- $solr->addDocuments($docs);
- }
-
- apachesolr_index_updated(time());
- }
- catch (Exception $e) {
- $nids = array();
- if (!empty($docs)) {
- foreach ($docs as $doc) {
- $nids[] = $doc->nid;
- }
- }
- watchdog('Apache Solr', t('Indexing failed on one of the following nodes: @nids <br /> !message', array('@nids' => implode(', ', $nids), '!message' => nl2br(strip_tags($e->getMessage())))), WATCHDOG_ERROR);
- return FALSE;
- }
- }
-
-
- if ($namespace && $position != $old_position) {
- $stored = variable_get('apachesolr_index_last', array());
- $stored[$namespace] = $position;
- variable_set('apachesolr_index_last', $stored);
- }
-
- return $position;
- }
-
- * Convert date from timestamp into ISO 8601 format.
- * http://lucene.apache.org/solr/api/org/apache/solr/schema/DateField.html
- */
- function apachesolr_date_iso($date_timestamp) {
- return gmdate('Y-m-d\TH:i:s\Z', $date_timestamp);
- }
-
- function apachesolr_delete_node_from_index($node) {
- static $failed = FALSE;
- if ($failed) {
- return FALSE;
- }
- try {
- $solr = apachesolr_get_solr();
- $solr->deleteById(apachesolr_document_id($node->nid));
- apachesolr_index_updated(time());
- return TRUE;
- }
- catch (Exception $e) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), WATCHDOG_ERROR);
-
- $failed = TRUE;
- return FALSE;
- }
- }
-
- * Helper function to keep track of when the index has been updated.
- */
- function apachesolr_index_updated($updated = NULL) {
- if (isset($updated)) {
- if ($updated) {
- variable_set('apachesolr_index_updated', (int) $updated);
- }
- else {
- variable_del('apachesolr_index_updated');
- }
- }
- return variable_get('apachesolr_index_updated', 0);
- }
-
- * Implementation of hook_cron().
- */
- function apachesolr_cron() {
-
- include_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.index.inc');
- apachesolr_cron_check_node_table();
- try {
- $solr = apachesolr_get_solr();
-
- $optimize_interval = variable_get('apachesolr_optimize_interval', 60 * 60 * 24);
- $last = variable_get('apachesolr_last_optimize', 0);
- $time = time();
- if ($optimize_interval && ($time - $last > $optimize_interval)) {
- $solr->optimize(FALSE, FALSE);
- variable_set('apachesolr_last_optimize', $time);
- apachesolr_index_updated($time);
- }
-
-
-
- $updated = apachesolr_index_updated();
- if ($updated) {
- $solr->clearCache();
-
- $solr->getLuke();
-
- if ($time - $updated >= variable_get('apachesolr_cache_delay', 300)) {
-
- apachesolr_index_updated(FALSE);
- }
- }
- }
- catch (Exception $e) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())) .' in apachesolr_cron', WATCHDOG_ERROR);
- }
- }
-
- * Implementation of hook_nodeapi().
- */
- function apachesolr_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
- switch ($op) {
- case 'delete':
- _apachesolr_nodeapi_delete($node);
- break;
- case 'insert':
-
-
- db_query("INSERT INTO {apachesolr_search_node} (nid, status, changed) VALUES (%d, %d, %d)", $node->nid, $node->status, time());
- break;
- case 'update':
- _apachesolr_nodeapi_update($node);
- break;
- }
- }
-
- * Helper function for hook_nodeapi().
- */
- function _apachesolr_nodeapi_delete($node, $set_message = TRUE) {
- if (apachesolr_delete_node_from_index($node)) {
-
- db_query("DELETE FROM {apachesolr_search_node} WHERE nid = %d", $node->nid);
- if ($set_message && user_access('administer search') && variable_get('apachesolr_set_nodeapi_messages', 1)) {
- apachesolr_set_stats_message('Deleted content will be removed from the Apache Solr search index in approximately @autocommit_time.');
- }
- }
- }
-
- * Helper function for hook_nodeapi().
- */
- function _apachesolr_nodeapi_update($node, $set_message = TRUE) {
-
- if (!$node->status && db_result(db_query("SELECT status FROM {apachesolr_search_node} WHERE nid = %d", $node->nid))) {
- if (apachesolr_delete_node_from_index($node)) {
-
- db_query("UPDATE {apachesolr_search_node} SET changed = %d, status = %d WHERE nid = %d", time(), $node->status, $node->nid);
- if ($set_message && user_access('administer search') && variable_get('apachesolr_set_nodeapi_messages', 1)) {
- apachesolr_set_stats_message('Unpublished content will be removed from the Apache Solr search index in approximately @autocommit_time.');
- }
- }
- }
- else {
- db_query("UPDATE {apachesolr_search_node} SET changed = %d, status = %d WHERE nid = %d", time(), $node->status, $node->nid);
- }
- }
-
- * Call drupal_set_message() with the text.
- *
- * The text is translated with t() and substituted using Solr stats.
- */
- function apachesolr_set_stats_message($text, $type = 'status', $repeat = FALSE) {
- try {
- $solr = apachesolr_get_solr();
- $stats_summary = $solr->getStatsSummary();
- drupal_set_message(t($text, $stats_summary), $type, FALSE);
- }
- catch (Exception $e) {
- watchdog('apachesolr', nl2br(check_plain($e->getMessage())), WATCHDOG_ERROR);
- }
- }
-
- * Return the enabled facets from the specified block array.
- *
- * @param $module
- * The module (optional).
- * @return
- * An array consisting of info for facets that have been enabled
- * for the specified module, or all enabled facets.
- */
- function apachesolr_get_enabled_facets($module = NULL) {
- $enabled = variable_get('apachesolr_enabled_facets', array());
- if (isset($module)) {
- return isset($enabled[$module]) ? $enabled[$module] : array();
- }
- return $enabled;
- }
-
- * Save the enabled facets for all modules.
- *
- * @param $enabled
- * An array consisting of info for all enabled facets.
- * @return
- * The array consisting of info for all enabled facets.
- */
- function apachesolr_save_enabled_facets($enabled) {
- variable_set('apachesolr_enabled_facets', $enabled);
- return $enabled;
- }
-
- * Save the enabled facets for one module.
- *
- * @param $module
- * The module name.
- * @param $facets
- * Associative array of $delta => $facet_field pairs. If omitted, all facets
- * for $module are disabled.
- * @return
- * An array consisting of info for all enabled facets.
- */
- function apachesolr_save_module_facets($module, $facets = array()) {
- $enabled = variable_get('apachesolr_enabled_facets', array());
- if (!empty($facets) && is_array($facets)) {
- $enabled[$module] = $facets;
- }
- else {
- unset($enabled[$module]);
- }
- variable_set('apachesolr_enabled_facets', $enabled);
- return $enabled;
- }
-
- * Implementation of hook_block().
- */
- function apachesolr_block($op = 'list', $delta = 0, $edit = array()) {
- static $access;
-
- switch ($op) {
- case 'list':
-
- $blocks = apachesolr_mlt_list_blocks();
-
- $blocks['sort'] = array(
- 'info' => t('Apache Solr Core: Sorting'),
-
- );
- return $blocks;
-
- case 'view':
-
- if ($delta != 'sort' && (arg(0) == 'node'&& is_numeric(arg(1)) && $node = node_load(arg(1))) && (!arg(2) || arg(2) == 'view')) {
- $suggestions = array();
-
- if (!isset($access)) {
- $access = node_access('view', $node);
- }
- $block = apachesolr_mlt_load_block($delta);
- if ($access && $block) {
- $docs = apachesolr_mlt_suggestions($block, apachesolr_document_id($node->nid));
- if (!empty($docs)) {
- $suggestions['subject'] = check_plain($block['name']);
- $suggestions['content'] = theme('apachesolr_mlt_recommendation_block', $docs);
- if (user_access('administer search')) {
- $suggestions['content'] .= l(t('Configure this block'), 'admin/build/block/configure/apachesolr/' . $delta, array('class' => 'apachesolr-mlt-admin-link'));
- }
- }
- }
- return $suggestions;
- }
- elseif (apachesolr_has_searched() && $delta == 'sort') {
-
- $response = apachesolr_static_response_cache();
- if (empty($response) || ($response->response->numFound < 2)) {
- return;
- }
-
- $query = apachesolr_current_query();
- $sorts = $query->get_available_sorts();
-
-
- $solrsort = $query->get_solrsort();
-
- $sort_links = array();
- $path = $query->get_path();
- $new_query = clone $query;
- $toggle = array('asc' => 'desc', 'desc' => 'asc');
- foreach ($sorts as $name => $sort) {
- $active = $solrsort['#name'] == $name;
- $direction = '';
- $new_direction = $sort['default'];
- if ($name == 'score') {
-
- $new_direction = 'asc';
- }
- elseif ($active) {
- $direction = $toggle[$solrsort['#direction']];
- $new_direction = $toggle[$solrsort['#direction']];
- }
- $new_query->set_solrsort($name, $new_direction);
- $sort_links[$name] = array(
- 'title' => $sort['title'],
- 'path' => $path,
- 'options' => array('query' => $new_query->get_url_queryvalues()),
- 'active' => $active,
- 'direction' => $direction,
- );
- }
-
- drupal_alter('apachesolr_sort_links', $sort_links);
- if (!empty($sort_links)) {
- foreach ($sort_links as $name => $link) {
- $themed_links[$name] = theme('apachesolr_sort_link', $link['title'], $link['path'], $link['options'], $link['active'], $link['direction']);
- }
- return array(
- 'subject' => t('Sort by'),
- 'content' => theme('apachesolr_sort_list', $themed_links),
- );
- }
- }
- break;
- case 'configure':
- if ($delta != 'sort') {
- require_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.admin.inc');
- return apachesolr_mlt_block_form($delta);
- }
- break;
- case 'save':
- if ($delta != 'sort') {
- require_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.admin.inc');
- apachesolr_mlt_save_block($edit, $delta);
- }
- break;
- }
- }
-
- * Helper function for displaying a facet block.
- */
- function apachesolr_facet_block($response, $query, $module, $delta, $facet_field, $filter_by, $facet_callback = FALSE) {
- if (!empty($response->facet_counts->facet_fields->$facet_field)) {
- $contains_active = FALSE;
- $items = array();
- foreach ($response->facet_counts->facet_fields->$facet_field as $facet => $count) {
- $sortpre = 1000000 - $count;
- $options = array('delta' => $delta);
- $exclude = FALSE;
-
- if ($facet == '_empty_') {
- $exclude = TRUE;
- $facet = '[* TO *]';
- $facet_text = theme('placeholder', t('Missing this field'));
- $options['html'] = TRUE;
-
-
- $sortpre = '-';
- }
- else {
- $facet_text = $facet;
- }
-
- if ($facet_callback && function_exists($facet_callback)) {
- $facet_text = $facet_callback($facet, $options);
- }
- $unclick_link = '';
- $active = FALSE;
- $new_query = clone $query;
- if ($query->has_filter($facet_field, $facet)) {
- $contains_active = $active = TRUE;
-
- $sortpre = '*';
- $new_query->remove_filter($facet_field, $facet);
- $options['query'] = $new_query->get_url_queryvalues();
- $link = theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options);
- }
- else {
- $new_query->add_filter($facet_field, $facet, $exclude);
- $options['query'] = $new_query->get_url_queryvalues();
- $link = theme('apachesolr_facet_link', $facet_text, $new_query->get_path(), $options, $count, FALSE, $response->response->numFound);
- }
- if ($count || $active) {
- $items[$sortpre . '*' . $facet_text] = $link;
- }
- }
-
- if ($items && ($response->response->numFound > 1 || $contains_active)) {
- ksort($items, SORT_STRING);
-
- $initial_limits = variable_get('apachesolr_facet_query_initial_limits', array());
- $limit = isset($initial_limits[$module][$delta]) ? $initial_limits[$module][$delta] : variable_get('apachesolr_facet_query_initial_limit_default', 10);
- $output = theme('apachesolr_facet_list', $items, $limit);
- return array('subject' => $filter_by, 'content' => $output);
- }
- }
- return NULL;
- }
-
- * Helper function for displaying a date facet block.
- *
- * TODO: Refactor with apachesolr_facet_block().
- */
- function apachesolr_date_facet_block($response, $query, $module, $delta, $facet_field, $filter_by, $facet_callback = FALSE) {
- $items = array();
-
- $new_query = clone $query;
- foreach (array_reverse($new_query->get_filters($facet_field)) as $filter) {
- $options = array();
-
- $new_query->remove_filter($facet_field, $filter['#value']);
- if ($facet_callback && function_exists($facet_callback)) {
- $facet_text = $facet_callback($filter['#start'], $options);
- }
- else {
- $facet_text = apachesolr_date_format_iso_by_gap(apachesolr_date_find_query_gap($filter['#start'], $filter['#end']), $filter['#start']);
- }
- $options['query'] = $new_query->get_url_queryvalues();
- array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
- }
-
- if (!empty($response->facet_counts->facet_dates->$facet_field)) {
- $field = clone $response->facet_counts->facet_dates->$facet_field;
-
- $end = $field->end;
- unset($field->end);
-
- $gap = $field->gap;
- unset($field->gap);
-
-
-
- $range_end = array();
- foreach ($field as $facet => $count) {
- if (isset($prev_facet)) {
- $range_end[$prev_facet] = $facet;
- }
- $prev_facet = $facet;
- }
- $range_end[$prev_facet] = $end;
-
- foreach ($field as $facet => $count) {
- $options = array();
-
- if ($facet == '_empty_' || $count == 0) {
- continue;
- }
- if ($facet_callback && function_exists($facet_callback)) {
- $facet_text = $facet_callback($facet, $options);
- }
- else {
- $facet_text = apachesolr_date_format_iso_by_gap(substr($gap, 2), $facet);
- }
- $new_query = clone $query;
- $new_query->add_filter($facet_field, '['. $facet .' TO '. $range_end[$facet] .']');
- $options['query'] = $new_query->get_url_queryvalues();
- $items[] = theme('apachesolr_facet_link', $facet_text, $new_query->get_path(), $options, $count, FALSE, $response->response->numFound);
- }
- }
- if (count($items) > 0) {
-
- $initial_limits = variable_get('apachesolr_facet_query_initial_limits', array());
- $limit = isset($initial_limits[$module][$delta]) ? $initial_limits[$module][$delta] : variable_get('apachesolr_facet_query_initial_limit_default', 10);
- $output = theme('apachesolr_facet_list', $items, $limit);
- return array('subject' => $filter_by, 'content' => $output);
- }
- return NULL;
- }
-
- * Determine the gap in a date range query filter that we generated.
- *
- * This function assumes that the start and end dates are the
- * beginning and end of a single period: 1 year, month, day, hour,
- * minute, or second (all date range query filters we generate meet
- * this criteria). So, if the seconds are different, it is a second
- * gap. If the seconds are the same (incidentally, they will also be
- * 0) but the minutes are different, it is a minute gap. If the
- * minutes are the same but hours are different, it's an hour gap.
- * etc.
- *
- * @param $start
- * Start date as an ISO date string.
- * @param $end
- * End date as an ISO date string.
- * @return
- * YEAR, MONTH, DAY, HOUR, MINUTE, or SECOND.
- */
- function apachesolr_date_find_query_gap($start_iso, $end_iso) {
- $gaps = array('SECOND' => 6, 'MINUTE' => 5, 'HOUR' => 4, 'DAY' => 3, 'MONTH' => 2, 'YEAR' => 1);
- $re = '@(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})@';
- if (preg_match($re, $start_iso, $start) && preg_match($re, $end_iso, $end)) {
- foreach ($gaps as $gap => $idx) {
- if ($start[$idx] != $end[$idx]) {
- return $gap;
- }
- }
- }
-
- return 'YEAR';
- }
-
- * Format an ISO date string based on the gap used to generate it.
- *
- * This function assumes that gaps less than one day will be displayed
- * in a search context in which a larger containing gap including a
- * day is already displayed. So, HOUR, MINUTE, and SECOND gaps only
- * display time information, without date.
- *
- * @param $gap
- * A gap.
- * @param $iso
- * An ISO date string.
- * @return
- * A gap-appropriate formatted date.
- */
- function apachesolr_date_format_iso_by_gap($gap, $iso) {
-
-
-
-
-
-
- $unix = strtotime($iso);
- if ($unix !== FALSE) {
- switch ($gap) {
- case 'YEAR':
- return format_date($unix, 'custom', 'Y', 0);
- case 'MONTH':
- return format_date($unix, 'custom', 'F Y', 0);
- case 'DAY':
- return format_date($unix, 'custom', 'F j, Y', 0);
- case 'HOUR':
- return format_date($unix, 'custom', 'g A', 0);
- case 'MINUTE':
- return format_date($unix, 'custom', 'g:i A', 0);
- case 'SECOND':
- return format_date($unix, 'custom', 'g:i:s A', 0);
- }
- }
-
- return $iso;
- }
-
- * Format the beginning of a date range query filter that we
- * generated.
- *
- * @param $start_iso
- * The start date.
- * @param $end_iso
- * The end date.
- * @return
- * A display string reprepsenting the date range, such as "January
- * 2009" for "2009-01-01T00:00:00Z TO 2009-02-01T00:00:00Z"
- */
- function apachesolr_date_format_range($start_iso, $end_iso) {
- $gap = apachesolr_date_find_query_gap($start_iso, $end_iso);
- return apachesolr_date_format_iso_by_gap($gap, $start_iso);
- }
-
- * Determine the best search gap to use for an arbitrary date range.
- *
- * Generally, we the maximum gap that fits between the start and end
- * date. If they are more than a year apart, 1 year; if they are more
- * than a month apart, 1 month; etc.
- *
- * This function uses Unix timestamps for its computation and so is
- * not useful for dates outside that range.
- *
- * @param $start
- * Start date as an ISO date string.
- * @param $end
- * End date as an ISO date string.
- * @return
- * YEAR, MONTH, DAY, HOUR, MINUTE, or SECOND depending on how far
- * apart $start and $end are.
- */
- function apachesolr_date_determine_gap($start, $end) {
- $start = strtotime($start);
- $end = strtotime($end);
-
- if ($end - $start >= 86400*365) {
- return 'YEAR';
- }
- if (date('Ym', $start) != date('Ym', $end)) {
- return 'MONTH';
- }
- if ($end - $start > 86400) {
- return 'DAY';
- }
-
- return 'HOUR';
- }
-
- * Return the next smaller date gap.
- *
- * @param $gap
- * A gap.
- * @return
- * The next smaller gap, or NULL if there is no smaller gap.
- */
- function apachesolr_date_gap_drilldown($gap) {
- $drill = array(
- 'YEAR' => 'MONTH',
- 'MONTH' => 'DAY',
- 'DAY' => 'HOUR',
-
-
- );
- return isset($drill[$gap]) ? $drill[$gap] : NULL;
- }
-
- * Used by the 'configure' $op of hook_block so that modules can generically set
- * facet limits on their blocks.
- */
- function apachesolr_facetcount_form($module, $delta) {
- $initial = variable_get('apachesolr_facet_query_initial_limits', array());
- $limits = variable_get('apachesolr_facet_query_limits', array());
- $facet_missing = variable_get('apachesolr_facet_missing', array());
-
- $limit = drupal_map_assoc(array(50, 40, 30, 20, 15, 10, 5, 3));
-
- $form['apachesolr_facet_query_initial_limit'] = array(
- '#type' => 'select',
- '#title' => t('Initial filter links'),
- '#options' => $limit,
- '#description' => t('The initial number of filter links to show in this block.'),
- '#default_value' => isset($initial[$module][$delta]) ? $initial[$module][$delta] : variable_get('apachesolr_facet_query_initial_limit_default', 10),
- );
- $limit = drupal_map_assoc(array(100, 75, 50, 40, 30, 20, 15, 10, 5, 3));
- $form['apachesolr_facet_query_limit'] = array(
- '#type' => 'select',
- '#title' => t('Maximum filter links'),
- '#options' => $limit,
- '#description' => t('The maximum number of filter links to show in this block.'),
- '#default_value' => isset($limits[$module][$delta]) ? $limits[$module][$delta] : variable_get('apachesolr_facet_query_limit_default', 20),
- );
- $form['apachesolr_facet_missing'] = array(
- '#type' => 'radios',
- '#title' => t('Include a facet for missing'),
- '#options' => array(0 => t('No'), 1 => t('Yes')),
- '#description' => t('A facet can be generated corresponding to all documents entirely missing this field.'),
- '#default_value' => isset($facet_missing[$module][$delta]) ? $facet_missing[$module][$delta] : 0,
- );
- return $form;
- }
-
- * Used by the 'save' $op of hook_block so that modules can generically set
- * facet limits on their blocks.
- */
- function apachesolr_facetcount_save($edit) {
-
- $module = $edit['module'];
- $delta = $edit['delta'];
- $limits = variable_get('apachesolr_facet_query_limits', array());
- $limits[$module][$delta] = (int)$edit['apachesolr_facet_query_limit'];
- variable_set('apachesolr_facet_query_limits', $limits);
- $initial = variable_get('apachesolr_facet_query_initial_limits', array());
- $initial[$module][$delta] = (int)$edit['apachesolr_facet_query_initial_limit'];
- variable_set('apachesolr_facet_query_initial_limits', $initial);
- $facet_missing = variable_get('apachesolr_facet_missing', array());
- $facet_missing[$module][$delta] = (int)$edit['apachesolr_facet_missing'];
- variable_set('apachesolr_facet_missing', $facet_missing);
- }
-
- * Initialize a pager for theme('pager') without running an SQL query.
- *
- * @see pager_query()
- *
- * @param $total
- * The total number of items found.
- * @param $limit
- * The number of items you will display per page.
- * @param $element
- * An optional integer to distinguish between multiple pagers on one page.
- *
- * @return
- * The current page for $element. 0 by default if $_GET['page'] is empty.
- */
- function apachesolr_pager_init($total, $limit = 10, $element = 0) {
- global $pager_page_array, $pager_total, $pager_total_items;
- $page = isset($_GET['page']) ? $_GET['page'] : '';
-
-
- $pager_page_array = explode(',', $page);
-
-
- $pager_total_items[$element] = $total;
- $pager_total[$element] = ceil($pager_total_items[$element] / $limit);
- $pager_page_array[$element] = max(0, min((int)$pager_page_array[$element], ((int)$pager_total[$element]) - 1));
- return $pager_page_array[$element];
- }
-
- * This hook allows modules to modify the query and params objects.
- *
- * Example:
- *
- * function my_module_apachesolr_modify_query(&$query, &$params) {
- * // I only want to see articles by the admin!
- * $query->add_filter("uid", 1);
- *
- * }
- */
- function apachesolr_modify_query(&$query, &$params, $caller) {
- if (empty($query)) {
-
- return;
- }
-
- foreach (module_implements('apachesolr_modify_query') as $module) {
- $function_name = $module . '_apachesolr_modify_query';
- $function_name($query, $params, $caller);
- }
-
-
- if ($query && ($fq = $query->get_fq())) {
- $params['fq'] = $fq;
- }
-
- if ($query) {
- $sort = $query->get_solrsort();
- $sortstring = $sort['#name'] .' '. $sort['#direction'];
-
- if ($sortstring != 'score asc') {
- $params['sort'] = $sortstring;
- }
- }
- }
-
- * Semaphore that indicates whether a search has been done. Blocks use this
- * later to decide whether they should load or not.
- *
- * @param $searched
- * A boolean indicating whether a search has been executed.
- *
- * @return
- * TRUE if a search has been executed.
- * FALSE otherwise.
- */
- function apachesolr_has_searched($searched = NULL) {
- static $_searched = FALSE;
- if (is_bool($searched)) {
- $_searched = $searched;
- }
- return $_searched;
- }
-
- * Factory method for solr singleton object. Structure allows for an arbitrary
- * number of solr objects to be used based on the host, port, path combination.
- * Get an instance like this:
- * $solr = apachesolr_get_solr();
- */
- function apachesolr_get_solr($host = NULL, $port = NULL, $path = NULL) {
- static $solr_cache;
-
- if (empty($host)) {
- $host = variable_get('apachesolr_host', 'localhost');
- }
- if (empty($port)) {
- $port = variable_get('apachesolr_port', '8983');
- }
- if (empty($path)) {
- $path = variable_get('apachesolr_path', '/solr');
- }
-
- if (empty($solr_cache[$host][$port][$path])) {
- list($module, $filepath, $class) = variable_get('apachesolr_service_class', array('apachesolr', 'Drupal_Apache_Solr_Service.php', 'Drupal_Apache_Solr_Service'));
- include_once(drupal_get_path('module', $module) .'/'. $filepath);
- $solr = new $class($host, $port, $path);
-
- $solr->setCollapseSingleValueArrays(FALSE);
- $solr_cache[$host][$port][$path] = $solr;
- }
- return $solr_cache[$host][$port][$path];
- }
-
- * Execute a search based on a query object.
- *
- * Normally this function is used with the default (dismax) handler for keyword
- * searches. The $final_query that's returned will have been modified by
- * both hook_apachesolr_prepare_query() and hook_apachesolr_modify_query().
- *
- * @param $caller
- * String, name of the calling module or function for use as a cache namespace.
- * @param $current_query
- * A query object from apachesolr_drupal_query(). It will be modified by
- * hook_apachesolr_prepare_query() and then cached in apachesolr_current_query().
- * @param $params
- * Array of parameters to pass to Solr. Must include at least 'rows'.
- * @param $page
- * For paging into results, using $params['rows'] results per page.
- *
- * @return array($final_query, $response)
- *
- * @throws Exception
- */
- function apachesolr_do_query($caller, $current_query, &$params = array('rows' => 10), $page = 0) {
-
-
- foreach (module_implements('apachesolr_prepare_query') as $module) {
- $function_name = $module . '_apachesolr_prepare_query';
- $function_name($current_query, $params, $caller);
- }
-
-
-
- $query = apachesolr_current_query($current_query, $caller);
-
-
- apachesolr_modify_query($query, $params, $caller);
- $params['start'] = $page * $params['rows'];
-
- if (!$query) {
- return array(NULL, array());
- }
-
-
- $function = $caller . '_finalize_query';
- if (function_exists($function)) {
- $function($query, $params);
- }
-
- $keys = $query->get_query_basic();
- if ($keys == '' && isset($params['fq'])) {
-
- $qalt = array();
- foreach ($params['fq'] as $delta => $value) {
-
- if (!preg_match('/^(?:\{!|-)/', $value)) {
- $qalt[] = $value;
- unset($params['fq'][$delta]);
- }
- }
- if ($qalt) {
- $params['q.alt'] = implode(' ', $qalt);
- }
- }
-
- $solr = apachesolr_get_solr();
-
-
- $response = $solr->search(htmlspecialchars($keys, ENT_NOQUOTES, 'UTF-8'), $params['start'], $params['rows'], $params);
-
-
- apachesolr_static_response_cache($response, $caller);
- return array($query, $response);
- }
-
- * It is important to hold on to the Solr response object for the duration of the
- * page request so that we can use it for things like building facet blocks.
- *
- * @todo reverse the order of parameters in future branches.
- */
- function apachesolr_static_response_cache($response = NULL, $namespace = 'apachesolr_search') {
- static $_response = array();
-
- if (is_object($response)) {
- $_response[$namespace] = clone $response;
- }
- if (!isset($_response[$namespace])) {
- $_response[$namespace] = NULL;
- }
- return $_response[$namespace];
- }
-
- * Factory function for query objects.
- *
- * @param $keys
- * The string that a user would type into the search box. Suitable input
- * may come from search_get_keys().
- *
- * @param $filters
- * Key and value pairs that are applied as a filter query.
- *
- * @param $solrsort
- * Visible string telling solr how to sort.
- *
- * @param $base_path
- * The search base path (without the keywords) for this query.
- */
- function apachesolr_drupal_query($keys = '', $filters = '', $solrsort = '', $base_path = '') {
- list($module, $class) = variable_get('apachesolr_query_class', array('apachesolr', 'Solr_Base_Query'));
- include_once drupal_get_path('module', $module) .'/'. $class .'.php';
-
- try {
- $query = new $class(apachesolr_get_solr(), $keys, $filters, $solrsort, $base_path);
- }
- catch (Exception $e) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), WATCHDOG_ERROR);
- $query = NULL;
- }
-
- return $query;
- }
-
- * Static getter/setter for the current query
- *
- * @todo reverse the order of parameters in future branches.
- */
- function apachesolr_current_query($query = NULL, $namespace = 'apachesolr_search') {
- static $saved_query = array();
-
- if (is_object($query)) {
- $saved_query[$namespace] = clone $query;
- }
-
- return is_object($saved_query[$namespace]) ? clone $saved_query[$namespace] : NULL;
- }
-
- * array('index_type' => 'integer',
- * 'multiple' => TRUE,
- * 'name' => 'fieldname',
- * ),
- */
- function apachesolr_index_key($field) {
- switch ($field['index_type']) {
- case 'text':
- $type_prefix = 't';
- break;
- case 'string':
- $type_prefix = 's';
- break;
- case 'integer':
- $type_prefix = 'i';
- break;
- case 'sint':
- $type_prefix = 'si';
- break;
- case 'double':
- $type_prefix = 'p';
- break;
- case 'boolean':
- $type_prefix = 'b';
- break;
- case 'date':
- $type_prefix = 'd';
- break;
- case 'float':
- $type_prefix = 'f';
- break;
- case 'tdate':
- $type_prefix = 'td';
- break;
- case 'tint':
- $type_prefix = 'ti';
- break;
- case 'tlong';
- $type_prefix = 'tl';
- break;
- case 'tfloat':
- $type_prefix = 'tf';
- break;
- case 'tdouble':
- $type_prefix = 'tp';
- break;
- default:
- $type_prefix = 's';
- }
- $sm = $field['multiple'] ? 'm_' : 's_';
- return $type_prefix . $sm . $field['name'];
- }
-
- * Try to map a schema field name to a human-readable description.
- */
- function apachesolr_field_name_map($field_name) {
- require_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.admin.inc');
- return _apachesolr_field_name_map($field_name);
- }
-
- * Invokes hook_apachesolr_cck_field_mappings to find out how to handle CCK fields.
- */
- function apachesolr_cck_fields($field = NULL, $reset = FALSE) {
- static $fields;
-
- if (!isset($fields) || $reset) {
- if (!$reset && ($cache = cache_get('cck_fields', 'cache_apachesolr'))) {
- $fields = unserialize($cache->data);
- }
- else {
- $fields = array();
-
- if (module_exists('content')) {
-
- $mappings['text'] = array(
- 'options_select' => array(
- 'indexing_callback' => '',
- 'display_callback' => 'apachesolr_cck_text_field_callback',
- 'index_type' => 'string',
- ),
- 'options_buttons' => array(
- 'indexing_callback' => '',
- 'display_callback' => 'apachesolr_cck_text_field_callback',
- 'index_type' => 'string',
- ),
- );
- $mappings['nodereference'] = array(
- 'nodereference_select' => array(
- 'display_callback' => 'apachesolr_cck_nodereference_field_callback',
- 'index_type' => 'integer',
- ),
- 'nodereference_autocomplete' => array(
- 'display_callback' => 'apachesolr_cck_nodereference_field_callback',
- 'index_type' => 'integer',
- ),
- );
- $mappings['userreference'] = array(
- 'userreference_select' => array(
- 'display_callback' => 'apachesolr_cck_userreference_field_callback',
- 'index_type' => 'integer',
- ),
- 'userreference_autocomplete' => array(
- 'display_callback' => 'apachesolr_cck_userreference_field_callback',
- 'index_type' => 'integer',
- ),
- );
-
-
-
-
-
- drupal_alter('apachesolr_cck_fields', $mappings);
- $result = db_query("SELECT i.field_name, f.multiple, f.type AS field_type, i.widget_type, i.label, i.type_name AS content_type FROM {node_field_instance} i INNER JOIN {node_field} f ON i.field_name = f.field_name;");
- while ($row = db_fetch_object($result)) {
-
-
- if ((isset($mappings[$row->field_type][$row->widget_type]) || isset($mappings['per-field'][$row->field_name]))) {
- if (isset($mappings['per-field'][$row->field_name])) {
- $row->index_type = $mappings['per-field'][$row->field_name]['index_type'];
- $row->indexing_callback = $mappings['per-field'][$row->field_name]['indexing_callback'];
- $row->display_callback = $mappings['per-field'][$row->field_name]['display_callback'];
- }
- else {
- $row->index_type = $mappings[$row->field_type][$row->widget_type]['index_type'];
- $row->indexing_callback = $mappings[$row->field_type][$row->widget_type]['indexing_callback'];
- $row->display_callback = $mappings[$row->field_type][$row->widget_type]['display_callback'];
- }
- $row->multiple = (bool) $row->multiple;
-
-
- $row->name = 'cck_' . $row->field_name;
- $fields[$row->field_name] = array_merge((array) $fields[$row->field_name], (array) $row);
- $fields[$row->field_name]['content types'][] = $row->content_type;
- unset($fields[$row->field_name]['content_type']);
- }
- }
- }
- cache_set('cck_fields', 'cache_apachesolr', serialize($fields));
- }
- }
- return is_null($field) ? $fields : $fields[$field];
- }
-
- * Use the content.module's content_format() to format the
- * field based on its value ($facet).
- *
- * @param $facet string
- * The indexed value
- * @param $options
- * An array of options including the hook_block $delta.
- */
- function apachesolr_cck_text_field_callback($facet, $options) {
- if (function_exists('content_format')) {
- return content_format($options['delta'], array('value' => $facet));
- }
- else {
- return $facet;
- }
- }
-
- * Use the content.module's content_format() to format the
- * field based on its nid ($facet).
- *
- * @param $facet string
- * The indexed value
- * @param $options
- * An array of options including the hook_block $delta.
- */
- function apachesolr_cck_nodereference_field_callback($facet, $options) {
- if (function_exists('content_format')) {
- return content_format($options['delta'], array('nid' => $facet), 'plain');
- }
- else {
- return $facet;
- }
- }
-
- * Use the content.module's content_format() to format the
- * field based on its uid ($facet).
- *
- * @param $facet string
- * The indexed value
- * @param $options
- * An array of options including the hook_block $delta.
- */
- function apachesolr_cck_userreference_field_callback($facet, $options) {
- if (function_exists('content_format')) {
- return content_format($options['delta'], array('uid' => $facet), 'plain');
- }
- else {
- return $facet;
- }
- }
-
- * Performs a moreLikeThis query using the settings and retrieves documents.
- *
- * @param $settings
- * An array of settings.
- * @param $id
- * The Solr ID of the document for which you want related content.
- * For a node that is apachesolr_document_id($node->nid)
- *
- * @return An array of response documents, or NULL
- */
- function apachesolr_mlt_suggestions($settings, $id) {
-
- try {
- $solr = apachesolr_get_solr();
- $fields = array(
- 'mlt_mintf' => 'mlt.mintf',
- 'mlt_mindf' => 'mlt.mindf',
- 'mlt_minwl' => 'mlt.minwl',
- 'mlt_maxwl' => 'mlt.maxwl',
- 'mlt_maxqt' => 'mlt.maxqt',
- 'mlt_boost' => 'mlt.boost',
- 'mlt_qf' => 'mlt.qf',
- );
-
- $params = array(
- 'qt' => 'mlt',
- 'fl' => 'nid,title,path,url',
- 'mlt.fl' => implode(',', $settings['mlt_fl']),
- );
-
- foreach ($fields as $form_key => $name) {
- if (!empty($settings[$form_key])) {
- $params[$name] = $settings[$form_key];
- }
- }
- $query = apachesolr_drupal_query('id:' . $id);
-
-
- apachesolr_modify_query($query, $params, 'apachesolr_mlt');
- if (empty($query)) {
- return;
- }
-
- $response = $solr->search($query->get_query_basic(), 0, $settings['num_results'], $params);
-
- if ($response->response) {
- $docs = (array) end($response->response);
- return $docs;
- }
- }
- catch ( Exception $e ) {
- watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), WATCHDOG_ERROR );
- }
- }
-
- * Implementation of hook_form_alter
- */
- function apachesolr_form_alter($form_id, &$form) {
- switch ($form_id) {
-
- * Wiping CCK fields mappings cache. We cannot invoke, as in D6, a hook
- * on fieldapi like we do in D6 with hook_content_fieldapi(), so we add a
- * new submit callback handler to CCK fields forms.
- */
- case '_content_admin_field':
- case '_content_admin_field_remove':
- case '_content_admin_field_add_existing':
- case '_content_admin_field_add_new':
- $form['#submit']['apachesolr_clear_cck_fields_cache'] = array();
- break;
- case 'block_admin_display_form':
- foreach ($form as $key => $block) {
- if ((strpos($key, "apachesolr_mlt-") === 0) && $block['module']['#value'] == 'apachesolr') {
- $form[$key]['delete'] = array('#value' => l(t('delete'), 'admin/settings/apachesolr/mlt/delete_block/'. $block['delta']['#value']));
- }
- }
- break;
- case 'block_admin_configure':
- if ($form['module']['#value'] == 'apachesolr' && $form['delta']['#value'] != 'sort') {
- $form['block_settings']['title']['#access'] = FALSE;
- }
- break;
- }
- }
-
- * This function is invoked after a CCK add/edit/delete and is used to clear the cache.
- */
- function apachesolr_clear_cck_fields_cache() {
- cache_clear_all('cck_fields', 'cache_apachesolr');
- }
-
- * Returns a list of blocks. Used by hook_block
- */
- function apachesolr_mlt_list_blocks() {
- $blocks = variable_get('apachesolr_mlt_blocks', array());
- foreach ($blocks as $delta => $settings) {
- $blocks[$delta] += array('info' => t('Apache Solr recommendations: !name', array('!name' => $settings['name'])) , 'cache' => BLOCK_CACHE_PER_PAGE);
- }
- return $blocks;
- }
-
- function apachesolr_mlt_load_block($delta) {
- $blocks = variable_get('apachesolr_mlt_blocks', array());
- return isset($blocks[$delta]) ? $blocks[$delta] : FALSE;
- }
-
- function theme_apachesolr_mlt_recommendation_block($docs) {
- $links = array();
- foreach ($docs as $result) {
-
- $links[] = l($result->title, $result->path, array('html' => TRUE));
- }
- return theme('item_list', $links);
- }
-
- function theme_apachesolr_facet_link($facet_text, $path, $options = array(), $count, $active = FALSE, $num_found = NULL) {
- $options['attributes']['class'][] = 'apachesolr-facet';
- if ($active) {
- $options['attributes']['class'][] = 'active';
- }
- $options['attributes']['class'] = implode(' ', $options['attributes']['class']);
- return apachesolr_l($facet_text ." ($count)", $path, $options);
- }
-
- * A replacement for l()
- * - doesn't add the 'active' class
- * - retains all $_GET parameters that ApacheSolr may not be aware of
- * - if set, $options['query'] MUST be an array
- *
- * @see http://api.drupal.org/api/function/l/6 for parameters and options.
- *
- * @return
- * an HTML string containing a link to the given path.
- */
- function apachesolr_l($text, $path, $options = array()) {
-
- $options += array(
- 'attributes' => array(),
- 'html' => FALSE,
- 'query' => array(),
- );
-
-
- unset($options['attributes']['title']);
-
- if (variable_get('clean_url', '0')) {
- $path = str_replace('+', '%2B', $path);
- }
-
-
- $query = apachesolr_current_query();
- $get = array_diff_key($_GET, array('q' => 1, 'page' => 1), $options['query'], $query->get_url_queryvalues());
- $options['query'] += $get;
- $options_query = drupal_query_string_encode($options['query']);
- $url = $options_query ? url($path, $options_query): url($path);
-
- return '<a href="'. check_url($url) .'"'. drupal_attributes($options['attributes']) .'>'. ($options['html'] ? $text : check_plain(html_entity_decode($text))) .'</a>';
- }
-
- function theme_apachesolr_unclick_link($facet_text, $path, $options = array()) {
- if (empty($options['html'])) {
- $facet_text = check_plain(html_entity_decode($facet_text));
- }
- else {
-
- unset($options['html']);
- }
- $options['attributes']['class'] = 'apachesolr-unclick';
- return apachesolr_l("(-)", $path, $options) . ' '. $facet_text;
- }
-
- function theme_apachesolr_sort_link($text, $path, $options = array(), $active = FALSE, $direction = '') {
- $icon = '';
- if ($direction) {
- $icon = ' '. theme('tablesort_indicator', $direction);
- }
- if ($active) {
- if (isset($options['attributes']['class'])) {
- $options['attributes']['class'] .= ' active';
- }
- else {
- $options['attributes']['class'] = 'active';
- }
- }
- return $icon . apachesolr_l($text, $path, $options);
- }
-
- function theme_apachesolr_facet_list($items, $display_limit = 0) {
-
- $items = array_values($items);
-
- if (($display_limit > 0) && (count($items) > $display_limit)) {
-
- drupal_add_js(drupal_get_path('module', 'apachesolr') . '/apachesolr.js');
-
- drupal_add_js(array('apachesolr' => array('showMore' => t('Show more'), 'showFewer' => t('Show fewer'))), 'setting');
-
- $hidden_items = array_splice($items, $display_limit);
- foreach ($hidden_items as $hidden_item) {
- if (!is_array($hidden_item)) {
- $hidden_item = array('data' => $hidden_item);
- }
- $items[] = $hidden_item + array('class' => 'apachesolr-hidden-facet');
- }
- }
- $admin_link = '';
- if (user_access('administer search')) {
- $admin_link = l(t('Configure enabled filters'), 'admin/settings/apachesolr/enabled-filters');
- }
- return theme('item_list', $items) . $admin_link;
- }
-
- function theme_apachesolr_sort_list($items) {
-
- $items = array_values($items);
- return theme('item_list', $items);
- }
-
- * The interface for all 'query' objects.
- */
- interface Drupal_Solr_Query_Interface {
-
- * Checks to see if a specific filter is already present.
- *
- * @param string $field
- * the facet field to check
- *
- * @param string $value
- * The facet value to check against
- */
- function has_filter($field, $value);
-
-
- * Remove a filter from the query
- *
- * @param string $field
- * the facet field to remove
- *
- * @param string $value
- * The facet value to remove
- * This value can be NULL
- */
- function remove_filter($field, $value = NULL);
-
-
- * Add a filter to a query
- *
- * @param string $field
- * the facet field to apply to this query
- *
- * @param string value
- * the value of the facet to apply
- *
- * @param boolean $exclude
- * Optional paramter. If TRUE, the filter will be negative,
- * meaning that matching values will be excluded from the
- * result set.
- */
- function add_filter($field, $value, $exclude = FALSE);
-
-
- * Return the search path (including the search keywords).
- */
- function get_path();
-
-
- * Return an array of parameters for use in the l function.
- *
- * @see l()
- */
- function get_url_queryvalues();
-
-
- * return the basic string query
- */
- function get_query_basic();
-
-
- * Set the solrsort.
- *
- * @param $field
- * The name of a field in the solr index that's an allowed sort.
- *
- * @param $direction
- * 'asc' or 'desc'
- */
- function set_solrsort($field, $direction);
-
-
- * Get the solrsort.
- *
- * Returns the non-urlencode, non-aliased sort field and direction.
- * as an array keyed with '#name' and '#direction'.
- */
- function get_solrsort();
-
-
- * Return an array of all filters.
- */
- function get_filters($name = NULL);
-
-
- * Add a subquery to the query.
- *
- * @param Drupal_Solr_Query_Interface $query
- * The query to add to the orginal query - may have keywords or filters.
- *
- * @param string $fq_operator
- * The operator to use within the filter part of the subquery
- *
- * @param string $q_operator
- * The operator to use in joining the subquery to
- * the main keywords. Note - this is unlikely to work
- * with the Dismax handler when the main query is only
- * keywords.
- */
- function add_subquery(Drupal_Solr_Query_Interface $query, $fq_operator = 'OR', $q_operator = 'AND');
-
-
- * return the sorts that are provided by the query object
- *
- * @return array all the sorts provided
- */
- function get_available_sorts();
-
-
- * Remove a specific subquery
- *
- * @param Drupal_Solr_Query_Interface $query
- * the query to remove
- */
- function remove_subquery(Drupal_Solr_Query_Interface $query);
-
-
- * remove all subqueries
- */
- function remove_subqueries();
-
-
- * make a sort available
- */
- function set_available_sort($field, $sort);
- }
-
- * Wrapper function for tt() if i18nstrings enabled.
- */
- function apachesolr_tt($name, $string, $langcode = NULL, $update = FALSE) {
- if (module_exists('i18nstrings')) {
- return tt($name, $string, $langcode, $update);
- }
- else {
- return $string;
- }
- }
-
-