summaryrefslogtreecommitdiffstats
path: root/apachesolr_multisitesearch.module
blob: a62e5c3796b856c3a85297ab968e27c20f8d1df2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
<?php

/**
 * @file
 *   Provides a multi-site search implementation for use with the Apache Solr module
 */

/**
 * Implements hook_menu().
 */
function apachesolr_multisitesearch_menu() {
  $items = array();
  $items['admin/config/search/apachesolr/multisite-filters'] = array(
    'title' => 'Multisite',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('apachesolr_multisitesearch_settings'),
    'weight' => -8,
    'access arguments' => array('administer search'),
    'file' => 'apachesolr_multisitesearch.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implements hook_facetapi_facet_info().
 *
 * Maps the hash label in Apache Solr to a facet
 * @param type $searcher_info
 * @return type
 */
function apachesolr_multisitesearch_facetapi_facet_info($searcher_info) {
  $facets = array();
  $facets['hash'] = array(
    'label' => t('Site'),
    'description' => t('Filter by Site (Multisite).'),
    'field' => 'hash',
    'map callback' => 'apachesolr_multisitesearch_map_hash',
  );
  // Create a multisite bundle name field
  $facets['bundle_name'] = array(
    'label' => t('Content Type'),
    'description' => t('Filter by content type (Multisite).'),
    'field' => 'bundle_name',
  );
  // Create a multisite facet field
  $facets['sm_vid_tags'] = array(
    'label' => t('Tags'),
    'description' => t('Filter by Tags (Multisite).'),
    'field' => 'sm_vid_Tags',
  );
  // Create a multisite facet field
  $facets['ss_name'] = array(
    'label' => t('User name'),
    'description' => t('Filter by user name (Multisite).'),
    'field' => 'ss_name',
    'map callback' => 'apachesolr_multisitesearch_map_username',
  );
  return $facets;
}

function apachesolr_multisitesearch_map_username($facets, $options) {
  $map = array();
  foreach ($facets as $key) {
    // @see https://drupal.org/node/2050747
    if ($key == '0' || $key == '_empty_') {
      $map[$key]['#markup'] = variable_get('anonymous', t('Anonymous'));
    }
    else {
      $map[$key]['#markup'] = $key;
    }
  }
  return $map;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Adds a "make multisite" option in the settings of any environment
 */
function apachesolr_multisitesearch_form_apachesolr_environment_edit_form_alter(&$form, &$form_state, $form_id) {
  $environment = reset($form_state['build_info']['args']);

  $form['make_multisite'] = array(
    '#type' => 'checkbox',
    '#title' => t('Make this Solr search environment multisite capable'),
    '#default_value' => apachesolr_environment_variable_get($environment['env_id'], 'multisitesearch', FALSE),
  );

  $options = apachesolr_multisitesearch_get_site_options();
  $form['multisitesearch_sites'] = array(
    '#type' => 'select',
    '#title' => t('Limit searching to the following sites:'),
    '#description' => t('If no sites are selected, searches will be performed across all sites on the index.'),
    '#multiple' => TRUE,
    '#options' => $options,
    '#default_value' => apachesolr_environment_variable_get($environment['env_id'], 'multisitesearch_sites', array()),
    '#states' => array(
      'visible' => array(
        ':input[name="make_multisite"]' => array('checked' => TRUE),
      ),
    ),
    '#access' => !empty($options),
  );

  $form['actions']['save']['#submit'][] = 'apachesolr_multisitesearch_environment_edit_submit';
}

/**
 * Submit callback for saving an environment to make it multisite capabe
 */
function apachesolr_multisitesearch_environment_edit_submit($form, &$form_state) {
  // Enable or disable multisite
  apachesolr_environment_variable_set($form_state['values']['env_id'], 'multisitesearch', $form_state['values']['make_multisite']);
  apachesolr_environment_variable_set($form_state['values']['env_id'], 'multisitesearch_sites', $form_state['values']['multisitesearch_sites']);
}

/**
 * Return an array of multisite search sites keyed by hash.
 */
function apachesolr_multisitesearch_get_site_options() {
  $options = &drupal_static(__FUNCTION__);

  if (!isset($options)) {
    $site_hash = apachesolr_site_hash();
    module_load_include('inc', 'apachesolr_multisitesearch', 'apachesolr_multisitesearch.index');
    $metadata = variable_get('apachesolr_multisitesearch_metadata', array());
    $hashes = apachesolr_multisitesearch_get_site_hashes();

    $options = array();
    foreach ($hashes as $hash => $count) {
      if ($hash == $site_hash) {
        $options[$hash] = t('This site (!site, !count documents)', array('!site' => variable_get('site_name', 'Drupal'), '!count' => $count));
      }
      elseif (!empty($metadata[$hash])) {
        $options[$hash] = $metadata[$hash]['site'] . ' ' . t('(!count documents)', array('!count' => $count));
      }
      else {
        $options[$hash] = $hash . ' ' . t('(!count documents)', array('!count' => $count));
      }
    }

    // This site should always be in the list of options.
    if (!isset($options[$site_hash])) {
      $options[$site_hash] = t('This site (!site)', array('!site' => variable_get('site_name', 'Drupal')));
    }
  }

  return $options;
}

/**
 * callback for mapping hashes to sites
 * @return array $data
 */
function apachesolr_multisitesearch_map_hash() {
  $data = variable_get('apachesolr_multisitesearch_metadata', array());
  foreach ($data as $key => $value) {
    $data[$key] = $value['ss_multisite_meta_sitename'];
  }
  return $data;
}

/**
 * Implements hook_apachesolr_process_results().
 *
 * Changes the links from results that come out of another index
 * @param array $results
 * @param DrupalSolrQueryInterface $query
 */
function apachesolr_multisitesearch_apachesolr_process_results(&$results, DrupalSolrQueryInterface $query) {
  $env_id = $query->solr('getId');
  $multisite = apachesolr_environment_variable_get($env_id, 'multisitesearch');
  if (!empty($multisite)) {
    foreach ($results as $id => $result) {
      $results[$id]['extra']['hash'] = theme('apachesolr_multisitesearch_breadcrumb_hash', array('hash' => $results[$id]['fields']['hash']));
      // Fix up results from remote sites.
      if ($results[$id]['fields']['hash'] != apachesolr_site_hash()) {
        $results[$id]['link'] = $results[$id]['fields']['url'];
        if (isset($results[$id]['user']) && !empty($results[$id]['fields']['name'])) {
          $results[$id]['user'] = check_plain($results[$id]['fields']['name']);
        }
      }
    }
  }
}

/**
* Returns available bundle names.
*
* @return array
*  An array listing all of the bundle names for content types.
*
*  TODO: Separate content types by site, and allow for exclusions by site.
*/
function apachesolr_multisitesearch_query_bundles() {
  $query_bundle_names = array();

  // Check variables for the metadata which contains the bundles and bundle
  // names.
  $sites = variable_get('apachesolr_multisitesearch_metadata', array());
  if (isset($sites) && !empty($sites)) {
    // Iterates for each site available in the multi-site search
    foreach ($sites as $key => $value) {
      // Grabs all of the bundle names and save them.
      foreach ($value['sm_multisite_meta_bundles'] as $bundle_name) {
        $query_bundle_names[] = $bundle_name;
      }
    }
    // Sort the bundle names for user readability. Sorting is done here so
    // mapping keys to values later happens properly.
    sort($query_bundle_names);
  }
  $query_bundle_names = array_unique($query_bundle_names);
  return $query_bundle_names;
}

/**
 * Create a Solr query for a multisite search from an environment's settings.
 *
 * @param string $env_id
 *   An Apache Solr environment ID.
 *
 * @return DrupalSolrQueryInterface|bool
 *   A subquery object to apply, or FALSE if there were no filters to apply.
 */
function apachesolr_multisitesearch_build_site_subquery($env_id) {
  $subquery = apachesolr_drupal_subquery();

  if (!apachesolr_environment_variable_get($env_id, 'multisitesearch', FALSE)) {
    // Limit single site searchs via the site hash.
    $subquery->addFilter('hash', apachesolr_site_hash());
  }
  elseif ($sites = apachesolr_environment_variable_get($env_id, 'multisitesearch_sites', array())) {
    foreach ($sites as $site) {
      $subquery->addFilter('hash', $site);
    }
  }

  return $subquery->getFilters() ? $subquery : FALSE;
}

/**
 * Implements hook_apachesolr_query_alter().
 *
 * Verifies if the environment is multisite enabled, and if so, returns
 * results from the while index. Otherwise it only returns results from
 * the current site.
 * @param DrupalSolrQueryInterface $query
 */
function apachesolr_multisitesearch_apachesolr_query_alter(DrupalSolrQueryInterface $query) {
  if (empty($query->multisite)) {
    // Add hash and site to our fields to retrieve
    $query->addParam('fl', 'hash');
    $query->addParam('fl', 'site');

    // Restrict the query to certain sites.
    if ($subquery = apachesolr_multisitesearch_build_site_subquery($query->solr('getId'))) {
      $query->addFilterSubQuery($subquery);
    }
  }

  // Get the variable which contains the query exclusion keys.
  $excluded_bundles = variable_get('apachesolr_multisitesearch_query_exclusions', array());
  if (isset($excluded_bundles) && !empty($excluded_bundles)) {
    // Get all of the bundle names which can be excluded.
    $query_exclusion_options = apachesolr_multisitesearch_query_bundles();
    // Map the excluded bundle keys to their values and bundle names.
    foreach ($excluded_bundles as $key) {
      $excluded_bundles[$key] = $query_exclusion_options[$key];
    }
    // Create filters for the flagged keys and exclude them from search.
    foreach ($excluded_bundles as $filtered_content) {
      $query->addFilter('bundle_name', $filtered_content, TRUE);
    }
  }
}

/**
 * Implements hook_apachesolr_delete_by_query_alter().
 *
 * Allows a module to modify the delete query.
 * @param string $query
 *   Defaults to *:*
 */
function apachesolr_multisitesearch_apachesolr_delete_by_query_alter(&$query) {
  // use the site hash so that you only delete this site's content
  if ($query == '*:*') {
    $query = 'hash:' . apachesolr_site_hash();
  }
  else {
    $query = "($query) AND hash:" . apachesolr_site_hash();
  }
}

/**
 * Implements hook_cron().
 */
function apachesolr_multisitesearch_cron() {
  module_load_include('inc', 'apachesolr_multisitesearch', 'apachesolr_multisitesearch.index');
  apachesolr_multisitesearch_refresh_metadata();
}

/**
 * Implements hook_theme().
 */
function apachesolr_multisitesearch_theme() {
  return array(
    'apachesolr_multisitesearch_breadcrumb_hash' => array(
      'variables' => array('hash' => NULL, 'exclude' => FALSE),
    ),
  );
}

function theme_apachesolr_multisitesearch_breadcrumb_hash($variables) {
  $hash = $variables['hash'];
  static $meta;
  if (!isset($meta)) {
    $meta = variable_get('apachesolr_multisitesearch_metadata', array());
  }
  if ($hash == apachesolr_site_hash()) {
    return t('This site (!site)', array('!site' => variable_get('site_name', 'Drupal')));
  }
  elseif (isset($meta[$hash]['ss_multisite_meta_sitename'])) {
    return $meta[$hash]['ss_multisite_meta_sitename'];
  }
  return $hash;
}

/**
 * Implements hook_form_alter().
 *
 * @see apachesolr_settings()
 */
function apachesolr_multisitesearch_form_apachesolr_settings_alter(&$form, &$form_state) {
  $form['multisite'] = array(
    '#type' => 'fieldset',
    '#title' => t('Multisite'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['multisite']['apachesolr_multisitesearch_metadata_update_interval'] = array(
    '#type' => 'select',
    '#title' => t('How often to push metadata updates from this site and commit them to Solr'),
    '#options' => drupal_map_assoc(array(300, 900, 1800, 3600, 10800, 21600, 43200, 86400, 604800, 1209600, 2592000), 'format_interval'),
    '#default_value' => variable_get('apachesolr_multisitesearch_metadata_update_interval', 3600),
  );
  $form['multisite']['apachesolr_multisitesearch_metadata_fetch_interval'] = array(
    '#type' => 'select',
    '#title' => t('How often to fetch metadata data from the index'),
    '#options' => drupal_map_assoc(array(300, 900, 1800, 3600, 10800, 21600, 43200, 86400, 604800), 'format_interval'),
    '#default_value' => variable_get('apachesolr_multisitesearch_metadata_fetch_interval', 300),
  );
}