function chado_node_sync_form

2.x tripal_core.chado_nodes.api.inc chado_node_sync_form($form, &$form_state)

Generic Sync Form to aid in sync'ing (create drupal nodes linking to chado content) any chado node type.

To use this you need to add a call to it from your hook_menu() and add some additional information to your hook_node_info(). The Following code gives an example of how this might be done:


 function modulename_menu() {

   //  the machine name of your module
   $module_name = 'tripal_example';

   // the base specified in hook_node_info
   $node_type = 'chado_example';

   // This menu item will be a tab on the admin/tripal/chado/tripal_example page
   // that is not selected by default
   $items['admin/tripal/chado/tripal_example/sync'] = array(
     'title' => ' Sync',
     'description' => 'Sync examples from Chado with Drupal',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('chado_node_sync_form', $module_name, $node_type),
     'access arguments' => array('administer tripal examples'),
     'type' => MENU_LOCAL_TASK,
     'weight' => 0
   );

   return $items;
 }

 function modulename_node_info() {
   return array(
     'chado_example' => array(
       'name' => t('example'),
       'base' => 'chado_example',
       'description' => t('A Chado example is a collection of material that can be sampled and have experiments performed on it.'),
       'has_title' => TRUE,
       'locked' => TRUE,

       // this is what differs from the regular Drupal-documented hook_node_info()
       'chado_node_api' => array(
         'base_table' => 'example',            // The name of the chado base table
         'hook_prefix' => 'chado_example',     // Usually the name of the node type
         'linking_table' => 'chado_example',   // Specifies the linking table used
                                               // to map records to Drupal nodes.
                                               // if 'linking_table' is not specified
                                               // it defaults to the node_type name.
         'record_type_title' => array(
           'singular' => t('Example'),         // Singular human-readable title
           'plural' => t('Examples')           // Plural human-readable title
         ),
         'sync_filters' => array( // filters for syncing
           'type_id'     => TRUE,     // TRUE if there is an example.type_id field
           'organism_id' => TRUE,     // TRUE if there is an example.organism_id field
           'checkboxes'  => array('name')  // If the 'checkboxes' key is present then the
                                           // value must be an array of column names in
                                           // base table. The values from these columns will
                                           // be retreived, contentated with a space delimeter
                                           // and provided in a list of checkboxes
                                           // for the user to choose which to sync.
         ),
       )
     ),
   );
 }

For more information on how you can override some of this behaviour while still benifiting from as much of the common architecture as possible see the following functions: hook_chado_node_sync_create_new_node(), hook_chado_node_sync_form(), hook_chado_node_sync_select_query().

Related topics

1 call to chado_node_sync_form()
12 string references to 'chado_node_sync_form'
tripal_analysis_menu in tripal_analysis/tripal_analysis.module
Implementation of hook_menu(). Entry points and paths of the module
tripal_contact_menu in tripal_contact/tripal_contact.module
Implemets hook_menu(). Adds menu items for the tripal_contact module menu. This section gives the outline for the main menu of the Tripal-contact module
tripal_core_chado_node_sync_form in tripal_core/api/tripal_core.DEPRECATED.api.inc
tripal_example_menu in tripal_example/tripal_example.module
Implements hook_menu()
tripal_featuremap_menu in tripal_featuremap/tripal_featuremap.module
Implements hook_menu().

... See full list

File

tripal_core/api/tripal_core.chado_nodes.api.inc, line 416
API to handle much of the common functionality implemented when creating a drupal node type.

Code

