1971 lines
70 KiB
PHP
1971 lines
70 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Page callback that shows an overview of defined servers and indexes.
|
|
*/
|
|
function search_api_admin_overview() {
|
|
$base_path = drupal_get_path('module', 'search_api') . '/';
|
|
drupal_add_css($base_path . 'search_api.admin.css');
|
|
drupal_add_js($base_path . 'search_api.admin.js');
|
|
|
|
$servers = search_api_server_load_multiple(FALSE);
|
|
$indexes = array();
|
|
// When any entity was not normally created in the database, then show status for all.
|
|
$show_config_status = FALSE;
|
|
foreach (search_api_index_load_multiple(FALSE) as $index) {
|
|
$indexes[$index->server][$index->machine_name] = $index;
|
|
if (!$show_config_status && $index->status != ENTITY_CUSTOM) {
|
|
$show_config_status = TRUE;
|
|
}
|
|
}
|
|
// Show disabled servers after enabled ones.
|
|
foreach ($servers as $id => $server) {
|
|
if (!$server->enabled) {
|
|
unset($servers[$id]);
|
|
$servers[$id] = $server;
|
|
}
|
|
if (!$show_config_status && $server->status != ENTITY_CUSTOM) {
|
|
$show_config_status = TRUE;
|
|
}
|
|
}
|
|
|
|
$rows = array();
|
|
$t_server = array('data' => t('Server'), 'colspan' => 2);
|
|
$t_index = t('Index');
|
|
$t_enabled['data'] = array(
|
|
'#theme' => 'image',
|
|
'#path' => $base_path . 'enabled.png',
|
|
'#alt' => t('enabled'),
|
|
'#title' => t('enabled'),
|
|
);
|
|
$t_enabled['class'] = array('search-api-status');
|
|
$t_disabled['data'] = array(
|
|
'#theme' => 'image',
|
|
'#path' => $base_path . 'disabled.png',
|
|
'#alt' => t('disabled'),
|
|
'#title' => t('disabled'),
|
|
);
|
|
$t_disabled['class'] = array('search-api-status');
|
|
$t_enable = t('enable');
|
|
$t_disable = t('disable');
|
|
$t_edit = t('edit');
|
|
$pre_server = 'admin/config/search/search_api/server';
|
|
$pre_index = 'admin/config/search/search_api/index';
|
|
$enable = '/enable';
|
|
$disable = '/disable';
|
|
$edit = '/edit';
|
|
$edit_link_options['attributes']['class'][] = 'search-api-edit-menu-toggle';
|
|
foreach ($servers as $server) {
|
|
$url = $pre_server . '/' . $server->machine_name;
|
|
$row = array();
|
|
$row[] = $server->enabled ? $t_enabled : $t_disabled;
|
|
if ($show_config_status) {
|
|
$row[] = theme('entity_status', array('status' => $server->status));
|
|
}
|
|
$row[] = $t_server;
|
|
$row[] = l($server->name, $url);
|
|
$row[] = $server->enabled ? l($t_disable, $url . $disable) : l($t_enable, $url . $enable, array('query' => array('token' => drupal_get_token($server->machine_name))));
|
|
$row[] = l($t_edit, $url . $edit);
|
|
$row[] = _search_api_admin_delete_link($server);
|
|
$rows[] = $row;
|
|
if (!empty($indexes[$server->machine_name])) {
|
|
foreach ($indexes[$server->machine_name] as $index) {
|
|
$url = $pre_index . '/' . $index->machine_name;
|
|
$row = array();
|
|
$row[] = $index->enabled ? $t_enabled : $t_disabled;
|
|
if ($show_config_status) {
|
|
$row[] = theme('entity_status', array('status' => $index->status));
|
|
}
|
|
$row[] = '';
|
|
$row[] = $t_index;
|
|
$row[] = l($index->name, $url);
|
|
$row[] = $index->enabled
|
|
? l($t_disable, $url . $disable)
|
|
: ($server->enabled ? l($t_enable, $url . $enable, array('query' => array('token' => drupal_get_token($index->machine_name)))) : '');
|
|
$row[] = l($t_edit, $url . $edit, $edit_link_options) .
|
|
'<div class="search-api-edit-menu collapsed">' .
|
|
theme('links', array('links' => menu_contextual_links('search-api-index', $pre_index, array($index->machine_name)))) .
|
|
'</div>';
|
|
$row[] = _search_api_admin_delete_link($index);
|
|
$rows[] = $row;
|
|
}
|
|
}
|
|
}
|
|
if (!empty($indexes[''])) {
|
|
foreach ($indexes[''] as $index) {
|
|
$url = $pre_index . '/' . $index->machine_name;
|
|
$row = array();
|
|
$row[] = $t_disabled;
|
|
if ($show_config_status) {
|
|
$row[] = theme('entity_status', array('status' => $index->status));
|
|
}
|
|
$row[] = array('data' => $t_index, 'colspan' => 2);
|
|
$row[] = l($index->name, $url);
|
|
$row[] = '';
|
|
$row[] = l($t_edit, $url . $edit, $edit_link_options) .
|
|
'<div class="search-api-edit-menu collapsed">' .
|
|
theme('links', array('links' => menu_contextual_links('search-api-index', $pre_index, array($index->machine_name)))) .
|
|
'</div>';
|
|
$row[] = _search_api_admin_delete_link($index);
|
|
$rows[] = $row;
|
|
}
|
|
}
|
|
|
|
$header = array();
|
|
$header[] = t('Status');
|
|
if ($show_config_status) {
|
|
$header[] = t('Configuration');
|
|
}
|
|
$header[] = array('data' => t('Type'), 'colspan' => 2);
|
|
$header[] = t('Name');
|
|
$header[] = array('data' => t('Operations'), 'colspan' => 3);
|
|
|
|
return array(
|
|
'#theme' => 'table',
|
|
'#header' => $header,
|
|
'#rows' => $rows,
|
|
'#empty' => t('There are no search servers or indexes defined yet.'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param Entity $entity
|
|
* The index or server for which a link should be generated.
|
|
*
|
|
* @return string
|
|
* A link to a delete form for the entity, if applicable.
|
|
*/
|
|
function _search_api_admin_delete_link(Entity $entity) {
|
|
// Delete link only makes sense if entity is in the database (custom or overridden).
|
|
if ($entity->hasStatus(ENTITY_CUSTOM)) {
|
|
$type = $entity instanceof SearchApiServer ? 'server' : 'index';
|
|
$url = 'admin/config/search/search_api/' . $type . '/' . $entity->machine_name . '/delete';
|
|
$title = $entity->hasStatus(ENTITY_IN_CODE) ? t('revert') : t('delete');
|
|
return l($title, $url);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Form callback showing a form for adding a server.
|
|
*/
|
|
function search_api_admin_add_server(array $form, array &$form_state) {
|
|
drupal_set_title(t('Add server'));
|
|
|
|
$class = empty($form_state['values']['class']) ? '' : $form_state['values']['class'];
|
|
$form_state['server'] = entity_create('search_api_server', array());
|
|
|
|
if (empty($form_state['storage']['step_one'])) {
|
|
$form['name'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Server name'),
|
|
'#description' => t('Enter the displayed name for the new server.'),
|
|
'#maxlength' => 50,
|
|
'#required' => TRUE,
|
|
);
|
|
|
|
$form['machine_name'] = array(
|
|
'#type' => 'machine_name',
|
|
'#maxlength' => 50,
|
|
'#machine_name' => array(
|
|
'exists' => 'search_api_server_load',
|
|
),
|
|
);
|
|
|
|
$form['enabled'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enabled'),
|
|
'#description' => t('Select if the new server will be enabled after creation.'),
|
|
'#default_value' => TRUE,
|
|
);
|
|
$form['description'] = array(
|
|
'#type' => 'textarea',
|
|
'#title' => t('Server description'),
|
|
'#description' => t('Enter a description for the new server.'),
|
|
);
|
|
$form['class'] = array(
|
|
'#type' => 'select',
|
|
'#title' => t('Service class'),
|
|
'#description' => t('Choose a service class to use for this server.'),
|
|
'#options' => array('' => '< ' . t('Choose a service class') . ' >'),
|
|
'#required' => TRUE,
|
|
'#default_value' => $class,
|
|
'#ajax' => array(
|
|
'callback' => 'search_api_admin_add_server_ajax_callback',
|
|
'wrapper' => 'search-api-class-options',
|
|
),
|
|
);
|
|
}
|
|
elseif (!$class) {
|
|
$class = $form_state['storage']['step_one']['class'];
|
|
}
|
|
|
|
foreach (search_api_get_service_info() as $id => $info) {
|
|
if (empty($form_state['storage']['step_one'])) {
|
|
$form['class']['#options'][$id] = $info['name'];
|
|
}
|
|
|
|
if (!$class || $class != $id) {
|
|
continue;
|
|
}
|
|
|
|
$service = NULL;
|
|
if (class_exists($info['class'])) {
|
|
$service = new $info['class']($form_state['server']);
|
|
}
|
|
if (!($service instanceof SearchApiServiceInterface)) {
|
|
watchdog('search_api', t('Service class @id specifies an illegal class: @class', array('@id' => $id, '@class' => $info['class'])), NULL, WATCHDOG_ERROR);
|
|
continue;
|
|
}
|
|
$service_form = isset($form['options']['form']) ? $form['options']['form'] : array();
|
|
$service_form = $service->configurationForm($service_form, $form_state);
|
|
$form['options']['form'] = $service_form ? $service_form : array('#markup' => t('There are no configuration options for this service class.'));
|
|
$form['options']['class']['#type'] = 'value';
|
|
$form['options']['class']['#value'] = $class;
|
|
$form['options']['#type'] = 'fieldset';
|
|
$form['options']['#tree'] = TRUE;
|
|
$form['options']['#collapsible'] = TRUE;
|
|
$form['options']['#title'] = $info['name'];
|
|
$form['options']['#description'] = $info['description'];
|
|
}
|
|
$form['options']['#prefix'] = '<div id="search-api-class-options">';
|
|
$form['options']['#suffix'] = '</div>';
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Create server'),
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* AJAX callback that just returns the "options" array of the already built form
|
|
* array.
|
|
*/
|
|
function search_api_admin_add_server_ajax_callback(array $form, array &$form_state) {
|
|
return $form['options'];
|
|
}
|
|
|
|
/**
|
|
* Form validation callback for adding a server.
|
|
*
|
|
* Validates the machine name and calls the service class' validation handler.
|
|
*/
|
|
function search_api_admin_add_server_validate(array $form, array &$form_state) {
|
|
if (!empty($form_state['values']['machine_name'])) {
|
|
$name = $form_state['values']['machine_name'];
|
|
if (is_numeric($name)) {
|
|
form_set_error('machine_name', t('The machine name must not be a pure number.'));
|
|
}
|
|
}
|
|
|
|
if (empty($form_state['values']['options']['class'])) {
|
|
return;
|
|
}
|
|
$class = $form_state['values']['options']['class'];
|
|
$info = search_api_get_service_info($class);
|
|
$service = NULL;
|
|
if (class_exists($info['class'])) {
|
|
$service = new $info['class']($form_state['server']);
|
|
}
|
|
if (!($service instanceof SearchApiServiceInterface)) {
|
|
form_set_error('class', t('There seems to be something wrong with the selected service class.'));
|
|
return;
|
|
}
|
|
$form_state['values']['options']['service'] = $service;
|
|
$values = isset($form_state['values']['options']['form']) ? $form_state['values']['options']['form'] : array();
|
|
$service->configurationFormValidate($form['options']['form'], $values, $form_state);
|
|
}
|
|
|
|
/**
|
|
* Form submit callback for adding a server.
|
|
*/
|
|
function search_api_admin_add_server_submit(array $form, array &$form_state) {
|
|
form_state_values_clean($form_state);
|
|
$values = $form_state['values'];
|
|
|
|
if (!empty($form_state['storage']['step_one'])) {
|
|
$values += $form_state['storage']['step_one'];
|
|
unset($form_state['storage']);
|
|
}
|
|
|
|
if (empty($values['options']) || ($values['class'] != $values['options']['class'])) {
|
|
unset($values['options']);
|
|
$form_state['storage']['step_one'] = $values;
|
|
$form_state['rebuild'] = TRUE;
|
|
drupal_set_message(t('Please configure the used service.'));
|
|
return;
|
|
}
|
|
|
|
$options = isset($values['options']['form']) ? $values['options']['form'] : array();
|
|
unset($values['options']);
|
|
$form_state['server'] = $server = entity_create('search_api_server', $values);
|
|
$server->configurationFormSubmit($form['options']['form'], $options, $form_state);
|
|
$server->save();
|
|
$form_state['redirect'] = 'admin/config/search/search_api/server/' . $server->machine_name;
|
|
drupal_set_message(t('The server was successfully created.'));
|
|
}
|
|
|
|
/**
|
|
* Title callback for viewing or editing a server or index.
|
|
*/
|
|
function search_api_admin_item_title($object) {
|
|
return $object->name;
|
|
}
|
|
|
|
/**
|
|
* Displays a server's details.
|
|
*
|
|
* @param SearchApiServer $server
|
|
* The server to display.
|
|
* @param $action
|
|
* One of 'enable', 'disable', 'delete'; or NULL if the server is only viewed.
|
|
*/
|
|
function search_api_admin_server_view(SearchApiServer $server, $action = NULL) {
|
|
if (!empty($action)) {
|
|
if ($action == 'enable') {
|
|
if (isset($_GET['token']) && drupal_valid_token($_GET['token'], $server->machine_name)) {
|
|
if ($server->update(array('enabled' => 1))) {
|
|
drupal_set_message(t('The server was successfully enabled.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('The server could not be enabled. Check the logs for details.'), 'error');
|
|
}
|
|
drupal_goto('admin/config/search/search_api/server/' . $server->machine_name);
|
|
}
|
|
else {
|
|
return MENU_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else {
|
|
$ret = drupal_get_form('search_api_admin_confirm', 'server', $action, $server);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
drupal_set_title(search_api_admin_item_title($server));
|
|
$class = search_api_get_service_info($server->class);
|
|
$options = $server->viewSettings();
|
|
return array(
|
|
'#theme' => 'search_api_server',
|
|
'#id' => $server->id,
|
|
'#name' => $server->name,
|
|
'#machine_name' => $server->machine_name,
|
|
'#description' => $server->description,
|
|
'#enabled' => $server->enabled,
|
|
'#class_name' => $class['name'],
|
|
'#class_description' => $class['description'],
|
|
'#options' => $options,
|
|
'#status' => $server->status,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Theme function for displaying a server.
|
|
*
|
|
* @param array $variables
|
|
* An associative array containing:
|
|
* - id: The server's id.
|
|
* - name: The server's name.
|
|
* - machine_name: The server's machine name.
|
|
* - description: The server's description.
|
|
* - enabled: Boolean indicating whether the server is enabled.
|
|
* - class_name: The used service class' display name.
|
|
* - class_description: The used service class' description.
|
|
* - options: An HTML string or render array containing information about the
|
|
* server's service-specific settings.
|
|
* - status: The entity configuration status (in database, in code, etc.).
|
|
*/
|
|
function theme_search_api_server(array $variables) {
|
|
extract($variables);
|
|
$output = '';
|
|
|
|
$output .= '<h3>' . check_plain($name) . '</h3>' . "\n";
|
|
|
|
$output .= '<dl>' . "\n";
|
|
|
|
$output .= '<dt>' . t('Status') . '</dt>' . "\n";
|
|
$output .= '<dd>';
|
|
if ($enabled) {
|
|
$output .= t('enabled (!disable_link)', array('!disable_link' => l(t('disable'), 'admin/config/search/search_api/server/' . $machine_name . '/disable')));
|
|
}
|
|
else {
|
|
$output .= t('disabled (!enable_link)', array('!enable_link' => l(t('enable'), 'admin/config/search/search_api/server/' . $machine_name . '/enable', array('query' => array('token' => drupal_get_token($machine_name))))));
|
|
}
|
|
$output .= '</dd>' . "\n";
|
|
|
|
$output .= '<dt>' . t('Machine name') . '</dt>' . "\n";
|
|
$output .= '<dd>' . check_plain($machine_name) . '</dd>' . "\n";
|
|
|
|
if (!empty($description)) {
|
|
$output .= '<dt>' . t('Description') . '</dt>' . "\n";
|
|
$output .= '<dd>' . nl2br(check_plain($description)) . '</dd>' . "\n";
|
|
}
|
|
|
|
if (!empty($class_name)) {
|
|
$output .= '<dt>' . t('Service class') . '</dt>' . "\n";
|
|
$output .= '<dd><em>' . check_plain($class_name) . '</em>';
|
|
if (!empty($class_description)) {
|
|
$output .= '<p class="description">' . $class_description . '</p>';
|
|
}
|
|
$output .= '</dd>' . "\n";
|
|
}
|
|
|
|
if (!empty($options)) {
|
|
$output .= '<dt>' . t('Service options') . '</dt>' . "\n";
|
|
$output .= '<dd>' . "\n";
|
|
$output .= render($options);
|
|
$output .= '</dd>' . "\n";
|
|
}
|
|
|
|
$output .= '<dt>' . t('Configuration status') . '</dt>' . "\n";
|
|
$output .= '<dd>' . "\n";
|
|
$output .= theme('entity_status', array('status' => $status));
|
|
$output .= '</dd>' . "\n";
|
|
|
|
$output .= '</dl>';
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Edit a server's settings.
|
|
*
|
|
* @param SearchApiServer $server
|
|
* The server to edit.
|
|
*/
|
|
function search_api_admin_server_edit(array $form, array &$form_state, SearchApiServer $server) {
|
|
$form_state['server'] = $server;
|
|
|
|
$form['name'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Server name'),
|
|
'#description' => t('Enter the displayed name for the server.'),
|
|
'#maxlength' => 50,
|
|
'#default_value' => $server->name,
|
|
'#required' => TRUE,
|
|
);
|
|
$form['enabled'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enabled'),
|
|
'#default_value' => $server->enabled,
|
|
);
|
|
$form['description'] = array(
|
|
'#type' => 'textarea',
|
|
'#title' => t('Server description'),
|
|
'#description' => t('Enter a description for the new server.'),
|
|
'#default_value' => $server->description,
|
|
);
|
|
|
|
$class = search_api_get_service_info($server->class);
|
|
|
|
$service_options = array();
|
|
$service_options = $server->configurationForm($service_options, $form_state);
|
|
if ($service_options) {
|
|
$form['options']['form'] = $service_options;
|
|
}
|
|
$form['options']['#type'] = 'fieldset';
|
|
$form['options']['#tree'] = TRUE;
|
|
$form['options']['#collapsible'] = TRUE;
|
|
$form['options']['#title'] = $class['name'];
|
|
$form['options']['#description'] = $class['description'];
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Save settings'),
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Validation function for search_api_admin_server_edit.
|
|
*/
|
|
function search_api_admin_server_edit_validate(array $form, array &$form_state) {
|
|
$form_state['server']->configurationFormValidate($form['options']['form'], $form_state['values']['options']['form'], $form_state);
|
|
}
|
|
|
|
/**
|
|
* Submit function for search_api_admin_server_edit.
|
|
*/
|
|
function search_api_admin_server_edit_submit(array $form, array &$form_state) {
|
|
form_state_values_clean($form_state);
|
|
$values = $form_state['values'];
|
|
|
|
$server = $form_state['server'];
|
|
if (isset($values['options'])) {
|
|
$server->configurationFormSubmit($form['options']['form'], $values['options']['form'], $form_state);
|
|
}
|
|
unset($values['options']);
|
|
|
|
$server->update($values);
|
|
$form_state['redirect'] = 'admin/config/search/search_api/server/' . $server->machine_name;
|
|
drupal_set_message(t('The search server was successfully edited.'));
|
|
}
|
|
|
|
/**
|
|
* Form callback showing a form for adding an index.
|
|
*/
|
|
function search_api_admin_add_index(array $form, array &$form_state) {
|
|
drupal_set_title(t('Add index'));
|
|
|
|
$form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
|
|
$form['#tree'] = TRUE;
|
|
$form['name'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Index name'),
|
|
'#maxlength' => 50,
|
|
'#required' => TRUE,
|
|
);
|
|
|
|
$form['machine_name'] = array(
|
|
'#type' => 'machine_name',
|
|
'#maxlength' => 50,
|
|
'#machine_name' => array(
|
|
'exists' => 'search_api_index_load',
|
|
),
|
|
);
|
|
|
|
$form['item_type'] = array(
|
|
'#type' => 'select',
|
|
'#title' => t('Item type'),
|
|
'#description' => t('Select the type of items that will be indexed in this index. ' .
|
|
'This setting cannot be changed afterwards.'),
|
|
'#options' => array(),
|
|
'#required' => TRUE,
|
|
);
|
|
foreach (search_api_get_item_type_info() as $type => $info) {
|
|
$form['item_type']['#options'][$type] = $info['name'];
|
|
}
|
|
$form['enabled'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enabled'),
|
|
'#description' => t('This will only take effect if the selected server is also enabled.'),
|
|
'#default_value' => TRUE,
|
|
);
|
|
$form['description'] = array(
|
|
'#type' => 'textarea',
|
|
'#title' => t('Index description'),
|
|
);
|
|
$form['server'] = array(
|
|
'#type' => 'select',
|
|
'#title' => t('Server'),
|
|
'#description' => t('Select the server this index should reside on.'),
|
|
'#default_value' => '',
|
|
'#options' => array('' => t('< No server >'))
|
|
);
|
|
$servers = search_api_server_load_multiple(FALSE);
|
|
// List enabled servers first.
|
|
foreach ($servers as $server) {
|
|
if ($server->enabled) {
|
|
$form['server']['#options'][$server->machine_name] = $server->name;
|
|
}
|
|
}
|
|
foreach ($servers as $server) {
|
|
if (!$server->enabled) {
|
|
$form['server']['#options'][$server->machine_name] = t('@server_name (disabled)', array('@server_name' => $server->name));
|
|
}
|
|
}
|
|
$form['read_only'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Read only'),
|
|
'#description' => t('Do not write to this index or track the status of items in this index.'),
|
|
'#default_value' => FALSE,
|
|
);
|
|
$form['options']['index_directly'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Index items immediately'),
|
|
'#description' => t('Immediately index new or updated items instead of waiting for the next cron run. ' .
|
|
'This might have serious performance drawbacks and is generally not advised for larger sites.'),
|
|
'#default_value' => FALSE,
|
|
);
|
|
$form['options']['cron_limit'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Cron batch size'),
|
|
'#description' => t('Set how many items will be indexed at once when indexing items during a cron run. ' .
|
|
'"0" means that no items will be indexed by cron for this index, "-1" means that cron should index all items at once.'),
|
|
'#default_value' => SEARCH_API_DEFAULT_CRON_LIMIT,
|
|
'#size' => 4,
|
|
'#attributes' => array('class' => array('search-api-cron-limit')),
|
|
);
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Create index'),
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Validation callback for search_api_admin_add_index.
|
|
*/
|
|
function search_api_admin_add_index_validate(array $form, array &$form_state) {
|
|
$name = $form_state['values']['machine_name'];
|
|
if (is_numeric($name)) {
|
|
form_set_error('machine_name', t('The machine name must not be a pure number.'));
|
|
}
|
|
|
|
$cron_limit = $form_state['values']['options']['cron_limit'];
|
|
if ($cron_limit != '' . ((int) $cron_limit)) {
|
|
// We don't enforce stricter rules and treat all negative values as -1.
|
|
form_set_error('options[cron_limit]', t('The cron batch size must be an integer.'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit callback for search_api_admin_add_index.
|
|
*/
|
|
function search_api_admin_add_index_submit(array $form, array &$form_state) {
|
|
form_state_values_clean($form_state);
|
|
|
|
$values = $form_state['values'];
|
|
|
|
// Validation of whether the server of an enabled index is also enabled is
|
|
// done in the *_insert() function.
|
|
search_api_index_insert($values);
|
|
|
|
drupal_set_message(t('The index was successfully created. Please set up its indexed fields now.'));
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $values['machine_name'] . '/fields';
|
|
}
|
|
|
|
/**
|
|
* Displays an index' details.
|
|
*
|
|
* @param SearchApiIndex $index
|
|
* The index to display.
|
|
*/
|
|
function search_api_admin_index_view(SearchApiIndex $index = NULL, $action = NULL) {
|
|
if (empty($index)) {
|
|
return MENU_NOT_FOUND;
|
|
}
|
|
|
|
if (!empty($action)) {
|
|
if ($action == 'enable') {
|
|
if (isset($_GET['token']) && drupal_valid_token($_GET['token'], $index->machine_name)) {
|
|
if ($index->update(array('enabled' => 1))) {
|
|
drupal_set_message(t('The index was successfully enabled.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('The index could not be enabled. Check the logs for details.'), 'error');
|
|
}
|
|
drupal_goto('admin/config/search/search_api/index/' . $index->machine_name);
|
|
}
|
|
else {
|
|
return MENU_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else {
|
|
$ret = drupal_get_form('search_api_admin_confirm', 'index', $action, $index);
|
|
if ($ret) {
|
|
return $ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
$ret = array(
|
|
'#theme' => 'search_api_index',
|
|
'#id' => $index->id,
|
|
'#name' => $index->name,
|
|
'#machine_name' => $index->machine_name,
|
|
'#description' => $index->description,
|
|
'#item_type' => $index->item_type,
|
|
'#enabled' => $index->enabled,
|
|
'#server' => $index->server(),
|
|
'#options' => $index->options,
|
|
'#fields' => $index->getFields(),
|
|
'#status' => $index->status,
|
|
'#read_only' => $index->read_only,
|
|
);
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Theme function for displaying an index.
|
|
*
|
|
* @param array $variables
|
|
* An associative array containing:
|
|
* - id: The index's id.
|
|
* - name: The index' name.
|
|
* - machine_name: The index' machine name.
|
|
* - description: The index' description.
|
|
* - item_type: The type of items stored in this index.
|
|
* - enabled: Boolean indicating whether the index is enabled.
|
|
* - server: The server this index currently rests on, if any.
|
|
* - options: The index' options, like cron limit.
|
|
* - fields: All indexed fields of the index.
|
|
* - indexed_items: The number of items already indexed in their latest
|
|
* version on this index.
|
|
* - total_items: The total number of items that have to be indexed for this
|
|
* index.
|
|
* - status: The entity configuration status (in database, in code, etc.).
|
|
* - read_only: Boolean indicating whether this index is read only.
|
|
*/
|
|
function theme_search_api_index(array $variables) {
|
|
extract($variables);
|
|
|
|
$output = '';
|
|
|
|
$output .= '<h3>' . check_plain($name) . '</h3>' . "\n";
|
|
|
|
$output .= '<dl>' . "\n";
|
|
|
|
$output .= '<dt>' . t('Status') . '</dt>' . "\n";
|
|
$output .= '<dd>';
|
|
if ($enabled) {
|
|
$output .= t('enabled (!disable_link)', array('!disable_link' => l(t('disable'), 'admin/config/search/search_api/index/' . $machine_name . '/disable')));
|
|
}
|
|
elseif ($server && $server->enabled) {
|
|
$output .= t('disabled (!enable_link)', array('!enable_link' => l(t('enable'), 'admin/config/search/search_api/index/' . $machine_name . '/enable', array('query' => array('token' => drupal_get_token($machine_name))))));
|
|
}
|
|
else {
|
|
$output .= t('disabled');
|
|
}
|
|
$output .= '</dd>' . "\n";
|
|
|
|
$output .= '<dt>' . t('Machine name') . '</dt>' . "\n";
|
|
$output .= '<dd>' . check_plain($machine_name) . '</dd>' . "\n";
|
|
|
|
$output .= '<dt>' . t('Item type') . '</dt>' . "\n";
|
|
$type = search_api_get_item_type_info($item_type);
|
|
$type = $type['name'];
|
|
$output .= '<dd>' . check_plain($type) . '</dd>' . "\n";
|
|
|
|
if (!empty($description)) {
|
|
$output .= '<dt>' . t('Description') . '</dt>' . "\n";
|
|
$output .= '<dd>' . nl2br(check_plain($description)) . '</dd>' . "\n";
|
|
}
|
|
|
|
if (!empty($server)) {
|
|
$output .= '<dt>' . t('Server') . '</dt>' . "\n";
|
|
$output .= '<dd>' . l($server->name, 'admin/config/search/search_api/server/' . $server->machine_name);
|
|
if (!empty($server->description)) {
|
|
$output .= '<p class="description">' . nl2br(check_plain($server->description)) . '</p>';
|
|
}
|
|
$output .= '</dd>' . "\n";
|
|
}
|
|
|
|
if (!$read_only && !empty($options)) {
|
|
$output .= '<dt>' . t('Index options') . '</dt>' . "\n";
|
|
$output .= '<dd><dl>' . "\n";
|
|
$output .= '<dt>' . t('Cron batch size') . '</dt>' . "\n";
|
|
if (empty($options['cron_limit'])) {
|
|
$output .= '<dd>' . t("Don't index during cron runs") . '</dd>' . "\n";
|
|
}
|
|
elseif ($options['cron_limit'] < 0) {
|
|
$output .= '<dd>' . t('Unlimited') . '</dd>' . "\n";
|
|
}
|
|
else {
|
|
$output .= '<dd>' . format_plural($options['cron_limit'], '1 item per cron batch.', '@count items per cron batch.') . '</dd>' . "\n";
|
|
}
|
|
|
|
if (!empty($fields)) {
|
|
$fields_list = array();
|
|
foreach ($fields as $name => $field) {
|
|
if (search_api_is_text_type($field['type'])) {
|
|
$fields_list[] = t('@field (@boost x)', array('@field' => $field['name'], '@boost' => $field['boost']));
|
|
}
|
|
else {
|
|
$fields_list[] = check_plain($field['name']);
|
|
}
|
|
}
|
|
if ($fields_list) {
|
|
$output .= '<dt>' . t('Indexed fields') . '</dt>' . "\n";
|
|
$output .= '<dd>' . implode(', ', $fields_list) . '</dd>' . "\n";
|
|
}
|
|
}
|
|
|
|
$output .= '</dl></dd>' . "\n";
|
|
}
|
|
elseif ($read_only) {
|
|
$output .= '<dt>' . t('Read only') . '</dt>' . "\n";
|
|
$output .= '<dd>' . t('This index is read-only.') . '</dd>' . "\n";
|
|
}
|
|
|
|
$output .= '<dt>' . t('Configuration status') . '</dt>' . "\n";
|
|
$output .= '<dd>' . "\n";
|
|
$output .= theme('entity_status', array('status' => $status));
|
|
$output .= '</dd>' . "\n";
|
|
|
|
$output .= '</dl>';
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Form function for displaying an index status form.
|
|
*
|
|
* @param SearchApiIndex $index
|
|
* The index whose status should be displayed.
|
|
*/
|
|
function search_api_admin_index_status_form(array $form, array &$form_state, SearchApiIndex $index) {
|
|
$enabled = !empty($index->enabled);
|
|
$status = search_api_index_status($index);
|
|
$server = $index->server();
|
|
|
|
$form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
|
|
$form_state['index'] = $index;
|
|
|
|
$form['status_message'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Status'),
|
|
'#description' => $enabled ? t('The index is currently enabled.') : t('The index is currently disabled.'),
|
|
);
|
|
if (!empty($server->enabled)) {
|
|
$form['status'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => $enabled ? t('Disable') : t('Enable'),
|
|
);
|
|
}
|
|
|
|
if ($index->read_only) {
|
|
$form['read_only'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Read only'),
|
|
'#description' => t('The index is currently in read-only mode. ' .
|
|
'No new items will be indexed, nor will old ones be deleted.'),
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
if ($enabled) {
|
|
$form['progress'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Progress'),
|
|
);
|
|
$all = ($status['indexed'] == $status['total']);
|
|
if ($all) {
|
|
$form['progress']['#description'] = t('All items have been indexed (@total / @total).',
|
|
array('@total' => $status['total']));
|
|
}
|
|
elseif (!$status['indexed']) {
|
|
$form['progress']['#description'] = t('All items still need to be indexed (@total total).',
|
|
array('@total' => $status['total']));
|
|
}
|
|
else {
|
|
$percentage = (int) (100 * $status['indexed'] / $status['total']);
|
|
$form['progress']['#description'] = t('About @percentage% of all items have been indexed in their latest version (@indexed / @total).',
|
|
array('@indexed' => $status['indexed'], '@total' => $status['total'], '@percentage' => $percentage));
|
|
}
|
|
|
|
if (!$all) {
|
|
$form['index'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Index now'),
|
|
'#collapsible' => TRUE,
|
|
);
|
|
$form['index']['settings'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Advanced settings'),
|
|
'#collapsible' => TRUE,
|
|
'#collapsed' => TRUE,
|
|
);
|
|
$form['index']['settings']['limit'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Number of items to index'),
|
|
'#default_value' => -1,
|
|
'#size' => 4,
|
|
'#attributes' => array('class' => array('search-api-limit')),
|
|
'#description' => t('Number of items to index. Set to -1 for all items.'),
|
|
);
|
|
$batch_size = empty($index->options['cron_limit']) ? SEARCH_API_DEFAULT_CRON_LIMIT : $index->options['cron_limit'];
|
|
$form['index']['settings']['batch_size'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Number of items per batch run'),
|
|
'#default_value' => $batch_size,
|
|
'#size' => 4,
|
|
'#attributes' => array('class' => array('search-api-batch-size')),
|
|
'#description' => t('Number of items per batch run. Set to -1 for all items at once (not recommended). Defaults to the cron batch size of the index.'),
|
|
);
|
|
$form['index']['button'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Index now'),
|
|
);
|
|
$form['index']['total'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $status['total'],
|
|
);
|
|
$form['index']['remaining'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $status['total'] - $status['indexed'],
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($server) {
|
|
if ($enabled && $status['indexed'] > 0) {
|
|
$form['reindex'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Re-indexing'),
|
|
'#collapsible' => TRUE,
|
|
);
|
|
$form['reindex']['message'] = array(
|
|
'#type' => 'item',
|
|
'#description' => t('This will add all items to the index again (overwriting the index), but existing items in the index will remain searchable.'),
|
|
);
|
|
$form['reindex']['button'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Re-index content'),
|
|
);
|
|
}
|
|
|
|
$form['clear'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Clear index'),
|
|
'#collapsible' => TRUE,
|
|
);
|
|
$form['clear']['message'] = array(
|
|
'#type' => 'item',
|
|
'#description' => t('All items will be deleted from the index and have to be inserted again by normally indexing them. ' .
|
|
'Until all items are re-indexed, searches on this index will return incomplete results.<br />' .
|
|
'Use with care, in most cases rebuilding the index might be enough.'),
|
|
);
|
|
$form['clear']['button'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Clear index'),
|
|
);
|
|
}
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Validation function for search_api_admin_index_status_form.
|
|
*/
|
|
function search_api_admin_index_status_form_validate(array $form, array &$form_state) {
|
|
if ($form_state['values']['op'] == t('Index now') && !$form_state['values']['limit']) {
|
|
form_set_error('number', t('You have to set the number of items to index. Set to -1 for indexing all items.'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit function for search_api_admin_index_status_form.
|
|
*/
|
|
function search_api_admin_index_status_form_submit(array $form, array &$form_state) {
|
|
$redirect = &$form_state['redirect'];
|
|
$values = $form_state['values'];
|
|
$index = $form_state['index'];
|
|
$pre = 'admin/config/search/search_api/index/' . $index->machine_name;
|
|
switch ($values['op']) {
|
|
case t('Enable'):
|
|
$redirect = $pre . '/enable';
|
|
break;
|
|
case t('Disable'):
|
|
$redirect = $pre . '/disable';
|
|
break;
|
|
case t('Index now'):
|
|
if (!_search_api_batch_indexing_create($index, $values['batch_size'], $values['limit'], $values['remaining'])) {
|
|
drupal_set_message(t("Couldn't create a batch, please check the batch size and limit."), 'warning');
|
|
}
|
|
$redirect = $pre . '/status';
|
|
break;
|
|
case t('Re-index content'):
|
|
if ($index->reindex()) {
|
|
drupal_set_message(t('The index was successfully scheduled for re-indexing.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('An error has occurred while performing the desired action. Check the logs for details.'), 'error');
|
|
}
|
|
$redirect = $pre . '/status';
|
|
break;
|
|
case t('Clear index'):
|
|
if ($index->clear()) {
|
|
drupal_set_message(t('The index was successfully cleared.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('An error has occurred while performing the desired action. Check the logs for details.'), 'error');
|
|
}
|
|
$redirect = $pre . '/status';
|
|
break;
|
|
|
|
default:
|
|
throw new SearchApiException(t('Unknown action.'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit an index' settings.
|
|
*
|
|
* @param SearchApiIndex $index
|
|
* The index to edit.
|
|
*/
|
|
function search_api_admin_index_edit(array $form, array &$form_state, SearchApiIndex $index) {
|
|
$form_state['index'] = $index;
|
|
|
|
$form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
|
|
$form['#tree'] = TRUE;
|
|
$form['name'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Index name'),
|
|
'#maxlength' => 50,
|
|
'#default_value' => $index->name,
|
|
'#required' => TRUE,
|
|
);
|
|
$form['enabled'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Enabled'),
|
|
'#default_value' => $index->enabled,
|
|
// Can't enable an index lying on a disabled server, or no server at all.
|
|
'#disabled' => !$index->enabled && (!$index->server() || !$index->server()->enabled),
|
|
);
|
|
$form['description'] = array(
|
|
'#type' => 'textarea',
|
|
'#title' => t('Index description'),
|
|
'#default_value' => $index->description,
|
|
);
|
|
$form['server'] = array(
|
|
'#type' => 'select',
|
|
'#title' => t('Server'),
|
|
'#description' => t('Select the server this index should reside on.'),
|
|
'#default_value' => $index->server,
|
|
'#options' => array('' => t('< No server >'))
|
|
);
|
|
$servers = search_api_server_load_multiple(FALSE);
|
|
// List enabled servers first.
|
|
foreach ($servers as $server) {
|
|
if ($server->enabled) {
|
|
$form['server']['#options'][$server->machine_name] = $server->name;
|
|
}
|
|
}
|
|
foreach ($servers as $server) {
|
|
if (!$server->enabled) {
|
|
$form['server']['#options'][$server->machine_name] = t('@server_name (disabled)', array('@server_name' => $server->name));
|
|
}
|
|
}
|
|
$form['read_only'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Read only'),
|
|
'#description' => t('Do not write to this index or track the status of items in this index.'),
|
|
'#default_value' => $index->read_only,
|
|
);
|
|
$form['options']['index_directly'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Index items immediately'),
|
|
'#description' => t('Immediately index new or updated items instead of waiting for the next cron run. ' .
|
|
'This might have serious performance drawbacks and is generally not advised for larger sites.'),
|
|
'#default_value' => !empty($index->options['index_directly']),
|
|
'#states' => array(
|
|
'invisible' => array(':input[name="read_only"]' => array('checked' => TRUE)),
|
|
),
|
|
);
|
|
$form['options']['cron_limit'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Cron batch size'),
|
|
'#description' => t('Set how many items will be indexed at once when indexing items during a cron run. ' .
|
|
'"0" means that no items will be indexed by cron for this index, "-1" means that cron should index all items at once.'),
|
|
'#default_value' => isset($index->options['cron_limit']) ? $index->options['cron_limit'] : SEARCH_API_DEFAULT_CRON_LIMIT,
|
|
'#size' => 4,
|
|
'#attributes' => array('class' => array('search-api-cron-limit')),
|
|
'#element_validate' => array('_element_validate_integer'),
|
|
'#states' => array(
|
|
'invisible' => array(':input[name="read_only"]' => array('checked' => TRUE)),
|
|
),
|
|
);
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Save settings'),
|
|
);
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Submit callback for search_api_admin_index_edit.
|
|
*/
|
|
function search_api_admin_index_edit_submit(array $form, array &$form_state) {
|
|
form_state_values_clean($form_state);
|
|
|
|
$values = $form_state['values'];
|
|
$index = $form_state['index'];
|
|
$values['options'] += $index->options;
|
|
|
|
$ret = $index->update($values);
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name;
|
|
if ($ret) {
|
|
drupal_set_message(t('The search index was successfully edited.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('No values were changed.'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit an index' workflow (data alter callbacks, pre-/postprocessors, and their
|
|
* order).
|
|
*
|
|
* @param SearchApiIndex $index
|
|
* The index to edit.
|
|
*/
|
|
// Copied from filter_admin_format_form
|
|
function search_api_admin_index_workflow(array $form, array &$form_state, SearchApiIndex $index) {
|
|
$callback_info = search_api_get_alter_callbacks();
|
|
$processor_info = search_api_get_processors();
|
|
$options = empty($index->options) ? array() : $index->options;
|
|
|
|
$form_state['index'] = $index;
|
|
$form['#tree'] = TRUE;
|
|
$form['#attached']['js'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.js';
|
|
|
|
// Callbacks
|
|
|
|
$callbacks = empty($options['data_alter_callbacks']) ? array() : $options['data_alter_callbacks'];
|
|
$callback_objects = isset($form_state['callbacks']) ? $form_state['callbacks'] : array();
|
|
foreach ($callback_info as $name => $callback) {
|
|
if (!isset($callbacks[$name])) {
|
|
$callbacks[$name]['status'] = 0;
|
|
$callbacks[$name]['weight'] = $callback['weight'];
|
|
}
|
|
$settings = empty($callbacks[$name]['settings']) ? array() : $callbacks[$name]['settings'];
|
|
if (empty($callback_objects[$name]) && class_exists($callback['class'])) {
|
|
$callback_objects[$name] = new $callback['class']($index, $settings);
|
|
}
|
|
if (!(class_exists($callback['class']) && $callback_objects[$name] instanceof SearchApiAlterCallbackInterface)) {
|
|
watchdog('search_api', t('Data alteration @id specifies illegal callback class @class.', array('@id' => $name, '@class' => $callback['class'])), NULL, WATCHDOG_WARNING);
|
|
unset($callback_info[$name]);
|
|
unset($callbacks[$name]);
|
|
unset($callback_objects[$name]);
|
|
continue;
|
|
}
|
|
if (!$callback_objects[$name]->supportsIndex($index)) {
|
|
unset($callback_info[$name]);
|
|
unset($callbacks[$name]);
|
|
unset($callback_objects[$name]);
|
|
continue;
|
|
}
|
|
}
|
|
$form_state['callbacks'] = $callback_objects;
|
|
$form['#callbacks'] = $callbacks;
|
|
$form['callbacks'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Data alterations'),
|
|
'#description' => t('Select the alterations that will be executed on indexed items, and their order.'),
|
|
'#collapsible' => TRUE,
|
|
);
|
|
|
|
// Callback status.
|
|
$form['callbacks']['status'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Enabled data alterations'),
|
|
'#prefix' => '<div class="search-api-status-wrapper">',
|
|
'#suffix' => '</div>',
|
|
);
|
|
foreach ($callback_info as $name => $callback) {
|
|
$form['callbacks']['status'][$name] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => $callback['name'],
|
|
'#default_value' => $callbacks[$name]['status'],
|
|
'#parents' => array('callbacks', $name, 'status'),
|
|
'#description' => $callback['description'],
|
|
'#weight' => $callback['weight'],
|
|
);
|
|
}
|
|
|
|
// Callback order (tabledrag).
|
|
$form['callbacks']['order'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Data alteration processing order'),
|
|
'#theme' => 'search_api_admin_item_order',
|
|
'#table_id' => 'search-api-callbacks-order-table',
|
|
);
|
|
foreach ($callback_info as $name => $callback) {
|
|
$form['callbacks']['order'][$name]['item'] = array(
|
|
'#markup' => $callback['name'],
|
|
);
|
|
$form['callbacks']['order'][$name]['weight'] = array(
|
|
'#type' => 'weight',
|
|
'#delta' => 50,
|
|
'#default_value' => $callbacks[$name]['weight'],
|
|
'#parents' => array('callbacks', $name, 'weight'),
|
|
);
|
|
$form['callbacks']['order'][$name]['#weight'] = $callbacks[$name]['weight'];
|
|
}
|
|
|
|
// Callback settings.
|
|
$form['callbacks']['settings_title'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Callback settings'),
|
|
);
|
|
$form['callbacks']['settings'] = array(
|
|
'#type' => 'vertical_tabs',
|
|
);
|
|
|
|
foreach ($callback_info as $name => $callback) {
|
|
$settings_form = $callback_objects[$name]->configurationForm();
|
|
if (!empty($settings_form)) {
|
|
$form['callbacks']['settings'][$name] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => $callback['name'],
|
|
'#parents' => array('callbacks', $name, 'settings'),
|
|
'#weight' => $callback['weight'],
|
|
);
|
|
$form['callbacks']['settings'][$name] += $settings_form;
|
|
}
|
|
}
|
|
|
|
// Processors
|
|
|
|
$processors = empty($options['processors']) ? array() : $options['processors'];
|
|
$processor_objects = isset($form_state['processors']) ? $form_state['processors'] : array();
|
|
foreach ($processor_info as $name => $processor) {
|
|
if (!isset($processors[$name])) {
|
|
$processors[$name]['status'] = 0;
|
|
$processors[$name]['weight'] = $processor['weight'];
|
|
}
|
|
$settings = empty($processors[$name]['settings']) ? array() : $processors[$name]['settings'];
|
|
if (empty($processor_objects[$name]) && class_exists($processor['class'])) {
|
|
$processor_objects[$name] = new $processor['class']($index, $settings);
|
|
}
|
|
if (!(class_exists($processor['class']) && $processor_objects[$name] instanceof SearchApiProcessorInterface)) {
|
|
watchdog('search_api', t('Processor @id specifies illegal processor class @class.', array('@id' => $name, '@class' => $processor['class'])), NULL, WATCHDOG_WARNING);
|
|
unset($processor_info[$name]);
|
|
unset($processors[$name]);
|
|
unset($processor_objects[$name]);
|
|
continue;
|
|
}
|
|
if (!$processor_objects[$name]->supportsIndex($index)) {
|
|
unset($processor_info[$name]);
|
|
unset($processors[$name]);
|
|
unset($processor_objects[$name]);
|
|
continue;
|
|
}
|
|
}
|
|
$form_state['processors'] = $processor_objects;
|
|
$form['#processors'] = $processors;
|
|
$form['processors'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Processors'),
|
|
'#description' => t('Select processors which will pre- and post-process data at index and search time, and their order. ' .
|
|
'Most processors will only influence fulltext fields, but refer to their individual descriptions for details regarding their effect.'),
|
|
'#collapsible' => TRUE,
|
|
);
|
|
|
|
// Processor status.
|
|
$form['processors']['status'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Enabled processors'),
|
|
'#prefix' => '<div class="search-api-status-wrapper">',
|
|
'#suffix' => '</div>',
|
|
);
|
|
foreach ($processor_info as $name => $processor) {
|
|
$form['processors']['status'][$name] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => $processor['name'],
|
|
'#default_value' => $processors[$name]['status'],
|
|
'#parents' => array('processors', $name, 'status'),
|
|
'#description' => $processor['description'],
|
|
'#weight' => $processor['weight'],
|
|
);
|
|
}
|
|
|
|
// Processor order (tabledrag).
|
|
$form['processors']['order'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Processor processing order'),
|
|
'#description' => t('Set the order in which preprocessing will be done at index and search time. ' .
|
|
'Postprocessing of search results will be in the exact opposite direction.'),
|
|
'#theme' => 'search_api_admin_item_order',
|
|
'#table_id' => 'search-api-processors-order-table',
|
|
);
|
|
foreach ($processor_info as $name => $processor) {
|
|
$form['processors']['order'][$name]['item'] = array(
|
|
'#markup' => $processor['name'],
|
|
);
|
|
$form['processors']['order'][$name]['weight'] = array(
|
|
'#type' => 'weight',
|
|
'#delta' => 50,
|
|
'#default_value' => $processors[$name]['weight'],
|
|
'#parents' => array('processors', $name, 'weight'),
|
|
);
|
|
$form['processors']['order'][$name]['#weight'] = $processors[$name]['weight'];
|
|
}
|
|
|
|
// Processor settings.
|
|
$form['processors']['settings_title'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Processor settings'),
|
|
);
|
|
$form['processors']['settings'] = array(
|
|
'#type' => 'vertical_tabs',
|
|
);
|
|
|
|
foreach ($processor_info as $name => $processor) {
|
|
$settings_form = $processor_objects[$name]->configurationForm();
|
|
if (!empty($settings_form)) {
|
|
$form['processors']['settings'][$name] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => $processor['name'],
|
|
'#parents' => array('processors', $name, 'settings'),
|
|
'#weight' => $processor['weight'],
|
|
);
|
|
$form['processors']['settings'][$name] += $settings_form;
|
|
}
|
|
}
|
|
|
|
$form['actions'] = array('#type' => 'actions');
|
|
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Returns HTML for a processor/callback order form.
|
|
*
|
|
* @param array $variables
|
|
* An associative array containing:
|
|
* - element: A render element representing the form.
|
|
*/
|
|
function theme_search_api_admin_item_order(array $variables) {
|
|
$element = $variables['element'];
|
|
|
|
$rows = array();
|
|
foreach (element_children($element, TRUE) as $name) {
|
|
$element[$name]['weight']['#attributes']['class'][] = 'search-api-order-weight';
|
|
$rows[] = array(
|
|
'data' => array(
|
|
drupal_render($element[$name]['item']),
|
|
drupal_render($element[$name]['weight']),
|
|
),
|
|
'class' => array('draggable'),
|
|
);
|
|
}
|
|
$output = drupal_render_children($element);
|
|
$output .= theme('table', array('rows' => $rows, 'attributes' => array('id' => $element['#table_id'])));
|
|
drupal_add_tabledrag($element['#table_id'], 'order', 'sibling', 'search-api-order-weight', NULL, NULL, TRUE);
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Validation callback for search_api_admin_index_workflow.
|
|
*/
|
|
function search_api_admin_index_workflow_validate(array $form, array &$form_state) {
|
|
// Call validation functions.
|
|
foreach ($form_state['callbacks'] as $name => $callback) {
|
|
if (isset($form['callbacks']['settings'][$name]) && isset($form_state['values']['callbacks'][$name]['settings'])) {
|
|
$callback->configurationFormValidate($form['callbacks']['settings'][$name], $form_state['values']['callbacks'][$name]['settings'], $form_state);
|
|
}
|
|
}
|
|
foreach ($form_state['processors'] as $name => $processor) {
|
|
if (isset($form['processors']['settings'][$name]) && isset($form_state['values']['processors'][$name]['settings'])) {
|
|
$processor->configurationFormValidate($form['processors']['settings'][$name], $form_state['values']['processors'][$name]['settings'], $form_state);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit callback for search_api_admin_index_workflow.
|
|
*/
|
|
function search_api_admin_index_workflow_submit(array $form, array &$form_state) {
|
|
$values = $form_state['values'];
|
|
unset($values['callbacks']['settings']);
|
|
unset($values['processors']['settings']);
|
|
$index = $form_state['index'];
|
|
|
|
$options = empty($index->options) ? array() : $index->options;
|
|
$fields_set = !empty($options['fields']);
|
|
|
|
// Store callback and processor settings.
|
|
foreach ($form_state['callbacks'] as $name => $callback) {
|
|
$callback_form = isset($form['callbacks']['settings'][$name]) ? $form['callbacks']['settings'][$name] : array();
|
|
$values['callbacks'][$name] += array('settings' => array());
|
|
$values['callbacks'][$name]['settings'] = $callback->configurationFormSubmit($callback_form, $values['callbacks'][$name]['settings'], $form_state);
|
|
}
|
|
foreach ($form_state['processors'] as $name => $processor) {
|
|
$processor_form = isset($form['processors']['settings'][$name]) ? $form['processors']['settings'][$name] : array();
|
|
$values['processors'][$name] += array('settings' => array());
|
|
$values['processors'][$name]['settings'] = $processor->configurationFormSubmit($processor_form, $values['processors'][$name]['settings'], $form_state);
|
|
}
|
|
|
|
$types = search_api_field_types();
|
|
foreach ($form_state['callbacks'] as $name => $callback) {
|
|
// Check whether callback status has changed.
|
|
if ($values['callbacks'][$name]['status'] == empty($options['data_alter_callbacks'][$name]['status'])) {
|
|
if ($values['callbacks'][$name]['status']) {
|
|
// Callback was just enabled, add its fields.
|
|
$properties = $callback->propertyInfo();
|
|
if ($properties) {
|
|
foreach ($properties as $key => $field) {
|
|
$type = $field['type'];
|
|
$inner = search_api_extract_inner_type($type);
|
|
if ($inner != 'token' && empty($types[$inner])) {
|
|
// Someone apparently added a structure or entity as a property in a data-alter callback.
|
|
continue;
|
|
}
|
|
if ($inner == 'token' || (search_api_is_text_type($inner) && !empty($field['options list']))) {
|
|
$old = $type;
|
|
$type = 'string';
|
|
while (search_api_is_list_type($old)) {
|
|
$old = substr($old, 5, -1);
|
|
$type = "list<$type>";
|
|
}
|
|
}
|
|
$index->options['fields'][$key] = array(
|
|
'type' => $type,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Callback was just disabled, remove its fields.
|
|
$properties = $callback->propertyInfo();
|
|
if ($properties) {
|
|
foreach ($properties as $key => $field) {
|
|
unset($index->options['fields'][$key]);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($options['data_alter_callbacks']) || !isset($options['processors'])
|
|
|| $options['data_alter_callbacks'] != $values['callbacks']
|
|
|| $options['processors'] != $values['processors']) {
|
|
$index->options['data_alter_callbacks'] = $values['callbacks'];
|
|
$index->options['processors'] = $values['processors'];
|
|
|
|
// Save the already sorted arrays to avoid having to sort them at each use.
|
|
uasort($index->options['data_alter_callbacks'], 'search_api_admin_element_compare');
|
|
uasort($index->options['processors'], 'search_api_admin_element_compare');
|
|
|
|
// Reset the index's internal property cache to correctly incorporate the
|
|
// new data alterations.
|
|
$index->resetCaches();
|
|
|
|
$index->save();
|
|
$index->reindex();
|
|
drupal_set_message(t("The search index' workflow was successfully edited. " .
|
|
'All content was scheduled for re-indexing so the new settings can take effect.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('No values were changed.'));
|
|
}
|
|
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name . '/workflow';
|
|
}
|
|
|
|
/**
|
|
* Sort callback sorting array elements by their "weight" key, if present.
|
|
*
|
|
* @see element_sort
|
|
*/
|
|
function search_api_admin_element_compare($a, $b) {
|
|
$a_weight = (is_array($a) && isset($a['weight'])) ? $a['weight'] : 0;
|
|
$b_weight = (is_array($b) && isset($b['weight'])) ? $b['weight'] : 0;
|
|
if ($a_weight == $b_weight) {
|
|
return 0;
|
|
}
|
|
return ($a_weight < $b_weight) ? -1 : 1;
|
|
}
|
|
|
|
/**
|
|
* Select the indexed fields.
|
|
*
|
|
* @param SearchApiIndex $index
|
|
* The index to edit.
|
|
*/
|
|
function search_api_admin_index_fields(array $form, array &$form_state, SearchApiIndex $index) {
|
|
$options = $index->getFields(FALSE, TRUE);
|
|
$fields = $options['fields'];
|
|
$additional = $options['additional fields'];
|
|
|
|
// An array of option arrays for types, keyed by nesting level.
|
|
$types = array(0 => search_api_field_types());
|
|
$fulltext_type = array(0 => 'text');
|
|
$entity_types = entity_get_info();
|
|
$default_types = search_api_default_field_types();
|
|
$boosts = drupal_map_assoc(array('0.1', '0.2', '0.3', '0.5', '0.8', '1.0', '2.0', '3.0', '5.0', '8.0', '13.0', '21.0'));
|
|
|
|
$form_state['index'] = $index;
|
|
$form['#theme'] = 'search_api_admin_fields_table';
|
|
$form['#tree'] = TRUE;
|
|
$form['description'] = array(
|
|
'#type' => 'item',
|
|
'#title' => t('Select fields to index'),
|
|
'#description' => t('<p>The datatype of a field determines how it can be used for searching and filtering. ' .
|
|
'The boost is used to give additional weight to certain fields, e.g. titles or tags. It only takes effect for fulltext fields.</p>' .
|
|
'<p>Whether detailed field types are supported depends on the type of server this index resides on. ' .
|
|
'In any case, fields of type "Fulltext" will always be fulltext-searchable.</p>'),
|
|
);
|
|
if ($index->server) {
|
|
$form['description']['#description'] .= '<p>' . t('Check the <a href="@server-url">' . "server's</a> service class description for details.",
|
|
array('@server-url' => url('admin/config/search/search_api/server/' . $index->server))) . '</p>';
|
|
}
|
|
foreach ($fields as $key => $info) {
|
|
$form['fields'][$key]['title']['#markup'] = check_plain($info['name']);
|
|
if (isset($info['description'])) {
|
|
$form['fields'][$key]['description'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $info['description'],
|
|
);
|
|
}
|
|
$form['fields'][$key]['indexed'] = array(
|
|
'#type' => 'checkbox',
|
|
'#default_value' => $info['indexed'],
|
|
);
|
|
if (empty($info['entity_type'])) {
|
|
// Determine the correct type options (i.e., with the correct nesting level).
|
|
$level = search_api_list_nesting_level($info['type']);
|
|
if (empty($types[$level])) {
|
|
$type_prefix = str_repeat('list<', $level);
|
|
$type_suffix = str_repeat('>', $level);
|
|
$types[$level] = array();
|
|
foreach ($types[0] as $type => $name) {
|
|
// We use the singular name for list types, since the user usually doesn't care about the nesting level.
|
|
$types[$level][$type_prefix . $type . $type_suffix] = $name;
|
|
}
|
|
$fulltext_type[$level] = $type_prefix . 'text' . $type_suffix;
|
|
}
|
|
$css_key = '#edit-fields-' . drupal_clean_css_identifier($key);
|
|
$form['fields'][$key]['type'] = array(
|
|
'#type' => 'select',
|
|
'#options' => $types[$level],
|
|
'#default_value' => isset($info['real_type']) ? $info['real_type'] : $info['type'],
|
|
'#states' => array(
|
|
'visible' => array(
|
|
$css_key . '-indexed' => array('checked' => TRUE),
|
|
),
|
|
),
|
|
);
|
|
$form['fields'][$key]['boost'] = array(
|
|
'#type' => 'select',
|
|
'#options' => $boosts,
|
|
'#default_value' => $info['boost'],
|
|
'#states' => array(
|
|
'visible' => array(
|
|
$css_key . '-indexed' => array('checked' => TRUE),
|
|
$css_key . '-type' => array('value' => $fulltext_type[$level]),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
else {
|
|
// This is an entity.
|
|
$label = $entity_types[$info['entity_type']]['label'];
|
|
if (!isset($entity_description_added)) {
|
|
$form['description']['#description'] .= '<p>' .
|
|
t('Note that indexing an entity-valued field (like %field, which has type %type) directly will only index the entity ID. ' .
|
|
'This will be used for filtering and also sorting (which might not be what you expect). ' .
|
|
'The entity label will usually be used when displaying the field, though. ' .
|
|
'Use the "Add related fields" option at the bottom for indexing other fields of related entities.',
|
|
array('%field' => $info['name'], '%type' => $label)) . '</p>';
|
|
$entity_description_added = TRUE;
|
|
}
|
|
$form['fields'][$key]['type'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $info['type'],
|
|
);
|
|
$form['fields'][$key]['entity_type'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $info['entity_type'],
|
|
);
|
|
$form['fields'][$key]['type_name'] = array(
|
|
'#markup' => check_plain($label),
|
|
);
|
|
$form['fields'][$key]['boost'] = array(
|
|
'#type' => 'value',
|
|
'#value' => $info['boost'],
|
|
);
|
|
$form['fields'][$key]['boost_text'] = array(
|
|
'#markup' => ' ',
|
|
);
|
|
}
|
|
if ($key == 'search_api_language') {
|
|
// Is treated specially to always index the language.
|
|
$form['fields'][$key]['type']['#default_value'] = 'string';
|
|
$form['fields'][$key]['type']['#disabled'] = TRUE;
|
|
$form['fields'][$key]['boost']['#default_value'] = '1.0';
|
|
$form['fields'][$key]['boost']['#disabled'] = TRUE;
|
|
$form['fields'][$key]['indexed']['#default_value'] = 1;
|
|
$form['fields'][$key]['indexed']['#disabled'] = TRUE;
|
|
}
|
|
}
|
|
|
|
$form['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Save changes'),
|
|
);
|
|
|
|
if ($additional) {
|
|
reset($additional);
|
|
$form['additional'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Add related fields'),
|
|
'#description' => t('There are entities related to entities of this type. ' .
|
|
'You can add their fields to the list above so they can be indexed too.') . '<br />',
|
|
'#collapsible' => TRUE,
|
|
'#collapsed' => TRUE,
|
|
'#attributes' => array('class' => array('container-inline')),
|
|
'field' => array(
|
|
'#type' => 'select',
|
|
'#options' => $additional,
|
|
'#default_value' => key($additional),
|
|
),
|
|
'add' => array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Add fields'),
|
|
),
|
|
);
|
|
}
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Helper function for building the field list for an index.
|
|
*
|
|
* @deprecated Use SearchApiIndex::getFields() instead.
|
|
*/
|
|
function _search_api_admin_get_fields(SearchApiIndex $index, EntityMetadataWrapper $wrapper) {
|
|
$fields = empty($index->options['fields']) ? array() : $index->options['fields'];
|
|
$additional = array();
|
|
$entity_types = entity_get_info();
|
|
|
|
// First we need all already added prefixes.
|
|
$added = array();
|
|
foreach (array_keys($fields) as $key) {
|
|
$key = substr($key, 0, strrpos($key, ':'));
|
|
$added[$key] = TRUE;
|
|
}
|
|
|
|
// Then we walk through all properties and look if they are already contained in one of the arrays.
|
|
// Since this uses an iterative instead of a recursive approach, it is a bit complicated, with three arrays tracking the current depth.
|
|
|
|
// A wrapper for a specific field name prefix, e.g. 'user:' mapped to the user wrapper
|
|
$wrappers = array('' => $wrapper);
|
|
// Display names for the prefixes
|
|
$prefix_names = array('' => '');
|
|
// The list nesting level for entities with a certain prefix
|
|
$nesting_levels = array('' => 0);
|
|
|
|
$types = search_api_default_field_types();
|
|
$flat = array();
|
|
while ($wrappers) {
|
|
foreach ($wrappers as $prefix => $wrapper) {
|
|
$prefix_name = $prefix_names[$prefix];
|
|
// Deal with lists of entities.
|
|
$nesting_level = $nesting_levels[$prefix];
|
|
$type_prefix = str_repeat('list<', $nesting_level);
|
|
$type_suffix = str_repeat('>', $nesting_level);
|
|
if ($nesting_level) {
|
|
$info = $wrapper->info();
|
|
// The real nesting level of the wrapper, not the accumulated one.
|
|
$level = search_api_list_nesting_level($info['type']);
|
|
for ($i = 0; $i < $level; ++$i) {
|
|
$wrapper = $wrapper[0];
|
|
}
|
|
}
|
|
// Now look at all properties.
|
|
foreach ($wrapper as $property => $value) {
|
|
$info = $value->info();
|
|
// We hide the complexity of multi-valued types from the user here.
|
|
$type = search_api_extract_inner_type($info['type']);
|
|
// Treat Entity API type "token" as our "string" type.
|
|
// Also let text fields with limited options be of type "string" by default.
|
|
if ($type == 'token' || ($type == 'text' && !empty($info['options list']))) {
|
|
// Inner type is changed to "string".
|
|
$type = 'string';
|
|
// Set the field type accordingly.
|
|
$info['type'] = search_api_nest_type('string', $info['type']);
|
|
}
|
|
$info['type'] = $type_prefix . $info['type'] . $type_suffix;
|
|
$key = $prefix . $property;
|
|
if (isset($types[$type]) || isset($entity_types[$type])) {
|
|
if (isset($fields[$key])) {
|
|
// This field is already known in the index configuration.
|
|
$fields[$key]['name'] = $prefix_name . $info['label'];
|
|
$fields[$key]['description'] = empty($info['description']) ? NULL : $info['description'];
|
|
$flat[$key] = $fields[$key];
|
|
// Update its type.
|
|
if (isset($entity_types[$type])) {
|
|
// Always enforce the proper entity type.
|
|
$flat[$key]['type'] = $info['type'];
|
|
}
|
|
else {
|
|
// Else, only update the nesting level.
|
|
$set_type = search_api_extract_inner_type(isset($flat[$key]['real_type']) ? $flat[$key]['real_type'] : $flat[$key]['type']);
|
|
$flat[$key]['type'] = $info['type'];
|
|
$flat[$key]['real_type'] = search_api_nest_type($set_type, $info['type']);
|
|
}
|
|
}
|
|
else {
|
|
$flat[$key] = array(
|
|
'name' => $prefix_name . $info['label'],
|
|
'description' => empty($info['description']) ? NULL : $info['description'],
|
|
'type' => $info['type'],
|
|
'boost' => '1.0',
|
|
'indexed' => FALSE,
|
|
);
|
|
}
|
|
}
|
|
if (empty($types[$type])) {
|
|
if (isset($added[$key])) {
|
|
// Visit this entity/struct in a later iteration.
|
|
$wrappers[$key . ':'] = $value;
|
|
$prefix_names[$key . ':'] = $prefix_name . $info['label'] . ' » ';
|
|
$nesting_levels[$key . ':'] = search_api_list_nesting_level($info['type']);
|
|
}
|
|
else {
|
|
$name = $prefix_name . $info['label'];
|
|
// Add machine names to discern fields with identical labels.
|
|
if (isset($used_names[$name])) {
|
|
if ($used_names[$name] !== FALSE) {
|
|
$additional[$used_names[$name]] .= ' [' . $used_names[$name] . ']';
|
|
$used_names[$name] = FALSE;
|
|
}
|
|
$name .= ' [' . $key . ']';
|
|
}
|
|
$additional[$key] = $name;
|
|
$used_names[$name] = $key;
|
|
}
|
|
}
|
|
}
|
|
unset($wrappers[$prefix]);
|
|
}
|
|
}
|
|
|
|
$options = array();
|
|
$options['fields'] = $flat;
|
|
$options['additional fields'] = $additional;
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Returns HTML for a field list form.
|
|
*
|
|
* @param array $variables
|
|
* An associative array containing:
|
|
* - element: A render element representing the form.
|
|
*/
|
|
function theme_search_api_admin_fields_table($variables) {
|
|
$form = $variables['element'];
|
|
$header = array(t('Field'), t('Indexed'), t('Type'), t('Boost'));
|
|
|
|
$rows = array();
|
|
foreach (element_children($form['fields']) as $name) {
|
|
$row = array();
|
|
foreach (element_children($form['fields'][$name]) as $field) {
|
|
if ($cell = render($form['fields'][$name][$field])) {
|
|
$row[] = $cell;
|
|
}
|
|
}
|
|
if (empty($form['fields'][$name]['description']['#value'])) {
|
|
$rows[] = $row;
|
|
}
|
|
else {
|
|
$rows[] = array(
|
|
'data' => $row,
|
|
'title' => strip_tags($form['fields'][$name]['description']['#value']),
|
|
);
|
|
}
|
|
}
|
|
|
|
$submit = $form['submit'];
|
|
$additional = isset($form['additional']) ? $form['additional'] : FALSE;
|
|
unset($form['submit'], $form['additional']);
|
|
$output = drupal_render_children($form);
|
|
$output .= theme('table', array('header' => $header, 'rows' => $rows));
|
|
$output .= render($submit);
|
|
if ($additional) {
|
|
$output .= render($additional);
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Submit function for search_api_admin_index_fields.
|
|
*/
|
|
function search_api_admin_index_fields_submit(array $form, array &$form_state) {
|
|
$index = $form_state['index'];
|
|
$options = isset($index->options) ? $index->options : array();
|
|
if ($form_state['values']['op'] == t('Save changes')) {
|
|
$fields = $form_state['values']['fields'];
|
|
$default_types = search_api_default_field_types();
|
|
$custom_types = search_api_get_data_type_info();
|
|
foreach ($fields as $name => $field) {
|
|
if (empty($field['indexed'])) {
|
|
unset($fields[$name]);
|
|
}
|
|
else {
|
|
// Don't store the description. "indexed" is implied.
|
|
unset($fields[$name]['description'], $fields[$name]['indexed']);
|
|
// For non-default types, set type to the fallback and only real_type to
|
|
// the custom type.
|
|
$inner_type = search_api_extract_inner_type($field['type']);
|
|
if (!isset($default_types[$inner_type])) {
|
|
$fields[$name]['real_type'] = $field['type'];
|
|
$fields[$name]['type'] = search_api_nest_type($custom_types[$inner_type]['fallback'], $field['type']);
|
|
}
|
|
// Boost defaults to 1.0.
|
|
if ($field['boost'] == '1.0') {
|
|
unset($fields[$name]['boost']);
|
|
}
|
|
}
|
|
}
|
|
$options['fields'] = $fields;
|
|
unset($options['additional fields']);
|
|
$ret = $index->update(array('options' => $options));
|
|
|
|
if ($ret) {
|
|
drupal_set_message(t('The indexed fields were successfully changed. ' .
|
|
'The index was cleared and will have to be re-indexed with the new settings.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('No values were changed.'));
|
|
}
|
|
if (isset($index->options['data_alter_callbacks']) || isset($index->options['processors'])) {
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name . '/fields';
|
|
}
|
|
else {
|
|
drupal_set_message(t('Please set up the index workflow.'));
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name . '/workflow';
|
|
}
|
|
return;
|
|
}
|
|
// Adding a related entity's fields.
|
|
$prefix = $form_state['values']['additional']['field'];
|
|
$options['additional fields'][$prefix] = $prefix;
|
|
$ret = $index->update(array('options' => $options));
|
|
|
|
if ($ret) {
|
|
drupal_set_message(t('The available fields were successfully changed.'));
|
|
}
|
|
else {
|
|
drupal_set_message(t('No values were changed.'));
|
|
}
|
|
$form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name . '/fields';
|
|
}
|
|
|
|
|
|
/**
|
|
* Helper function for displaying a generic confirmation form.
|
|
*
|
|
* @return
|
|
* Either a form array, or FALSE if this combination of type and action is
|
|
* not supported.
|
|
*/
|
|
function search_api_admin_confirm(array $form, array &$form_state, $type, $action, Entity $entity) {
|
|
switch ($type) {
|
|
case 'server':
|
|
switch ($action) {
|
|
case 'disable':
|
|
$text = array(
|
|
t('Disable server @name', array('@name' => $entity->name)),
|
|
t('Do you really want to disable this server?'),
|
|
t('This will disable both the server and all associated indexes. ' .
|
|
"Searches on these indexes won't be available until they are re-enabled."),
|
|
t('The server and its indexes were successfully disabled.'),
|
|
);
|
|
break;
|
|
case 'delete':
|
|
if ($entity->hasStatus(ENTITY_OVERRIDDEN)) {
|
|
$text = array(
|
|
t('Revert server @name', array('@name' => $entity->name)),
|
|
t('Do you really want to revert this server?'),
|
|
t('This will revert all settings for this server back to the defaults. This action cannot be undone.'),
|
|
t('The server settings have been successfully reverted.'),
|
|
);
|
|
}
|
|
else {
|
|
$text = array(
|
|
t('Delete server @name', array('@name' => $entity->name)),
|
|
t('Do you really want to delete this server?'),
|
|
t('This will delete the server and disable all associated indexes. ' .
|
|
"Searches on these indexes won't be available until they are moved to another server and re-enabled."),
|
|
t('The server was successfully deleted.'),
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case 'index':
|
|
switch ($action) {
|
|
case 'disable':
|
|
$text = array(
|
|
t('Disable index @name', array('@name' => $entity->name)),
|
|
t('Do you really want to disable this index?'),
|
|
t("Searches on this index won't be available until it is re-enabled."),
|
|
t('The index was successfully disabled.'),
|
|
);
|
|
break;
|
|
case 'delete':
|
|
if ($entity->hasStatus(ENTITY_OVERRIDDEN)) {
|
|
$text = array(
|
|
t('Revert index @name', array('@name' => $entity->name)),
|
|
t('Do you really want to revert this index?'),
|
|
t('This will revert all settings on this index back to the defaults. This action cannot be undone.'),
|
|
t('The index settings have been successfully reverted.'),
|
|
);
|
|
}
|
|
else {
|
|
$text = array(
|
|
t('Delete index @name', array('@name' => $entity->name)),
|
|
t('Do you really want to delete this index?'),
|
|
t('This will remove the index from the server and delete all settings. ' .
|
|
'All data on this index will be lost.'),
|
|
t('The index has been successfully deleted.'),
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
$form = array(
|
|
'type' => array(
|
|
'#type' => 'value',
|
|
'#value' => $type,
|
|
),
|
|
'action' => array(
|
|
'#type' => 'value',
|
|
'#value' => $action,
|
|
),
|
|
'id' => array(
|
|
'#type' => 'value',
|
|
'#value' => $entity->machine_name,
|
|
),
|
|
'message' => array(
|
|
'#type' => 'value',
|
|
'#value' => $text[3],
|
|
),
|
|
);
|
|
$desc = "<h3>{$text[1]}</h3><p>{$text[2]}</p>";
|
|
return confirm_form($form, $text[0], "admin/config/search/search_api/$type/{$entity->machine_name}", $desc);
|
|
}
|
|
|
|
/**
|
|
* Submit function for search_api_admin_confirm().
|
|
*/
|
|
function search_api_admin_confirm_submit(array $form, array &$form_state) {
|
|
$values = $form_state['values'];
|
|
|
|
$type = $values['type'];
|
|
$action = $values['action'];
|
|
$id = $values['id'];
|
|
|
|
$function = "search_api_{$type}_{$action}";
|
|
if ($function($id)) {
|
|
drupal_set_message($values['message']);
|
|
}
|
|
else {
|
|
drupal_set_message(t('An error has occurred while performing the desired action. Check the logs for details.'), 'error');
|
|
}
|
|
|
|
$form_state['redirect'] = $action == 'delete'
|
|
? "admin/config/search/search_api"
|
|
: "admin/config/search/search_api/$type/$id";
|
|
}
|