You are here

finder_views.module in Finder 7

Same filename and directory in other branches
  1. 6 modules/finder_views/finder_views.module

The finder views module.

File

modules/finder_views/finder_views.module
View source
<?php

// $Id: finder_views.module,v 1.1.2.56 2011/02/12 06:55:19 danielb Exp $

/**
 * @file
 * The finder views module.
 */

/**
 * Implements hook_views_api().
 *
 * @see hook_views_api()
 */
function finder_views_views_api() {
  return array(
    'api' => 3,
    'path' => finder_inc_path('finder_views'),
  );
}

/**
 * Implements hook_theme().
 *
 * @see hook_theme()
 */
function finder_views_theme() {
  return array(
    'finder_views_results' => array(
      'variables' => array(
        'results' => NULL,
        'finder' => NULL,
        'form_state' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_finder_base_handlers().
 *
 * @see hook_finder_base_handlers()
 */
function finder_views_finder_base_handlers() {
  return array(
    'views' => array(
      '#title' => t('Views finder'),
      '#module' => 'finder_views',
    ),
  );
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * @see hook_form_FORM_ID_alter()
 */
function finder_views_form_finder_admin_edit_alter(&$form, $form_state) {
  $finder =& $form_state['storage']['finder'];
  if ($finder->base == 'views') {
    $form['settings']['advanced']['pager']['#description'] .= ' ' . t('For the results pager to work properly, ensure your Views display has "Items per page" set to "unlimited".');
    $form['settings']['views'] = array(
      '#type' => 'fieldset',
      '#title' => t('Views'),
      '#weight' => 80,
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    );
    if ($views = finder_views_get_views()) {
      $form['settings']['views']['view'] = array(
        '#type' => 'select',
        '#title' => t('Find items from this view'),
        '#default_value' => $finder->settings['views']['view'] ? $finder->settings['views']['view'] : '',
        '#options' => $views,
        '#required' => TRUE,
        '#weight' => 10,
      );
      $form['settings']['views']['displays'] = array(
        '#type' => 'fieldset',
        '#title' => t('Views displays'),
        '#weight' => 20,
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
        '#description' => t('Leaving these set to "Defaults" is perfectly suitable in most cases.'),
      );
      $displays = finder_views_get_displays($finder->settings['views']['view']);
      $form['settings']['views']['displays']['query'] = array(
        '#type' => 'select',
        '#title' => t('Query display'),
        '#default_value' => $finder->settings['views']['displays']['query'] ? $finder->settings['views']['displays']['query'] : 'default',
        '#options' => $displays,
        '#required' => TRUE,
        '#weight' => 10,
        '#description' => t('Allows you to use a specific display to calculate results, you can use this to add sort/filter settings via Views that do not affect the element choices.'),
      );
      $form['settings']['views']['displays']['output'] = array(
        '#type' => 'select',
        '#title' => t('Output display'),
        '#default_value' => $finder->settings['views']['displays']['output'] ? $finder->settings['views']['displays']['output'] : 'default',
        '#options' => $displays,
        '#required' => TRUE,
        '#weight' => 20,
        '#description' => t('Allows you to use a specific display to output the results page, you can use this to change output settings via Views that do not affect the element choices.'),
      );
      if (count($displays) === 1) {
        $form['settings']['views']['displays']['query']['#disabled'] = TRUE;
        $form['settings']['views']['displays']['output']['#disabled'] = TRUE;
      }
      $form['settings']['views']['results'] = array(
        '#type' => 'radios',
        '#title' => t('Results page'),
        '#default_value' => $finder->settings['views']['results'] ? $finder->settings['views']['results'] : 0,
        '#weight' => 40,
        '#description' => t('"Output display" is configured under the "Views displays" fieldset above.  Custom results page can be themed using theme_finder_views_results().'),
        '#options' => array(
          0 => t('Build results page from "Output display".'),
          1 => t('Build custom results page.'),
        ),
      );
      $relationships = finder_view_get_relationships($finder);
      if (!empty($relationships)) {
        $form['settings']['views']['relationships'] = array(
          '#type' => 'fieldset',
          '#title' => t('Relationships'),
          '#weight' => 70,
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
          '#description' => t('If any fields in your finder rely on relationships, here is where you inform finder of this.'),
        );
        $fields = finder_views_finder_fields($finder, 0);
        foreach ($relationships as $rel_key => $rel_label) {
          $form['settings']['views']['relationships'][$rel_key] = array(
            '#type' => 'select',
            '#title' => $rel_label,
            '#default_value' => isset($finder->settings['views']['relationships'][$rel_key]) ? $finder->settings['views']['relationships'][$rel_key] : array(),
            '#options' => $fields,
            '#multiple' => TRUE,
            '#size' => min(count($fields) + 1, 20),
            '#description' => t('Select the fields that use the relationship %rel.  You do not need to select fields that are not used in this finder.', array(
              '%rel' => $rel_label,
            )),
          );
        }
      }
      $form['settings']['views']['views_args'] = array(
        '#type' => 'fieldset',
        '#title' => t('Views arguments'),
        '#weight' => 80,
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
        '#description' => t('Restrict results using arguments.  These arguments will not apply to element choices - use with caution.'),
      );
      $form['settings']['views']['views_args']['args'] = finder_php_setting(array(
        '#type' => 'textarea',
        '#default_value' => isset($finder->settings['views']['views_args']['args']) ? $finder->settings['views']['views_args']['args'] : '',
        '#title' => t('Arguments'),
        '#rows' => 1,
        '#description' => t('
            You can provide a list of arguments seperated by a delimiter.
            e.g: <em>term_1/term_2</em>.<br />Or insert PHP code to generate the
            list of arguments. e.g: <em>term_1/&lt;?php print "term_x/term_y";
            ?&gt;/term_2</em>.'),
      ), array(
        'finder' => t('Object containing data about this finder.'),
      ));
      $form['settings']['views']['views_args']['delimiter'] = array(
        '#type' => 'textfield',
        '#default_value' => isset($finder->settings['views']['views_args']['delimiter']) ? $finder->settings['views']['views_args']['delimiter'] : '/',
        '#title' => t('Delimiter'),
        '#size' => 5,
        '#maxlength' => 10,
        '#description' => t('This is the character used to split multiple arguments above.'),
        '#required' => TRUE,
      );
      $form['settings']['views']['empty_text'] = array(
        '#type' => 'checkbox',
        '#title' => t('Show view display when there are no results'),
        '#default_value' => $finder->settings['views']['empty_text'],
        '#weight' => 50,
        '#description' => t("Use the view display's empty text instead of finder's no results output."),
      );
    }
    else {
      $form['settings']['views']['no_view'] = array(
        '#value' => t("<em>There are currently no views to choose from.</em>"),
        '#weight' => 10,
      );
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * @see hook_form_FORM_ID_alter()
 */
function finder_views_form_finder_admin_element_edit_alter(&$form, $form_state) {
  $finder =& $form_state['storage']['finder'];
  if ($finder->base == 'views') {
    $element =& $form_state['storage']['finder_element_defaults'];
    unset($form['settings']['choices']['sort']);
    $form['settings']['choices']['displays'] = array(
      '#type' => 'fieldset',
      '#title' => t('Views displays'),
      '#weight' => 270,
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#description' => t('Leaving this set to "Defaults" is perfectly suitable for most cases.'),
    );
    $displays = finder_views_get_displays($finder->settings['views']['view']);
    $form['settings']['choices']['displays']['query'] = array(
      '#type' => 'select',
      '#title' => t('Query display'),
      '#default_value' => $element->settings['choices']['displays']['query'] ? $element->settings['choices']['displays']['query'] : 'default',
      '#options' => $displays,
      '#required' => TRUE,
      '#weight' => 10,
      '#description' => t('
          Allows you to use a specific display to calculate the choices list,
          you can use this to add sort/filter settings via Views that do not
          affect other elements or the results.'),
    );
    $form['settings']['choices']['views'] = array(
      '#type' => 'fieldset',
      '#title' => t('Views arguments'),
      '#weight' => 280,
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#description' => t('Restrict possible choices using arguments.  These arguments will not apply to the results - use with caution.'),
    );
    $form['settings']['choices']['views']['args'] = finder_php_setting(array(
      '#type' => 'textarea',
      '#default_value' => isset($element->settings['choices']['views']['args']) ? $element->settings['choices']['views']['args'] : '',
      '#title' => t('Arguments'),
      '#rows' => 1,
      '#description' => t('
          You can provide a list of arguments seperated by a delimiter.
          e.g: <em>term_1/term_2</em>.<br />Or insert PHP code to generate the
          list of arguments. e.g: <em>term_1/&lt;?php print "term_x/term_y";
          ?&gt;/term_2</em>. (Variables available: $finder_element)'),
    ), array(
      'finder' => t('Object containing data about this finder.'),
    ));
    $form['settings']['choices']['views']['delimiter'] = array(
      '#type' => 'textfield',
      '#default_value' => isset($element->settings['choices']['views']['delimiter']) ? $element->settings['choices']['views']['delimiter'] : '/',
      '#title' => t('Delimiter'),
      '#size' => 5,
      '#maxlength' => 10,
      '#description' => t('This is the character used to split multiple arguments above.'),
      '#required' => TRUE,
    );
  }
}

/**
 * Implements hook_finder_fields().
 *
 * @see hook_finder_fields()
 */
function finder_views_finder_fields($finder, $finder_element_id) {
  if ($view = views_get_view($finder->settings['views']['view'])) {
    views_include('admin');
    $display = $view
      ->add_display('finder_views');
    $view
      ->set_display($display);
    $base_tables = $view
      ->get_base_tables();
    $views_fields = views_fetch_fields(array_keys($base_tables), 'filter');
    $options = array();
    foreach ($views_fields as $k => $v) {
      $options[$v['group']][$k] = $v['title'];
    }
    return $options;
  }
  return FALSE;
}

/**
 * Get an array of content types for use in select forms.
 */
function finder_views_get_views() {
  $views = array(
    '' => ' - ' . t('Select a view') . ' - ',
  );
  $all_views = views_get_all_views();
  if (!empty($all_views)) {
    foreach ($all_views as $view) {
      if ($view->type == 'Default') {
        $views[t('Default Views')][$view->name] = $view->name;
      }
      else {
        $views[t('Existing Views')][$view->name] = $view->name;
      }
    }
    return $views;
  }
  return FALSE;
}

/**
 * Get an array of content types for use in select forms.
 */
function finder_views_get_displays($view_name = NULL) {
  if (!$view_name) {
    return array(
      'default' => t('Defaults'),
    );
  }
  $options = array();
  $all_views = views_get_all_views();
  $view = $all_views[$view_name];
  foreach ($view->display as $key => $display) {
    $options[$key] = $display->display_title . ' (' . $key . ')';
  }
  return $options;
}

/**
 * Get an array of relationships for use in admin screens.
 */
function finder_view_get_relationships($finder) {
  if ($view = views_get_view($finder->settings['views']['view'])) {
    $options = array();
    $display = $finder->settings['views']['displays']['query'] ? $finder->settings['views']['displays']['query'] : 'default';
    if (isset($view->display[$display]->display_options['relationships'])) {
      foreach ($view->display[$display]->display_options['relationships'] as $rel_key => $rel) {
        $options[$rel_key] = $rel['label'];
      }
    }
    return $options;
  }
  return FALSE;
}

/**
 * Implements hook_finder_find().
 *
 * @see hook_finder_find()
 */
function finder_views_finder_find($finder, $finder_element_id, $keywords, $mode, $match, $pager) {
  $options = array();
  $view_name =& $finder->settings['views']['view'];
  if ($view = views_get_view($view_name)) {
    $view_args = array();

    // We add a display, and let it derive from the 'default' display.
    $display = $view
      ->add_display('finder_views');

    // Change the display options based on 'query display' setting.
    if ($mode == 'results' && $finder->settings['views']['displays']['query']) {
      $custom_display =& $finder->settings['views']['displays']['query'];
    }
    elseif ($mode == 'choices' && ($fe =& finder_element($finder, $finder_element_id)) && $fe->settings['choices']['displays']['query']) {
      $custom_display =& $fe->settings['choices']['displays']['query'];
    }
    if (isset($custom_display) && $custom_display != 'default') {
      $view->display[$display]->display_options = $view->display[$custom_display]->display_options;
    }

    // Activate the display
    $view
      ->set_display($display);

    // For choices, remove all the currently added fields.
    // This prevents problems with the 'group by' clauses.

    /*
    if ($mode == 'choices') {
      // Get a list of currently added fields.
      $fields = $view->get_items('field', $display);
      foreach ($fields as $key => $field) {
        $view->set_item($display, 'field', $field['id'], NULL);
        unset($fields[$key]);
      }
    }
    */
    $view->display_handler
      ->set_option('style_plugin', 'finder_views_php_array_finder');
    $view->display_handler
      ->set_option('row_plugin', 'fields');
    $field_info = array();
    foreach ($keywords as $feid => $keyword_array) {
      if ($mode == 'choices' && $feid == $finder_element_id) {
        $element =& finder_element($finder, $feid);

        // Select the 'choices' field.
        $element_fields =& $element->settings['choices']['field'];
        foreach ($element_fields as $key => $field) {
          $field_info[$feid][$key] = finder_split_field($field);
          $field_alias = finder_field_alias($feid, $field_info[$feid][$key]['table'], $field_info[$feid][$key]['field']);
          $view
            ->add_item($display, 'field', $field_info[$feid][$key]['table'], $field_info[$feid][$key]['field'], array(), $field_alias);
          $groups[] = $field_alias;
        }

        // Add element args for 'choices'.
        $view_args = finder_views_get_element_args($element);
      }

      // Temporary hack - rather than doing this, the functions calling finder_find() should set this up?
      // or maybe this func should handle the whole thing?  i.e. creating the dummy keywords for choices.
      // See #1270150.
      if (is_null($keywords[$feid])) {
        $keywords[$feid][] = NULL;
      }

      /*

            This code is removed because of #1270150.

            // Remove empty keyword strings.
            $keywords[$feid] = array_filter((array)$keywords[$feid], 'finder_empty_keyword');
            // Remove blank keyword array.
            if (empty($keywords[$feid])) {
              unset($keywords[$feid]);
            }
      */
    }
    $options = array(
      'finder' => $finder,
      'finder_element_id' => $finder_element_id,
      'keywords' => $keywords,
      'mode' => $mode,
      'match' => $match,
      'groups' => isset($groups) ? $groups : array(),
    );
    $view->display_handler
      ->set_option('finder_views_options', $options);

    // Save $field_info into the view, so we can use it in the display and style plugins.
    $view->display_handler
      ->set_option('finder_views_field_info', $field_info);

    // Limit result set size.
    if (isset($pager)) {
      $view->display_handler
        ->set_option('use_pager', TRUE);
      $view->display_handler
        ->set_option('items_per_page', $pager);
      $pager_element = $mode == 'results' ? 0 : 'finder_choices_' . $finder_element_id;
      $view->display_handler
        ->set_option('pager_element', $pager_element);
    }
    if ($mode == 'results') {
      $view_args = finder_views_get_finder_args($finder);

      // Limit result for redirect.
      if (isset($finder->go) && $finder->go) {
        $view->display_handler
          ->set_option('use_pager', TRUE);
        $view->display_handler
          ->set_option('items_per_page', 1);
        $view->display_handler
          ->set_option('pager_element', 0);
      }
    }

    // Make sure the query is not cached
    $view->is_cacheable = FALSE;
    $view
      ->build($display);
    $result = $view
      ->execute_display($display, $view_args);
  }
  else {
    $result = FALSE;
  }
  return $result;
}

/**
 * Implements hook_finder_result().
 *
 * @see hook_finder_result()
 */
function finder_views_finder_result($finder, $keywords, $results, $form_state) {
  $output = '';
  if ($results || $finder->settings['views']['empty_text']) {
    if ($finder->settings['views']['results']) {
      $output .= theme('finder_views_results', array(
        'results' => $results,
        'finder' => $finder,
        'form_state' => $form_state,
      ));
    }
    else {
      $args = array();
      $view = views_get_view($finder->settings['views']['view']);
      $display_id = 'default';
      if ($finder->settings['views']['displays']['output']) {
        $display_id = $finder->settings['views']['displays']['output'];
      }
      $view
        ->set_display($display_id);
      $view
        ->set_arguments($args);
      $view->is_cacheable = FALSE;
      $view->display_handler
        ->set_option('use_pager', 0);

      // compile ids so that finder_views_views_query_alter() knows what to do
      $ids = array();
      foreach ($results as $result) {
        $ids[] = $result->{$result->base_field};
      }
      $view->finder_ids = $ids;
      $view
        ->preview();
      $output .= $view
        ->render($display_id);
    }
  }
  return $output;
}

/**
 * Implements hook_views_query_alter().
 *
 * @see hook_views_query_alter()
 */
function finder_views_views_query_alter($view, &$query) {
  if (isset($view->finder_ids)) {
    if (!empty($view->finder_ids)) {
      $alias = $query
        ->ensure_table($view->base_table);
      $query
        ->add_where(NULL, $alias . '.' . $view->base_field, $view->finder_ids, 'IN');
    }
    else {
      $query
        ->add_where_expression(NULL, '1=0');
    }
  }
}

/**
 * Implements hook_finder_goto().
 *
 * @see hook_finder_goto()
 */
function finder_views_finder_goto($finder, $result) {
  $id =& $result->{$result->base_field};
  $path = finder_views_path($result->base_table, $id);
  if ($path) {
    if ($result->base_table == 'files') {
      file_download($path);
    }
    drupal_goto($path);
  }
}

/**
 * Get the raw link to an object given the table and id.
 *
 * You would think Drupal or Views would provide this feature? :(
 *
 * @param $table
 *   Base table for this type of object.
 * @param $id
 *   The value of the primary key for this record.
 * @return
 *   A raw path that can be put into url() or l() that can be used to link to
 *   or redirect to the object.
 */
function finder_views_path($table, $id) {
  switch ($table) {
    case 'node':
      $path = 'node/' . $id;
      break;
    case 'users':
      $path = 'user/' . $id;
      break;
    case 'term_data':
      $path = 'taxonomy/term/' . $id;
      break;
    case 'node_revisions':
      $revision = node_load(NULL, $id);
      $path = 'node/' . $revision->nid . '/revisions/' . $id . '/view';
      break;
    case 'files':
      $path = file_load($id)->uri;
      break;
  }
  drupal_alter('finder_views_path', $path, $table, $id);
  return $path;
}

/**
 * Theme the views finder results.
 *
 * @param $variables
 *   'results' - An array of result objects.
 *   'finder' - The finder object.
 *   'form_state' - The Forms API form state.
 */
function theme_finder_views_results($variables) {
  extract($variables);
  $output = '';
  foreach ($results as $key => $result) {

    // Open the results wrapper
    $output .= '<div id="finder-views-result-' . $key . '" class="finder-views-result">';

    // Output the identity of this result object
    $id =& $result->{$result->base_field};
    $path = finder_views_path($result->base_table, $id);
    $id_output = $path ? l($id, $path) : $id;
    $identity = $result->base_table . ', ' . $result->base_field . ': ' . $id_output;
    $output .= '<div class="identity">' . $identity . '</div>';

    // Output a list of finder element titles and the submitted keywords.
    if (!empty($result->field_names)) {
      $keywords = array();
      foreach ($result->field_names as $finder_element_id => $element_fields) {
        $element =& finder_element($finder, $finder_element_id);
        $element_output = '<span class="element-title">' . $element->title . ': </span>';
        $element_values = array();
        foreach ($element_fields as $field_name) {
          if (!empty($result->{$field_name})) {
            $element_values[] = $result->{$field_name};
          }
        }
        $element_output .= implode(', ', $element_values);
        $keywords[] = $element_output;
      }
      $output .= '<div class="keywords">' . implode('<br>', $keywords) . '</div>';
    }

    // Close the results wrapper
    $output .= '</div>';
  }
  return $output;
}

/**
 * Get element arguments.
 *
 * @param $element
 *   The finder element object.
 * @return
 *   The array of views arguments.
 */
function finder_views_get_element_args($element) {
  $variables = array(
    'finder_element' => $element,
  );
  $string =& $element->settings['choices']['views']['args'];
  $delimiter =& $element->settings['choices']['views']['delimiter'];
  return finder_views_get_args($string, $delimiter, $variables);
}

/**
 * Get finder arguments.
 *
 * @param $element
 *   The finder element object.
 * @return
 *   The array of views arguments.
 */
function finder_views_get_finder_args($finder) {
  $variables = array(
    'finder' => $finder,
  );
  $string =& $finder->settings['views']['views_args']['args'];
  $delimiter =& $finder->settings['views']['views_args']['delimiter'];
  return finder_views_get_args($string, $delimiter, $variables);
}

/**
 * Convert finder arguments text field entry to an array of arguments.
 *
 * @param $string
 *   The typed string of arguments, can include PHP code.
 * @param $delimiter
 *   The string by which arguments in $string are delimited.
 * @param $variables
 *   Any variables that should be available to any PHP provided in the input.
 * @return
 *   The array of views arguments.
 */
function finder_views_get_args($string, $delimiter, $variables) {
  $args = array();
  $arguments = finder_eval($string, $variables);
  if ($arguments) {
    $args = explode($delimiter, $arguments);
    foreach ($args as $k => $v) {
      $args[$k] = trim($v);
    }
  }
  return $args;
}

Functions

Namesort descending Description
finder_views_finder_base_handlers Implements hook_finder_base_handlers().
finder_views_finder_fields Implements hook_finder_fields().
finder_views_finder_find Implements hook_finder_find().
finder_views_finder_goto Implements hook_finder_goto().
finder_views_finder_result Implements hook_finder_result().
finder_views_form_finder_admin_edit_alter Implements hook_form_FORM_ID_alter().
finder_views_form_finder_admin_element_edit_alter Implements hook_form_FORM_ID_alter().
finder_views_get_args Convert finder arguments text field entry to an array of arguments.
finder_views_get_displays Get an array of content types for use in select forms.
finder_views_get_element_args Get element arguments.
finder_views_get_finder_args Get finder arguments.
finder_views_get_views Get an array of content types for use in select forms.
finder_views_path Get the raw link to an object given the table and id.
finder_views_theme Implements hook_theme().
finder_views_views_api Implements hook_views_api().
finder_views_views_query_alter Implements hook_views_query_alter().
finder_view_get_relationships Get an array of relationships for use in admin screens.
theme_finder_views_results Theme the views finder results.