View source
<?php
function search_api_location_page_form_search_api_page_admin_add_alter(&$form, &$form_state) {
if (!isset($form_state['step_one'])) {
return;
}
$index = search_api_index_load($form_state['step_one']['index_id']);
if ($fields = search_api_location_get_location_fields($index)) {
$form['#validate'][] = 'search_api_location_page_edit_validate';
$form['search_api_location'] = array(
'#type' => 'fieldset',
'#title' => t('Location'),
'#collapsible' => TRUE,
'#tree' => TRUE,
'#prefix' => '<div id="search-api-loaction-fieldset">',
'#suffix' => '</div>',
);
$form['submit']['#weight'] = 5;
$radius_types = array(
'fixed' => t('Fixed value'),
'textfield' => t('Text field'),
'select' => t('Select field'),
);
$plugin_options = search_api_location_get_input_plugin_options();
$plugin_default = key($plugin_options);
$values =& $form_state['values']['search_api_location'];
foreach ($fields as $key => $field) {
$css_key = '#edit-search-api-location-' . drupal_clean_css_identifier($key);
$states['visible'][$css_key . '-enabled']['checked'] = TRUE;
$form['search_api_location'][$key] = array(
'#type' => 'fieldset',
'#title' => check_plain($field['name']),
'#collapsible' => TRUE,
);
$form['search_api_location'][$key]['enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Include location filter'),
'#default_value' => FALSE,
);
$form['search_api_location'][$key]['compact'] = array(
'#type' => 'checkbox',
'#title' => t('Show filter in the search block'),
'#default_value' => FALSE,
'#states' => $states,
);
$form['search_api_location'][$key]['plugin'] = array(
'#type' => 'select',
'#title' => t('Input method'),
'#description' => t('Select the method to use for parsing locations entered by the user.'),
'#options' => $plugin_options,
'#default_value' => $plugin_default,
'#states' => $states,
'#ajax' => array(
'callback' => 'search_api_location_page_ajax_callback',
'wrapper' => 'search-api-loaction-fieldset',
),
);
$plugin_id = !empty($values[$key]['plugin']) ? $values[$key]['plugin'] : $plugin_default;
$plugin = search_api_location_get_input_plugins($plugin_id);
$form['search_api_location'][$key]['plugin_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Input method settings'),
'#description' => $plugin['description'],
'#states' => $states,
);
if (!empty($plugin['form callback'])) {
$plugin_form = $plugin['form callback']($form_state, array());
if ($plugin_form) {
$form['search_api_location'][$key]['plugin_settings'] += $plugin_form;
}
}
$form['search_api_location'][$key]['radius_type'] = array(
'#type' => 'select',
'#title' => t('Type of distance filter'),
'#options' => $radius_types,
'#default_value' => 'fixed',
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'fixed';
$form['search_api_location'][$key]['radius_value'] = array(
'#type' => 'textfield',
'#title' => t('Maximum distance from location (in kilometers)'),
'#default_value' => 5,
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'textfield';
$form['search_api_location'][$key]['radius_unit'] = array(
'#type' => 'select',
'#title' => t('Unit used'),
'#options' => search_api_location_get_units(),
'#default_value' => '1',
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'select';
$form['search_api_location'][$key]['radius_options'] = array(
'#type' => 'textarea',
'#title' => t('Distance options'),
'#description' => t('Add one line per option for “Distance” you want to provide. The first part of each line is the distance in kilometers, everything after the first space is the label. Include a line starting with "- " to include a no-op option.'),
'#default_value' => "- -\n5 5 km\n10 10 km\n16.0935 10 mi",
'#states' => $states,
);
}
}
}
function search_api_location_page_ajax_callback(array $form, array &$form_state) {
return !empty($form['search_api_location']) ? $form['search_api_location'] : $form['options']['search_api_location'];
}
function search_api_location_page_edit_validate(array $form, array &$form_state) {
$form_values =& $form_state['values'];
if (!isset($form_values['search_api_location'])) {
if (isset($form_values['options'])) {
unset($form_values);
$form_values =& $form_state['values']['options'];
$form = $form['options'];
}
else {
return;
}
}
foreach ($form_values['search_api_location'] as $key => $values) {
if (empty($values['enabled'])) {
continue;
}
$sub_form = $form['search_api_location'][$key];
switch ($values['radius_type']) {
case 'fixed':
$value = $values['radius_value'];
if ($value != '' && !is_numeric($value) || (double) $value < 0) {
form_error($sub_form['radius_value'], t('Maximum distance must be a non-negative number.'));
}
break;
case 'select':
$options = array();
$lines = array_filter(array_map('trim', explode("\n", $values['radius_options'])));
foreach ($lines as $line) {
list($range, $label) = explode(' ', $line, 2);
if ($range == '-') {
$range = NULL;
}
elseif (is_numeric($range)) {
$range = (double) $range;
}
else {
continue;
}
$options[$range] = trim($label);
}
if (empty($options[$range])) {
form_error($sub_form['radius_options'], t('Specify at least one distance option.'));
}
$form_values['search_api_location'][$key]['radius_options'] = $options;
break;
}
}
}
function search_api_location_page_form_search_api_page_admin_edit_alter(&$form, &$form_state) {
$page = $form_state['page'];
$index = search_api_index_load($page->index_id);
if ($fields = search_api_location_get_location_fields($index)) {
$options = isset($page->options['search_api_location']) ? $page->options['search_api_location'] : array();
$form['#validate'][] = 'search_api_location_page_edit_validate';
$form['options']['search_api_location'] = array(
'#type' => 'fieldset',
'#title' => t('Location filters'),
'#collapsible' => TRUE,
'#tree' => TRUE,
'#prefix' => '<div id="search-api-loaction-fieldset">',
'#suffix' => '</div>',
);
$form['submit']['#weight'] = 5;
$radius_types = array(
'fixed' => t('Fixed value'),
'textfield' => t('Text field'),
'select' => t('Select field'),
);
$plugin_options = search_api_location_get_input_plugin_options();
$plugin_default = key($plugin_options);
$values =& $form_state['values']['options']['search_api_location'];
foreach ($fields as $key => $field) {
$css_key = '#edit-options-search-api-location-' . drupal_clean_css_identifier($key);
$states['visible'][$css_key . '-enabled']['checked'] = TRUE;
$options += array(
$key => array(),
);
$options[$key] += array(
'enabled' => FALSE,
'compact' => FALSE,
'plugin' => $plugin_default,
'plugin_settings' => array(),
'radius_type' => 'fixed',
'radius_value' => 5,
'radius_unit' => '1',
'radius_options' => "- -\n5 5 km\n10 10 km\n16.0935 10 mi",
);
if (is_array($options[$key]['radius_options'])) {
$radius_options = array();
foreach ($options[$key]['radius_options'] as $range => $label) {
$range = isset($range) ? $range : '-';
$radius_options[] = "{$range} {$label}";
}
$options[$key]['radius_options'] = implode("\n", $radius_options);
}
$form['options']['search_api_location'][$key] = array(
'#type' => 'fieldset',
'#title' => check_plain($field['name']),
'#collapsible' => TRUE,
);
$form['options']['search_api_location'][$key]['enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Include location filter'),
'#default_value' => $options[$key]['enabled'],
);
$form['options']['search_api_location'][$key]['compact'] = array(
'#type' => 'checkbox',
'#title' => t('Show filter in the search block'),
'#default_value' => $options[$key]['compact'],
'#states' => $states,
);
$form['options']['search_api_location'][$key]['plugin'] = array(
'#type' => 'select',
'#title' => t('Input method'),
'#description' => t('Select the method to use for parsing locations entered by the user.'),
'#options' => $plugin_options,
'#default_value' => $options[$key]['plugin'],
'#states' => $states,
'#ajax' => array(
'callback' => 'search_api_location_page_ajax_callback',
'wrapper' => 'search-api-loaction-fieldset',
),
);
$plugin_id = !empty($values[$key]['plugin']) ? $values[$key]['plugin'] : $options[$key]['plugin'];
$plugin = search_api_location_get_input_plugins($plugin_id);
$form['options']['search_api_location'][$key]['plugin_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Input method settings'),
'#description' => $plugin['description'],
'#states' => $states,
);
if (!empty($plugin['form callback'])) {
$plugin_options = $plugin_id == $options[$key]['plugin'] ? $options[$key]['plugin_settings'] : array();
$plugin_form = $plugin['form callback']($form_state, $plugin_options);
if ($plugin_form) {
$form['options']['search_api_location'][$key]['plugin_settings'] += $plugin_form;
}
}
$form['options']['search_api_location'][$key]['radius_type'] = array(
'#type' => 'select',
'#title' => t('Type of distance filter'),
'#options' => $radius_types,
'#default_value' => $options[$key]['radius_type'],
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'fixed';
$form['options']['search_api_location'][$key]['radius_value'] = array(
'#type' => 'textfield',
'#title' => t('Maximum distance from location (in kilometers)'),
'#default_value' => $options[$key]['radius_value'],
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'textfield';
$form['options']['search_api_location'][$key]['radius_unit'] = array(
'#type' => 'select',
'#title' => t('Unit used'),
'#options' => search_api_location_get_units(),
'#default_value' => $options[$key]['radius_unit'],
'#states' => $states,
);
$states['visible'][$css_key . '-radius-type']['value'] = 'select';
$form['options']['search_api_location'][$key]['radius_options'] = array(
'#type' => 'textarea',
'#title' => t('Distance options'),
'#description' => t('Add one line per option for “Distance” you want to provide. The first part of each line is the distance in kilometers, everything after the first space is the label. Include a line starting with "- " to include a no-op option.'),
'#default_value' => $options[$key]['radius_options'],
'#states' => $states,
);
}
}
}
function search_api_location_page_form_search_api_page_search_form_alter(&$form, &$form_state) {
$compact = TRUE;
$orig_form =& $form;
if (isset($form['form'])) {
$form =& $form['form'];
$compact = FALSE;
}
$page = search_api_page_load($form['id']['#value']);
$index = search_api_index_load($page->index_id);
$fields = search_api_location_get_location_fields($index);
if ($fields && !empty($page->options['search_api_location'])) {
$orig_form['#submit'][] = 'search_api_location_page_search_form_submit';
$units = search_api_location_get_units();
$form['submit_' . $page->id]['#weight'] = 5;
foreach ($page->options['search_api_location'] as $field => $options) {
if (empty($fields[$field]) || empty($options['enabled']) || $compact && empty($options['compact'])) {
continue;
}
$name = $fields[$field]['name'];
$name_parts = explode(' » ', $name);
if (count($name_parts) > 1) {
$name = $name_parts[count($name_parts) - 2];
}
$form[$field] = array(
'#type' => 'fieldset',
'#title' => check_plain($name),
'#attributes' => array(
'class' => array(
'container-inline',
),
),
);
$default = !empty($_GET['location']) ? $_GET['location'] : (!empty($_GET["{$field}-location"]) ? $_GET["{$field}-location"] : '');
$form[$field]["{$field}-location"] = array(
'#type' => 'textfield',
'#size' => $compact ? 10 : 20,
'#default_value' => $default,
);
switch ($options['radius_type']) {
case 'textfield':
$form[$field]["{$field}-radius"] = array(
'#type' => 'textfield',
'#title' => $compact ? t('within') : t('Maximum distance'),
'#size' => $compact ? 3 : 5,
'#element_validate' => array(
'search_api_location_validate_distance',
),
);
if (isset($units[$options['radius_unit']])) {
$form[$field]["{$field}-radius"]['#suffix'] = '<div>' . $units[$options['radius_unit']] . '</div>';
}
break;
case 'select':
$form[$field]["{$field}-radius"] = array(
'#type' => 'select',
'#title' => $compact ? t('within') : t('Maximum distance'),
'#options' => $options['radius_options'],
);
break;
}
$default = !empty($_GET['radius']) ? $_GET['radius'] : (!empty($_GET["{$field}-radius"]) ? $_GET["{$field}-radius"] : '');
if ($default) {
$form[$field]["{$field}-radius"]['#default_value'] = $default;
}
}
}
}
function search_api_location_page_search_form_submit(array $form, array &$form_state) {
if (is_array($form_state['redirect'])) {
list($redirect, $url_options) = $form_state['redirect'];
}
else {
$redirect = $form_state['redirect'];
$url_options = array();
}
$url_options += array(
'query' => array(),
);
$page = search_api_page_load($form_state['values']['id']);
$num = 0;
foreach ($page->options['search_api_location'] as $field) {
if (!empty($field['enabled'])) {
++$num;
}
}
if ($num == 1) {
$params = _search_api_location_page_filter_parameters($form_state['values'], FALSE);
$location = reset($params);
$field = key($params);
if ($field) {
$field = substr($field, 0, -9);
$url_options['query']['location'] = $location;
if (!empty($form_state['values'][$field . '-radius'])) {
$url_options['query']['radius'] = $form_state['values'][$field . '-radius'];
}
}
}
else {
$url_options['query'] += _search_api_location_page_filter_parameters($form_state['values']);
}
if ($url_options) {
$form_state['redirect'] = array(
$redirect,
$url_options,
);
}
}
function search_api_location_page_search_api_query_alter(SearchApiQueryInterface $query) {
if (!preg_match('/^search_api_page:(.*)$/', $query
->getOption('search id'), $m)) {
return;
}
$page = search_api_page_load_multiple(FALSE, array(
'path' => $m[1],
));
$page = reset($page);
if (!$page) {
return;
}
$location_options = $query
->getOption('search_api_location', array());
if (!empty($_GET['location'])) {
foreach ($page->options['search_api_location'] as $key => $field) {
if (!empty($field['enabled'])) {
$plugin = search_api_location_get_input_plugins($field['plugin']);
if (!$plugin) {
return;
}
$plugin_options = !empty($field['plugin_settings']) ? $field['plugin_settings'] : array();
$location = $plugin['input callback']($_GET['location'], $plugin_options);
if (!$location) {
drupal_set_message(t('The location %address could not be resolved and was ignored.', array(
'%address' => $_GET['location'],
)), 'warning');
return;
}
$location = explode(',', $location, 2);
$filter = array(
'field' => $key,
'lat' => $location[0],
'lon' => $location[1],
);
if (isset($_GET['radius'])) {
$filter['radius'] = $_GET['radius'];
if ($field['radius_type'] == 'textfield' && is_numeric($field['radius_unit'])) {
$filter['radius'] *= $field['radius_unit'];
}
}
$location_options[] = $filter;
break;
}
}
}
else {
foreach (_search_api_location_page_filter_parameters($_GET, FALSE) as $key => $value) {
$field = substr($key, 0, -9);
$field_options = $page->options['search_api_location'][$field];
$plugin = search_api_location_get_input_plugins($field_options['plugin']);
if (!$plugin) {
continue;
}
$plugin_options = !empty($field_options['plugin_settings']) ? $field_options['plugin_settings'] : array();
$location = $plugin['input callback']($value, $plugin_options);
if (!$location) {
drupal_set_message(t('The location %address could not be resolved and was ignored.', array(
'%address' => $value,
)), 'warning');
continue;
}
unset($radius);
if (!empty($_GET[$field . '-radius'])) {
$radius = $_GET[$field . '-radius'];
}
elseif (!empty($field_options['radius_type'])) {
if ($field_options['radius_type'] == 'fixed') {
$radius = $field_options['radius_value'];
}
}
$location = explode(',', $location, 2);
$filter = array(
'field' => $field,
'lat' => $location[0],
'lon' => $location[1],
);
if (isset($radius)) {
$filter['radius'] = $radius;
$field = $field_options;
if ($field['radius_type'] == 'textfield' && is_numeric($field['radius_unit'])) {
$filter['radius'] *= $field['radius_unit'];
}
}
$location_options[] = $filter;
}
}
if ($location_options) {
$query
->setOption('search_api_location', $location_options);
}
}
function _search_api_location_page_filter_parameters(array $params, $include_radius = TRUE) {
$ret = array();
foreach ($params as $key => $value) {
if (!$value) {
continue;
}
$pos = strrpos($key, '-');
if (!$pos) {
continue;
}
if (substr($key, $pos + 1) == 'location') {
$ret[$key] = $value;
if ($include_radius && isset($params[$key = substr($key, 0, $pos) . '-radius'])) {
$ret[$key] = $params[$key];
}
}
}
return $ret;
}