|
@@ -0,0 +1,782 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+/**
|
|
|
+ * @file
|
|
|
+ * Implements the phylotree node content type
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_node_info().
|
|
|
+ *
|
|
|
+ * Provide information to drupal about the node types that we're creating
|
|
|
+ * in this module.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function tripal_phylogeny_node_info() {
|
|
|
+ $nodes = array();
|
|
|
+ $nodes['chado_phylotree'] = array(
|
|
|
+ 'name' => t('Phylotree'),
|
|
|
+ 'base' => 'chado_phylotree',
|
|
|
+ 'description' => t('A phylotree from the chado database'),
|
|
|
+ 'has_title' => TRUE,
|
|
|
+ 'locked' => TRUE,
|
|
|
+ 'chado_node_api' => array(
|
|
|
+ 'base_table' => 'phylotree',
|
|
|
+ 'hook_prefix' => 'chado_phylotree',
|
|
|
+ 'record_type_title' => array(
|
|
|
+ 'singular' => t('Phylotree'),
|
|
|
+ 'plural' => t('Phylotrees')
|
|
|
+ ),
|
|
|
+
|
|
|
+ /* sync_filters: tripal is hardcoded to look for this
|
|
|
+ sync_filter settings: type_id and organism_id. (phylotree does
|
|
|
+ not have organism_id but need to set it false anyways. */
|
|
|
+ 'sync_filters' => array(
|
|
|
+ 'type_id' => FALSE,
|
|
|
+ 'organism_id' => FALSE
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ );
|
|
|
+ return $nodes;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_node_view(). Acts on all content types
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function tripal_phylogeny_node_view($node, $view_mode, $langcode) {
|
|
|
+
|
|
|
+ if($node->type != 'chado_phylotree') { return; }
|
|
|
+
|
|
|
+ switch($view_mode) {
|
|
|
+ case 'full':
|
|
|
+ $node->content['tripal_phylogeny_base'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_base',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'base',
|
|
|
+ '#tripal_toc_title' => 'Overview',
|
|
|
+ '#weight' => -100,
|
|
|
+ );
|
|
|
+ $node->content['tripal_phylogeny_phylogram'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_phylogram',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'phylotree_phylogram',
|
|
|
+ '#tripal_toc_title' => 'Phylogram',
|
|
|
+ '#weight' => -90,
|
|
|
+ );
|
|
|
+ $node->content['tripal_phylogeny_taxonomic_tree'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_taxonomic_tree',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'tripal_phylogeny_taxonomic_tree',
|
|
|
+ '#tripal_toc_title' => 'Taxonomic Tree',
|
|
|
+ '#weight' => -80,
|
|
|
+ );
|
|
|
+ $node->content['tripal_phylogeny_organisms'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_organisms',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'phylotree_organisms',
|
|
|
+ '#tripal_toc_title' => 'Organisms',
|
|
|
+ '#weight' => -70,
|
|
|
+ );
|
|
|
+ $node->content['tripal_phylogeny_references'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_references',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'phylotree_references',
|
|
|
+ '#tripal_toc_title' => 'Cross References',
|
|
|
+ );
|
|
|
+ $node->content['tripal_phylogeny_analysis'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_analysis',
|
|
|
+ '#node' => $node,
|
|
|
+ '#tripal_toc_id' => 'phylotree_analysis',
|
|
|
+ '#tripal_toc_title' => 'Analysis',
|
|
|
+ );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'teaser':
|
|
|
+ $node->content['tripal_phylogeny_teaser'] = array(
|
|
|
+ '#theme' => 'tripal_phylogeny_teaser',
|
|
|
+ '#node' => $node,
|
|
|
+ );
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implementation of hook_form().
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_form($node, &$form_state) {
|
|
|
+
|
|
|
+ $form = array();
|
|
|
+
|
|
|
+ // Default values can come in the following ways:
|
|
|
+ //
|
|
|
+ // 1) as elements of the $node object. This occurs when editing an existing phylotree
|
|
|
+ // 2) in the $form_state['values'] array which occurs on a failed validation or
|
|
|
+ // ajax callbacks from non submit form elements
|
|
|
+ // 3) in the $form_state['input'[ array which occurs on ajax callbacks from submit
|
|
|
+ // form elements and the form is being rebuilt
|
|
|
+ //
|
|
|
+ // set form field defaults
|
|
|
+ $phylotree = null;
|
|
|
+ $phylotree_id = null;
|
|
|
+ $tree_name = '';
|
|
|
+ $leaf_type = '';
|
|
|
+ $analysis_id = '';
|
|
|
+ $dbxref = '';
|
|
|
+ $comment = '';
|
|
|
+ $tree_required = TRUE;
|
|
|
+ $tree_file = '';
|
|
|
+ $name_re = '';
|
|
|
+ $match = '';
|
|
|
+
|
|
|
+ // If we are editing an existing node then the phylotree is already part of the node.
|
|
|
+ if (property_exists($node, 'phylotree')) {
|
|
|
+ $phylotree = $node->phylotree;
|
|
|
+ $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
|
|
|
+ $phylotree_id = $phylotree->phylotree_id;
|
|
|
+ $tree_name = $phylotree->name;
|
|
|
+ $leaf_type = $phylotree->type_id ? $phylotree->type_id->name : '';
|
|
|
+ $comment = $phylotree->comment;
|
|
|
+ $analysis_id = $phylotree->analysis_id ? $phylotree->analysis_id->analysis_id : '';
|
|
|
+ $dbxref = $phylotree->dbxref_id->db_id->name . ":" . $phylotree->dbxref_id->accession;
|
|
|
+ $name_re = $phylotree->tripal_variables->phylotree_name_re;
|
|
|
+ $match = $phylotree->tripal_variables->phylotree_use_uniquename;
|
|
|
+
|
|
|
+ // If the dbxref is the null db then hide it.
|
|
|
+ if ($phylotree->dbxref_id->db_id->name == 'null') {
|
|
|
+ $dbxref = '';
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get the tree file name. If the file was added via the Drupal interface
|
|
|
+ // then a numeric file_id will be present in the phylotree_tree_file
|
|
|
+ // variable. If not then the tree was loaded on the command-line and
|
|
|
+ // the actual filename is in this variable.
|
|
|
+ $file_id = $phylotree->tripal_variables->phylotree_tree_file;
|
|
|
+ if (is_numeric($file_id)) {
|
|
|
+ $file = file_load($file_id);
|
|
|
+ if ($file) {
|
|
|
+ $tree_file = $file->filename;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $tree_file = $file_id;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The tree file is not a required input field when editing the node.
|
|
|
+ $tree_required = FALSE;
|
|
|
+
|
|
|
+ // Keep track of the phylotree id.
|
|
|
+ $form['phylotree_id'] = array(
|
|
|
+ '#type' => 'value',
|
|
|
+ '#value' => $phylotree_id,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ // If we are re constructing the form from a failed validation or ajax callback
|
|
|
+ // then use the $form_state['values'] values.
|
|
|
+ if (array_key_exists('values', $form_state) and isset($form_state['values']['tree_name'])) {
|
|
|
+ $tree_name = $form_state['values']['tree_name'];
|
|
|
+ $leaf_type = $form_state['values']['leaf_type'];
|
|
|
+ $analysis_id = $form_state['values']['analysis_id'];
|
|
|
+ $dbxref = $form_state['values']['dbxref'];
|
|
|
+ $comment = $form_state['values']['description'];
|
|
|
+ }
|
|
|
+ // If we are re building the form from after submission (from ajax call) then
|
|
|
+ // the values are in the $form_state['input'] array.
|
|
|
+ if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
|
|
|
+ $tree_name = $form_state['input']['tree_name'];
|
|
|
+ $leaf_type = $form_state['input']['leaf_type'];
|
|
|
+ $analysis_id = $form_state['input']['analysis_id'];
|
|
|
+ $comment = $form_state['input']['description'];
|
|
|
+ $dbxref = $form_state['input']['dbxref'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $form['tree_name']= array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('Tree Name'),
|
|
|
+ '#required' => TRUE,
|
|
|
+ '#default_value' => $tree_name,
|
|
|
+ '#description' => t('Enter the name used to refer to this phylogenetic tree.'),
|
|
|
+ '#maxlength' => 255
|
|
|
+ );
|
|
|
+
|
|
|
+ $type_cv = tripal_get_default_cv('phylotree', 'type_id');
|
|
|
+ $so_cv = tripal_get_cv(array('name' => 'sequence'));
|
|
|
+ $cv_id = $so_cv->cv_id;
|
|
|
+ if (!$so_cv) {
|
|
|
+ drupal_set_message('The Sequence Ontolgoy does not appear to be imported.
|
|
|
+ Please import the Sequence Ontology before adding a tree.', 'error');
|
|
|
+ }
|
|
|
+
|
|
|
+ $form['leaf_type'] = array(
|
|
|
+ '#title' => t('Tree Type'),
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#description' => t("Choose the tree type. The type is
|
|
|
+ a valid Sequence Ontology (SO) term. For example, trees derived
|
|
|
+ from protein sequences should use the SO term 'polypeptide'.
|
|
|
+ Alternatively, a phylotree can be used for representing a taxonomic
|
|
|
+ tree. In this case, the word 'taxonomy' should be used."),
|
|
|
+ '#required' => TRUE,
|
|
|
+ '#default_value' => $leaf_type,
|
|
|
+ '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv_id",
|
|
|
+ );
|
|
|
+
|
|
|
+ // Get the list of analyses.
|
|
|
+ $sql = "SELECT * FROM {analysis} ORDER BY name";
|
|
|
+ $arset = chado_query($sql);
|
|
|
+ $analyses = array();
|
|
|
+ $analyses[''] = '';
|
|
|
+ while ($analysis = $arset->fetchObject()) {
|
|
|
+ $analyses[$analysis->analysis_id] = $analysis->name;
|
|
|
+ }
|
|
|
+ $form['analysis_id'] = array(
|
|
|
+ '#title' => t('Analysis'),
|
|
|
+ '#type' => 'select',
|
|
|
+ '#description' => t("Choose the analysis from which this phylogenetic tree was derived"),
|
|
|
+ '#required' => TRUE,
|
|
|
+ '#default_value' => $analysis_id,
|
|
|
+ '#options' => $analyses,
|
|
|
+ );
|
|
|
+
|
|
|
+ $form['dbxref'] = array(
|
|
|
+ '#title' => t('Database Cross-Reference'),
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#description' => t("Enter a database cross-reference of the form
|
|
|
+ [DB name]:[accession]. The database name must already exist in the
|
|
|
+ database. If the accession does not exist it is automatically added."),
|
|
|
+ '#required' => FALSE,
|
|
|
+ '#default_value' => $dbxref,
|
|
|
+ );
|
|
|
+
|
|
|
+ $form['description']= array(
|
|
|
+ '#type' => 'textarea',
|
|
|
+ '#title' => t('Description'),
|
|
|
+ '#required' => TRUE,
|
|
|
+ '#default_value' => $comment,
|
|
|
+ '#description' => t('Enter a description for this tree.'),
|
|
|
+ );
|
|
|
+
|
|
|
+ $upload_location = tripal_get_files_stream('tripal_phylogeny');
|
|
|
+ $form['tree_file'] = array(
|
|
|
+ '#type' => 'fieldset',
|
|
|
+ '#title' => t('Tree File Import'),
|
|
|
+ '#collapsible' => FALSE,
|
|
|
+ );
|
|
|
+
|
|
|
+ $description = t('Please provide a file in the Newick format that contains
|
|
|
+ the nodes of this tree.');
|
|
|
+ if ($tree_file) {
|
|
|
+ $form['tree_file']['curr_file'] = array(
|
|
|
+ '#type' => 'item',
|
|
|
+ '#title' => 'Current Tree File',
|
|
|
+ '#markup' => $tree_file,
|
|
|
+ );
|
|
|
+ $description = t('Please provide a file in the Newick format that
|
|
|
+ contains the nodes of this tree. Please note that uploading a new
|
|
|
+ file will overwrite the current tree.');
|
|
|
+ }
|
|
|
+ $form['tree_file']['tree_file'] = array(
|
|
|
+ '#type' => 'managed_file',
|
|
|
+ '#title' => t('New Tree File'),
|
|
|
+ '#description' => $description,
|
|
|
+ '#upload_location' => $upload_location,
|
|
|
+ '#upload_validators' => array(
|
|
|
+ // We don't want to require a specific file extension so leave the array empty.
|
|
|
+ 'file_validate_extensions' => array(),
|
|
|
+ // The following is for checking the Newick file format.
|
|
|
+ 'chado_phylotree_validate_newick_format' => array(),
|
|
|
+ ),
|
|
|
+ '#required' => $tree_required,
|
|
|
+ );
|
|
|
+
|
|
|
+ $form['tree_file']['name_re'] = array(
|
|
|
+ '#title' => t('Feature Name Regular Expression'),
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#description' => t('If this is a phylogenetic (non taxonomic) tree, then
|
|
|
+ the tree nodes will be automatically associated with features. However,
|
|
|
+ if the nodes in the tree file are not exactly as the names of features
|
|
|
+ but have enough information to uniquely identify the feature then you
|
|
|
+ may provide a regular expression that the importer will use to extract
|
|
|
+ the feature names from the node names.'),
|
|
|
+ '#default_value' => $name_re,
|
|
|
+ );
|
|
|
+ $form['tree_file']['match'] = array(
|
|
|
+ '#title' => t('Use Unique Feature Name'),
|
|
|
+ '#type' => 'checkbox',
|
|
|
+ '#description' => t('If this is a phylogenetic (non taonomic tree) and the nodes ' .
|
|
|
+ 'should match the unique name of the feature rather than the name of the feautre ' .
|
|
|
+ 'then select this box. If unselected the loader will try to match the feature ' .
|
|
|
+ 'using the feature name.'),
|
|
|
+ '#default_value' => $match,
|
|
|
+ );
|
|
|
+
|
|
|
+ return $form;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * A validation function for checking the newick file format.
|
|
|
+ *
|
|
|
+ * @param stdClass $file
|
|
|
+ * A Drupal file object.
|
|
|
+ */
|
|
|
+function chado_phylotree_validate_newick_format(stdClass $file) {
|
|
|
+ // An array of strings where each string represents a unique error
|
|
|
+ // when examining the file.
|
|
|
+ $errors = array();
|
|
|
+
|
|
|
+ // TODO: check the newick file format for errors.
|
|
|
+
|
|
|
+ return $errors;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implementation of hook_validate().
|
|
|
+ *
|
|
|
+ * This validation is being used for three activities:
|
|
|
+ * CASE A: Update a node that exists in both drupal and chado
|
|
|
+ * CASE B: Synchronizing a node from chado to drupal
|
|
|
+ * CASE C: Inserting a new node that exists in niether drupal nor chado
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_validate($node, $form, &$form_state) {
|
|
|
+
|
|
|
+ // We are syncing if we do not have a node ID but we do have a phylotree_id. We don't
|
|
|
+ // need to validate during syncing so just skip it.
|
|
|
+ if (is_null($node->nid) and property_exists($node, 'phylotree_id') and $node->phylotree_id != 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove surrounding white-space on submitted values.
|
|
|
+ $node->tree_name = trim($node->tree_name);
|
|
|
+ $node->description = trim($node->description);
|
|
|
+ $node->dbxref = trim($node->dbxref);
|
|
|
+
|
|
|
+ // if this is a delete then don't validate
|
|
|
+ if ($node->op == 'Delete') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $errors = array();
|
|
|
+ $warnings = array();
|
|
|
+ $options = array(
|
|
|
+ 'name' => $node->tree_name,
|
|
|
+ 'description' => $node->description,
|
|
|
+ 'analysis_id' => $node->analysis_id,
|
|
|
+ 'leaf_type' => $node->leaf_type,
|
|
|
+ 'tree_file' => $node->tree_file,
|
|
|
+ 'format' => 'newick',
|
|
|
+ 'dbxref' => $node->dbxref,
|
|
|
+ 'match' => $node->match,
|
|
|
+ 'name_re' => $node->name_re,
|
|
|
+ );
|
|
|
+ // If we have a node id already then this is an update:
|
|
|
+ if ($node->nid) {
|
|
|
+ $options['phylotree_id'] = $node->phylotree_id;
|
|
|
+ tripal_validate_phylotree('update', $options, $errors, $warnings);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tripal_validate_phylotree('insert', $options, $errors, $warnings);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now set form errors if any errors were detected.
|
|
|
+ if (count($errors) > 0) {
|
|
|
+ foreach($errors as $field => $message) {
|
|
|
+ if ($field == 'name') {
|
|
|
+ $field = 'tree_name';
|
|
|
+ }
|
|
|
+ form_set_error($field, $message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Add any warnings if any were detected
|
|
|
+ if (count($warnings) > 0) {
|
|
|
+ foreach($warnings as $field => $message) {
|
|
|
+ drupal_set_message($message, 'warning');
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Implements hook_node_presave(). Acts on all node content types.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function tripal_phylogeny_node_presave($node) {
|
|
|
+
|
|
|
+ switch ($node->type) {
|
|
|
+ // This step is for setting the title for the Drupal node. This title
|
|
|
+ // is permanent and thus is created to be unique. Title changes provided
|
|
|
+ // by tokens are generated on the fly dynamically, but the node title
|
|
|
+ // seen in the content listing needs to be set here. Do not call
|
|
|
+ // the chado_get_node_title() function here to set the title as the node
|
|
|
+ // object isn't properly filled out and the function will fail.
|
|
|
+ case 'chado_phylotree':
|
|
|
+ // for a form submission the 'phylotreename' field will be set,
|
|
|
+ // for a sync, we must pull from the phylotree object
|
|
|
+ if (property_exists($node, 'phylotreename')) {
|
|
|
+ // set the title
|
|
|
+ $node->title = $node->tree_name;
|
|
|
+ }
|
|
|
+ else if (property_exists($node, 'phylotree')) {
|
|
|
+ $node->title = $node->phylotree->name;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_node_insert().
|
|
|
+ * Acts on all content types.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function tripal_phylogeny_node_insert($node) {
|
|
|
+
|
|
|
+ switch ($node->type) {
|
|
|
+ case 'chado_phylotree':
|
|
|
+
|
|
|
+ $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
|
|
|
+ $values = array('phylotree_id' => $phylotree_id);
|
|
|
+ $phylotree = chado_generate_var('phylotree', $values);
|
|
|
+ $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
|
|
|
+ $node->phylotree = $phylotree;
|
|
|
+
|
|
|
+ // Now use the API to set the path.
|
|
|
+ chado_set_node_url($node);
|
|
|
+
|
|
|
+ // Now get the title.
|
|
|
+ $node->title = chado_get_node_title($node);
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_node_update().
|
|
|
+ * Acts on all content types.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function tripal_phylogeny_node_update($node) {
|
|
|
+
|
|
|
+ switch ($node->type) {
|
|
|
+ case 'chado_phylotree':
|
|
|
+
|
|
|
+ $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
|
|
|
+ $values = array('phylotree_id' => $phylotree_id);
|
|
|
+ $phylotree = chado_generate_var('phylotree', $values);
|
|
|
+ $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
|
|
|
+ $node->phylotree = $phylotree;
|
|
|
+
|
|
|
+ // Now get the title
|
|
|
+ $node->title = chado_get_node_title($node);
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements [content_type]_chado_node_default_title_format().
|
|
|
+ *
|
|
|
+ * Defines a default title format for the Chado Node API to set the titles on
|
|
|
+ * Chado phylotree nodes based on chado fields.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_chado_node_default_title_format() {
|
|
|
+ return '[phylotree.name]';
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_chado_node_default_url_format().
|
|
|
+ *
|
|
|
+ * Designates a default URL format for phylotree nodes.
|
|
|
+ */
|
|
|
+function chado_phylotree_chado_node_default_url_format() {
|
|
|
+ return '/phylotree/[phylotree.name]';
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_insert().
|
|
|
+ *
|
|
|
+ * When a new chado_phylotree node is created we also need to add
|
|
|
+ * information to our chado_phylotree table. This function is called
|
|
|
+ * on insert of a new node of type 'chado_phylotree' and inserts the
|
|
|
+ * necessary information.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_insert($node) {
|
|
|
+ global $user;
|
|
|
+
|
|
|
+ $node->tree_name = trim($node->tree_name);
|
|
|
+ $node->description = trim($node->description);
|
|
|
+ $node->dbxref = trim($node->dbxref);
|
|
|
+
|
|
|
+ // if there is a phylotree_id in the $node object then this must
|
|
|
+ // be a sync (not an insert) so we can skip adding the phylotree as it is
|
|
|
+ // already there, although we do need to proceed with the rest of the
|
|
|
+ // insert.
|
|
|
+ $phylotree_id = NULL;
|
|
|
+ if (!property_exists($node, 'phylotree_id')) {
|
|
|
+ $options = array(
|
|
|
+ 'name' => $node->tree_name,
|
|
|
+ 'description' => $node->description,
|
|
|
+ 'analysis_id' => $node->analysis_id,
|
|
|
+ 'leaf_type' => $node->leaf_type,
|
|
|
+ 'tree_file' => $node->tree_file,
|
|
|
+ 'format' => 'newick',
|
|
|
+ 'dbxref' => $node->dbxref,
|
|
|
+ 'match' => $node->match,
|
|
|
+ 'name_re' => $node->name_re,
|
|
|
+ );
|
|
|
+ $errors = array();
|
|
|
+ $warnings = array();
|
|
|
+ if (tripal_insert_phylotree($options, $errors, $warnings)) {
|
|
|
+ $phylotree_id = $options['phylotree_id'];
|
|
|
+
|
|
|
+ // Add the Tripal variables to this node.
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_name_re', $node->name_re);
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_use_uniquename', $node->match);
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_tree_file', $node->tree_file);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ drupal_set_message(t('Unable to insert phylotree.'), 'error');
|
|
|
+ tripal_report_error('tripal_phylogeny', TRIPAL_WARNING,
|
|
|
+ 'Insert phylotree: Unable to insert phylotree where values: %values',
|
|
|
+ array('%values' => print_r($options, TRUE))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $phylotree_id = $node->phylotree_id;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Make sure the entry for this phylotree doesn't already exist in the
|
|
|
+ // chado_phylotree table if it doesn't exist then we want to add it.
|
|
|
+ $check_org_id = chado_get_id_from_nid('phylotree', $node->nid);
|
|
|
+ if (!$check_org_id) {
|
|
|
+ $record = new stdClass();
|
|
|
+ $record->nid = $node->nid;
|
|
|
+ $record->vid = $node->vid;
|
|
|
+ $record->phylotree_id = $phylotree_id;
|
|
|
+ drupal_write_record('chado_phylotree', $record);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_update().
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_update($node) {
|
|
|
+
|
|
|
+ global $user;
|
|
|
+
|
|
|
+ $node->tree_name = trim($node->tree_name);
|
|
|
+ $node->description = trim($node->description);
|
|
|
+ $node->dbxref = trim($node->dbxref);
|
|
|
+
|
|
|
+ // Get the phylotree_id for this node.
|
|
|
+ $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid) ;
|
|
|
+
|
|
|
+
|
|
|
+ $options = array(
|
|
|
+ 'phylotree_id' => $node->phylotree_id,
|
|
|
+ 'name' => $node->tree_name,
|
|
|
+ 'description' => $node->description,
|
|
|
+ 'analysis_id' => $node->analysis_id,
|
|
|
+ 'leaf_type' => $node->leaf_type,
|
|
|
+ 'tree_file' => $node->tree_file,
|
|
|
+ 'format' => 'newick',
|
|
|
+ 'dbxref' => $node->dbxref,
|
|
|
+ 'match' => $node->match,
|
|
|
+ 'name_re' => $node->name_re,
|
|
|
+ );
|
|
|
+
|
|
|
+ $success = tripal_update_phylotree($phylotree_id, $options);
|
|
|
+
|
|
|
+ if (!$success) {
|
|
|
+ drupal_set_message("Unable to update phylotree.", "error");
|
|
|
+ tripal_report_error('tripal_phylogeny', TRIPAL_WARNING,
|
|
|
+ 'Update phylotree: Unable to update phylotree where values: %values',
|
|
|
+ array('%values' => print_r($options, TRUE))
|
|
|
+ );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove any variables and then add back the variables from the form.
|
|
|
+ tripal_delete_node_variables($node->nid);
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_name_re', $node->name_re);
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_use_uniquename', $node->match);
|
|
|
+ tripal_add_node_variable($node->nid, 'phylotree_tree_file', $node->tree_file);
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Implements hook_load().
|
|
|
+ *
|
|
|
+ * When a node is requested by the user this function is called to allow us
|
|
|
+ * to add auxiliary data to the node object.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_load($nodes) {
|
|
|
+
|
|
|
+ foreach ($nodes as $nid => $node) {
|
|
|
+
|
|
|
+ $phylotree_id = chado_get_id_from_nid('phylotree', $nid);
|
|
|
+
|
|
|
+ // If the nid does not have a matching record then skip this node.
|
|
|
+ // this can happen with orphaned nodes.
|
|
|
+ if (!$phylotree_id) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Build the Chado variable for the phylotree.
|
|
|
+ $values = array('phylotree_id' => $phylotree_id);
|
|
|
+ $phylotree = chado_generate_var('phylotree', $values);
|
|
|
+ $nodes[$nid]->phylotree = $phylotree;
|
|
|
+
|
|
|
+ // Expand the comment field, chado_generate_var() omits it by default
|
|
|
+ // because it is a large text field.
|
|
|
+ $phylotree = chado_expand_var($phylotree, 'field', 'phylotree.comment');
|
|
|
+
|
|
|
+ // Add non Chado information to the object. These variables are needed
|
|
|
+ // for the edit/update forms.
|
|
|
+ $phylotree->tripal_variables = new stdClass;
|
|
|
+ $variables = tripal_get_node_variables($nid, 'phylotree_name_re');
|
|
|
+ $phylotree->tripal_variables->phylotree_name_re = count($variables) > 0 ? $variables[0]->value : '';
|
|
|
+
|
|
|
+ $variables = tripal_get_node_variables($nid, 'phylotree_use_uniquename');
|
|
|
+ $phylotree->tripal_variables->phylotree_use_uniquename = count($variables) > 0 ? $variables[0]->value : '';
|
|
|
+
|
|
|
+ $variables = tripal_get_node_variables($nid, 'phylotree_tree_file');
|
|
|
+ $phylotree->tripal_variables->phylotree_tree_file = count($variables) > 0 ? $variables[0]->value : '';
|
|
|
+
|
|
|
+ // Set the title for this node.
|
|
|
+ $node->title = chado_get_node_title($node);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements hook_delete().
|
|
|
+ *
|
|
|
+ * Delete data from drupal and chado databases when a node is deleted
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_delete(&$node) {
|
|
|
+
|
|
|
+ $phylotree_id = chado_get_id_from_nid('phylotree', $node->nid);
|
|
|
+
|
|
|
+ // if we don't have a phylotree id for this node then this isn't a node of
|
|
|
+ // type chado_phylotree or the entry in the chado_phylotree table was lost.
|
|
|
+ if (!$phylotree_id) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove data from {chado_phylotree}, {node} and {node_revisions} tables of
|
|
|
+ // drupal database
|
|
|
+ $sql_del = "DELETE FROM {chado_phylotree} WHERE nid = :nid AND vid = :vid";
|
|
|
+ db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
|
|
|
+ $sql_del = "DELETE FROM {node_revision} WHERE nid = :nid AND vid = :vid";
|
|
|
+ db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
|
|
|
+ $sql_del = "DELETE FROM {node} WHERE nid = :nid AND vid = :vid";
|
|
|
+ db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
|
|
|
+
|
|
|
+ // Remove data from phylotree and phylotreeprop tables of chado
|
|
|
+ // database as well
|
|
|
+
|
|
|
+ chado_query("DELETE FROM {phylotree} WHERE phylotree_id = :phylotree_id", array(':phylotree_id' => $phylotree_id));
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implement hook_node_access().
|
|
|
+ *
|
|
|
+ * This hook allows node modules to limit access to the node types they define.
|
|
|
+ *
|
|
|
+ * @param $node
|
|
|
+ * The node on which the operation is to be performed, or, if it does not yet exist, the
|
|
|
+ * type of node to be created
|
|
|
+ *
|
|
|
+ * @param $op
|
|
|
+ * The operation to be performed
|
|
|
+ *
|
|
|
+ * @param $account
|
|
|
+ * A user object representing the user for whom the operation is to be performed
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ * If the permission for the specified operation is not set then return FALSE. If the
|
|
|
+ * permission is set then return NULL as this allows other modules to disable
|
|
|
+ * access. The only exception is when the $op == 'create'. We will always
|
|
|
+ * return TRUE if the permission is set.
|
|
|
+ *
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function chado_phylotree_node_access($node, $op, $account) {
|
|
|
+
|
|
|
+ $node_type = $node;
|
|
|
+ if (is_object($node)) {
|
|
|
+ $node_type = $node->type;
|
|
|
+ }
|
|
|
+
|
|
|
+ if($node_type == 'chado_phylotree') {
|
|
|
+ if ($op == 'create') {
|
|
|
+ if (!user_access('create chado_phylotree content', $account)) {
|
|
|
+ return NODE_ACCESS_DENY;
|
|
|
+ }
|
|
|
+ return NODE_ACCESS_ALLOW;
|
|
|
+ }
|
|
|
+ if ($op == 'update') {
|
|
|
+ if (!user_access('edit chado_phylotree content', $account)) {
|
|
|
+ return NODE_ACCESS_DENY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($op == 'delete') {
|
|
|
+ if (!user_access('delete chado_phylotree content', $account)) {
|
|
|
+ return NODE_ACCESS_DENY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($op == 'view') {
|
|
|
+ if (!user_access('access chado_phylotree content', $account)) {
|
|
|
+ return NODE_ACCESS_DENY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NODE_ACCESS_IGNORE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Phylotree feature summary.
|
|
|
+ *
|
|
|
+ * Get an array of feature counts by organism. key = organism
|
|
|
+ * abbreviation. value = number of features for this phylotree having
|
|
|
+ * this organism.
|
|
|
+ *
|
|
|
+ * @param int phylotree_id
|
|
|
+ * @return array
|
|
|
+ * @ingroup tripal_phylogeny
|
|
|
+ */
|
|
|
+function phylotree_feature_summary($phylotree_id) {
|
|
|
+
|
|
|
+ $sql = "
|
|
|
+ SELECT o.abbreviation, COUNT(o.organism_id) AS count
|
|
|
+ FROM {phylonode} n
|
|
|
+ LEFT OUTER JOIN {feature} f ON n.feature_id = f.feature_id
|
|
|
+ LEFT OUTER JOIN {organism} o ON f.organism_id = o.organism_id
|
|
|
+ WHERE n.phylotree_id = :phylotree_id
|
|
|
+ AND n.feature_id IS NOT NULL
|
|
|
+ GROUP BY o.organism_id
|
|
|
+ ";
|
|
|
+
|
|
|
+ $args = array(':phylotree_id' => $phylotree_id);
|
|
|
+ $result = chado_query($sql, $args);
|
|
|
+ $summary = array();
|
|
|
+ foreach($result as $r) {
|
|
|
+ $summary[$r->abbreviation] = $r->count;
|
|
|
+ }
|
|
|
+ return $summary;
|
|
|
+}
|