function tripal_views_views_data

2.x tripal_views.views.inc tripal_views_views_data()
1.x tripal_views.views.inc tripal_views_views_data()

Implements hook_views_data().

Generates a dynamic data array for Views

This function is a hook used by the Views module. It populates and returns a data array that specifies for the Views module the base table, the tables it joins with and handlers. The data array is populated using the data stored in the tripal_views tables.

Return value

a data array formatted for the Views module

D7 @todo: Add support for materialized views relationships using the new method

Related topics

File

tripal_views/tripal_views.views.inc, line 51
Tripal Views Integration

Code

function tripal_views_views_data() {
  $data = array();

  // Manually integrate the drupal.tripal_views* tables
  $data = tripal_views_views_data_tripal_views_tables($data);

  // Determine the name of the chado schema
  $chado_schema = tripal_get_schema_name('chado');

  // MAKE SURE ALL CHADO TABLES ARE INTEGRATED
  tripal_views_integrate_all_chado_tables();

  // DEFINE GLOBAL FIELDS
  // Filter handler that lets the admin say:
  // "Show no results until they enter search parameters"
  $data['views']['search_results'] = array(
    'title' => t('Delay Results'),
    'help' => t('Delay results until Apply/Search is clicked by the user.'),
    'filter' => array(
      'handler' => 'tripal_views_handler_filter_no_results',
    ),
  );

  $data['views']['action_links_area'] = array(
    'title' => t('Action Links'),
    'help' => t('Add action links to the view.'),
    'area' => array(
      'handler' => 'tripal_views_handler_area_action_links',
    ),
  );

  $tvi_query = db_query('SELECT * FROM {tripal_views}');

  // INTEGRATE THE LIGHTEST SETUP FOR EACH TABLE
  foreach ($tvi_query as $tvi_row) {

    // check to see if this is the lightest (drupal-style) priority setup for this table
    // if not then don't use this definition
    $lightest_priority_setup = tripal_is_lightest_priority_setup($tvi_row->setup_id, $tvi_row->table_name);
    if (!$lightest_priority_setup) {
      continue;
    }

    // ids we'll use for queries
    $setup_id = $tvi_row->setup_id;
    $mview_id = $tvi_row->mview_id;

    // holds the base table name and fields
    $base_table = '';
    $base_fields = array();

    // indicated whether the current table is a base table or not
    $is_base_table = $tvi_row->base_table;

    // POPULATE THE BASE TABLE NAME AND FIELDS
    // If an $mview_id is given then get the materialized view info,
    // otherwise get the Chado table info
    $legacy_mview = FALSE;
    if ($mview_id) {

      // get the base table name from the materialized view
      // D7 TODO: Check DBTNG changes work
      $sql = "SELECT name, mv_specs FROM {tripal_mviews} WHERE mview_id = :id";
      $mview_table = db_query($sql, array(':id' => $mview_id));
      $mview_table = $mview_table->fetchObject();
      $base_table = $mview_table->name;

      if (!empty($mview_table->mv_specs)) {
        $legacy_mview = TRUE;
      }
    }

    if ($legacy_mview) {
      // get the columns in this materialized view.  They are separated by commas
      // where the first word is the column name and the rest is the type
      $columns = explode(",", $mview_table->mv_specs);
      foreach ($columns as $column) {
        $column = trim($column); // trim trailing and leading spaces
        preg_match("/^(.*?)\ (.*?)$/", $column, $matches);
        $column_name = $matches[1];
        $column_type = $matches[2];
        $base_fields[$column_name] = array(
          'column_name' => $column_name,
          'type' => $column_type,
        );
      }

      // get the field name and descriptions
      // D7 TODO: Check DBTNG changes work
      $sql = "SELECT * FROM {tripal_views_field} WHERE setup_id=:setup";
      $query = db_query($sql, array(':setup' => $setup_id));
      foreach ($query as $field) {
        $base_fields[$field->column_name]['name'] = $field->name;
        $base_fields[$field->column_name]['help'] = $field->description;
      }
    }
    // if this is not a legacy materialized view
    else {
      $base_table = $tvi_row->table_name;

      // get the table description
      $table_desc = chado_get_schema($base_table);

      $fields = $table_desc['fields'];
      if (!is_array($fields)) {
        $fields = array();
      }
      foreach ($fields as $column => $attrs) {
        $base_fields[$column] = array(
          'column_name' => $column,
          // Add a default for type since module developers may sometimes need to use a
          // PostgreSQL-specific type.
          'type' => (isset($attrs['type'])) ? $attrs['type'] : 'text',
        );
        // If PostgreSQL-specifc types are needed the module developer should be given
        // a way to set the most closely matching type for views. They should also be
        // allowed to override the type for views. This can be done by adding a views_type
        // to the schema definition :-).
        if (isset($attrs['views_type'])) {
          $base_fields[$column]['type'] = $attrs['views_type'];
        }
        // Tell admin about this feature and warn them that we made an assumption for them.
        if (!isset($attrs['type']) AND !isset($attrs['views_type'])) {
          tripal_report_error(
          'tripal_views', 
          TRIPAL_WARNING, 
          "Unable to determine the type for %column thus we have defaulted to type 'text'.
              Tip: This may be due to setting a  postgresql-specific type. Solution: Add a
              'views_type' to your schema definition to specify what type should be used.", 
          array('%column' => $column)
          );
        }
      }

      // get the field name and descriptions
      $sql = "SELECT * FROM {tripal_views_field} WHERE setup_id=:setup";
      $query = db_query($sql, array(':setup' => $setup_id));
      foreach ($query as $field) {
        $base_fields[$field->column_name]['name'] = $field->name;
        $base_fields[$field->column_name]['help'] = $field->description;
      }
    }

    // SETUP THE BASE TABLE INFO IN THE DATA ARRAY
    $data[$base_table]['table']['group'] = t("$tvi_row->name");

    if ($is_base_table) {
      $data[$base_table]['table']['base'] = array(
        'group' => "$tvi_row->name",
        'title' => "$tvi_row->name",
        'help' => $tvi_row->comment,
        'search_path' => $chado_schema
      );
    }
    else {
      $data[$base_table]['table'] = array(
        'group' => "$tvi_row->name",
        'title' => "$tvi_row->name",
        'help' => $tvi_row->comment,
        'search_path' => $chado_schema
      );
    }

    // ADD THE FIELDS TO THE DATA ARRAY
    foreach ($base_fields as $column_name => $base_field) {
      if (!isset($base_field['name'])) {
        $data[$base_table][$column_name] = array(
          'title' => t($column_name),
          'help' => t($column_name),
          'field' => array(
            'click sortable' => TRUE,
          ),
        );

        tripal_report_error(
        'tripal_views', 
        TRIPAL_DEBUG, 
        "The name and help were not set for %table.%column. As a consequence the column
            name has been used... You should ensure that the 'name' and 'help' keys for
            this field are set in the integration array (priority = %priority)", 
        array(
          '%table' => $base_table,
          '%column' => $column_name,
          '%priority' => $tvi_row->priority
        )
        );
      }
      else {
        $data[$base_table][$column_name] = array(
          'title' => t($base_field['name']),
          'help' => t($base_field['help']),
          'field' => array(
            'click sortable' => TRUE,
          ),
        );
      }

      // now add the handlers
      $sql = "SELECT * FROM {tripal_views_handlers} WHERE setup_id = :setup AND column_name = :column";
      $handlers = db_query($sql, array(':setup' => $setup_id, ':column' => $column_name));
      $num_handlers = 0;
      foreach ($handlers as $handler) {
        $num_handlers++;

        $data[$base_table][$column_name][$handler->handler_type]['handler'] = $handler->handler_name;

        // Add in any additional arguments
        // This should be a serialized array including (at a minimum) name => <handler name>
        if ($handler->arguments) {
          $data[$base_table][$column_name][$handler->handler_type] = array_merge($data[$base_table][$column_name][$handler->handler_type], unserialize($handler->arguments));
        }
      }

      // If there were no handlers applied to the current field then warn the administrator!
      if ($num_handlers == 0) {
        tripal_report_error(
        'tripal_views', 
        TRIPAL_DEBUG, 
        "No handlers were registered for %table.%column. This means there is no views
            functionality for this column. To register handlers, make sure the 'handlers'
            key for this field is set in the integration array (priority = %priority).
            The supported keys include 'field', 'filter', 'sort', 'relationship'. Look
            at the tripal_add_views_integration() for additional details.", 
        array(
          '%table' => $base_table,
          '%column' => $column_name,
          '%priority' => $tvi_row->priority
        )
        );
      }
    }

    // ADD JOINS & RELATIONSHIPS TO DATA ARRAY
    // only add joins if this is a base table
    // this keeps the list of available fields manageable
    // all other tables should be added via relationships
    $sql = "SELECT * FROM {tripal_views_join} WHERE setup_id = :setup";
    $joins = db_query($sql, array(':setup' => $setup_id));
    if (!isset($joins)) {
      $joins = array();
    }
    foreach ($joins as $join) {
      $left_table = $join->left_table;
      $left_field = $join->left_field;
      $base_table = $join->base_table;
      $base_field = $join->base_field;
      $handler = $join->handler;
      $base_title = ucwords(str_replace('_', ' ', $base_table));
      $left_title = ucwords(str_replace('_', ' ', $left_table));

      // if the 'node' table is in our integrated list then
      // we want to skip it. It shouldn't be there.
      if ($left_table == 'node') {
        continue;
      }

      // add join entry
      if (!$join->relationship_only) {
        $data[$left_table]['table']['join'][$base_table] = array(
          'left_field' => $base_field,
          'field' => $left_field,
        );
        if ($handler) {
          $data[$left_table]['table']['join'][$base_table]['handler'] = $handler;
        }
        if (!empty($join->arguments)) {
          array_merge($data[$left_table]['table']['join'][$base_table], unserialize($join->arguments));
        }
      }

      // warn if deprecated method of relationship addition was used (ie: through handlers)
      if (isset($data[$base_table][$base_field]['relationship'])) {
        tripal_report_error('tripal_views', TRIPAL_NOTICE, 
        'DEPRECATED: Currently using tripal_views_handlers to store relationship for %base => %left when you should be using tripal_views_joins.', 
        array('%base' => $base_table, '%left' => $left_table));
      }

      // Add relationship entry.
      // NOTE: we use a fake field name to allow us to have multiple
      // relationships for the same field (ie: feature.feature_id has many
      // Many relationships but views only supports a single one).
      $fake_field = $base_field . '_to_' . $left_table;

      // Bug Fix: The old $fake_field used above doesn't take into account
      // multiple relationships to the same left table. To keep backwards
      // compatibility, this old fake_field needs to continue to be used for
      // the LAST recorded relationship. However, for all previously set
      // relationships we can use an improved fake name which takes into
      // account the left field and ensures all relationships for a single
      // left table are not condensed into a single relationship.
      if (array_key_exists($fake_field, $data[$base_table])) {

        // Again, note that we can't just change the fake_name after finding
        // there is more than one relationship because then the FIRST
        // relationship would keep the old fake_name rather than the LAST
        // which keeps backwards compatiblity since the old naming caused all
        // previous relationships be be overridden by the next one.
        // Thus we first need to determine the left field of the previous
        // join for this table combination and then use that to form our
        // improved fake field.
        $previous_left_field = $data[$base_table][$fake_field]['relationship']['base field'];
        $improved_fake_field = $base_field . '_to_' . $left_table . "." . $previous_left_field;
        $data[$base_table][$improved_fake_field] = $data[$base_table][$fake_field];
      }
      $data[$base_table][$fake_field] = array(
        'title' => "$base_title.$base_field => $left_title.$left_field",
        'help' => t("Joins @base to @left", array('@base' => "$base_title.$base_field", '@left' => "$left_title.$left_field")),
        'relationship' => array(
          'handler' => $join->relationship_handler,
          'title' => t("$base_field => $left_title ($left_field)"),
          'label' => t("$base_field => $left_title ($left_field)"),
          'real field' => $base_field,
          'base' => $left_table,
          'base field' => $left_field
        )
      );
      if (!empty($join->arguments)) {
        array_merge($data[$base_table][$fake_field]['relationship'], unserialize($join->arguments));
      }
    }
  }
  return $data;
}