You are here

apachesolr_multilingual.module in Apache Solr Multilingual 6.2

Multilingual search using Apache Solr.

@author Markus Kalkbrenner (mkalkbrenner) | Cocomore AG

File

apachesolr_multilingual.module
View source
<?php

/**
 * @file
 * Multilingual search using Apache Solr.
 *
 * @see apachesolr.module
 *
 * @author Markus Kalkbrenner (mkalkbrenner) | Cocomore AG
 *   @see http://drupal.org/user/124705
 *   @see http://drupal.cocomore.com
 */

/**
 * Implements hook_nodeapi().
 *
 * @param $node
 * @param $op
 * @param $a3
 * @param $a4
 * @return mixed
 */
function apachesolr_multilingual_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'delete':
    case 'insert':
    case 'update':
      if (variable_get('apachesolr_multilingual_index_translations', 0) && !empty($node->tnid)) {
        $translations = translation_node_get_translations($node->tnid);
        foreach ($translations as $language => $translation) {
          if ($translation->nid != $node->nid) {
            if ($translation_node = node_load($translation->nid)) {
              apachesolr_nodeapi_update($translation_node);
            }
          }
        }
      }
      break;
  }
}

/**
 * Implements hook_apachesolr_update_index().
 *
 * @param $document
 * @param $node
 * @param $namespace
 * @return mixed
 */
