2.0, ); } /************************************************************************ * Display help and module information * @param path which path of the site we're displaying help * @param arg array that holds the current path as would be returned from arg() function * @return help text for the path */ function tripal_feature_help($path, $arg) { $output = ''; switch ($path) { case "admin/help#tripal_feature": $output='
'.t("Displays links to nodes created on this date").'
'; break; } return $output; } /************************************************************************ * Provide information to drupal about the node types that we're creating * in this module */ function tripal_feature_node_info() { $nodes = array(); $nodes['chado_feature'] = array( 'name' => t('Feature'), 'module' => 'chado_feature', 'description' => t('A feature from the chado database'), 'has_title' => FALSE, 'title_label' => t('Feature'), 'has_body' => FALSE, 'body_label' => t('Feature Description'), 'locked' => TRUE ); return $nodes; } /************************************************************************ * Set the permission types that the chado module uses. Essentially we * want permissionis that protect creation, editing and deleting of chado * data objects */ function tripal_feature_perm(){ return array( 'access chado_feature content', 'create chado_feature content', 'delete chado_feature content', 'edit chado_feature content', 'manage chado_feature aggregator', ); } /************************************************************************ * Set the permission types that the module uses. */ function chado_feature_access($op, $node, $account) { if ($op == 'create') { return user_access('create chado_feature content', $account); } if ($op == 'update') { if (user_access('edit chado_feature content', $account)) { return TRUE; } } if ($op == 'delete') { if (user_access('delete chado_feature content', $account)) { return TRUE; } } if ($op == 'view') { if (user_access('access chado_feature content', $account)) { return TRUE; } } return FALSE; } /************************************************************************ * Menu items are automatically added for the new node types created * by this module to the 'Create Content' Navigation menu item. This function * adds more menu items needed for this module. */ function tripal_feature_menu() { $items = array(); // the administative settings menu $items['admin/tripal/tripal_feature'] = array( 'title' => 'Features', 'description' => 'Settings for Chado Features', 'page callback' => 'drupal_get_form', 'page arguments' => array('tripal_feature_admin'), 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); $items['admin/tripal/fasta_loader'] = array( 'title' => 'Import a multi-FASTA file', 'description' => 'Load sequences from a multi-FASTA file into Chado', 'page callback' => 'drupal_get_form', 'page arguments' => array('tripal_feature_fasta_load_form'), 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); // managing relationship aggregates $items['admin/tripal/tripal_feature/aggregate'] = array( 'title' => 'Feature Relationship Aggegators', 'description' => t('Features have relationships with other features and it may be desirable to aggregate the content from one ore more child or parent feature.'), 'page callback' => 'tripal_feature_aggregator_page', 'access arguments' => array('manage chado_feature aggregator'), 'type' => MENU_NORMAL_ITEM, ); $items['admin/tripal/tripal_feature/aggregate/new'] = array( 'title' => 'Add an Aggregator', 'page callback' => 'drupal_get_form', 'page arguments' => array('tripal_feature_aggregator_form'), 'access arguments' => array('manage chado_feature aggregator'), 'type' => MENU_NORMAL_ITEM, ); $items['admin/tripal/tripal_feature/aggregate/edit/js'] = array( 'title' => 'Edit an Aggegator', 'page callback' => 'tripal_feature_aggregator_ajax_edit', 'access arguments' => array('manage chado_feature aggregator'), 'type' => MENU_CALLBACK, ); // Adding Secondary Properties----------------- $items['node/%tripal_feature_node/properties'] = array( 'title' => t('Add Properties & Synonyms'), 'description' => t('Settings for Features'), 'page callback' => 'tripal_feature_add_ALL_property_page', 'page arguments' => array(1), 'access arguments' => array('create chado_feature content'), 'type' => MENU_CALLBACK ); $items['node/%tripal_feature_node/db_references'] = array( 'title' => t('Add Database References'), 'description' => t('Settings for Features'), 'page callback' => 'tripal_feature_add_ALL_dbreferences_page', 'page arguments' => array(1), 'access arguments' => array('create chado_feature content'), 'type' => MENU_CALLBACK ); $items['node/%tripal_feature_node/relationships'] = array( 'title' => t('Add Relationships'), 'description' => t('Settings for Features'), 'page callback' => 'tripal_feature_add_ALL_relationships_page', 'page arguments' => array(1), 'access arguments' => array('create chado_feature content'), 'type' => MENU_CALLBACK ); //Edit/Deleting Secondary Properties------------- $items['node/%tripal_feature_node/edit_properties'] = array( 'title' => t('Edit Properties'), 'description' => t('Settings for Features'), 'page callback' => 'tripal_feature_edit_ALL_properties_page', 'page arguments' => array(1), 'access arguments' => array('edit chado_feature content'), 'type' => MENU_LOCAL_TASK, 'weight' => 8, ); $items['node/%tripal_feature_node/edit_relationships'] = array( 'title' => t('Edit Relationships'), 'description' => t('Settings for Feature'), 'page callback' => 'tripal_feature_edit_ALL_relationships_page', 'page arguments' => array(1), 'access arguments' => array('edit chado_feature content'), 'type' => MENU_LOCAL_TASK, 'weight' => 9, ); $items['node/%tripal_feature_node/edit_db_references'] = array( 'title' => t('Edit References'), 'description' => t('Settings for Feature'), 'page callback' => 'tripal_feature_edit_ALL_dbreferences_page', 'page arguments' => array(1), 'access arguments' => array('edit chado_feature content'), 'type' => MENU_LOCAL_TASK, 'weight' => 10, ); return $items; } /************************************************************************* * Implements Menu wildcard_load hook * Purpose: Allows the node ID of a chado stock to be dynamically * pulled from the path. The node is loaded from this node ID * and supplied to the page as an arguement */ function tripal_feature_node_load($nid) { if (is_numeric($nid)) { $node = node_load($nid); if ($node->type == 'chado_feature') { return $node; } } return FALSE; } /************************************************************************ * When a new chado_feature node is created we also need to add information * to our chado_feature table. This function is called on insert of a new node * of type 'chado_feature' and inserts the necessary information. */ function chado_feature_insert($node){ // remove spaces, newlines from residues $residues = preg_replace("/[\n\r\s]/","",$node->residues); // If this feature already exists then don't recreate it in chado // TODO: the unique index in chado for this also includes the type_id. If the site // ever needs to have the same feature name for different types then this will break. $feature_sql = "SELECT * FROM {Feature} F INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id WHERE uniquename = '%s' and organism_id = %d and CVT.name = '%s'"; $previous_db = tripal_db_set_active('chado'); $feature = db_fetch_object(db_query($feature_sql,$node->uniquename,$node->organism_id,$node->feature_type)); tripal_db_set_active($previous_db); // if the feature doesn't exist then let's create it in chado. if(!$feature){ $sql = "INSERT INTO {feature} (organism_id, name, uniquename, residues, seqlen,". " is_obsolete, type_id)". " VALUES(%d,'%s','%s','%s',%d, %s, ". " (SELECT cvterm_id ". " FROM {CVTerm} CVT ". " INNER JOIN CV ON CVT.cv_id = CV.cv_id ". " WHERE CV.name = 'sequence' and CVT.name = '%s'))"; $obsolete = 'FALSE'; if($node->is_obsolete){ $obsolete = 'TRUE'; } // use chado database $previous_db = tripal_db_set_active('chado'); db_query($sql,$node->organism_id,$node->name,$node->uniquename, $residues,strlen($residues),$obsolete,$node->feature_type); // now that we've added the feature, get the feature id for this feature $feature = db_fetch_object(db_query($feature_sql,$node->uniquename,$node->organism_id,$node->feature_type)); // now use drupal database tripal_db_set_active($previous_db); } // add the genbank accession and synonyms chado_feature_add_synonyms($node->synonyms,$feature->feature_id); // make sure the entry for this feature doesn't already exist in the chado_feature table // if it doesn't exist then we want to add it. $node_check_sql = "SELECT * FROM {chado_feature} ". "WHERE feature_id = '%s'"; $node_check = db_fetch_object(db_query($node_check_sql,$feature->feature_id)); if(!$node_check){ // next add the item to the drupal table $sql = "INSERT INTO {chado_feature} (nid, vid, feature_id, sync_date) ". "VALUES (%d, %d, %d, " . time() . ")"; db_query($sql,$node->nid,$node->vid,$feature->feature_id); } } /************************************************************************ */ function chado_feature_delete($node){ // get feature_id so we can remove it from chado database $sql_drupal = "SELECT feature_id ". "FROM {chado_feature} ". "WHERE nid = %d AND vid = %d"; $feature_id = db_result(db_query($sql_drupal, $node->nid, $node->vid)); // remove the drupal content $sql_del = "DELETE FROM {chado_feature} ". "WHERE nid = %d ". "AND vid = %d"; db_query($sql_del, $node->nid, $node->vid); $sql_del = "DELETE FROM {node} ". "WHERE nid = %d ". "AND vid = %d"; db_query($sql_del, $node->nid, $node->vid); $sql_del = "DELETE FROM {node_revisions} ". "WHERE nid = %d ". "AND vid = %d"; db_query($sql_del, $node->nid, $node->vid); // Remove data from feature tables of chado database. This will // cause a cascade delete and remove all data in referencing tables // for this feature $previous_db = tripal_db_set_active('chado'); db_query("DELETE FROM {feature} WHERE feature_id = %d", $feature_id); tripal_db_set_active($previous_db); drupal_set_message("The feature and all associated data were removed from ". "chado"); } /************************************************************************ */ function chado_feature_update($node){ if($node->revision){ // TODO -- decide what to do about revisions } else { // get the feature for this node: $sql = 'SELECT feature_id FROM {chado_feature} WHERE vid = %d'; $feature = db_fetch_object(db_query($sql, $node->vid)); // remove spaces, newlines from residues $residues = preg_replace("/[\n\r\s]/","",$node->residues); $sql = "UPDATE {feature} ". " SET residues = '%s', ". " name = '%s', ". " uniquename = '%s', ". " seqlen = %d, ". " organism_id = %d, ". " is_obsolete = %s, ". " type_id = (SELECT cvterm_id ". " FROM {CVTerm} CVT ". " INNER JOIN CV ON CVT.cv_id = CV.cv_id ". " WHERE CV.name = 'sequence' and CVT.name = '%s') ". "WHERE feature_id = %d "; $obsolete = 'FALSE'; if($node->is_obsolete){ $obsolete = 'TRUE'; } $previous_db = tripal_db_set_active('chado'); // use chado database db_query($sql,$residues,$node->name,$node->uniquename, strlen($residues),$node->organism_id,$obsolete,$node->feature_type, $feature->feature_id); tripal_db_set_active($previous_db); // now use drupal database // add the genbank accession & synonyms // chado_feature_add_gbaccession($node->gbaccession,$feature->feature_id); chado_feature_add_synonyms($node->synonyms,$feature->feature_id); } } /************************************************************************ * */ function chado_feature_add_synonyms($synonyms,$feature_id){ // make sure we only have a single space between each synonym $synonyms = preg_replace("/[\s\n\r]+/"," ",$synonyms); // split the synonyms into an array based on a space as the delimieter $syn_array = array(); $syn_array = explode(" ",$synonyms); // use the chado database $previous_db = tripal_db_set_active('chado'); // remove any old synonyms $feature_syn_dsql = "DELETE FROM {feature_synonym} WHERE feature_id = %d"; if(!db_query($feature_syn_dsql,$feature_id)){ $error .= "Could not remove synonyms from feature. "; } // return if we don't have any synonmys to add if(!$synonyms){ tripal_db_set_active($previous_db); return; } // iterate through each synonym and add it to the database foreach($syn_array as $syn){ // skip this item if it's empty if(!$syn){ break; } // check to see if we have this accession number already in the database // if so then don't add it again. it messes up drupal if the insert fails. // It is possible for the accession number to be present and not the feature $synonym_sql = "SELECT synonym_id FROM {synonym} ". "WHERE name = '%s'"; $synonym = db_fetch_object(db_query($synonym_sql,$syn)); if(!$synonym){ $synonym_isql = "INSERT INTO {synonym} (name,synonym_sgml,type_id) ". "VALUES ('%s','%s', ". " (SELECT cvterm_id ". " FROM {CVTerm} CVT ". " INNER JOIN CV ON CVT.cv_id = CV.cv_id ". " WHERE CV.name = 'feature_property' and CVT.name = 'synonym'))"; if(!db_query($synonym_isql,$syn,$syn)){ $error .= "Could not add synonym. "; } // now get the synonym we just added $synonym_sql = "SELECT synonym_id FROM {synonym} ". "WHERE name = '%s'"; $synonym = db_fetch_object(db_query($synonym_sql,$syn)); } // now add in our new sysnonym $feature_syn_isql = "INSERT INTO {feature_synonym} (synonym_id,feature_id,pub_id) ". "VALUES (%d,%d,1)"; if(!db_query($feature_syn_isql,$synonym->synonym_id,$feature_id)){ $error .= "Could not add synonyms to feature. "; } } // return to the drupal database tripal_db_set_active($previous_db); return $error; } /************************************************************************ * */ function chado_feature_add_gbaccession($accession,$feature_id){ // use chado database $previous_db = tripal_db_set_active('chado'); // remove any old accession from genbank dbEST $fdbxref_dsql = "DELETE FROM {feature_dbxref} ". "WHERE feature_id = %d and dbxref_id IN ". " (SELECT DBX.dbxref_id FROM {dbxref} DBX ". " INNER JOIN DB ON DB.db_id = DBX.db_id ". " INNER JOIN feature_dbxref FDBX ON DBX.dbxref_id = FDBX.dbxref_id ". " WHERE DB.name = 'DB:Genbank' and FDBX.feature_id = %d)"; if(!db_query($fdbxref_dsql,$feature_id,$feature_id)){ $error .= "Could not remove accession from feature. "; } // if we don't have an accession number to add then just return if(!$accession){ tripal_db_set_active($previous_db); return; } // get the db_id $db_sql = "SELECT db_id FROM {DB} ". "WHERE name = 'DB:Genbank_est'"; $db = db_fetch_object(db_query($db_sql)); // check to see if we have this accession number already in the database // if so then don't add it again. it messes up drupal if the insert fails. // It is possible for the accession number to be present and not the feature $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ". "WHERE db_id = %d and accession = '%s'"; $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession)); if(!$dbxref){ // add the accession number $dbxref_isql = "INSERT INTO {dbxref} (db_id,accession) ". " VALUES (%d, '%s') "; if(!db_query($dbxref_isql,$db->db_id,$accession)){ $error .= 'Could not add accession as a database reference '; } // get the dbxref_id for the just added accession number $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ". "WHERE db_id = %d and accession = '%s'"; $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession)); } // associate the accession number with the feature $feature_dbxref_isql = "INSERT INTO {feature_dbxref} (feature_id,dbxref_id) ". " VALUES (%d, %d) "; if(!db_query($feature_dbxref_isql,$feature_id,$dbxref->dbxref_id)){ $error .= 'Could not add feature database reference. '; } tripal_db_set_active($previous_db); return $error; } /************************************************************************ * */ function chado_feature_form ($node,$param){ $type = node_get_types('type', $node); $form = array(); $feature = $node->feature; $synonyms = $node->synonyms; $analyses = $node->analyses; $references = $node->references; // We need to pass above variables for preview to show $form['feature'] = array( '#type' => 'value', '#value' => $feature ); // This field is read when previewing a node $form['synonyms'] = array( '#type' => 'value', '#value' => $synonyms ); // This field is read when previewing a node $form['analyses'] = array( '#type' => 'value', '#value' => $analyses ); // This field is read when previewing a node $form['references'] = array( '#type' => 'value', '#value' => $references ); // keep track of the feature id if we have one. If we do have one then // this would indicate an update as opposed to an insert. $form['feature_id'] = array( '#type' => 'value', '#value' => $feature->feature_id, ); $form['title']= array( '#type' => 'textfield', '#title' => t('Title'), '#required' => TRUE, '#default_value' => $feature->featurename, '#description' => t('The title must be a unique identifier for this feature. It is recommended to use a combination of uniquename, organism and feature type in the title as this is guranteed to be unique.'), '#weight' => 1, '#maxlength' => 255 ); $form['uniquename']= array( '#type' => 'textfield', '#title' => t('Unique Feature Name'), '#required' => TRUE, '#default_value' => $feature->featurename, '#description' => t('Enter a unique name for this feature. This name must be unique for the organism and feature type.'), '#weight' => 1, '#maxlength' => 255 ); $form['name']= array( '#type' => 'textfield', '#title' => t('Feature Name'), '#required' => TRUE, '#default_value' => $feature->featurename, '#description' => t('Enter the name used by humans to refer to this feature.'), '#weight' => 1, '#maxlength' => 255 ); // get the list of supported feature types $ftypes = array(); $ftypes[''] = ''; $supported_ftypes = split("[ \n]",variable_get('chado_feature_types','EST contig')); foreach($supported_ftypes as $ftype){ $ftypes["$ftype"] = $ftype; } $form['feature_type'] = array ( '#title' => t('Feature Type'), '#type' => t('select'), '#description' => t("Choose the feature type."), '#required' => TRUE, '#default_value' => $feature->cvname, '#options' => $ftypes, '#weight' => 2 ); // get the list of organisms $sql = "SELECT * FROM {Organism} ORDER BY genus, species"; $previous_db = tripal_db_set_active('chado'); // use chado database $org_rset = db_query($sql); tripal_db_set_active($previous_db); // now use drupal database // $organisms = array(); $organisms[''] = ''; while($organism = db_fetch_object($org_rset)){ $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)"; } $form['organism_id'] = array ( '#title' => t('Organism'), '#type' => t('select'), '#description' => t("Choose the organism with which this feature is associated "), '#required' => TRUE, '#default_value' => $feature->organism_id, '#options' => $organisms, '#weight' => 3, ); // Get synonyms if ($synonyms) { if (is_array($synonyms)) { foreach ($synonyms as $synonym){ $syn_text .= "$synonym->name\n"; } } else { $syn_text = $synonyms; } } $form['synonyms']= array( '#type' => 'textarea', '#title' => t('Synonyms'), '#required' => FALSE, '#default_value' => $syn_text, '#description' => t('Enter alternate names (synonmys) for this feature to help in searching and identification. You may enter as many alternate names as needed separated by spaces or on different lines.'), '#weight' => 5, ); $form['residues']= array( '#type' => 'textarea', '#title' => t('Residues'), '#required' => FALSE, '#default_value' => $feature->residues, '#description' => t('Enter the nucelotide sequences for this feature'), '#weight' => 6 ); $checked = ''; if($feature->is_obsolete == 't'){ $checked = '1'; } $form['is_obsolete']= array( '#type' => 'checkbox', '#title' => t('Is Obsolete'), '#required' => FALSE, '#default_value' => $checked, '#description' => t('Check this box if this sequence should be retired and no longer included in further analysis.'), '#weight' => 8 ); return $form; } /************************************************************************ * */ function chado_feature_validate($node){ $result = 0; // if this is an update, we want to make sure that a different feature for // the organism doesn't already have this uniquename. We don't want to give // two sequences the same uniquename if($node->feature_id){ $sql = "SELECT * FROM {Feature} F INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id WHERE uniquename = '%s' AND organism_id = %d AND CVT.name = '%s' AND NOT feature_id = %d"; $previous_db = tripal_db_set_active('chado'); $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type,$node->feature_id)); tripal_db_set_active($previous_db); if($result){ form_set_error('uniquename',t("Feature update cannot proceed. The feature name '$node->uniquename' is not unique for this organism. Please provide a unique name for this feature. ")); } } // if this is an insert then we just need to make sure this name doesn't // already exist for this organism if it does then we need to throw an error else { $sql = "SELECT * FROM {Feature} F INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id WHERE uniquename = '%s' AND organism_id = %d AND CVT.name = '%s'"; $previous_db = tripal_db_set_active('chado'); $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type)); tripal_db_set_active($previous_db); if($result){ form_set_error('uniquename',t("Feature insert cannot proceed. The feature name '$node->uniquename' already exists for this organism. Please provide a unique name for this feature. ")); } } // we want to remove all characters except IUPAC nucleotide characters from the // the residues. however, residues are not required so if blank then we'll skip // this step if($node->residues){ $residues = preg_replace("/[^\w]/",'',$node->residues); if(!preg_match("/^[ACTGURYMKSWBDHVN]+$/i",$residues)){ form_set_error('residues',t("The residues in feature $node->name contains more than the nucleotide IUPAC characters. Only the following characters are allowed: A,C,T,G,U,R,Y,M,K,S,W,B,D,H,V,N: '" . $residues ."'")); } } // we don't allow a genbank accession number for a contig if($node->feature_type == 'contig' and $node->gbaccession){ form_set_error('gbaccession',t("Contigs cannot have a genbank accession number. Please change the feature type or remove the accession number")); } } /************************************************************************ * When a node is requested by the user this function is called to allow us * to add auxiliary data to the node object. */ function chado_feature_load($node){ // add the feature_id for this node: $sql = 'SELECT feature_id FROM {chado_feature} WHERE vid = %d'; $feature = db_fetch_object(db_query($sql, $node->vid)); $feature_id = $feature->feature_id; // get information about this feature and add it to the items in this node $sql = "SELECT F.feature_id, F.name as featurename, F.uniquename, ". "F.residues, F.seqlen, O.genus, O.species, O.common_name, ". " CVT.name as cvname, O.organism_id, F.type_id, F.is_obsolete ". "FROM {Feature} F ". " INNER JOIN Organism O ON F.organism_id = O.organism_id ". " INNER JOIN CVterm CVT ON F.type_id = CVT.cvterm_id ". "WHERE F.feature_id = %d"; $previous_db = tripal_db_set_active('chado'); // use chado database $feature = db_fetch_object(db_query($sql,$feature_id)); tripal_db_set_active($previous_db); // now use drupal database $additions->feature = $feature; $additions->seqlen = $feature->seqlen; $organism_id = $feature->organism_id; // add organism node nid $sql = "SELECT nid FROM {chado_organism} WHERE organism_id = %d"; $org_nid = db_result(db_query($sql, $additions->feature->organism_id)); $additions->org_nid = $org_nid; $additions->accession = variable_get('chado_feature_accession_prefix','ID') . $feature->feature_id; // add the relationships for which this feature is the subject $additions->subject_relationships = tripal_feature_load_relationships($feature_id,'as_subject'); // add the relationships for which this feature is the object $additions->object_relationships = tripal_feature_get_aggregate_relationships($feature_id,0); // add details about the organism $additions->organism = tripal_feature_load_organism($organism_id); // add the list of synomyms $additions->synonyms = tripal_feature_load_synonyms($feature_id); // add the list of refernces $additions->references = tripal_feature_load_references($feature_id); // add the list of children located on this feature $additions->myfeaturelocs = tripal_feature_load_featurelocs($feature_id,'as_parent'); // add the list of features on which this feature is located $additions->featurelocs = tripal_feature_load_featurelocs($feature_id,'as_child',0); // add the formatted featureloc sequence with highlighting from relationship sequences $additions->floc_sequences = tripal_feature_load_featureloc_sequence ($feature_id,$additions->featurelocs); return $additions; } /************************************************************************ * */ function tripal_feature_load_organism ($organism_id){ // add organism details $sql = "SELECT * FROM {organism} WHERE organism_id = %d"; $previous_db = tripal_db_set_active('chado'); // use chado database $organism = db_fetch_object(db_query($sql,$organism_id)); tripal_db_set_active($previous_db); // now use drupal database return $organism; } /************************************************************************ * */ function tripal_feature_load_synonyms ($feature_id){ $sql = "SELECT S.name ". "FROM {Feature_Synonym} FS ". " INNER JOIN Synonym S ". " ON FS.synonym_id = S.Synonym_id ". "WHERE FS.feature_id = %d"; $previous_db = tripal_db_set_active('chado'); // use chado database $results = db_query($sql,$feature_id); tripal_db_set_active($previous_db); // now use drupal database $synonyms = array(); $i=0; while($synonym = db_fetch_object($results)){ $synonyms[$i++] = $synonym; } return $synonyms; } /************************************************************************ * */ function tripal_feature_load_references ($feature_id){ $sql = "SELECT F.uniquename,F.Feature_id,DBX.accession,DB.description as dbdesc, ". " DB.db_id, DB.name as db_name, DB.urlprefix,DBX.dbxref_id ". "FROM {feature} F ". " INNER JOIN Feature_dbxref FDBX on F.feature_id = FDBX.feature_id ". " INNER JOIN Dbxref DBX on DBX.dbxref_id = FDBX.dbxref_id ". " INNER JOIN DB on DB.db_id = DBX.db_id ". "WHERE F.feature_id = %d"; $previous_db = tripal_db_set_active('chado'); // use chado database $results = db_query($sql,$feature_id); tripal_db_set_active($previous_db); // now use drupal database $references = array(); $i=0; while($accession = db_fetch_object($results)){ $references[$i++] = $accession; } return $references; } /************************************************************************ * */ function tripal_feature_load_featurelocs ($feature_id,$side = 'as_parent',$aggregate = 1){ $sql = "SELECT F.name, F.feature_id, F.uniquename, FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename, CVT.name as cvname, CVT.cvterm_id, CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id, FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase FROM {featureloc} FL INNER JOIN {feature} F on FL.feature_id = F.feature_id INNER JOIN {feature} FS on FS.feature_id = FL.srcfeature_id INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id INNER JOIN {cvterm} CVTS on FS.type_id = CVTS.cvterm_id "; if(strcmp($side,'as_parent')==0){ $sql .= "WHERE FL.srcfeature_id = %d "; } if(strcmp($side,'as_child')==0){ $sql .= "WHERE FL.feature_id = %d "; } $previous_db = tripal_db_set_active('chado'); // use chado database $flresults = db_query($sql, $feature_id); tripal_db_set_active($previous_db); // now use drupal database // copy the results into an array $i=0; $featurelocs = array(); while($loc = db_fetch_object($flresults)){ // if a drupal node exists for this feature then add the nid to the // results object $sql = 'SELECT nid FROM {chado_feature} WHERE feature_id = %d'; if(strcmp($side,'as_parent')==0){ $feature = db_fetch_object(db_query($sql, $loc->feature_id)); } if(strcmp($side,'as_child')==0){ $feature = db_fetch_object(db_query($sql, $loc->src_feature_id)); } $loc->nid = $feature->nid; // add the result to the array $featurelocs[$i++] = $loc; } // Add the relationship feature locs if aggregate is turned on if($aggregate and strcmp($side,'as_parent')==0){ // get the relationships for this feature without substituting any children // for the parent. We want all relationships $relationships = tripal_feature_get_aggregate_relationships($feature_id,0); foreach($relationships as $rindex => $rel){ // get the featurelocs for each of the relationship features $rel_featurelocs = tripal_feature_load_featurelocs ($rel->subject_id,'as_child',0); foreach($rel_featurelocs as $findex => $rfloc){ $featurelocs[$i++] = $rfloc; } } } usort($featurelocs,'tripal_feature_sort_locations'); return $featurelocs; } /************************************************************************ * used to sort the feature locs by start position */ function tripal_feature_sort_locations($a,$b){ return strnatcmp($a->fmin, $b->fmin); } /************************************************************************ * */ function tripal_feature_load_relationships ($feature_id,$side = 'as_subject'){ // get the relationships for this feature. The query below is used for both // querying the object and subject relationships $sql = "SELECT FS.name as subject_name, FS.uniquename as subject_uniquename, CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id, FR.subject_id, FR.type_id as relationship_type_id, CVT.name as rel_type, FO.name as object_name, FO.uniquename as object_uniquename, CVTO.name as object_type, CVTO.cvterm_id as object_type_id, FR.object_id, FR.rank FROM {feature_relationship} FR INNER JOIN {cvterm} CVT ON FR.type_id = CVT.cvterm_id INNER JOIN {feature} FS ON FS.feature_id = FR.subject_id INNER JOIN {feature} FO ON FO.feature_id = FR.object_id INNER JOIN {cvterm} CVTO ON FO.type_id = CVTO.cvterm_id INNER JOIN {cvterm} CVTS ON FS.type_id = CVTS.cvterm_id "; if(strcmp($side,'as_object')==0){ $sql .= " WHERE FR.object_id = %d"; } if(strcmp($side,'as_subject')==0){ $sql .= " WHERE FR.subject_id = %d"; } $sql .= " ORDER BY FR.rank"; // get the relationships $previous_db = tripal_db_set_active('chado'); // use chado database $results = db_query($sql, $feature_id); tripal_db_set_active($previous_db); // now use drupal database // iterate through the relationships, put these in an array and add // in the Drupal node id if one exists $i=0; $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = %d"; $relationships = array(); while($rel = db_fetch_object($results)){ $node = db_fetch_object(db_query($nodesql,$rel->subject_id)); if($node){ $rel->subject_nid = $node->nid; } $node = db_fetch_object(db_query($nodesql,$rel->object_id)); if($node){ $rel->object_nid = $node->nid; } $relationships[$i++] = $rel; } return $relationships; } /************************************************************************ * */ function tripal_feature_get_aggregate_types($feature_id){ // get the feature details $sql = 'SELECT type_id FROM {feature} WHERE feature_id = %d'; $previous_db = tripal_db_set_active('chado'); // use chado database $feature = db_fetch_object(db_query($sql, $feature_id)); tripal_db_set_active($previous_db); // now use drupal database // check to see if this feature is of a type with an aggregate $sql = "SELECT * FROM {tripal_feature_relagg} WHERE type_id = %d"; $types = array(); $results = db_query($sql,$feature->type_id); while($agg = db_fetch_object($results)){ $types[] = $agg->rel_type_id; } return $types; } /************************************************************************ * */ function tripal_feature_get_aggregate_relationships($feature_id, $substitute=1, $levels=0, $base_type_id=NULL, $depth=0) { // we only want to recurse to as many levels deep as indicated by the // $levels variable, but only if this variable is > 0. If 0 then we // recurse until we reach the end of the relationships tree. if($levels > 0 and $levels == $depth){ return NULL; } // first get the relationships for this feature $relationships = tripal_feature_load_relationships($feature_id,'as_object'); // next, iterate through these relationships and descend, adding in those // that are specified by the aggregator. $i=0; $new_relationships = array(); foreach($relationships as $rindex => $rel){ // set the base type id if(!$base_type_id){ $base_type_id = $rel->object_type_id; } // check to see if we have an aggregator for this base type $sql = "SELECT * FROM {tripal_feature_relagg} WHERE type_id = %d and rel_type_id = %d"; $agg = db_fetch_object(db_query($sql,$base_type_id,$rel->subject_type_id)); if($agg){ // if we're not going to substitute the resulting relationships for the // parent then we need to add the parent to our list if(!$substitute){ $new_relationships[$i++] = $rel; } // recurse all relationships $agg_relationships = tripal_feature_get_aggregate_relationships( $rel->subject_id,$levels,$base_type_id,$depth++); // if we have an aggregate defined but we have no relationships beyond // this point then there's nothing we can substitute if(!$agg_relationships and $substitute){ $new_relationships[$i++] = $rel; } // merge all relationships into one array foreach($agg_relationships as $aindex => $arel){ $new_relationships[$i++] = $arel; } } else { // if we don't have an aggregate then keep the current relationship $new_relationships[$i++] = $rel; } } return $new_relationships; } /************************************************************************ * */ function tripal_feature_load_featureloc_sequence($feature_id,$featurelocs){ $floc_sequences = array(); // if we don't have any featurelocs then no point in continuing if(!$featurelocs){ return false; } // get the list of relationships (including any aggregators) and iterate // through each one to find information needed to color-code the reference sequence $relationships = tripal_feature_get_aggregate_relationships($feature_id); if(!$relationships){ return false; } foreach($relationships as $rindex => $rel){ // get the featurelocs for each of the relationship features $rel_featurelocs = tripal_feature_load_featurelocs ($rel->subject_id,'as_child',0); foreach($rel_featurelocs as $rfindex => $rel_featureloc){ // keep track of this unique source feature $src = $rel_featureloc->src_feature_id ."-". $rel_featureloc->src_type_id; // copy over the results to the relationship object. Since there can // be more than one feature location for each relationship feature we // use the '$src' variable to keep track of these. $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename; $rel->featurelocs->$src->src_type_id = $rel_featureloc->src_type_id; $rel->featurelocs->$src->src_cvname = $rel_featureloc->src_cvname; $rel->featurelocs->$src->fmin = $rel_featureloc->fmin; $rel->featurelocs->$src->fmax = $rel_featureloc->fmax; $rel->featurelocs->$src->src_name = $rel_featureloc->src_name; // keep track of the individual parts for each relationship $start = $rel->featurelocs->$src->fmin; $end = $rel->featurelocs->$src->fmax; $rel_locs[$src]['parts'][$start]['type'] = $rel->subject_type; $rel_locs[$src]['parts'][$start]['start'] = $start; $rel_locs[$src]['parts'][$start]['end'] = $end; } } // now get the sequence for each featureloc and highlight the different // relationships $sql = "SELECT residues FROM {feature} WHERE feature_id = %d"; foreach ($featurelocs as $findex => $featureloc){ // get the residues for this feature $previous_db = tripal_db_set_active('chado'); // use chado database $feature = db_fetch_object(db_query($sql,$featureloc->src_feature_id)); tripal_db_set_active($previous_db); // now use drupal database $src = $featureloc->src_feature_id ."-". $featureloc->src_type_id; // orient the parts to the beginning of the feature sequence $parts = $rel_locs[$src]['parts']; usort($parts, 'tripal_feature_sort_rel_parts'); foreach ($parts as $start => $attrs){ $parts[$start]['start'] = $parts[$start]['start'] - $featureloc->fmin; $parts[$start]['end'] = $parts[$start]['end'] - $featureloc->fmin; } $floc_sequences[$src]['src'] = $src; $floc_sequences[$src]['type'] = $featureloc->cvname; $sequence = substr($feature->residues,$featureloc->fmin,$featureloc->fmax - $featureloc->fmin); $floc_sequences[$src]['formatted_seq'] = tripal_feature_color_sequence ( $sequence,$parts); } return $floc_sequences; } /************************************************************************ * used to sort the list of relationship objects by start position */ function tripal_feature_sort_rel_objects($a,$b){ return strnatcmp($a->fmin, $b->fmin); } /************************************************************************ * used to sort the list of relationship parts by start position */ function tripal_feature_sort_rel_parts($a,$b){ return strnatcmp($a['start'], $b['start']); } /************************************************************************ * */ function tripal_feature_color_sequence ($sequence,$parts){ $types = array(); // first get the list of types so we can create a color legend foreach ($parts as $index => $child){ $type = $child['type']; if(!in_array($type,$types)){ $types[] = $type; } } $newseq .= "";
foreach ($parts as $index => $child){
$type = $child['type'];
$start = $child['start'];
$end = $child['end'];
$class = "class=\"tripal_feature-sequence-$type\"";
// iterate through the sequence up to the end of the child
for ($i = $pos; $i < $end; $i++){
// if we're at the beginning of the child sequence then set the
// appropriate text color
if($pos == $start){
$newseq .= "";
$func = 'uc'; // nucleotides within the child should be uppercase
}
$newseq .= $sequence{$pos};
$seqcount++;
if($seqcount % 100 == 0){
$newseq .= "\n";
}
$pos++;
if($pos == $end){
$newseq .= "";
$func = 'lc';
}
}
}
$newseq .= "
";
return $newseq;
}
/************************************************************************
* This function customizes the view of the chado_feature node. It allows
* us to generate the markup.
*/
function chado_feature_view ($node, $teaser = FALSE, $page = FALSE) {
if (!$teaser) {
// use drupal's default node view:
$node = node_prepare($node, $teaser);
// if we're building the node for searching then
// we want to handle this within the module and
// not allow theme customization. We don't want to
// index all items (such as DNA sequence).
if($node->build_mode == NODE_BUILD_SEARCH_INDEX){
$node->content['index_version'] = array(
'#value' => theme('tripal_feature_search_index',$node),
'#weight' => 1,
);
}
else if($node->build_mode == NODE_BUILD_SEARCH_RESULT){
$node->content['index_version'] = array(
'#value' => theme('tripal_feature_search_results',$node),
'#weight' => 1,
);
}
else {
// do nothing here, let the theme derived template handle display
}
}
return $node;
}
/*******************************************************************************
* Display feature information for associated organisms. This function also
* provides contents for indexing
*/
function tripal_feature_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
// Note that this function only adds feature view to an organism node.
// The view of a feature node is controled by the theme *.tpl file
case 'view':
// Set the node types for showing feature information
$types_to_show = array('chado_organism', 'chado_library');
// Abort if this node is not one of the types we should show.
if (!in_array($node->type, $types_to_show, TRUE)) {
break;
}
// Add feature to the content item if it's not a teaser
if (!$teaser) {
// Show feature browser
$node->content['tripal_feature_browser'] = array(
'#value' => theme('tripal_feature_browser', $node),
'#weight' => 5
);
$node->content['tripal_feature_org_counts'] = array(
'#value' => theme('tripal_feature_counts', $node),
'#weight' => 4
);
}
}
}
/************************************************************************
* We need to let drupal know about our theme functions and their arguments.
* We create theme functions to allow users of the module to customize the
* look and feel of the output generated in this module
*/
function tripal_feature_theme () {
return array(
'tripal_feature_search_index' => array (
'arguments' => array('node'),
),
'tripal_feature_search_results' => array (
'arguments' => array('node'),
),
'tripal_feature_browser' => array (
'arguments' => array('node'),
),
'tripal_feature_counts' => array (
'arguments' => array('node'),
)
);
}
/*******************************************************************************
* create a list of features for the organism and pie chart
*/
function theme_tripal_feature_counts($node){
// don't show the summary if the settings in the admin page is turned off
$show_browser = variable_get('tripal_feature_summary_setting',array('show_feature_summary'));
if(strcmp($show_browser[0],'show_feature_summary')!=0){
return;
}
// get the feature counts. This is dependent on a materialized view
// installed with the organism module
$content = '';
if ($node->organism_id && $node->type == 'chado_organism') {
$sql = "SELECT * FROM {organism_feature_count} ".
"WHERE organism_id = %d AND NOT feature_type = 'EST_match' ".
"ORDER BY num_features desc";
$features = array();
$previous_db = tripal_db_set_active('chado'); // use chado database
$results = db_query($sql,$node->organism_id);
tripal_db_set_active($previous_db); // now use drupal database
$feature = db_fetch_object($results); // retrieve the first result
if ($feature) {
$content .= "