function chado_node_sync_form($form, &$form_state) {
  $form = array();

  if (isset($form_state['build_info']['args'][0])) {
    $module = $form_state['build_info']['args'][0];
    $node_type = $form_state['build_info']['args'][1];
    $node_info = call_user_func($module . '_node_info');

    // If a linking table is set in the node_info array then use that,
    // otherwise ues the node_type as the linking table.
    if (array_key_exists('linking_table', $node_info[$node_type]['chado_node_api'])) {
      $linking_table = $node_info[$node_type]['chado_node_api']['linking_table'];
    }
    else {
      $linking_table = 'chado_' . $node_info[$node_type]['chado_node_api']['base_table'];
    }
    $args = $node_info[$node_type]['chado_node_api'];
    $form_state['chado_node_api'] = $args;
  }

  $form['linking_table'] = array(
    '#type' => 'hidden',
    '#value' => $linking_table
  );

  $form['node_type'] = array(
    '#type' => 'hidden',
    '#value' => $node_type
  );

  // define the fieldsets
  $form['sync'] = array(
    '#type' => 'fieldset',
    '#title' => 'Sync ' . $args['record_type_title']['plural'],
    '#descrpition' => '',
  );

  $form['sync']['description'] = array(
    '#type' => 'item',
    '#value' => t("%title_plural of the types listed " .
      "below in the %title_singular Types box will be synced (leave blank to sync all types). You may limit the " .
      "%title_plural to be synced by a specific organism. Depending on the " .
      "number of %title_plural in the chado database this may take a long " .
      "time to complete. ", 
    array(
      '%title_singular' => $args['record_type_title']['singular'],
      '%title_plural' => $args['record_type_title']['plural']
    )),
  );

  if ($args['sync_filters']['type_id']) {
    $form['sync']['type_ids'] = array(
      '#title' => t('%title_singular Types', 
      array(
        '%title_singular' => $args['record_type_title']['singular'],
        '%title_plural' => $args['record_type_title']['plural']
      )),
      '#type' => 'textarea',
      '#description' => t("Enter the names of the %title_singular types to sync. " .
        "Leave blank to sync all %title_plural. Separate each type with a comma " .
        "or new line. Pages for these %title_singular " .
        "types will be created automatically for %title_plural that exist in the " .
        "chado database. The names must match " .
        "exactly (spelling and case) with terms in the ontologies", 
      array(
        '%title_singular' => strtolower($args['record_type_title']['singular']),
        '%title_plural' => strtolower($args['record_type_title']['plural'])
      )),
      '#default_value' => (isset($form_state['values']['type_id'])) ? $form_state['values']['type_id'] : '',
    );
  }

  // get the list of organisms
  if ($args['sync_filters']['organism_id']) {
    $sql = "SELECT * FROM {organism} ORDER BY genus, species";
    $results = chado_query($sql);
    $organisms[] = '';
    foreach ($results as $organism) {
      $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
    }
    $form['sync']['organism_id'] = array(
      '#title' => t('Organism'),
      '#type' => t('select'),
      '#description' => t("Choose the organism for which %title_plural types set above will be synced.", 
      array(
        '%title_singular' => $args['record_type_title']['singular'],
        '%title_plural' => $args['record_type_title']['plural']
      )),
      '#options' => $organisms,
      '#default_value' => (isset($form_state['values']['organism_id'])) ? $form_state['values']['organism_id'] : 0,
    );
  }
  // get the list of organisms
  if (array_key_exists('checkboxes', $args['sync_filters'])) {
    // get the base schema
    $base_table = $args['base_table'];
    $table_info = chado_get_schema($base_table);

    // if the base table does not have a primary key or has more than one then
    // we can't proceed, otherwise, generate the checkboxes
    if (array_key_exists('primary key', $table_info) and count($table_info['primary key']) == 1) {
      $pkey = $table_info['primary key'][0];
      $columns = $args['sync_filters']['checkboxes'];
      $select_cols = '';
      foreach ($columns as $column) {
        $select_cols .= $base_table . '.' . $column . "|| ' ' ||";
      }
      // Remove trailing || ' ' ||
      $select_cols = substr($select_cols, 0, -9);
      $base_table_id = $base_table . '_id';

      $select = array($base_table . '.' . $pkey, $select_cols . ' as value');
      $joins = array();
      $where_clauses = array();
      $where_args = array();

      // Allow module to update the query.
      $hook_query_alter = $node_type . '_chado_node_sync_select_query';
      if (function_exists($hook_query_alter)) {
        $update = call_user_func($hook_query_alter, array(
          'select' => $select,
          'joins' => $joins,
          'where_clauses' => $where_clauses,
          'where_args' => $where_args,
        ));
        // Now add in any new changes
        if ($update and is_array($update)) {
          $select = $update['select'];
          $joins = $update['joins'];
          $where_clauses = $update['where_clauses'];
          $where_args = $update['where_args'];
        }
      }

      // Build Query, we do a left join on the chado_xxxx table in the Drupal schema
      // so that if no criteria are specified we only get those items that have not
      // yet been synced.
      // @todo: re-write the query to support external chado databases.
      $query = "SELECT " . implode(', ', $select) . ' ' .
        'FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins) . ' ' .
        "  LEFT JOIN [$linking_table] CT ON CT.$base_table_id = $base_table.$base_table_id " .
        "WHERE CT.$base_table_id IS NULL";

      // extend the where clause if needed
      $where = '';
      $sql_args = array();
      foreach ($where_clauses as $category => $items) {
        $where .= ' AND (';
        foreach ($items as $item) {
          $where .= $item . ' OR ';
        }
        $where = substr($where, 0, -4); // remove the trailing 'OR'
        $where .= ') ';
        $sql_args = array_merge($sql_args, $where_args[$category]);
      }

      if ($where) {
        $query .= $where;
      }
      $query .= " ORDER BY $base_table." . implode(", $base_table.", $columns);
      $results = chado_query($query, $sql_args);

      $values = array();
      foreach ($results as $result) {
        $values[$result->$pkey] = $result->value;
      }
      if (count($values) > 0) {
        $form['sync']['ids'] = array(
          '#title' => 'Avaliable ' . $args['record_type_title']['plural'],
          '#type' => 'checkboxes',
          '#options' => $values,
          '#default_value' => (isset($form_state['values']['ids'])) ? $form_state['values']['ids'] : array(),
          '#suffix' => '</div><br>',
          '#prefix' => t("The following  %title_plural have not been synced. Check those to be synced or leave all unchecked to sync them all.", 
          array(
            '%title_singular' => strtolower($args['record_type_title']['singular']),
            '%title_plural' => strtolower($args['record_type_title']['plural'])
          )) . '<div style="height: 200px; overflow: scroll">',
        );
      }
      else {
        $form['sync']['no_ids'] = array(
          '#markup' => "<p>There are no " . strtolower($args['record_type_title']['plural']) . " to sync.</p>",
        );
      }
    }
  }
  // if we provide a list of checkboxes we shouldn't need a max_sync
  else {
    $form['sync']['max_sync'] = array(
      '#type' => 'textfield',
      '#title' => t('Maximum number of records to Sync'),
      '#description' => t('Leave this field empty to sync all records, regardless of number'),
      '#default_value' => (isset($form_state['values']['max_sync'])) ? $form_state['values']['max_sync'] : '',
    );
  }

  $form['sync']['button'] = array(
    '#type' => 'submit',
    '#value' => t('Sync ' . $args['record_type_title']['plural']),
    '#weight' => 3,
  );


  $form['cleanup'] = array(
    '#type' => 'fieldset',
    '#title' => t('Clean Up')
  );
  $form['cleanup']['description'] = array(
    '#markup' => t("<p>With Drupal and chado residing in different databases " .
      "it is possible that nodes in Drupal and " . strtolower($args['record_type_title']['plural']) . " in Chado become " .
      "\"orphaned\".  This can occur if a node in Drupal is " .
      "deleted but the corresponding chado records is not and/or vice " .
      "versa. Click the button below to resolve these discrepancies.</p>"),
    '#weight' => -10,
  );
  $form['cleanup']['cleanup_batch_size'] = array(
    '#type' => 'textfield',
    '#title' => t('Batch Size'),
    '#description' => t('The number of records to analyze together in a batch. If you are having memory issues you might want to decrease this number.'),
    '#default_value' => variable_get('chado_node_api_cleanup_batch_size', 25000),
  );
  $form['cleanup']['button'] = array(
    '#type' => 'submit',
    '#value' => 'Clean up orphaned ' . strtolower($args['record_type_title']['plural']),
    '#weight' => 2,
  );

  // Allow each module to alter this form as needed
  $hook_form_alter = $args['hook_prefix'] . '_chado_node_sync_form';
  if (function_exists($hook_form_alter)) {
    $form = call_user_func($hook_form_alter, $form, $form_state);
  }

  return $form;
}