Skip to content
search_autocomplete.form.configure.inc 12.7 KiB
Newer Older
<?php

/**
 * @file
 * Search Autocomplete
 * Helper functions to retrive suggestions from database
 *
 * Sponsored by:
 * www.axiomcafe.fr
 */

/**
 * MENU CALLBACK: Define the form to configure the suggestions.
 *
 * @return array
 *   A rendered form.
 */
function search_autocomplete_form_configure($form, &$form_state) {
  $fid = arg(4);

  $result = db_select('search_autocomplete_forms', 'f')
    ->fields('f')
    ->condition('fid', $fid)
    ->execute()
    ->fetchAllAssoc('fid');

  foreach ($result as $item) {
    $form['fid'] = array(
      '#type' => 'hidden',
      '#value' => $fid,
    );
    // ------------------------------------------------------------------.
    // HOW - How to display Search Autocomplete suggestions.
    $form['search_autocomplete_how'] = array(
      '#type'           => 'fieldset',
      '#title'          => t('HOW - How to display Search Autocomplete suggestions?'),
      '#collapsible'    => TRUE,
    // Minimum characters to set autocompletion on.
    $form['search_autocomplete_how']['min_char'] = array(
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#type'           => 'textfield',
      '#title'          => t('Minimum keyword size that uncouple autocomplete search'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#description'    => t('Please enter the minimum number of character a user must input before autocompletion starts.'),
      '#default_value'  => $item->min_char,
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#maxlength'      => 2,
    // Number of suggestions to display.
    $form['search_autocomplete_how']['max_sug'] = array(
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#type'           => 'textfield',
      '#title'          => t('Limit of the autocomplete search result'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#description'    => t('Please enter the maximim number of suggestion to display.'),
      '#default_value'  => $item->max_sug,
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#maxlength'      => 2,
    // Check if form should be autosubmitted.
    $form['search_autocomplete_how']['no_results'] = array(
      '#type'           => 'textfield',
      '#title'          => t('Behaviour when no suggestions are found'),
      '#description'    => t('Enter a message to display when no results are found. Leave empty for no message.'),
      '#default_value'  => $item->no_results,
      '#maxlength'      => 50,
    // Check if form should be autosubmitted.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_how']['auto_submit'] = array(
      '#type'           => 'checkbox',
      '#title'          => t('Auto Submit'),
      '#description'    => t('If enabled, the form will be submitted automatically as soon as your user choose a suggestion in the popup list.'),
      '#default_value'  => $item->auto_submit,
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    // Check if form should be autoredirected.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_how']['auto_redirect'] = array(
      '#type'           => 'checkbox',
      '#title'          => t('Auto Redirect'),
      '#description'    => t('If enabled, the user will be directly routed to the suggestion he choosed instead of performing form validation process. Only works if "link" attribute is existing and if "Auto Submit" is enabled.'),
      '#default_value'  => $item->auto_redirect,
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    // ------------------------------------------------------------------.
    // WHAT - What to display in Search Autocomplete suggestions.
    $form['search_autocomplete_what'] = array(
      '#type'           => 'fieldset',
      '#title'          => t('WHAT - What to display in Search Autocomplete suggestions?'),
      '#description'    => t('Choose which data should be added to autocompletion suggestions.'),
      '#collapsible'    => TRUE,
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      '#collapsed'      => FALSE,
      '#theme'          => 'search_autocomplete_form_configuration_fieldset',
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_what']['suggestions'] = array(
      '#type'           => 'item',
      '#title'          => t('Suggestion source'),
      '#description'    => t('Choose the source of suggestions to display in this form'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    $form['search_autocomplete_what']['suggestions']['callback'] = array();
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_what']['callback']['callback_option'] = array(
      '#type'           => 'radio',
      '#title'          => t('Callback URL:'),
      '#return_value'   => 'callback',
      '#default_value'  => $item->data_source,
      '#prefix'         => '<div class="form-radios">',
      '#parents'        => array('suggestions'),
    $descr = t('Enter the url where to retrieve suggestions. It can be internal (absolute or relative) or external.');
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_what']['callback']['callback_textfield'] = array(
      '#description'    => $descr,
      '#default_value'  => $item->data_source == 'callback' ? $item->data_callback : '',
      // The default size is a bit large...
      '#size'           => 80,
      // End of the "form-radios" style.
      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=1]").attr("checked", true);'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    $form['search_autocomplete_what']['suggestions']['staticresource'] = array();
    $form['search_autocomplete_what']['staticresource']['staticresource_option'] = array(
      '#type'           => 'radio',
      '#title'          => t('Static resource :'),
      '#return_value'   => 'static',
      '#default_value'  => $item->data_source,
      '#parents'        => array('suggestions'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    $form['search_autocomplete_what']['staticresource']['staticresource_textfield'] = array(
      '#description'    => t('Please enter one suggestion per line. You can use the syntax: "foo => http://bar" per line if you wish to add a jumping to URL for the suggestion. Please refer to <a href="http://drupal-addict.com/nos-projets/search-autocomplete">documentation</a>.'),
      '#default_value'  => $item->data_static,
      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=2]").attr("checked", true);'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    );
    // Use a view.
    $form['search_autocomplete_what']['suggestions']['view'] = array();
    $form['search_autocomplete_what']['view']['view_option'] = array(
      '#type'           => 'radio',
      '#title'          => t('Use an existing view:'),
      '#return_value'   => 'view',
      '#default_value'  => $item->data_source,
      '#suffix'         => '</div>',
      '#parents'        => array('suggestions'),
      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=3]").attr("checked", true);'),
    );
    $form['search_autocomplete_what']['view']['view_textfield'] = array(
      '#type'           => 'textfield',
      '#description'    => t('Use autocompletion to match an eligible view.'),
      '#default_value'  => $item->data_view,
      '#autocomplete_path' => 'views/autocomplete',
      // The default size is a bit large...
      '#size'           => 80,
      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=3]").attr("checked", true);'),
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $themes = array();
    $files = file_scan_directory(drupal_get_path('module', 'search_autocomplete') . '/css/themes', '/.*\.css\z/', array('recurse' => FALSE));
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    foreach ($files as $file) {
      if ($file->name != 'jquery.autocomplete') {
        $themes[$file->filename] = $file->name;
      }
Dominique CLAUSE's avatar
Dominique CLAUSE committed
    $form['search_autocomplete_what']['theme'] = array(
      '#type'           => 'select',
      '#title'          => t('Select a theme for your suggestions'),
      '#options'        => $themes,
      '#default_value'  => $item->theme,
      '#description'    => t('Choose the theme to use for autocompletion dropdown popup. Read <a href="http://drupal-addict.com/nos-projets/search-autocomplete">documentation</a> to learn how to make your own.'),
    // ------------------------------------------------------------------.
    // ADVANCED - Advanced options.
    $form['search_autocomplete_advanced'] = array(
      '#type'             => 'fieldset',
      '#title'            => t('ADVANCED - Advanced options'),
      '#collapsible'      => TRUE,
    );
    $form['search_autocomplete_advanced']['selector'] = array(
      '#type'             => 'textfield',
      '#title'            => t('ID selector for this form'),
      '#description'      => t('Please change only if you know what you do, read <a href="http://drupal-addict.com/nos-projets/search-autocomplete">documentation</a> first.'),
      '#default_value'    => $item->selector,
      '#maxlength'        => 255,
    // Add button validation.
    $form['submit'] = array(
      '#type'             => 'submit',
      '#value'            => t('Save configuration'),
// --------------------------------------------------------------------------.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
/**
 * Implements hook_validate().
 *
 * Save the changes in the database.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
 */
function search_autocomplete_form_configure_validate($form, &$form_state) {
Dominique CLAUSE's avatar
Dominique CLAUSE committed
  $values = $form_state['values'];
  if ($values['suggestions'] == 1) {
    $new_url = preg_replace('/\?[^=]*=[^&]*/', '', $values['callback_textfield']);
    if (!drupal_valid_path($new_url)) {
      form_set_error('url', t('callback url is not valid: @new_url', array('@new_url' => $new_url)));
// -------------------------------------------------------------------------.
 * Implements hook_submit().
 *
 * Save the changes in the database.
 */
function search_autocomplete_form_configure_submit($form, &$form_state) {
Dominique CLAUSE's avatar
Dominique CLAUSE committed
  global $base_url;

  $ok_query = TRUE;
Dominique CLAUSE's avatar
Dominique CLAUSE committed
  $values = $form_state['values'];
  // Analyse incoming callback.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
  $callback = $values['callback_textfield'];
  // Static resource => type = 2.
  $data_type = $values['suggestions'];
  if ($data_type == 'callback' && $callback != '') {
    // If path is absolute:
    if (url_is_external($callback)) {
      // If path is internal:
      if (strcmp(substr($callback, 0, strlen($base_url)), $base_url) === 0) {
        // Get it relative.
        $callback = str_replace($base_url . "/", "", $callback);
  // In the case of view, we use a custom callback to retrieve the view data.
  if ($data_type == 'view') {
    $callback = 'search_autocomplete/autocomplete/' . $values['fid'] . '/';
  // ###.
  // -> update form.
  db_update('search_autocomplete_forms')
    ->fields(array(
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      'min_char'        => $values['min_char'],
      'max_sug'         => $values['max_sug'],
      'auto_submit'     => $values['auto_submit'],
      'auto_redirect'   => $values['auto_redirect'],
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      'selector'        => $values['selector'],
      'data_source'     => $values['suggestions'],
Dominique CLAUSE's avatar
Dominique CLAUSE committed
      'data_callback'   => $callback,
      'data_static'     => $values['staticresource_textfield'],
      'data_view'       => $values['view_textfield'],
      'theme'           => $values['theme'],
    ))
    ->condition('fid', $values['fid'])
    ->execute();
  // ###
  // UPDATE CHILD LIST BUT NOT THE ADVANCED OPTIONS.
  $fids = _search_autocomplete_get_all_children($values['fid']);
  // Update the settings for this form + every children form.
  foreach ($fids as $fid) {
    // -> update form.
    db_update('search_autocomplete_forms')
      ->fields(array(
Dominique CLAUSE's avatar
Dominique CLAUSE committed
        'min_char'        => $values['min_char'],
        'max_sug'         => $values['max_sug'],
Dominique CLAUSE's avatar
Dominique CLAUSE committed
        'auto_submit'     => $values['auto_submit'],
        'auto_redirect'   => $values['auto_redirect'],
        'theme'           => $values['theme'],
      ))
      ->condition('fid', $fid)
  // ###.
Dominique CLAUSE's avatar
Dominique CLAUSE committed
  drupal_clear_css_cache();
  $form_state['redirect'] = 'admin/config/search/search_autocomplete';
  $ok_query ? drupal_set_message(t("Configuration success !")) : drupal_set_message(t("An error has occured while saving the settings. Please, double check your settings!"), 'error');
}

// ///////////////////////////////////////////////////////////////////////// //
// //                        HELPER FUNCTIONS                             // //
// ----------------------------------------------------------------------------.
 * Get the fids from all the children of the caller, excluding the caller.
 */
function _search_autocomplete_get_all_children($fid, &$items = array(), $depth = 0) {
  if ($depth) {
  $result = db_select('search_autocomplete_forms', 'f')
      ->fields('f')
      ->condition('parent_fid', $fid)
      ->execute()
      ->fetchAllAssoc('fid');
  foreach ($result as $item) {
    _search_autocomplete_get_all_children($item->fid, $items, $depth);
  }
  return $items;