function apachesolr_multilingual_apachesolr_update_index(&$document, $node, $namespace) {
  static $reentrance = FALSE;
  if (!$reentrance) {
    $reentrance = TRUE;
    $language = $node->language;
    if (!$language) {

      // Language neutral
      $language = variable_get('apachesolr_multilingual_map_language_neutral', '');
      if ($language) {
        $document->language = $node->language = $language;
      }
    }
    if ($language) {
      $fields = $document
        ->getFieldNames();
      if (in_array('vid', $fields) && is_array($document->vid)) {

        // vid is vocabulary id in this case
        $term_languages = array(
          $language,
        );
        if (module_exists('i18ntaxonomy') && variable_get('apachesolr_multilingual_index_term_translations', 0)) {
          $term_languages = variable_get('apachesolr_multilingual_languages', array());
        }
        foreach ($term_languages as $term_language) {
          if ($term_language) {
            $vids = array_unique($document->vid);
            $terms = array();
            foreach ($vids as $vid) {
              if (module_exists('i18ntaxonomy')) {
                $tmp = '';
                if (in_array('im_vid_' . $vid, $fields)) {
                  foreach ($document->{'im_vid_' . $vid} as $tid) {
                    $term = i18nstrings("taxonomy:term:{$tid}:name", '', $term_language);
                    if (!empty($term)) {
                      $tmp .= $term . ' ';
                    }
                  }
                }
                if (!empty($tmp)) {
                  $terms[] = $tmp;
                }
              }
              else {

                // module i18ntaxonomy isn't installed
                // in this case we simply copy the terms
                if (in_array('ts_vid_' . $vid . '_names', $fields)) {
                  $terms[] = $document->{'ts_vid_' . $vid . '_names'};
                }

                // REVIEW see http://drupal.org/node/783924
              }
            }
            if ($terms) {
              $document->{'taxonomy_names_' . $term_language} = $terms;
            }
          }
        }
      }

      // use language specific stemming and so on ..
      if (in_array('title', $fields)) {
        $document->{'title_' . $language} = $document->title;
      }
      if (in_array('body', $fields)) {
        $document->{'body_' . $language} = $document->body;
      }
      if (in_array('tags_h1', $fields)) {
        $document->{'tags_h1_' . $language} = $document->tags_h1;
      }
      if (in_array('tags_h2_h3', $fields)) {
        $document->{'tags_h2_h3_' . $language} = $document->tags_h2_h3;
      }
      if (in_array('tags_h4_h5_h6', $fields)) {
        $document->{'tags_h4_h5_h6_' . $language} = $document->tags_h4_h5_h6;
      }
      if (in_array('tags_a', $fields)) {
        $document->{'tags_a_' . $language} = $document->tags_a;
      }
      if (in_array('tags_inline', $fields)) {
        $document->{'tags_inline_' . $language} = $document->tags_inline;
      }
      foreach ($fields as $field_name) {
        if ((strpos($field_name, 'ts_') === 0 || strpos($field_name, 'tm_') === 0) && !empty($document->{$field_name})) {

          // deal with fields like cck using dynamic ts_* fields
          // search for existing language identifier at second position
          $tmp = explode('_', $field_name);
          if ($language != $tmp[1]) {
            $document->{$tmp[0] . '_' . $language . drupal_substr($field_name, 2)} = $document->{$field_name};
          }
        }
      }
      if (variable_get('apachesolr_multilingual_index_translations', 0) && $node->tnid) {
        $translations = translation_node_get_translations($node->tnid);
        foreach ($translations as $translation_language => $translation) {
          if ($translation->nid != $node->nid) {
            if ($translation_node = node_load($translation->nid)) {
              if ($translation_document = apachesolr_node_to_document($translation_node, $namespace)) {
                if (in_array('title', $fields)) {
                  $document->{'title_' . $translation_language} = $translation_document->title;
                }
                if (in_array('body', $fields)) {
                  $document->{'body_' . $translation_language} = $translation_document->body;
                }
                if (in_array('tags_h1', $fields)) {
                  $document->{'tags_h1_' . $translation_language} = $translation_document->tags_h1;
                }
                if (in_array('tags_h2_h3', $fields)) {
                  $document->{'tags_h2_h3_' . $translation_language} = $translation_document->tags_h2_h3;
                }
                if (in_array('tags_h4_h5_h6', $fields)) {
                  $document->{'tags_h4_h5_h6_' . $translation_language} = $translation_document->tags_h4_h5_h6;
                }
                if (in_array('tags_a', $fields)) {
                  $document->{'tags_a_' . $translation_language} = $translation_document->tags_a;
                }
                if (in_array('tags_inline', $fields)) {
                  $document->{'tags_inline_' . $translation_language} = $translation_document->tags_inline;
                }
                foreach ($fields as $field_name) {
                  if ((strpos($field_name, 'ts_') === 0 || strpos($field_name, 'tm_') === 0) && !empty($translation_document->{$field_name})) {

                    // deal with fields like cck using dynamic ts_* fields
                    // search for existing language identifier at second position
                    $tmp = explode('_', $field_name);
                    if ($translation_language != $tmp[1]) {
                      $document->{$tmp[0] . '_' . $translation_language . drupal_substr($field_name, 2)} = $translation_document->{$field_name};
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    $reentrance = FALSE;
  }
}

/**
 * Implements hook_form_alter().
 *
 * By default we only show text fields. Use hook_form_alter to change.
 *
 * @param $form
 * @param $state
 * @param $form_id
 * @return mixed
 */
function apachesolr_multilingual_form_alter(&$form, $form_state, $form_id) {
  if ('apachesolr_search_settings_form' == $form_id) {
    $active_languages = locale_language_list();
    $solr = apachesolr_get_solr();
    $fields = $solr
      ->getFields();
    $form['apachesolr_search_query_fields']['#description'] .= '<br />' . t('<b>Note:</b> If you are missing some language specific fields here you have to index some corresponding content first.');
    $qf = variable_get('apachesolr_search_query_fields', array());

    // Note - we have default values set in solrconfig.xml, which will operate
    // when none are set.  That's the preferred state.
    $defaults = array(
      'body' => '1.0',
      'title' => '5.0',
      'name' => '3.0',
      'taxonomy_names' => '2.0',
      'tags_h1' => '5.0',
      'tags_h2_h3' => '3.0',
      'tags_h4_h5_h6' => '2.0',
      'tags_inline' => '1.0',
      'tags_a' => '0',
    );
    if (!$qf) {
      $qf = $defaults;
    }
    foreach ($fields as $field_name => $field) {

      // Only indexed fields are searchable.
      if ($field->schema[0] == 'I') {
        if ('text' != $field->type && strpos($field->type, 'text') === 0 && strpos($field->type, 'textSpell') !== 0) {

          // search for language identifier at last or second position
          $tmp = explode('_', $field_name);
          $lang = array_pop($tmp);
          if (empty($active_languages[$lang])) {
            $tmp[] = $lang;
            if (!empty($active_languages[$tmp[1]])) {
              $lang = $tmp[1];
              unset($tmp[1]);
            }
          }
          if (!empty($active_languages[$lang])) {
            $base_field_name = implode('_', $tmp);
            $form['apachesolr_search_query_fields'][$base_field_name]['#description'] = t('Recommended to "Omit". Use language specific fields instead.');
            $form['apachesolr_search_query_fields'][$field_name]['#access'] = TRUE;
            if (!array_key_exists($field_name, $qf)) {
              $form['apachesolr_search_query_fields'][$field_name]['#default_value'] = isset($qf[$base_field_name]) ? $qf[$base_field_name] : '0';
            }
          }
        }
      }
    }
  }
}

/**
 * Implements hook_apachesolr_field_name_map_alter().
 */
function apachesolr_multilingual_apachesolr_field_name_map_alter(&$map) {
  $active_languages = locale_language_list();
  $solr = apachesolr_get_solr();
  $fields = $solr
    ->getFields();
  foreach ($fields as $field_name => $field) {

    // Only indexed fields are searchable.
    if ($field->schema[0] == 'I') {
      if ('text' != $field->type && strpos($field->type, 'text') === 0 && strpos($field->type, 'textSpell') !== 0) {

        // serach for language identifier at last or second position within the field name
        $tmp = explode('_', $field_name);
        $lang = array_pop($tmp);
        if (empty($active_languages[$lang])) {
          $tmp[] = $lang;
          if (!empty($active_languages[$tmp[1]])) {
            $lang = $tmp[1];
            unset($tmp[1]);
          }
        }
        $base_field_name = implode('_', $tmp);
        if (!empty($active_languages[$lang])) {
          $map[$field_name] = '<em>' . $active_languages[$lang] . '</em> - ' . $map[$base_field_name];
        }
      }
    }
  }
}

/**
 * Implements hook_menu().
 */
function apachesolr_multilingual_menu() {
  $items = array();
  $items['admin/settings/apachesolr/multilingual'] = array(
    'title' => 'Multilingual',
    'weight' => 0,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'apachesolr_multilingual_admin_form',
    ),
    'file' => 'apachesolr_multilingual.admin.inc',
    'access arguments' => array(
      'administer search',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/settings/apachesolr/schema_generator'] = array(
    'title' => 'Config files',
    'weight' => 10,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'apachesolr_multilingual_schema_generator_form',
    ),
    'file' => 'apachesolr_multilingual.schema_generator.inc',
    'access arguments' => array(
      'administer search',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Helper funktion that returns the name of a stemmer
 * if available
 *
 * @param string
 *   the language id
 *
 * @return string
 *   the name of the stemmer
 */
function apachesolr_multilingual_get_stemmer($language_id = NULL) {
  static $available_stemmers = array(
    'da' => 'Danish',
    'nl' => 'Dutch',
    'en' => 'English',
    'fi' => 'Finnish',
    'fr' => 'French',
    'de' => 'German',
    'it' => 'Italian',
    'nn' => 'Norwegian',
    'nb' => 'Norwegian',
    'pt-br' => 'Portuguese',
    'pt-pt' => 'Portuguese',
    'ro' => 'Romanian',
    'ru' => 'Russian',
    'es' => 'Spanish',
    'sv' => 'Swedish',
    'tr' => 'Turkish',
  );
  if (is_null($language_id)) {
    return $available_stemmers;
  }
  if (array_key_exists($language_id, $available_stemmers)) {
    return $available_stemmers[$language_id];
  }
  return variable_get('apachesolr_multilingual_stemmer_' . $language_id, '');
}

/**
 * Implements hook_apachesolr_modify_query().
 */
function apachesolr_multilingual_apachesolr_modify_query(&$query, &$params, $caller) {
  global $language;
  $filter_language = '';

  // We assume that a user is not able to select two different languages as filter
  $language_filters = $query
    ->get_filters('language');
  if (!empty($language_filters)) {
    $filter_language = $language_filters[0]['#value'];
  }
  $languages = variable_get('apachesolr_multilingual_languages', array());
  if (!$filter_language && variable_get('apachesolr_multilingual_auto_language_filter', 0) && (!variable_get('apachesolr_multilingual_auto_language_filter_detachable', 0) || variable_get('apachesolr_multilingual_auto_language_filter_detachable', 0) && empty($_GET['detach-auto-language-filter']))) {
    if (!empty($language->language)) {
      if (in_array($language->language, $languages)) {
        $filter_language = $language->language;
        $query
          ->add_filter('language', $filter_language);
      }
    }
    elseif (variable_get('apachesolr_multilingual_map_language_neutral', '')) {
      $filter_language = variable_get('apachesolr_multilingual_map_language_neutral', '');
      if ($filter_language) {
        $query
          ->add_filter('language', $filter_language);
      }
    }
  }
  if (empty($params['hl.fl'])) {
    $params['hl.fl'] = 'body';
  }
  if ($filter_language && in_array($filter_language, $languages)) {
    $solr = apachesolr_get_solr();
    $fields = $solr
      ->getFields();
    $highlighted_fields = explode(',', $params['hl.fl']);
    foreach ($highlighted_fields as $key => $highlighted_field) {
      if (array_key_exists($highlighted_field . '_' . $filter_language, $fields)) {

        // title, body, spell
        $highlighted_fields[$key] .= '_' . $filter_language;
      }
      elseif (strpos('ts_', $highlighted_field) === 0 && strpos('ts_' . $filter_language, $highlighted_field) !== 0) {
        $highlighted_fields[$key] = 'ts_' . $filter_language . substr($highlighted_field, 2);
      }
      elseif (strpos('tm_', $highlighted_field) === 0 && strpos('tm_' . $filter_language, $highlighted_field) !== 0) {
        $highlighted_fields[$key] = 'tm_' . $filter_language . substr($highlighted_field, 2);
      }
    }
    $params['hl.fl'] = implode(',', $highlighted_fields);
    if (variable_get('apachesolr_search_spellcheck', FALSE) && array_key_exists('spell_' . $filter_language, $fields)) {
      $params['spellcheck.dictionary'] = 'spellchecker_' . $filter_language;
    }
  }
}

/**
 * Implements hook_form_search_form_alter().
 *
 * @param $form
 * @param $form_state
 */
function apachesolr_multilingual_form_search_form_alter(&$form, $form_state) {
  if ($form['module']['#value'] == 'apachesolr_search') {
    if (variable_get('apachesolr_multilingual_auto_language_filter', 0) && variable_get('apachesolr_multilingual_auto_language_filter_detachable', 0)) {
      $lang_filter = !empty($_GET['filters']) && strpos($_GET['filters'], 'language:') !== FALSE;
      $form['basic']['apachesolr_search']['detach_auto_language_filter'] = array(
        '#type' => $lang_filter ? 'hidden' : 'checkbox',
        '#title' => t('Search all languages'),
        '#default_value' => isset($_GET['detach-auto-language-filter']),
      );
      if (!isset($form['#submit']) || !is_array($form['#submit'])) {
        $form['#submit'] = array();
      }
      $form['#submit'] = array_merge(array(
        'apachesolr_multilingual_form_search_submit',
      ), $form['#submit']);
    }
  }
}

/**
 * @see apachesolr_multilingual_form_search_form_alter()
 */
function apachesolr_multilingual_form_search_submit($form, &$form_state) {
  $fv = $form_state['values'];
  if (!empty($fv['apachesolr_search']['get'])) {
    $get = json_decode($fv['apachesolr_search']['get'], TRUE);
    if (!empty($fv['apachesolr_search']['detach_auto_language_filter'])) {
      $get['detach-auto-language-filter'] = '1';
    }
    elseif (isset($get['detach-auto-language-filter'])) {
      unset($get['detach-auto-language-filter']);
    }
    $form_state['values']['apachesolr_search']['get'] = json_encode($get);
  }
}

/**
 * Implements hook_apachesolr_facets().
 */
function apachesolr_multilingual_apachesolr_facets() {
  $facets['apachesolr_multilingual_language'] = array(
    'info' => t('Apache Solr Multilingual: Filter by Language'),
    'facet_field' => 'language',
  );
  return $facets;
}

/**
 * Implements hook_block().
 */
function apachesolr_multilingual_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $enabled_facets = apachesolr_get_enabled_facets('apachesolr_multilingual');
      $facets = apachesolr_multilingual_apachesolr_facets();

      // Add the blocks
      $blocks = array();
      foreach ($enabled_facets as $delta => $facet_field) {
        if (isset($facets[$delta])) {
          $blocks[$delta] = $facets[$delta] + array(
            'cache' => BLOCK_CACHE_PER_PAGE,
          );
        }
      }
      return $blocks;
    case 'view':
      if (apachesolr_has_searched()) {
        $response = apachesolr_static_response_cache();
        if (empty($response)) {
          return;
        }
        $query = apachesolr_current_query();
        $facets = apachesolr_multilingual_apachesolr_facets();
        switch ($delta) {
          case 'apachesolr_multilingual_language':
            if (!variable_get('apachesolr_multilingual_auto_language_filter', 0) || variable_get('apachesolr_multilingual_auto_language_filter', 0) && variable_get('apachesolr_multilingual_auto_language_filter_detachable', 0) && (count((array) $response->facet_counts->facet_fields->{$facets}[$delta]['facet_field']) > 1 || !empty($_GET['filters']) && strpos($_GET['filters'], 'language:') !== FALSE)) {
              return apachesolr_facet_block($response, $query, 'apachesolr_multilingual', $delta, $facets[$delta]['facet_field'], t('Filter by language'), 'apachesolr_search_language_name');
            }
            break;
        }
      }
      break;
    case 'configure':
      return apachesolr_facetcount_form('apachesolr_multilingual', $delta);
    case 'save':
      apachesolr_facetcount_save($edit);
      break;
  }
}