Browse Source

Merge branch '7.x-2.x' of git.drupal.org:sandbox/spficklin/1337878 into 7.x-2.x

Lacey Sanderson 11 years ago
parent
commit
5b8962cd3d
100 changed files with 6880 additions and 6907 deletions
  1. 339 0
      LICENSE.txt
  2. 253 3
      tripal_analysis/includes/tripal_analysis.chado_node.inc
  3. 1 1
      tripal_analysis/includes/tripal_analysis.sync.inc
  4. 11 0
      tripal_analysis/theme/tripal_analysis/tripal_analysis_base.tpl.php
  5. 2 253
      tripal_analysis/tripal_analysis.module
  6. 1 1
      tripal_contact/includes/contact_sync.inc
  7. 467 0
      tripal_contact/includes/tripal_contact.chado_node.inc
  8. 0 211
      tripal_contact/includes/tripal_contact.form.inc
  9. 8 1
      tripal_contact/theme/tripal_contact/tripal_contact_publications.tpl.php
  10. 19 1
      tripal_contact/tripal_contact.install
  11. 26 264
      tripal_contact/tripal_contact.module
  12. 20 119
      tripal_core/api/tripal_core_chado.api.inc
  13. 243 76
      tripal_core/api/tripal_core_chado_nodes.api.inc
  14. 26 8
      tripal_core/api/tripal_core_jobs.api.inc
  15. 2 2
      tripal_core/tripal_core.drush.inc
  16. 8 2
      tripal_cv/api/tripal_cv.api.inc
  17. 1 1
      tripal_feature/includes/tripal_feature.sync_features.inc
  18. 175 0
      tripal_feature/theme/tripal_feature.theme.inc
  19. 2 2
      tripal_feature/theme/tripal_feature/tripal_feature_base.tpl.php
  20. 85 0
      tripal_feature/theme/tripal_feature/tripal_feature_publications.tpl.php
  21. 7 4
      tripal_feature/theme/tripal_feature/tripal_feature_terms.tpl.php
  22. 10 174
      tripal_feature/tripal_feature.module
  23. 3 358
      tripal_featuremap/includes/tripal_featuremap.admin.inc
  24. 397 0
      tripal_featuremap/includes/tripal_featuremap.chado_node.inc
  25. 0 533
      tripal_featuremap/includes/tripal_featuremap.form.inc
  26. 0 142
      tripal_featuremap/theme/node--chado-featuremap.tpl.php
  27. 0 5
      tripal_featuremap/theme/tripal_featuremap.help.tpl.php
  28. 0 0
      tripal_featuremap/theme/tripal_featuremap.theme.inc
  29. 76 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.base.tpl.php
  30. 158 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.featurepos.tpl.php
  31. 52 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.properties.tpl.php
  32. 85 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.publication.tpl.php
  33. 69 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.references.tpl.php
  34. 16 0
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.teaser.tpl.php
  35. 0 39
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_base.tpl.php
  36. 0 126
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_featurepos.tpl.php
  37. 0 50
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_properties.tpl.php
  38. 0 33
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_publication.tpl.php
  39. 0 56
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_references.tpl.php
  40. 0 60
      tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_teaser.tpl.php
  41. 129 33
      tripal_featuremap/tripal_featuremap.install
  42. 113 422
      tripal_featuremap/tripal_featuremap.module
  43. 4 4
      tripal_library/api/tripal_library.api.inc
  44. 4 565
      tripal_library/includes/tripal_library.admin.inc
  45. 350 0
      tripal_library/includes/tripal_library.chado_node.inc
  46. 0 142
      tripal_library/theme/node--chado-library.tpl.php
  47. 69 0
      tripal_library/theme/tripal_feature/tripal_feature.libraries.tpl.php
  48. 0 57
      tripal_library/theme/tripal_feature/tripal_feature_libraries.tpl.php
  49. 0 4
      tripal_library/theme/tripal_library.help.tpl.php
  50. 1 0
      tripal_library/theme/tripal_library.theme.inc
  51. 105 0
      tripal_library/theme/tripal_library/tripal_library.base.tpl.php
  52. 62 0
      tripal_library/theme/tripal_library/tripal_library.properties.tpl.php
  53. 85 0
      tripal_library/theme/tripal_library/tripal_library.publications.tpl.php
  54. 70 0
      tripal_library/theme/tripal_library/tripal_library.references.tpl.php
  55. 53 0
      tripal_library/theme/tripal_library/tripal_library.synonyms.tpl.php
  56. 19 0
      tripal_library/theme/tripal_library/tripal_library.teaser.tpl.php
  57. 71 0
      tripal_library/theme/tripal_library/tripal_library.terms.tpl.php
  58. 0 54
      tripal_library/theme/tripal_library/tripal_library_base.tpl.php
  59. 0 44
      tripal_library/theme/tripal_library/tripal_library_properties.tpl.php
  60. 0 49
      tripal_library/theme/tripal_library/tripal_library_references.tpl.php
  61. 0 31
      tripal_library/theme/tripal_library/tripal_library_synonyms.tpl.php
  62. 0 54
      tripal_library/theme/tripal_library/tripal_library_teaser.tpl.php
  63. 0 51
      tripal_library/theme/tripal_library/tripal_library_terms.tpl.php
  64. 73 0
      tripal_library/theme/tripal_organism/tripal_organism.libraries.tpl.php
  65. 0 74
      tripal_library/theme/tripal_organism/tripal_organism_libraries.tpl.php
  66. 96 14
      tripal_library/tripal_library.install
  67. 132 498
      tripal_library/tripal_library.module
  68. 1 1
      tripal_natural_diversity/tripal_natural_diversity.module
  69. 1 1
      tripal_organism/includes/organism_sync.inc
  70. 1 1
      tripal_organism/tripal_organism.module
  71. 1 1
      tripal_phenotype/tripal_phenotype.module
  72. 4 4
      tripal_project/api/tripal_project.api.inc
  73. 8 333
      tripal_project/includes/tripal_project.admin.inc
  74. 395 0
      tripal_project/includes/tripal_project.chado_node.inc
  75. 0 142
      tripal_project/theme/node--chado-project.tpl.php
  76. 0 0
      tripal_project/theme/tripal_project.help.tpl.php
  77. 75 0
      tripal_project/theme/tripal_project.theme.inc
  78. 84 0
      tripal_project/theme/tripal_project/tripal_project.base.tpl.php
  79. 80 0
      tripal_project/theme/tripal_project/tripal_project.contact.tpl.php
  80. 65 0
      tripal_project/theme/tripal_project/tripal_project.properties.tpl.php
  81. 85 0
      tripal_project/theme/tripal_project/tripal_project.publications.tpl.php
  82. 88 0
      tripal_project/theme/tripal_project/tripal_project.relationships.tpl.php
  83. 36 0
      tripal_project/theme/tripal_project/tripal_project.teaser.tpl.php
  84. 0 53
      tripal_project/theme/tripal_project/tripal_project_base.tpl.php
  85. 0 50
      tripal_project/theme/tripal_project/tripal_project_contact.tpl.php
  86. 0 41
      tripal_project/theme/tripal_project/tripal_project_properties.tpl.php
  87. 0 58
      tripal_project/theme/tripal_project/tripal_project_publications.tpl.php
  88. 0 81
      tripal_project/theme/tripal_project/tripal_project_relationships.tpl.php
  89. 0 20
      tripal_project/theme/tripal_project/tripal_project_teaser.tpl.php
  90. 59 6
      tripal_project/tripal_project.install
  91. 92 371
      tripal_project/tripal_project.module
  92. 242 180
      tripal_pub/api/tripal_pub.api.inc
  93. 0 0
      tripal_pub/includes/importers/tripal_pub.AGL.inc
  94. 0 0
      tripal_pub/includes/importers/tripal_pub.PMID.inc
  95. 0 413
      tripal_pub/includes/pub_form.inc
  96. 0 522
      tripal_pub/includes/pub_search.inc
  97. 890 0
      tripal_pub/includes/tripal_pub.chado_node.inc
  98. 0 0
      tripal_pub/includes/tripal_pub.pub_citation.inc
  99. 41 8
      tripal_pub/includes/tripal_pub.pub_importers.inc
  100. 634 0
      tripal_pub/includes/tripal_pub.pub_search.inc

+ 339 - 0
LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 253 - 3
tripal_analysis/includes/tripal_analysis.form.inc → tripal_analysis/includes/tripal_analysis.chado_node.inc

@@ -47,7 +47,7 @@ function chado_analysis_form($node, &$form_state) {
     $timeexecuted   = $analysis->timeexecuted;
     $description    = $analysis->description;
      
-    // set the organism_id in the form
+    // set the analysis_id in the form
     $form['analysis_id'] = array(
       '#type' => 'value',
       '#value' => $analysis->analysis_id,
@@ -95,7 +95,7 @@ function chado_analysis_form($node, &$form_state) {
         are derived from some software package. But, data can also be derived via retreival
         from an external source or an analysis pipeline with multipel software components.
         In these cases, provide values for the fields below that best makes sense
-        '),
+     '),
   );
   $form['analysisname']= array(
     '#type' => 'textfield',
@@ -250,7 +250,7 @@ function tripal_analysis_validate($node, $form, &$form_state) {
   }
   
   // Validating for an update
-  if (!is_null($node->nid)) {    
+  if (!is_null($node->nid)) {
    
     // get the existing node    
     $values = array('analysis_id' => $node->analysis_id);      
@@ -317,4 +317,254 @@ function tripal_analysis_validate($node, $form, &$form_state) {
       return;
     }
   }
+}
+
+/**
+ *  When a new chado_analysis node is created we also need to add information
+ *  to our chado_analysis table.  This function is called on insert of a new
+ *  node of type 'chado_analysis' and inserts the necessary information.
+ *
+ * @ingroup tripal_analysis
+ */
+function chado_analysis_insert($node) {
+
+  $node->analysisname = trim($node->analysisname);
+  $node->description = trim($node->description);
+  $node->program = trim($node->program);
+  $node->programversion = trim($node->programversion);
+  $node->algorithm = trim($node->algorithm);
+  $node->sourcename = trim($node->sourcename);
+  $node->sourceversion = trim($node->sourceversion);
+  $node->sourceuri = trim($node->sourceuri);
+
+  // if there is an analysis_id in the $node object then this must be a sync so
+  // we can skip adding the analysis as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'analysis_id')) {
+
+    // Create a timestamp so we can insert it into the chado database
+    $time  = $node->timeexecuted;
+    $month = $time['month'];
+    $day   = $time['day'];
+    $year  = $time['year'];
+    $timestamp = $month . '/' . $day . '/' . $year;
+
+    // insert and then get the newly inserted analysis record
+    $values = array(
+      'name'           => $node->analysisname,
+      'description'    => $node->description,
+      'program'        => $node->program,
+      'programversion' => $node->programversion,
+      'algorithm'      => $node->algorithm,
+      'sourcename'     => $node->sourcename,
+      'sourceversion'  => $node->sourceversion,
+      'sourceuri'      => $node->sourceuri,
+      'timeexecuted'   => $timestamp
+    );
+    $analysis = tripal_core_chado_insert('analysis', $values);
+    if (!$analysis) {
+      drupal_set_message(t('Unable to add analysis.', 'warning'));
+      watchdog('tripal_analysis', 'Insert analysis: Unable to create analysis where values:%values',
+      array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+      return;
+    }
+    $analysis_id = $analysis['analysis_id'];
+
+    // now add in the properties
+    $properties = tripal_core_properties_form_retreive($node, 'analysis_property');
+    foreach ($properties as $property => $elements) {
+      foreach ($elements as $rank => $value) {
+
+        $status = tripal_analysis_insert_property($analysis_id, $property, $value, FALSE, 'analysis_property');
+        if (!$status) {
+          drupal_set_message("Error cannot add property: $property", "error");
+          watchdog('t_analysis', "Error cannot add property: %prop",
+          array('%property' => $property), WATCHDOG_ERROR);
+        }
+      }
+    }
+  }
+  else {
+    $analysis_id = $node->analysis_id;
+  }
+
+  // Make sure the entry for this analysis doesn't already exist in the
+  // chado_analysis table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('analysis', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->analysis_id = $analysis_id;
+    drupal_write_record('chado_analysis', $record);
+  }
+
+  // add the analysis to the node object for
+  // use by other analysis modules that may be using this function
+  $node->analysis = $analysis;
+  $node->analysis_id = $analysis_id; // we need to set this for children
+}
+
+/**
+ * Removes analysis from the chado database
+ *
+ * @param $node
+ *   The node object specifying which chado record to delete
+ *
+ * @ingroup tripal_analysis
+ */
+function chado_analysis_delete($node) {
+  $analysis_id = chado_get_id_for_node('analysis', $node->nid);
+
+  // if we don't have an analysis id for this node then this isn't a node of
+  // type chado_analysis or the entry in the chado_analysis table was lost.
+  if (!$analysis_id) {
+    return;
+  }
+
+  // Remove data from the {chado_analysis}, {node}, and {node_revisions} tables
+  $sql_del = "DELETE FROM {chado_analysis} 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));
+  $sql_del = "DELETE FROM {node_revision} WHERE nid = :nid AND vid = :vid";
+  db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
+
+  //Remove from analysis and analysisprop tables of chado database as well
+  chado_query("DELETE FROM {analysis} WHERE analysis_id = :analysis_id", array(':analysis_id' => $analysis_id));
+}
+
+/**
+ * Update analyses
+ *
+ * @param $node
+ *   The updated node object
+ *
+ * @ingroup tripal_analysis
+ */
+function chado_analysis_update($node) {
+  $node->analysisname = trim($node->analysisname);
+  $node->description = trim($node->description);
+  $node->program = trim($node->program);
+  $node->programversion = trim($node->programversion);
+  $node->algorithm = trim($node->algorithm);
+  $node->sourcename = trim($node->sourcename);
+  $node->sourceversion = trim($node->sourceversion);
+  $node->sourceuri = trim($node->sourceuri);
+
+  // Create a timestamp so we can insert it into the chado database
+  $time = $node->timeexecuted;
+  $month = $time['month'];
+  $day = $time['day'];
+  $year = $time['year'];
+  $timestamp = $month . '/' . $day . '/' . $year;
+
+  // update the record in Chado
+  $analysis_id = chado_get_id_for_node('analysis', $node->nid);
+  $match = array(
+    'analysis_id' => $node->analysis_id,
+  );
+  $values = array(
+    'name'           => $node->analysisname,
+    'description'    => $node->description,
+    'program'        => $node->program,
+    'programversion' => $node->programversion,
+    'algorithm'      => $node->algorithm,
+    'sourcename'     => $node->sourcename,
+    'sourceversion'  => $node->sourceversion,
+    'sourceuri'      => $node->sourceuri,
+    'timeexecuted'   => $timestamp,
+    'analysis_id'    => $analysis_id
+  );
+  $status = tripal_core_chado_update('analysis', $match, $values);
+  if (!$status) {
+    drupal_set_message(t('Unable to update analysis.', 'warning'));
+    watchdog('tripal_analysis', 'Update analysis: Unable to update analysis where values: %values',
+    array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+  }
+
+  // now add in the properties by first removing any the analysis
+  // already has and adding the ones we have
+  tripal_core_chado_delete('analysisprop', array('analysis_id' => $analysis_id));
+  $properties = tripal_core_properties_form_retreive($node, 'analysis_property');
+  foreach ($properties as $property => $elements) {
+    foreach ($elements as $rank => $value) {
+      $status = tripal_analysis_insert_property($analysis_id, $property, $value, FALSE, 'analysis_property');
+      if (!$status) {
+        drupal_set_message("Error cannot add property: '$property'", "error");
+        watchdog('t_analysis', "Error cannot add property: '%prop'",
+        array('%prop' => $property), WATCHDOG_ERROR);
+      }
+    }
+  }
+}
+/**
+ *  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_analysis
+ */
+function chado_analysis_load($nodes) {
+
+  foreach ($nodes as $nid => $node) {
+    // find the analysis and add in the details
+    $analysis_id = chado_get_id_for_node('analysis', $nid);
+
+    // build the analysis variable
+    $values = array('analysis_id' => $analysis_id);
+    $analysis = tripal_core_generate_chado_var('analysis', $values);
+
+    // add in the description field
+    $analysis = tripal_core_expand_chado_vars($analysis, 'field', 'analysis.description');
+    $nodes[$nid]->analysis = $analysis;
+  }
+}
+
+/**
+ * Implement hook_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_analysis
+ */
+function chado_analysis_node_access($node, $op, $account) {
+
+  if ($op == 'create') {
+    if (!user_access('create chado_analysis content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+  if ($op == 'update') {
+    if (!user_access('edit chado_analysis content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'delete') {
+    if (!user_access('delete chado_analysis content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'view') {
+    if (!user_access('access chado_analysis content', $account)) {
+      return FALSE;
+    }
+  }
+  return NULL;
 }

+ 1 - 1
tripal_analysis/includes/tripal_analysis.sync.inc

@@ -216,6 +216,6 @@ function tripal_analysis_sync_analyses($analysis_id = NULL, $job_id = NULL) {
  */
 function tripal_analyses_cleanup($dummy = NULL, $job_id = NULL) {
 
-  return tripal_core_clean_orphaned_nodes('analysis', $job_id);
+  return tripal_core_chado_node_cleanup_orphaned('analysis', $job_id);
 
 }

+ 11 - 0
tripal_analysis/theme/tripal_analysis/tripal_analysis_base.tpl.php

@@ -72,6 +72,17 @@ $analysis = tripal_core_expand_chado_vars($analysis,'field','analysis.descriptio
     preg_replace("/^(\d+-\d+-\d+) .*/","$1", $analysis->timeexecuted),
   ); 
   
+  // allow site admins to see the feature ID
+  if (user_access('access administration pages')) {
+    // Analysis ID
+    $rows[] = array(
+      array(
+        'data' => 'Analysis ID',
+        'header' => TRUE
+      ),
+      $analysis->analysis_id
+    );
+  }
   // the $table array contains the headers and rows array as well as other
   // options for controlling the display of the table.  Additional
   // documentation can be found here:

+ 2 - 253
tripal_analysis/tripal_analysis.module

@@ -17,7 +17,7 @@
 require_once 'api/tripal_analysis.api.inc';
 require_once 'includes/tripal_analysis_privacy.inc';
 require_once 'includes/tripal_analysis.admin.inc';
-require_once 'includes/tripal_analysis.form.inc';
+require_once 'includes/tripal_analysis.chado_node.inc';
 require_once 'includes/tripal_analysis.sync.inc';
 require_once "api/tripal_analysis.schema.api.inc";
 
@@ -235,7 +235,7 @@ function tripal_analysis_block_view($delta = '') {
 
 /**
  *
- * @ingroup tripal_feature
+ * @ingroup tripal_analysis
  */
 function tripal_analysis_node_view($node, $view_mode, $langcode) {
   switch ($node->type) {
@@ -290,9 +290,6 @@ function tripal_analysis_views_api() {
   );
 }
 
-
-
-
 /**
  * Implementation of hook_form_alter()
  * 
@@ -306,255 +303,7 @@ function tripal_analysis_form_alter(&$form, &$form_state, $form_id) {
     $form['actions']['preview']['#access'] = FALSE;
   }
 }
-/**
- *  When a new chado_analysis node is created we also need to add information
- *  to our chado_analysis table.  This function is called on insert of a new
- *  node of type 'chado_analysis' and inserts the necessary information.
- *
- * @ingroup tripal_analysis
- */
-function chado_analysis_insert($node) {
-
-  $node->analysisname = trim($node->analysisname);
-  $node->description = trim($node->description);
-  $node->program = trim($node->program);
-  $node->programversion = trim($node->programversion);
-  $node->algorithm = trim($node->algorithm);
-  $node->sourcename = trim($node->sourcename);
-  $node->sourceversion = trim($node->sourceversion);
-  $node->sourceuri = trim($node->sourceuri);
-
-  // if there is an analysis_id in the $node object then this must be a sync so
-  // we can skip adding the analysis as it is already there, although
-  // we do need to proceed with the rest of the insert
-  if (!property_exists($node, 'analysis_id')) {
-
-    // Create a timestamp so we can insert it into the chado database
-    $time  = $node->timeexecuted;
-    $month = $time['month'];
-    $day   = $time['day'];
-    $year  = $time['year'];
-    $timestamp = $month . '/' . $day . '/' . $year;
-
-    // insert and then get the newly inserted analysis record
-    $values = array(
-      'name'           => $node->analysisname,
-      'description'    => $node->description,
-      'program'        => $node->program,
-      'programversion' => $node->programversion,
-      'algorithm'      => $node->algorithm,
-      'sourcename'     => $node->sourcename,
-      'sourceversion'  => $node->sourceversion,
-      'sourceuri'      => $node->sourceuri,
-      'timeexecuted'   => $timestamp
-    );
-    $analysis = tripal_core_chado_insert('analysis', $values);
-    if (!$analysis) {
-      drupal_set_message(t('Unable to add analysis.', 'warning'));
-      watchdog('tripal_analysis', 'Insert analysis: Unable to create analysis where values:%values',
-      array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
-      return;
-    }
-    $analysis_id = $analysis['analysis_id'];
-    
-    // now add in the properties
-    $properties = tripal_core_properties_form_retreive($node, 'analysis_property');
-    foreach ($properties as $property => $elements) {
-      foreach ($elements as $rank => $value) {
-    
-        $status = tripal_analysis_insert_property($analysis_id, $property, $value, FALSE, 'analysis_property');
-        if (!$status) {
-          drupal_set_message("Error cannot add property: $property", "error");
-          watchdog('t_analysis', "Error cannot add property: %prop",
-          array('%property' => $property), WATCHDOG_ERROR);
-        }
-      }
-    }
-  }
-  else {
-    $analysis_id = $node->analysis_id;
-  }
-
-  // Make sure the entry for this analysis doesn't already exist in the
-  // chado_analysis table if it doesn't exist then we want to add it.
-  $check_org_id = chado_get_id_for_node('analysis', $node->nid);
-  if (!$check_org_id) {
-    $record = new stdClass();
-    $record->nid = $node->nid;
-    $record->vid = $node->vid;
-    $record->analysis_id = $analysis_id;
-    drupal_write_record('chado_analysis', $record);
-  }
-
-  // add the analysis to the node object for
-  // use by other analysis modules that may be using this function
-  $node->analysis = $analysis;
-  $node->analysis_id = $analysis_id; // we need to set this for children
-}
-
-/**
- * Removes analysis from the chado database
- *
- * @param $node
- *   The node object specifying which chado record to delete
- *
- * @ingroup tripal_analysis
- */
-function chado_analysis_delete($node) {
-  $analysis_id = chado_get_id_for_node('analysis', $node->nid);
-
-  // if we don't have an analysis id for this node then this isn't a node of
-  // type chado_analysis or the entry in the chado_analysis table was lost.
-  if (!$analysis_id) {
-    return;
-  }
-
-  // Remove data from the {chado_analysis}, {node}, and {node_revisions} tables
-  $sql_del = "DELETE FROM {chado_analysis} 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));
-  $sql_del = "DELETE FROM {node_revision} WHERE nid = :nid AND vid = :vid";
-  db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
-
-  //Remove from analysis and analysisprop tables of chado database as well
-  chado_query("DELETE FROM {analysis} WHERE analysis_id = :analysis_id", array(':analysis_id' => $analysis_id));
-}
-
-/**
- * Update analyses
- *
- * @param $node
- *   The updated node object
- *
- * @ingroup tripal_analysis
- */
-function chado_analysis_update($node) {
-  $node->analysisname = trim($node->analysisname);
-  $node->description = trim($node->description);
-  $node->program = trim($node->program);
-  $node->programversion = trim($node->programversion);
-  $node->algorithm = trim($node->algorithm);
-  $node->sourcename = trim($node->sourcename);
-  $node->sourceversion = trim($node->sourceversion);
-  $node->sourceuri = trim($node->sourceuri);
-
-  // Create a timestamp so we can insert it into the chado database
-  $time = $node->timeexecuted;
-  $month = $time['month'];
-  $day = $time['day'];
-  $year = $time['year'];
-  $timestamp = $month . '/' . $day . '/' . $year;
-
-  // update the record in Chado
-  $analysis_id = chado_get_id_for_node('analysis', $node->nid);
-  $sql = "
-    UPDATE {analysis}
-    SET name = :name, description = :description, program = :program,
-        programversion = :programversion, algorithm = :algorithm, sourcename = :sourcename,
-        sourceversion = :sourceversion, sourceuri = :sourceuri, timeexecuted = :timeexecuted
-    WHERE analysis_id = :analysis_id
-  ";
-  $args = array(
-    ':name' => $node->analysisname,
-    ':description' => $node->description,
-    ':program' => $node->program,
-    ':programversion' => $node->programversion,
-    ':algorithm' => $node->algorithm,
-    ':sourcename' => $node->sourcename,
-    ':sourceversion' => $node->sourceversion,
-    ':sourceuri' => $node->sourceuri,
-    ':timeexecuted' => $timestamp,
-    ':analysis_id' => $analysis_id
-  );
-  chado_query($sql, $args);
-
-  // now update the properties
-  $properties = array(); // stores all of the properties we need to add
-  
-  // now add in the properties by first removing any the analysis
-  // already has and adding the ones we have
-  tripal_core_chado_delete('analysisprop', array('analysis_id' => $analysis_id));
-  $properties = tripal_core_properties_form_retreive($node, 'analysis_property');
-  foreach ($properties as $property => $elements) {
-    foreach ($elements as $rank => $value) {
-      $status = tripal_analysis_insert_property($analysis_id, $property, $value, FALSE, 'analysis_property');
-      if (!$status) {
-        drupal_set_message("Error cannot add property: '$property'", "error");
-        watchdog('t_analysis', "Error cannot add property: '%prop'",
-        array('%prop' => $property), WATCHDOG_ERROR);
-      }
-    }
-  }
-}
- /**
-  *  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_analysis
-  */
-function chado_analysis_load($nodes) {
 
-  foreach ($nodes as $nid => $node) {
-    // find the analysis and add in the details
-    $analysis_id = chado_get_id_for_node('analysis', $nid);
-
-    // build the analysis variable
-    $values = array('analysis_id' => $analysis_id);
-    $analysis = tripal_core_generate_chado_var('analysis', $values);
-    
-    // add in the description field
-    $analysis = tripal_core_expand_chado_vars($analysis, 'field', 'analysis.description');
-    $nodes[$nid]->analysis = $analysis;
-  }
-}
 
-/**
- * Implement hook_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_analysis
- */
-function chado_analysis_node_access($node, $op, $account) {
 
-  if ($op == 'create') {
-    if (!user_access('create chado_analysis content', $account)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-  if ($op == 'update') {
-    if (!user_access('edit chado_analysis content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'delete') {
-    if (!user_access('delete chado_analysis content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'view') {
-    if (!user_access('access chado_analysis content', $account)) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
 

+ 1 - 1
tripal_contact/includes/contact_sync.inc

@@ -126,6 +126,6 @@ function tripal_contact_sync_contacts($job_id = NULL) {
  */
 function tripal_contact_cleanup($dummy = NULL, $job_id = NULL) {
 
-  return tripal_core_clean_orphaned_nodes('contact', $job_id);
+  return tripal_core_chado_node_cleanup_orphaned('contact', $job_id);
 
 }

+ 467 - 0
tripal_contact/includes/tripal_contact.chado_node.inc

@@ -0,0 +1,467 @@
+<?php
+/**
+ * Implementation of tripal_contact_form().
+ *
+ *
+ *
+ *  @parm $node
+ *    The node that is created when the database is initialized
+ *
+ *  @parm $form_state
+ *    The state of the form, that has the user entered information that is neccessary for, setting
+ *    up the database tables for the contact
+ *
+ *  @return $form
+ *    The information that was enterd allong with
+ *
+ */
+function chado_contact_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 contact
+  // 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
+  $contact_id  = null;
+  $type_id     = 0;
+  $title       = '';
+  $description = '';
+  
+  // if we are editing an existing node then the contact is already part of the node
+  if (property_exists($node, 'contact')) {
+    $contact = $node->contact;
+    $contact_id = $contact->contact_id;
+    
+    // get form defaults
+    $type_id     = $contact->type_id->cvterm_id;
+    $title       = $contact->name;
+    
+    // get the contact default values.  When this module was first created
+    // the contact description was incorrectly stored in the $node->body field.
+    // It is better to store it in the Chado tables.  However, the 'description'
+    // field of the contact table is only 255 characters.  So, we are going
+    // to follow the same as the contact module and store the description in
+    // the contactprop table and leave the contact.description field blank.
+    // however, for backwards compatibitily, we check to see if the description
+    // is in the $node->body field. If it is we'll use that.  When the node is
+    // edited the text will be moved out of the body and into the contactprop
+    // table where it should belong.
+    $description = '';
+    if (property_exists($node, 'body')) {
+      $description = $node->body;
+    }
+    else {
+      $description = $contact->description;
+    }
+    if (!$description) {
+      $contactprop = tripal_contact_get_property($contact->contact_id, 'contact_description');
+      $description = $contactprop->value;
+    }
+     
+    // set the contact_id in the form
+    $form['contact_id'] = array(
+      '#type' => 'value',
+      '#value' => $contact->contact_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)) {
+    $type_id     = $form_state['values']['type_id'];
+    $title       = $form_state['values']['title'];
+    $description = $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'])) {
+    $type_id     = $form_state['input']['type_id'];
+    $title       = $form_state['input']['title'];
+    $description = $form_state['input']['description'];
+  }
+
+  // get the contact types. These are those that are part of the tripal_contact
+  // vocabulary and are children of the term 'Contact Type', so we need
+  // to join on the cvtermpath table and select those with a distance of 1
+  $sql = "
+    SELECT CVTS.cvterm_id, CVTS.name
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+      INNER JOIN {cv} CV       ON CVTO.cv_id = CV.cv_id
+    WHERE 
+      CV.name = 'tripal_contact' AND 
+      CVTO.name = 'Contact Type' AND
+      CVTP.pathdistance = 1
+    ORDER BY CVTS.name ASC 
+  ";
+  $results = chado_query($sql);
+  $contact_types = array();
+  while ($contact_type = $results->fetchObject()) {
+    $contact_types[$contact_type->cvterm_id] = $contact_type->name;
+    if (strcmp($contact_type->name, "Person") == 0 and !$type_id) {
+      $type_id = $contact_type->cvterm_id;
+    }
+  }
+  $form['type_id'] = array(
+    '#type' => 'select',
+    '#title' => t('Contact Type'),
+    '#options' => $contact_types,
+    '#required' => TRUE,
+    '#default_value' => $type_id,
+  );
+  
+  $form['title']= array(
+    '#type'          => 'textfield',
+    '#title'         => t('Contact Name'),
+    '#description'   => t('Enter the name of this contact'),
+    '#required'      => TRUE,
+    '#default_value' => $title,
+    '#maxlength'     => 255,
+  );
+
+  $form['description']= array(
+    '#type'          => 'textarea',
+    '#title'         => t('Contact Description'),
+    '#description'   => t('A brief description of the contact'),
+    '#required'      => TRUE,
+    '#default_value' => $description,
+  );
+
+  // get the contact properties that the user can use for this form
+  $properties = array();
+  $properties[] = 'Select a Property';
+  $sql = "
+    SELECT CVTS.cvterm_id, CVTS.name
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+      INNER JOIN {cv} CV       ON CVTO.cv_id = CV.cv_id
+    WHERE
+      CV.name = 'tripal_contact' AND
+      NOT CVTO.name = 'Contact Type'
+    ORDER BY CVTS.name ASC
+  ";
+  $prop_types = chado_query($sql);
+  while ($prop = $prop_types->fetchObject()) {
+    $properties[$prop->cvterm_id] = $prop->name;
+  }
+  
+  $exclude = array('contact_description');
+  $include = array();
+  tripal_core_properties_form($form, $form_state, 'contactprop', 'contact_id', 'tripal_contact',
+    $properties, $contact_id, $exclude, $include, '', 'Properties');
+   
+  return $form;
+}
+
+/**
+ *  validates submission of form when adding or updating a contact node
+ *
+ * @ingroup tripal_contact
+ */
+function chado_contact_validate($node, $form, &$form_state) {
+  // remove surrounding white-space on submitted values
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+ 
+  // if this is a delete then don't validate
+  if($node->op == 'Delete') {
+    return;
+  }
+  
+  // we are syncing if we do not have a node ID but we do have a contact_id. We don't
+  // need to validate during syncing so just skip it.
+  if (is_null($node->nid) and property_exists($node, 'contact_id') and $node->contact_id != 0) {
+    return;
+  }
+  
+  // Validating for an update
+  if (property_exists($node, 'nid')) {    
+    // get the existing node    
+    $values = array('contact_id' => $node->contact_id);
+    $result = tripal_core_chado_select('contact', array('*'), $values);
+    $contact = $result[0];
+      
+    // if the name has changed make sure it doesn't conflict with an existing name
+    if ($contact->name != $node->title) {
+      $values = array('name' => $node->title);
+      $result = tripal_core_chado_select('contact', array('contact_id'), $values);
+      if ($result and count($result) > 0) {
+        form_set_error('title', 'Cannot update the contact with this contact name. A contact with this name already exists.');
+        return;
+      }  
+    }
+  }
+  // Validating for an insert
+  else {
+    // The unique constraint for the chado contact table is: name
+    $values = array(
+      'name' => $node->title,
+    );
+    $contact = tripal_core_chado_select('contact', array('contact_id'), $values);
+    if ($contact and count($contact) > 0) {
+      form_set_error('title', 'Cannot add the contact with this name. A contact with these values already exists.');
+      return;
+    }
+  }
+}
+
+/**
+ * Implement hook_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.
+ *
+ */
+function chado_contact_node_access($node, $op, $account ) {
+  if ($op == 'create') {
+    if (!user_access('create chado_contact content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  if ($op == 'update') {
+    if (!user_access('edit chado_contact content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'delete') {
+    if (!user_access('delete chado_contact content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'view') {
+    if (!user_access('access chado_contact content', $account)) {
+      return FALSE;
+    }
+  }
+  return NULL;
+}
+
+
+
+/**
+ * Implementation of tripal_contact_insert().
+ *
+ * This function inserts user entered information pertaining to the contact instance into the
+ * 'contactauthor', 'contactprop', 'chado_contact', 'contact' talble of the database.
+ *
+ *  @parm $node
+ *    Then node which contains the information stored within the node-ID
+ *
+ *
+ */
+function chado_contact_insert($node) {
+
+  // remove surrounding white-space on submitted values
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+
+  // if there is a contact_id in the $node object then this must be a sync so
+  // we can skip adding the contact as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'contact_id')) {
+    // insert and then get the newly inserted contact record
+    $values = array(
+      'name'           => $node->title,
+      'description'    => '',
+      'type_id'        => $node->type_id,
+    );
+    $contact = tripal_core_chado_insert('contact', $values);
+    if (!$contact) {
+      drupal_set_message(t('Unable to add contact.', 'warning'));
+      watchdog('tripal_contact', 'Insert contact: Unable to create contact where values: %values',
+      array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+      return;
+    }
+    $contact_id = $contact['contact_id'];
+
+    // now add in the properties
+    $properties = tripal_core_properties_form_retreive($node, 'tripal_contact');
+    foreach ($properties as $property => $elements) {
+      foreach ($elements as $rank => $value) {
+
+        $status = tripal_contact_insert_property($contact_id, $property, $value, FALSE);
+        if (!$status) {
+          drupal_set_message("Error cannot add property: $property", "error");
+          watchdog('t_contact', "Error cannot add property: %prop",
+          array('%property' => $property), WATCHDOG_ERROR);
+        }
+      }
+    }
+
+    // add in the description as a separate property
+    tripal_contact_insert_property($contact_id, 'contact_description', $node->description, FALSE);
+  }
+  else {
+    $contact_id = $node->contact_id;
+  }
+
+  // Make sure the entry for this contact doesn't already exist in the
+  // chado_contact table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('contact', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->contact_id = $contact_id;
+    drupal_write_record('chado_contact', $record);
+  }
+  return TRUE;
+}
+
+/*
+ *
+* Implements hook_update
+*
+* The purpose of the function is to allow the module to take action when an edited node is being
+* updated. It updates any name changes to the database tables that werec reated upon registering a contact.
+* As well, the database will be changed, so the user changed information will be saved to the database.
+*
+* @param $node
+*   The node being updated
+*
+* @ingroup tripal_contact
+*/
+function chado_contact_update($node) {
+  // remove surrounding white-space on submitted values
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+
+  $contact_id = chado_get_id_for_node('contact', $node->nid) ;
+
+  // update the contact record
+  $match = array(
+    'contact_id' => $contact_id,
+  );
+  $values = array(
+    'name' => $node->title,
+    'description' => '',
+    'type_id' => $node->type_id
+  );
+  $status = tripal_core_chado_update('contact', $match, $values);
+  if (!$status) {
+    drupal_set_message("Error updating contact", "error");
+    watchdog('t_contact', "Error updating contact", array(), WATCHDOG_ERROR);
+    return;
+  }
+
+  // now add in the properties by first removing any the contact
+  // already has and adding the ones we have
+  tripal_core_chado_delete('contactprop', array('contact_id' => $contact_id));
+  $properties = tripal_core_properties_form_retreive($node, 'tripal_contact');
+
+  foreach ($properties as $property => $elements) {
+    foreach ($elements as $rank => $value) {
+      $status = tripal_contact_insert_property($contact_id, $property, $value, FALSE);
+      if (!$status) {
+        drupal_set_message("Error cannot add property: '$property'", "error");
+        watchdog('t_contact', "Error cannot add property: '%prop'",
+        array('%prop' => $property), WATCHDOG_ERROR);
+      }
+    }
+  }
+
+  // add in the description as a separate property
+  tripal_contact_update_property($contact_id, 'contact_description', $node->description, 1);
+}
+
+
+/**
+ * Implementation of tripal_contact_load().
+ *
+ *
+ * @param $node
+ *   The node that is to be accessed from the database
+ *
+ * @return $node
+ *   The node with the information to be loaded into the database
+ *
+ */
+function chado_contact_load($nodes) {
+
+  foreach ($nodes as $nid => $node) {
+    // find the contact and add in the details
+    $contact_id = chado_get_id_for_node('contact', $nid);
+
+    // get the contact
+    $values = array('contact_id' => $contact_id);
+    $contact = tripal_core_generate_chado_var('contact', $values);
+
+    // get the contact description from the contactprop table and replace
+    // the contact.description field with this one (we don't use the contact.description
+    // field because it is only 255 characters (too small)).
+    $values = array(
+      'contact_id' => $contact->contact_id,
+      'type_id' => array(
+        'name' => 'contact_description',
+      ),
+    );
+    $options = array(
+      'return_array' => 1,
+      'include_fk' => array('type_id' => 1),
+    );
+    $description = tripal_core_generate_chado_var('contactprop', $values, $options);
+    if (count($description) == 1) {
+      $description = tripal_core_expand_chado_vars($description, 'field', 'contactprop.value');
+      $contact->description = $description[0]->value;
+    }
+
+    $nodes[$nid]->contact = $contact;
+  }
+}
+
+/**
+ * Implementation of tripal_contact_delete().
+ *
+ * This function takes a node and if the delete button has been chosen by the user, the contact
+ * and it's details will be removed.Following,given the node-ID, the instance will be deleted from
+ * the 'chado_contact' table.
+ *
+ *  @parm $node
+ *    Then node which contains the information stored within the node-ID
+ *
+ */
+function chado_contact_delete(&$node) {
+
+  $contact_id = chado_get_id_for_node('contact', $node->nid);
+
+  // if we don't have a contact id for this node then this isn't a node of
+  // type chado_contact or the entry in the chado_contact table was lost.
+  if (!$contact_id) {
+    return;
+  }
+
+  // Remove data from {chado_contact}, {node} and {node_revisions} tables of
+  // drupal database
+  $sql_del = "DELETE FROM {chado_contact} 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 contact and contactprop tables of chado database as well
+  chado_query("DELETE FROM {contactprop} WHERE contact_id = :contact_id", array(':contact_id' => $contact_id));
+  chado_query("DELETE FROM {contact} WHERE contact_id = :contact_id", array(':contact_id' => $contact_id));
+}

+ 0 - 211
tripal_contact/includes/tripal_contact.form.inc

@@ -1,211 +0,0 @@
-<?php
-/**
- * Implementation of tripal_contact_form().
- *
- *
- *
- *  @parm $node
- *    The node that is created when the database is initialized
- *
- *  @parm $form_state
- *    The state of the form, that has the user entered information that is neccessary for, setting
- *    up the database tables for the contact
- *
- *  @return $form
- *    The information that was enterd allong with
- *
- */
-function chado_contact_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 contact
-  // 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
-  $contact_id  = null;
-  $type_id     = 0;
-  $title       = '';
-  $description = '';
-  
-  // if we are editing an existing node then the contact is already part of the node
-  if (property_exists($node, 'contact')) {
-    $contact = $node->contact;
-    $contact_id = $contact->contact_id;
-    
-    // get form defaults
-    $type_id     = $contact->type_id->cvterm_id;
-    $title       = $contact->name;
-    
-    // get the contact default values.  When this module was first created
-    // the contact description was incorrectly stored in the $node->body field.
-    // It is better to store it in the Chado tables.  However, the 'description'
-    // field of the contact table is only 255 characters.  So, we are going
-    // to follow the same as the contact module and store the description in
-    // the contactprop table and leave the contact.description field blank.
-    // however, for backwards compatibitily, we check to see if the description
-    // is in the $node->body field. If it is we'll use that.  When the node is
-    // edited the text will be moved out of the body and into the contactprop
-    // table where it should belong.
-    $description = '';
-    if (property_exists($node, 'body')) {
-      $description = $node->body;
-    }
-    else {
-      $description = $contact->description;
-    }
-    if (!$description) {
-      $contactprop = tripal_contact_get_property($contact->contact_id, 'contact_description');
-      $description = $contactprop->value;
-    }
-     
-    // set the contact_id in the form
-    $form['contact_id'] = array(
-      '#type' => 'value',
-      '#value' => $contact->contact_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)) {
-    $type_id     = $form_state['values']['type_id'];
-    $title       = $form_state['values']['title'];
-    $description = $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'])) {
-    $type_id     = $form_state['input']['type_id'];
-    $title       = $form_state['input']['title'];
-    $description = $form_state['input']['description'];
-  }
-
-  // get the contact types. These are those that are part of the tripal_contact
-  // vocabulary and are children of the term 'Contact Type', so we need
-  // to join on the cvtermpath table and select those with a distance of 1
-  $sql = "
-    SELECT CVTS.cvterm_id, CVTS.name
-    FROM {cvtermpath} CVTP
-      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
-      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
-      INNER JOIN {cv} CV       ON CVTO.cv_id = CV.cv_id
-    WHERE 
-      CV.name = 'tripal_contact' AND 
-      CVTO.name = 'Contact Type' AND
-      CVTP.pathdistance = 1
-    ORDER BY CVTS.name ASC 
-  ";
-  $results = chado_query($sql);
-  $contact_types = array();
-  while ($contact_type = $results->fetchObject()) {
-    $contact_types[$contact_type->cvterm_id] = $contact_type->name;
-    if (strcmp($contact_type->name, "Person") == 0 and !$type_id) {
-      $type_id = $contact_type->cvterm_id;
-    }
-  }
-  $form['type_id'] = array(
-    '#type' => 'select',
-    '#title' => t('Contact Type'),
-    '#options' => $contact_types,
-    '#required' => TRUE,
-    '#default_value' => $type_id,
-  );
-  
-  $form['title']= array(
-    '#type'          => 'textfield',
-    '#title'         => t('Contact Name'),
-    '#description'   => t('Enter the name of this contact'),
-    '#required'      => TRUE,
-    '#default_value' => $title,
-    '#maxlength'     => 255,
-  );
-
-  $form['description']= array(
-    '#type'          => 'textarea',
-    '#title'         => t('Contact Description'),
-    '#description'   => t('A brief description of the contact'),
-    '#required'      => TRUE,
-    '#default_value' => $description,
-  );
-
-  // get the contact properties that the user can use for this form
-  $properties = array();
-  $properties[] = 'Select a Property';
-  $sql = "
-    SELECT CVTS.cvterm_id, CVTS.name
-    FROM {cvtermpath} CVTP
-      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
-      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
-      INNER JOIN {cv} CV       ON CVTO.cv_id = CV.cv_id
-    WHERE
-      CV.name = 'tripal_contact' AND
-      NOT CVTO.name = 'Contact Type'
-    ORDER BY CVTS.name ASC
-  ";
-  $prop_types = chado_query($sql);
-  while ($prop = $prop_types->fetchObject()) {
-    $properties[$prop->cvterm_id] = $prop->name;
-  }
-  
-  $exclude = array('contact_description');
-  $include = array();
-  tripal_core_properties_form($form, $form_state, 'contactprop', 'contact_id', 'tripal_contact',
-    $properties, $contact_id, $exclude, $include, '', 'Properties');
-   
-  return $form;
-}
-
-/**
- *  validates submission of form when adding or updating a contact node
- *
- * @ingroup tripal_contact
- */
-function chado_contact_validate($node, $form, &$form_state) {
-  // remove surrounding white-space on submitted values
-  $node->title          = trim($node->title);
-  $node->description    = trim($node->description);
- 
-  // if this is a delete then don't validate
-  if($node->op == 'Delete') {
-    return;
-  }
-  
-  // we are syncing if we do not have a node ID but we do have a contact_id. We don't
-  // need to validate during syncing so just skip it.
-  if (is_null($node->nid) and property_exists($node, 'contact_id') and $node->contact_id != 0) {
-    return;
-  }
-  
-  // Validating for an update
-  if (property_exists($node, 'nid')) {    
-    // get the existing node    
-    $values = array('contact_id' => $node->contact_id);      
-    $result = tripal_core_chado_select('contact', array('*'), $values);
-    $contact = $result[0];
-      
-    // if the name has changed make sure it doesn't conflict with an existing name
-    if ($contact->name != $node->title) {
-      $values = array('name' => $node->title);
-      $result = tripal_core_chado_select('contact', array('contact_id'), $values);
-      if ($result and count($result) > 0) {
-        form_set_error('title', 'Cannot update the contact with this contact name. A contact with this name already exists.');
-        return;
-      }  
-    }
-  }
-  // Validating for an insert
-  else {
-    // The unique constraint for the chado contact table is: name
-    $values = array(
-      'name' => $node->title,
-    );
-    $contact = tripal_core_chado_select('contact', array('contact_id'), $values);
-    if ($contact and count($contact) > 0) {
-      form_set_error('title', 'Cannot add the contact with this name. A contact with these values already exists.');
-      return;
-    }
-  }
-}

+ 8 - 1
tripal_contact/theme/tripal_contact/tripal_contact_publications.tpl.php

@@ -46,7 +46,14 @@ if (count($pubauthor_contacts) > 0) { ?>
       if ($pub->nid) {
         // replace the title with a link
         $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
-        $citation = preg_replace('/' . $pub->title . '/', $link, $citation);
+        $patterns = array(
+          '/(\()/', '/(\))/', 
+          '/(\])/', '/(\[)/',
+          '/(\{)/', '/(\})/',
+          '/(\+)/', '/(\.)/', '/(\?)/', 
+        );
+        $fixed_title = preg_replace($patterns, "\\\\$1", $pub->title);
+        $citation = preg_replace('/' . $fixed_title . '/', $link, $citation);
       }
       
       $rows[] = array(

+ 19 - 1
tripal_contact/tripal_contact.install

@@ -58,13 +58,31 @@ function tripal_contact_install() {
   $obo_path = drupal_realpath(drupal_get_path('module', 'tripal_contact') . '/files/tcontact.obo');
   $obo_id = tripal_cv_add_obo_ref('Tripal Contacts', $obo_path);
   tripal_cv_submit_obo_job($obo_id);
+  
+  /*
+  // Install our custom block visibility settings per node type
+  $query = db_insert('block_node_type')
+    ->fields(array('type', 'module', 'delta'))
+    ->values(array(
+      'type'   => 'chado_contact',
+      'module' => 'tripal_contact', // My module name
+      'delta'  => 'contbase', // Same delta used in hook_block_info
+    )
+  )->execute();
+  */
 }
 
 /**
  * Implementation of hook_uninstall().
  */
 function tripal_contact_uninstall() {
-
+  /*
+  // remove our custom block visibility settings per node type
+  db_delete('block_node_type')
+    ->condition('module', 'chado_contact')
+    ->condition('delta', 'contbase')
+    ->execute();
+    */
 }
 
 /**

+ 26 - 264
tripal_contact/tripal_contact.module

@@ -12,7 +12,7 @@
 require('api/tripal_contact.api.inc');
 require('includes/contact_sync.inc');
 require('includes/tripal_contact.admin.inc');
-require('includes/tripal_contact.form.inc');
+require('includes/tripal_contact.chado_node.inc');
 
 /**
  * @defgroup tripal_contact Contact Module
@@ -203,16 +203,16 @@ function tripal_contact_theme($existing, $type, $theme, $path) {
 function tripal_contact_block_info() {
 
   $blocks['contbase']['info'] = t('Tripal Contact Details');
-  $blocks['contbase']['cache'] = 'BLOCK_NO_CACHE';
+  $blocks['contbase']['cache'] = 'DRUPAL_NO_CACHE';
 
   $blocks['contprops']['info'] = t('Tripal Contact Properties');
-  $blocks['contprops']['cache'] = 'BLOCK_NO_CACHE';
+  $blocks['contprops']['cache'] = 'DRUPAL_NO_CACHE';
 
   $blocks['contrels']['info'] = t('Tripal Contact Relationships');
-  $blocks['contrels']['cache'] = 'BLOCK_NO_CACHE';
+  $blocks['contrels']['cache'] = 'DRUPAL_NO_CACHE';
 
-  $blocks['contpubs']['info'] = t('Tripal Cotact Publications');
-  $blocks['contpubs']['cache'] = 'BLOCK_NO_CACHE';
+  $blocks['contpubs']['info'] = t('Tripal Contact Publications');
+  $blocks['contpubs']['cache'] = 'DRUPAL_NO_CACHE';
 
   return $blocks;
 }
@@ -229,19 +229,35 @@ function tripal_contact_block_view($delta = '') {
     switch ($delta) {
       case 'contbase':
         $block['subject'] = t('Details');
-        $block['content'] = theme('tripal_contact_base', $node);
+        $block['content'] = array(
+          '#theme' => 'tripal_contact_base', 
+          '#nodes' => $node,
+          '#title' => '',
+        );
         break;
       case 'contprops':
         $block['subject'] = t('Properties');
-        $block['content'] = theme('tripal_contact_properties', $node);
+        $block['content'] = array(
+          '#theme' => 'tripal_contact_properties', 
+          '#nodes' => $node,
+          '#title' => '',
+        );
         break;
       case 'contrels':
         $block['subject'] = t('Relationships');
-        $block['content'] = theme('tripal_contact_relationships', $node);
+        $block['content'] = array(
+          '#theme' => 'tripal_contact_relationships', 
+          '#nodes' => $node,
+          '#title' => '',
+        );
         break;
       case 'contpubs':
         $block['subject'] = t('Publications');
-        $block['content'] = theme('tripal_contact_publications', $node);
+        $block['content'] = array(
+          '#theme' => 'tripal_contact_publications', 
+          '#nodes' => $node,
+          '#title' => '',
+        );
         break;
       default :
     }
@@ -277,261 +293,7 @@ function tripal_contact_permissions() {
   );
 }
 
-/**
- * Implement hook_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.
- *
- */
-function chado_contact_node_access($node, $op, $account ) {
-  if ($op == 'create') {
-    if (!user_access('create chado_contact content', $account)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-
-  if ($op == 'update') {
-    if (!user_access('edit chado_contact content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'delete') {
-    if (!user_access('delete chado_contact content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'view') {
-    if (!user_access('access chado_contact content', $account)) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
-
-
 
-/**
- * Implementation of tripal_contact_insert().
- *
- * This function inserts user entered information pertaining to the contact instance into the
- * 'contactauthor', 'contactprop', 'chado_contact', 'contact' talble of the database.
- *
- *  @parm $node
- *    Then node which contains the information stored within the node-ID
- *
- *
- */
-function chado_contact_insert($node) {
-
-  // remove surrounding white-space on submitted values
-  $node->title          = trim($node->title);
-  $node->description    = trim($node->description);
-  
-  // if there is a contact_id in the $node object then this must be a sync so
-  // we can skip adding the contact as it is already there, although
-  // we do need to proceed with the rest of the insert
-  if (!property_exists($node, 'contact_id')) {
-    // insert and then get the newly inserted contact record
-    $values = array(
-      'name'           => $node->title,
-      'description'    => '',
-      'type_id'        => $node->type_id,
-    );
-    $contact = tripal_core_chado_insert('contact', $values);
-    if (!$contact) {
-      drupal_set_message(t('Unable to add contact.', 'warning'));
-      watchdog('tripal_contact', 'Insert contact: Unable to create contact where values: %values',
-      array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
-      return;
-    }
-    $contact_id = $contact['contact_id'];
-    
-    // now add in the properties
-    $properties = tripal_core_properties_form_retreive($node, 'tripal_contact');
-    foreach ($properties as $property => $elements) {
-      foreach ($elements as $rank => $value) {
-    
-        $status = tripal_contact_insert_property($contact_id, $property, $value, FALSE);
-        if (!$status) {
-          drupal_set_message("Error cannot add property: $property", "error");
-          watchdog('t_contact', "Error cannot add property: %prop",
-          array('%property' => $property), WATCHDOG_ERROR);
-        }
-      }
-    }
-    
-    // add in the description as a separate property
-    tripal_contact_insert_property($contact_id, 'contact_description', $node->description, FALSE);
-  }
-  else {
-    $contact_id = $node->contact_id;
-  }
-  
-  // Make sure the entry for this contact doesn't already exist in the
-  // chado_contact table if it doesn't exist then we want to add it.
-  $check_org_id = chado_get_id_for_node('contact', $node->nid);
-  if (!$check_org_id) {
-    $record = new stdClass();
-    $record->nid = $node->nid;
-    $record->vid = $node->vid;
-    $record->contact_id = $contact_id;
-    drupal_write_record('chado_contact', $record);
-  }
-  return TRUE;
-}
-
-/*
- *
- * Implements hook_update
- *
- * The purpose of the function is to allow the module to take action when an edited node is being
- * updated. It updates any name changes to the database tables that werec reated upon registering a contact.
- * As well, the database will be changed, so the user changed information will be saved to the database.
- *
- * @param $node
- *   The node being updated
- *
- * @ingroup tripal_contact
- */
-function chado_contact_update($node) {
-  // remove surrounding white-space on submitted values
-  $node->title          = trim($node->title);
-  $node->description    = trim($node->description);
-
-  $contact_id = chado_get_id_for_node('contact', $node->nid) ;
-
-  // update the contact record
-  $match = array(
-    'contact_id' => $contact_id,
-  );
-  $values = array(
-    'name' => $node->title,
-    'description' => '',
-    'type_id' => $node->type_id
-  );
-  $status = tripal_core_chado_update('contact', $match, $values);
-  if (!$status) {
-    drupal_set_message("Error updating contact", "error");
-    watchdog('t_contact', "Error updating contact", array(), WATCHDOG_ERROR);
-    return;
-  }
-
-  // now add in the properties by first removing any the contact
-  // already has and adding the ones we have
-  tripal_core_chado_delete('contactprop', array('contact_id' => $contact_id));
-  $properties = tripal_core_properties_form_retreive($node, 'tripal_contact');
-  
-  foreach ($properties as $property => $elements) {
-    foreach ($elements as $rank => $value) {
-      $status = tripal_contact_insert_property($contact_id, $property, $value, FALSE);
-      if (!$status) {
-        drupal_set_message("Error cannot add property: '$property'", "error");
-        watchdog('t_contact', "Error cannot add property: '%prop'",
-        array('%prop' => $property), WATCHDOG_ERROR);
-      }
-    }
-  }
-
-  // add in the description as a separate property
-  tripal_contact_update_property($contact_id, 'contact_description', $node->description, 1);
-}
-
-
-/**
- * Implementation of tripal_contact_load().
- *
- *
- * @param $node
- *   The node that is to be accessed from the database
- *
- * @return $node
- *   The node with the information to be loaded into the database
- *
- */
-function chado_contact_load($nodes) {
-  
-  foreach ($nodes as $nid => $node) {
-    // find the contact and add in the details
-    $contact_id = chado_get_id_for_node('contact', $nid);
-  
-    // get the contact 
-    $values = array('contact_id' => $contact_id);
-    $contact = tripal_core_generate_chado_var('contact', $values);
-    
-    // get the contact description from the contactprop table and replace 
-    // the contact.description field with this one (we don't use the contact.description
-    // field because it is only 255 characters (too small)).
-    $values = array(
-      'contact_id' => $contact->contact_id,
-      'type_id' => array(
-        'name' => 'contact_description',
-      ),
-    );
-    $options = array(
-      'return_array' => 1,
-      'include_fk' => array('type_id' => 1),
-    );
-    $description = tripal_core_generate_chado_var('contactprop', $values, $options);
-    if (count($description) == 1) {
-      $description = tripal_core_expand_chado_vars($description, 'field', 'contactprop.value');
-      $contact->description = $description[0]->value;
-    }
-    
-    $nodes[$nid]->contact = $contact;
-  }
-}
-
-/**
- * Implementation of tripal_contact_delete().
- *
- * This function takes a node and if the delete button has been chosen by the user, the contact
- * and it's details will be removed.Following,given the node-ID, the instance will be deleted from
- * the 'chado_contact' table.
- *
- *  @parm $node
- *    Then node which contains the information stored within the node-ID
- *
- */
-function chado_contact_delete(&$node) {
-
-  $contact_id = chado_get_id_for_node('contact', $node->nid);
-
-  // if we don't have a contact id for this node then this isn't a node of
-  // type chado_contact or the entry in the chado_contact table was lost.
-  if (!$contact_id) {
-    return;
-  }
-
-  // Remove data from {chado_contact}, {node} and {node_revisions} tables of
-  // drupal database
-  $sql_del = "DELETE FROM {chado_contact} 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 contact and contactprop tables of chado database as well
-  chado_query("DELETE FROM {contactprop} WHERE contact_id = :contact_id", array(':contact_id' => $contact_id));
-  chado_query("DELETE FROM {contact} WHERE contact_id = :contact_id", array(':contact_id' => $contact_id));
-}
 /**
  *
  *

+ 20 - 119
tripal_core/api/tripal_core_chado.api.inc

@@ -1782,7 +1782,9 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
         $table_desc = tripal_core_get_chado_table_schema($tablename);
         $values = array();
         foreach ($table_desc['primary key'] as $key) {
-          $values[$key] = $object->{$key};
+          if(property_exists($object, $key)) {
+            $values[$key] = $object->{$key};
+          }
         }
         if ($base_table == $tablename) {
           //get the field
@@ -1818,7 +1820,7 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
       $foreign_table_desc = tripal_core_get_chado_table_schema($foreign_table);
 
       // If it's connected to the base table via a FK constraint
-      if ($foreign_table_desc['foreign keys'][$base_table]) {
+      if (array_key_exists($base_table, $foreign_table_desc['foreign keys'])) {
         foreach ($foreign_table_desc['foreign keys'][$base_table]['columns'] as $left => $right) {
           // if the FK value in the base table is not there then we can't expand it, so just skip it.
           if (!$object->{$right}) {
@@ -1873,7 +1875,10 @@ function tripal_core_expand_chado_vars($object, $type, $to_expand, $table_option
         $did_expansion = 0;
         foreach ((array) $object as $field_name => $field_value) {
           // if we have a nested object ->expand the table in it
-          if (is_object($field_value)) {
+          // check to see if the $field_name is a valid chado table, we don't need
+          // to call tripal_core_expand_chado_vars on fields that aren't tables          
+          $check = tripal_core_get_chado_table_schema($field_name);          
+          if ($check) {
             $did_expansion = 1;
             $object->{$field_name} = tripal_core_expand_chado_vars($field_value, 'table', $foreign_table);
           }
@@ -2042,10 +2047,10 @@ function tripal_core_exclude_field_from_feature_by_default() {
  *
  * @ingroup tripal_chado_api
  */
-function chado_pager_query($query, $args, $limit, $element, $count_query = NULL) {
+function chado_pager_query($query, $args, $limit, $element, $count_query = '') {
   
   // get the page and offset for the pager
-  $page = pager_find_page($element);
+  $page = isset($_GET['page']) ? $_GET['page'] : '0';
   $offset = $limit * $page;
 
   // Construct a count query if none was given.
@@ -2055,7 +2060,15 @@ function chado_pager_query($query, $args, $limit, $element, $count_query = NULL)
   }
 
   // We calculate the total of pages as ceil(items / limit).
-  $total_records = chado_query($count_query, $args)->fetchField();
+  $results = chado_query($count_query, $args);
+  if (!$results) {
+    tripal_core_report_error('tripal_core', TRIPAL_ERROR,
+      "chado_pager_query(): Query failed: %cq", array('%cq' => $count_query));
+    return;
+  }
+  $total_records = $results->fetchField();
+
+  // set a session variable for storing the total number of records
   $_SESSION['chado_pager'][$element]['total_records'] = $total_records;
   
   pager_default_initialize($total_records, $limit, $element);
@@ -2101,7 +2114,7 @@ function chado_query($sql, $args = array()) {
   if ($is_local) {
     $sql = preg_replace('/\n/', '', $sql);  // remove carriage returns
     $sql = preg_replace('/\{(.*?)\}/', 'chado.$1', $sql);
-    
+
     // the featureloc table has some indexes that use function that call other functions
     // and those calls do not reference a schema, therefore, any tables with featureloc
     // must automaticaly have the chado schema set as active to find 
@@ -2431,119 +2444,7 @@ function tripal_core_get_chado_table_schema($table) {
 
   return $table_arr;
 }
-/**
- * This function will delete Drupal nodes for any sync'ed table (e.g.
- * feature, organism, analysis, stock, library) if the chado record has been
- * deleted or the entry in the chado_[table] table has been removed.
- *
- * @param $table
- *   The name of the table that corresonds to the node type we want to clean up.
- * @param $job_id
- *   This should be the job id from the Tripal jobs system.  This function
- *   will update the job status using the provided job ID.
- *
- * @ingroup tripal_core_api
- */
-function tripal_core_clean_orphaned_nodes($table, $job_id) {
-  $count = 0;
-
-  // build the SQL statments needed to check if nodes point to valid analyses
-  $dsql = "SELECT * FROM {node} WHERE type = 'chado_" . $table . "' order by nid";
-  $nsql = "SELECT * FROM {node} WHERE nid = :nid";
-  $csql = "SELECT * FROM {chado_" . $table . "} WHERE nid = :nid ";
-  $clsql= "SELECT * FROM {chado_" . $table . "}";
-  $lsql = "SELECT * FROM {" . $table . "} where " . $table . "_id = :" . $table . "_id ";
-
-  // load into nodes array
-  print "Getting nodes\n";
-  $nodes = array();
-  $res = db_query($dsql);
-  foreach ($res as $node) {
-    $nodes[$count] = $node;
-    $count++;
-  }
-
-  // load the chado_$table into an array
-  print "Getting chado_$table\n";
-  $cnodes = array();
-  $res = db_query($clsql);
-  foreach ($res as $node) {
-    $cnodes[$count] = $node;
-    $count++;
-  }
-  $interval = intval($count * 0.01);
-  if ($interval < 1) {
-    $interval = 1;
-  }
-
-  // iterate through all of the chado_$table entries and remove those
-  // that don't have a node or don't have a $table record in chado.libary
-  print "Verifying all chado_$table Entries\n";
-  $deleted = 0;
-  foreach ($cnodes as $nid) {
-
-    // update the job status every 1% analyses
-    if ($job_id and $i % $interval == 0) {
-      tripal_job_set_progress($job_id, intval(($i / $count) * 100));
-    }
-
-    // see if the node exits, if not remove the entry from the chado_$table table
-    $results = db_query($nsql, array(':nid' => $nid->nid));
-    $node = $results->fetchObject();
-    if (!$node) {
-      $deleted++;
-      db_query("DELETE FROM {chado_" . $table . "} WHERE nid = :nid", array(':nid' => $nid->nid));
-      $message = "chado_$table missing node.... DELETING: $nid->nid";
-      watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
-    }
 
-    // see if the record in chado exist, if not remove the entry from the chado_$table
-    $table_id = $table . "_id";
-    $results = chado_query($lsql, array(":" . $table . "_id" => $nid->$table_id));
-    $record = $results->fetchObject();
-    if (!$record) {
-      $deleted++;
-      $sql = "DELETE FROM {chado_" . $table . "} WHERE " . $table . "_id = :" . $table . "_id";
-      db_query($sql, array(":" . $table . "_id" => $nid->$table_id));
-      $message = "chado_$table missing $table.... DELETING entry.";
-      watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
-    }
-    $i++;
-  }
-  print "\t$deleted chado_$table entries missing either a node or chado entry.\n";
-
-  // iterate through all of the nodes and delete those that don't
-  // have a corresponding entry in chado_$table
-  $deleted = 0;
-  foreach ($nodes as $node) {
-
-    // update the job status every 1% libraries
-    if ($job_id and $i % $interval == 0) {
-      tripal_job_set_progress($job_id, intval(($i / $count) * 100));
-    }
-
-    // check to see if the node has a corresponding entry
-    // in the chado_$table table. If not then delete the node.
-    $results = db_query($csql, array(":nid" => $node->nid));
-    $link = $results->fetchObject();
-    if (!$link) {
-      if (node_access('delete', $node)) {
-        $deleted++;
-        $message = "Node missing in chado_$table table.... DELETING node $node->nid";
-        watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
-        node_delete($node->nid);
-      }
-      else {
-        $message = "Node missing in chado_$table table.... but cannot delete due to improper permissions (node $node->nid)";
-        watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
-      }
-    }
-    $i++;
-  }
-  print "\t$deleted nodes did not have corresponding chado_$table entries.\n";
-
-  return '';
-}
 /**
  * Check that the Chado schema exists within the local database
  *

+ 243 - 76
tripal_core/api/tripal_core_chado_nodes.api.inc

@@ -43,11 +43,11 @@
         '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
-          'title' => array(
+          'record_type_title' => array(
             'singular' => t('Example'),         // Singular human-readable title
             'plural' => t('Examples')           // Plural human-readable title
           ),
-          'select_by' => array(                 // foreign keys present in your table
+          'sync_filters' => array(                 // foreign keys present in your table
             'type_id' => TRUE,                  // TRUE if there is an example.type_id field
             'organism_id' => TRUE               // TRUE if there is an example.organism_id field
           ),
@@ -139,8 +139,14 @@ function tripal_core_chado_node_sync_form($form, &$form_state) {
     $args = $node_info[$linking_table]['chado_node_api'];
     $form_state['chado_node_api'] = $args;
   }
+  
+  // define the fieldsets
+  $form['sync'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'Sync ' . $args['record_type_title']['plural'],
+  );
 
-  $form['description'] = array(
+  $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 ".
@@ -148,67 +154,86 @@ function tripal_core_chado_node_sync_form($form, &$form_state) {
      "number of %title_plural in the chado database this may take a long ".
      "time to complete. ",
      array(
-      '%title_singular' => $args['title']['singular'],
-      '%title_plural' => $args['title']['plural']
+      '%title_singular' => $args['record_type_title']['singular'],
+      '%title_plural' => $args['record_type_title']['plural']
     )),
   );
 
-  if ($args['select_by']['type_id']) {
-    $form['type_ids'] = array(
+  if ($args['sync_filters']['type_id']) {
+    $form['sync']['type_ids'] = array(
       '#title'       => t('%title_singular Types',
          array(
-          '%title_singular' => $args['title']['singular'],
-          '%title_plural' => $args['title']['plural']
+          '%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. Pages for these %title_singular ".
          "types will be created automatically for %title_plural that exist in the ".
-         "chado database.  The names listed here should be spearated by ".
-         "spaces or entered separately on new lines. The names must match ".
+         "chado database.  The names listed here should be separated by a comma".
+         "or entered separately on new lines. The names must match ".
          "exactly (spelling and case) with terms in the ontologies",
          array(
-          '%title_singular' => $args['title']['singular'],
-          '%title_plural' => $args['title']['plural']
+          '%title_singular' => $args['record_type_title']['singular'],
+          '%title_plural' => $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['select_by']['organism_id']) {
+  if ($args['sync_filters']['organism_id']) {
     $sql = "SELECT * FROM {organism} ORDER BY genus, species";
     $orgs = tripal_organism_get_synced();
     $organisms[] = '';
     foreach ($orgs as $organism) {
       $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
     }
-    $form['organism_id'] = array(
+    $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. Only organisms which also have been synced will appear in this list.",
          array(
-          '%title_singular' => $args['title']['singular'],
-          '%title_plural' => $args['title']['plural']
+          '%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,
     );
   }
 
-  $form['max_sync'] = array(
+  $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['button'] = array(
+  $form['sync']['button'] = array(
     '#type' => 'submit',
-    '#value' => t('Sync all ' . $args['title']['plural']),
+    '#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' => 1,
+  );
+  $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';
@@ -226,57 +251,71 @@ function tripal_core_chado_node_sync_form_submit($form, $form_state) {
 
   global $user;
 
-  // get arguments
-  $args = $form_state['chado_node_api'];
-  $module = $form_state['chado_node_api']['hook_prefix'];
-  $base_table = $form_state['chado_node_api']['base_table'];
-
-  // Allow each module to hijack the submit if needed
-  $hook_form_hijack_submit = $args['hook_prefix'] . '_chado_node_sync_form_submit';
-  if (function_exists($hook_form_hijack_submit)) {
-    return call_user_func($hook_form_hijack_submit, $form, $form_state);
-  }
-
-  // Get the types separated into a consistent string
-  if (isset($form_state['values']['type_ids'])) {
-    $types = preg_replace("/[\s\n\r]+/", '|||', $form_state['values']['type_ids']);
-  }
-  else {
-    $types = '';
-  }
-
-  // Job Arguments
-  $job_args = array(
-    'base_table' => $base_table,
-    'max_sync' => (!empty($form_state['values']['max_sync'])) ? $form_state['values']['max_sync'] : FALSE,
-    'organism_id' => FALSE,
-    'types' => $types,
-  );
-
-  // Create Job based on presence of organism
-  if (isset($form_state['values']['organism_id'])) {
-    $organism_id = $form_state['values']['organism_id'];
-    $organism = tripal_core_chado_select('organism', array('genus', 'species'), array('organism_id' => $organism_id));
-    $title = "Sync all " . $args['title']['plural'] . " for " . $organism[0]->genus . " " . $organism[0]->species;
-
-    $job_args['organism_id'] = $organism_id;
-    tripal_add_job($title, $module, 'tripal_core_chado_node_sync_records', $job_args, $user->uid);
+  if (preg_match('/^Sync/', $form_state['values']['op'])) {
+    // get arguments
+    $args = $form_state['chado_node_api'];
+    $module = $form_state['chado_node_api']['hook_prefix'];
+    $base_table = $form_state['chado_node_api']['base_table'];
+  
+    // Allow each module to hijack the submit if needed
+    $hook_form_hijack_submit = $args['hook_prefix'] . '_chado_node_sync_form_submit';
+    if (function_exists($hook_form_hijack_submit)) {
+      return call_user_func($hook_form_hijack_submit, $form, $form_state);
+    }
+  
+    // Get the types separated into a consistent string
+    $types = array();
+    if (isset($form_state['values']['type_ids'])) {
+      // seperate by new line or comma.
+      $temp_types = preg_split("/[,\n\r]+/", $form_state['values']['type_ids']);
+      
+      // remove any extra spacing around the types
+      for($i = 0; $i < count($temp_types); $i++) {
+        // skip empty types
+        if (trim($temp_types[$i]) == '') {
+          continue;
+        }
+        $types[$i] = trim($temp_types[$i]);
+      }
+    }
+      // Job Arguments
+    $job_args = array(
+      'base_table' => $base_table,
+      'max_sync' => (!empty($form_state['values']['max_sync'])) ? $form_state['values']['max_sync'] : FALSE,
+      'organism_id' => FALSE,
+      'types' => $types,
+    );
+    // Create Job based on presence of organism
+    if (array_key_exists('organism_id', $form_state['values']) and 
+        $form_state['values']['organism_id'] != 0) {
+      $organism_id = $form_state['values']['organism_id'];
+      $organism = tripal_core_chado_select('organism', array('genus', 'species'), array('organism_id' => $organism_id));
+      $title = "Sync all " . $args['record_type_title']['plural'] . " for " . $organism[0]->genus . " " . $organism[0]->species;
+  
+      $job_args['organism_id'] = $organism_id;
+      tripal_add_job($title, $module, 'tripal_core_chado_node_sync_records', $job_args, $user->uid);
+    }
+    else {
+      $title = t('Sync all ' . $args['record_type_title']['plural']);
+      tripal_add_job($title, $module, 'tripal_core_chado_node_sync_records', $job_args, $user->uid);
+    }
   }
-  else {
-    $title = t('Sync all ' . $args['title']['plural'] . ' for all synced organisms');
-    tripal_add_job($title, $module, 'tripal_core_chado_node_sync_records', $job_args, $user->uid);
+  if (preg_match('/^Clean up orphaned/', $form_state['values']['op'])) {
+    $module = $form_state['chado_node_api']['hook_prefix'];
+    $base_table = $form_state['chado_node_api']['base_table'];
+    $job_args = array($base_table);
+    tripal_add_job($form_state['values']['op'], $module, 'tripal_core_chado_node_cleanup_orphaned', $job_args, $user->uid);
   }
 }
 
 /**
  * Actual Sync Function. Works on a group of records
  */
-function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id = FALSE, $types = '') {
-
+function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $organism_id = FALSE, $types = array(), $job_id = NULL) {
   global $user;
   $base_table_id = $base_table . '_id';
 
-  print "\nSync'ing records from $base_table restricted to\n";
+  print "\nSync'ing $base_table records.  ";
 
   // START BUILDING QUERY TO GET ALL RECORD FROM BASE TABLE THAT MATCH
   $select = array("$base_table.*");
@@ -285,24 +324,26 @@ function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $or
   $where_args = array();
 
   // If types are supplied then handle them
-  if (!empty($types)) {
-    $types = explode('|||',$types);
-    print "  Types: " . implode(', ',$types) . "\n";
+  $restrictions = '';
+  if (count($types) > 0) {
+    $restrictions .= "  Type(s): " . implode(', ',$types) . "\n";
 
     $select[] = 'cvterm.name as cvtname';
     $joins[] = "LEFT JOIN {cvterm} cvterm ON $base_table.type_id = cvterm.cvterm_id";
     if (sizeof($types) == 1) {
       $where_clauses[] = 'cvterm.name = :type_name';
       $where_args[':type_name'] = $types[0];
-    } elseif (sizeof($types) > 1) {
+    } 
+    elseif (sizeof($types) > 1) {
       $where_clauses[] = "cvterm.name IN ('" . implode("', '", $types) . "')";
     }
   }
 
   // If Organism is supplied
   if ($organism_id) {
-    print "  Organism ID: $organism_id\n";
-
+    $organism = tripal_core_chado_select('organism', array('*'), array('organism_id' => $organism_id));
+    $restrictions .= "  Organism: " . $organism[0]->genus . " " . $organism[0]->species . "\n";
+    
     $select[] = 'organism.*';
     $joins[] = "LEFT JOIN {organism} organism ON organism.organism_id = $base_table.organism_id";
     $where_clauses[] = 'organism.organism_id = :organism_id';
@@ -316,20 +357,29 @@ function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $or
   }
 
   // Build Query
-  $query = "SELECT " . implode(', ',$select)
-    . ' FROM {' . $base_table . '} ' . $base_table . ' '
-    . implode(' ', $joins)
-    . " WHERE " . implode(' AND ', $where_clauses)
-    . " ORDER BY " . $base_table_id;
+  $query = "SELECT " . implode(', ',$select) . ' FROM {' . $base_table . '} ' . $base_table . ' ' . implode(' ', $joins);
+  if (count($where_clauses) > 0) {
+    $query .= " WHERE " . implode(' AND ', $where_clauses);
+  }
+  $query .- " ORDER BY " . $base_table_id;
 
   // If Maximum number to Sync is supplied
   if ($max_sync) {
     $query .= " LIMIT $max_sync";
+    $restrictions .= "  Limited to $max_sync records.\n";
   }
 
-  print "\nQuery: " . preg_replace(array("/FROM/","/LEFT/","/WHERE/"), array("\nFROM","\nLEFT","\nWHERE"), $query) . "\n";
+  if ($restrictions) {
+    print "Records matching these criteria will be synced: \n$restrictions";
+  }
+  else {
+    print "\n";
+  } 
+    
+  
+  //print "\nQuery: " . preg_replace(array("/FROM/","/LEFT/","/WHERE/"), array("\nFROM","\nLEFT","\nWHERE"), $query) . "\n";
 
-  print "Executing Query...\n";
+  //print "Executing Query...\n";
   $results = chado_query($query, $where_args);
 
   // Iterate through features that need to be synced
@@ -339,7 +389,7 @@ function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $or
     $interval = 1;
   }
 
-  print "\n$count $base_table records found.\nLoading...\n";
+  print "\n$count $base_table records found.\n";
 
   $i = 0;
   $transaction = db_transaction();
@@ -372,10 +422,14 @@ function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $or
         $new_node->type = 'chado_' . $base_table;
         $new_node->uid = $user->uid;
         $new_node->{$base_table_id} = $record->{$base_table_id};
+        $new_node->library = $record;
 
+        // TODO: should we get rid of this hook and use hook_node_presave() instead?
         // allow base module to set additional fields as needed
         $hook_create_new_node = 'chado_' . $base_table . '_chado_node_sync_create_new_node';
-        $new_node = call_user_func($hook_create_new_node, $new_node, $record);
+        if (function_exists($hook_create_new_node)) {
+          $new_node = call_user_func($hook_create_new_node, $new_node, $record);
+        }
 
         // Validate and Save New Node
         $form = array();
@@ -402,4 +456,117 @@ function tripal_core_chado_node_sync_records($base_table, $max_sync = FALSE, $or
     print "FAILED: Rolling back database changes...\n";
   }
 
+}
+/**
+ * This function will delete Drupal nodes for any sync'ed table (e.g.
+ * feature, organism, analysis, stock, library) if the chado record has been
+ * deleted or the entry in the chado_[table] table has been removed.
+ *
+ * @param $table
+ *   The name of the table that corresonds to the node type we want to clean up.
+ * @param $job_id
+ *   This should be the job id from the Tripal jobs system.  This function
+ *   will update the job status using the provided job ID.
+ *
+ * @ingroup tripal_core_api
+ */
+function tripal_core_chado_node_cleanup_orphaned($table, $job_id = NULL) {
+  $count = 0;
+
+  // build the SQL statments needed to check if nodes point to valid analyses
+  $dsql = "SELECT * FROM {node} WHERE type = 'chado_" . $table . "' order by nid";
+  $nsql = "SELECT * FROM {node} WHERE nid = :nid";
+  $csql = "SELECT * FROM {chado_" . $table . "} WHERE nid = :nid ";
+  $clsql= "SELECT * FROM {chado_" . $table . "}";
+  $lsql = "SELECT * FROM {" . $table . "} where " . $table . "_id = :" . $table . "_id ";
+
+  // load into nodes array
+  print "Getting nodes\n";
+  $nodes = array();
+  $res = db_query($dsql);
+  foreach ($res as $node) {
+    $nodes[$count] = $node;
+    $count++;
+  }
+
+  // load the chado_$table into an array
+  print "Getting chado_$table\n";
+  $cnodes = array();
+  $res = db_query($clsql);
+  foreach ($res as $node) {
+    $cnodes[$count] = $node;
+    $count++;
+  }
+  $interval = intval($count * 0.01);
+  if ($interval < 1) {
+    $interval = 1;
+  }
+
+  // iterate through all of the chado_$table entries and remove those
+  // that don't have a node or don't have a $table record in chado.libary
+  print "Verifying all chado_$table Entries\n";
+  $deleted = 0;
+  foreach ($cnodes as $nid) {
+
+    // update the job status every 1% analyses
+    if ($job_id and $i % $interval == 0) {
+      tripal_job_set_progress($job_id, intval(($i / $count) * 100));
+    }
+
+    // see if the node exits, if not remove the entry from the chado_$table table
+    $results = db_query($nsql, array(':nid' => $nid->nid));
+    $node = $results->fetchObject();
+    if (!$node) {
+      $deleted++;
+      db_query("DELETE FROM {chado_" . $table . "} WHERE nid = :nid", array(':nid' => $nid->nid));
+      $message = "chado_$table missing node.... DELETING: $nid->nid";
+      watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
+    }
+
+    // see if the record in chado exist, if not remove the entry from the chado_$table
+    $table_id = $table . "_id";
+    $results = chado_query($lsql, array(":" . $table . "_id" => $nid->$table_id));
+    $record = $results->fetchObject();
+    if (!$record) {
+      $deleted++;
+      $sql = "DELETE FROM {chado_" . $table . "} WHERE " . $table . "_id = :" . $table . "_id";
+      db_query($sql, array(":" . $table . "_id" => $nid->$table_id));
+      $message = "chado_$table missing $table.... DELETING entry.";
+      watchdog('tripal_core', $message, array(), WATCHDOG_WARNING);
+    }
+    $i++;
+  }
+  print "\t$deleted chado_$table entries missing either a node or chado entry.\n";
+
+  // iterate through all of the nodes and delete those that don't
+  // have a corresponding entry in chado_$table
+  $deleted = 0;
+  foreach ($nodes as $node) {
+
+    // update the job status every 1% libraries
+    if ($job_id and $i % $interval == 0) {
+      tripal_job_set_progress($job_id, intval(($i / $count) * 100));
+    }
+
+    // check to see if the node has a corresponding entry
+    // in the chado_$table table. If not then delete the node.
+    $results = db_query($csql, array(":nid" => $node->nid));
+    $link = $results->fetchObject();
+    if (!$link) {
+      if (node_access('delete', $node)) {
+        $deleted++;
+        $message = "Node missing in chado_$table table.... DELETING node $node->nid";
+        watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
+        node_delete($node->nid);
+      }
+      else {
+        $message = "Node missing in chado_$table table.... but cannot delete due to improper permissions (node $node->nid)";
+        watchdog("tripal_core", $message, array(), WATCHDOG_WARNING);
+      }
+    }
+    $i++;
+  }
+  print "\t$deleted nodes did not have corresponding chado_$table entries.\n";
+
+  return '';
 }

+ 26 - 8
tripal_core/api/tripal_core_jobs.api.inc

@@ -34,7 +34,7 @@
  * @param $callback
  *    The name of a function to be called when the job is executed
  * @param $arguments
- *    An array of arguements to be passed on to the callback
+ *    An array of arguments to be passed on to the callback
  * @param $uid
  *    The uid of the user adding the job
  * @param $priority
@@ -64,7 +64,11 @@
 function tripal_add_job($job_name, $modulename, $callback, $arguments, $uid, $priority = 10) {
 
   // convert the arguments into a string for storage in the database
-  $args = implode("::", $arguments);
+  $args = array();
+  if (is_array($arguments)) {
+    $args = serialize($arguments);
+  }
+  
   $record = new stdClass();
   $record->job_name = $job_name;
   $record->modulename = $modulename;
@@ -73,9 +77,8 @@ function tripal_add_job($job_name, $modulename, $callback, $arguments, $uid, $pr
   $record->submit_date = REQUEST_TIME;
   $record->uid = $uid;
   $record->priority = $priority;  # the lower the number the higher the priority
-  if ($args) {
-    $record->arguments = $args;
-  }
+  $record->arguments = $args;
+
   if (drupal_write_record('tripal_jobs', $record)) {
     $jobs_url = url("admin/tripal/tripal_jobs");
     drupal_set_message(t("Job '%job_name' submitted.  Check the <a href='!jobs_url'>jobs page</a> for status", array('%job_name' => $job_name, '!jobs_url' => $jobs_url)));
@@ -192,8 +195,15 @@ function tripal_jobs_rerun($job_id, $goto_jobs_page = TRUE) {
 
   $sql = "SELECT * FROM {tripal_jobs} WHERE job_id = :job_id";
   $results = db_query($sql, array(':job_id' => $job_id));
-  $job = $results->fetchObject();
-  $args = explode("::", $job->arguments);
+  $job = $results->fetchObject(); 
+  // arguments for jobs used to be stored as plain string with a double colon
+  // separating them.  But as of Tripal v2.0 the arguments are stored as 
+  // a serialized array.  To be backwards compatible, we should check for serialization
+  // and if not then we will use the old style
+  $args = unserialize($job->arguments);
+  if (!$args) {
+    $args = explode("::", $job->arguments);
+  }
   $job_id = tripal_add_job($job->job_name, $job->modulename, $job->callback, $args, $user_id, $job->priority);
 
   if ($goto_jobs_page) {
@@ -285,7 +295,15 @@ function tripal_jobs_launch($do_parallel = 0, $job_id = NULL) {
     // Add the job_id as the last item in the list of arguments. All
     // callback functions should support this argument.
     $callback = $job->callback;
-    $args = split("::", $job->arguments);
+    
+    // arguments for jobs used to be stored as plain string with a double colon
+    // separating them.  But as of Tripal v2.0 the arguments are stored as
+    // a serialized array.  To be backwards compatible, we should check for serialization
+    // and if not then we will use the old style
+    $args = unserialize($job->arguments);
+    if (!$args) {
+      $args = explode("::", $job->arguments);
+    }
     $args[] = $job->job_id;
     print "Calling: $callback(" . implode(", ", $args) . ")\n";
     call_user_func_array($callback, $args);

+ 2 - 2
tripal_core/tripal_core.drush.inc

@@ -187,7 +187,7 @@ function drush_tripal_core_set_user($username) {
   }
   else {
     drush_print('ERROR: Please provide a username for running this job.');
-    return;
+    exit;
   }
 }
 
@@ -368,5 +368,5 @@ function drush_tripal_core_tripal_node_sync($module) {
  *  The name of a module with nodes associated with it. For example, feature
  */
 function drush_tripal_core_tripal_node_clean($module) {
-  tripal_core_clean_orphaned_nodes($module, 0);
+  tripal_core_chado_node_cleanup_orphaned($module, 0);
 }

+ 8 - 2
tripal_cv/api/tripal_cv.api.inc

@@ -539,7 +539,10 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
   }
   
   // make sure the CV name exists
-  $cv = tripal_cv_add_cv($cvname, '');
+  $cv = tripal_cv_get_cv_by_name($cvname);
+  if (!$cv) {
+    $cv = tripal_cv_add_cv($cvname, '');
+  }
   if (!$cv) {
     watchdog('tripal_cv', "Cannot find namespace '$cvname' when adding/updating $id", NULL, WATCHDOG_WARNING);
     return 0;
@@ -561,7 +564,10 @@ function tripal_cv_add_cvterm($term, $defaultcv = '_global', $is_relationship =
   
   // add the database. The function will just return the DB object if the
   // database already exists.
-  $db = tripal_db_add_db($dbname);
+  $db = tripal_db_get_db_by_name($dbname);
+  if (!$db) {
+    $db = tripal_db_add_db($dbname);
+  }
   if (!$db) {
     watchdog('tripal_cv', "Cannot find database '$dbname' in Chado.", NULL, WATCHDOG_WARNING);
     return 0;

+ 1 - 1
tripal_feature/includes/tripal_feature.sync_features.inc

@@ -444,6 +444,6 @@ function tripal_feature_sync_features($max_sync = 0, $organism_id = NULL,
  */
 function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
 
-  return tripal_core_clean_orphaned_nodes('feature', $job_id);
+  return tripal_core_chado_node_cleanup_orphaned('feature', $job_id);
 
 }

+ 175 - 0
tripal_feature/theme/tripal_feature.theme.inc

@@ -0,0 +1,175 @@
+<?php 
+
+
+/**
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_feature_sequence(&$variables) {
+  // we want to provide a new variable that contains the matched features.
+  $feature = $variables['node']->feature;
+
+  // get the featureloc src features
+  $options = array(
+    'return_array' => 1,
+    'include_fk' => array(
+      'srcfeature_id' => array(
+        'type_id' => 1
+      ),
+    ),
+  );
+
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
+
+  // because there are two foriegn keys in the featureloc table with the feature table
+  // we have to access the records for each by specifying the field name after the table name:
+  $ffeaturelocs = $feature->featureloc->feature_id;
+
+  // now extract the sequences
+  $featureloc_sequences = tripal_feature_load_featureloc_sequences($feature->feature_id, $ffeaturelocs);
+  $feature->featureloc_sequences = $featureloc_sequences;
+}
+/**
+ *
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_feature_relationships(&$variables) {
+  // we want to provide a new variable that contains the matched features.
+  $feature = $variables['node']->feature;
+
+  if (!property_exists($feature, 'all_relationships')) {
+    $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
+  }
+}
+
+/**
+ *
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_feature_proteins(&$variables) {
+  // we want to provide a new variable that contains the matched features.
+  $feature = $variables['node']->feature;
+
+  if (!property_exists($feature, 'all_relationships')) {
+    $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
+  }
+}
+/**
+ *
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
+
+  // we want to provide a new variable that contains the matched features.
+  $feature = $variables['node']->feature;
+  $options = array(
+    'return_array' => 1,
+    'include_fk' => array(
+      'srcfeature_id' => array(
+        'type_id' => 1,
+      ),
+      'feature_id' => array(
+        'type_id' => 1
+      ),
+    )
+  );
+  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
+
+  // get alignments as child
+  $cfeaturelocs = $feature->featureloc->feature_id;
+  if (!$cfeaturelocs) {
+    $cfeaturelocs = array();
+  }
+  // get alignment as parent
+  $pfeaturelocs = $feature->featureloc->srcfeature_id;
+  if (!$pfeaturelocs) {
+    $pfeaturelocs = array();
+  }
+
+  // get matched alignments (those with an itermediate 'match' or 'EST_match', etc
+  $mfeaturelocs = tripal_feature_get_matched_alignments($feature);
+  $feature->matched_featurelocs = $mfeaturelocs;
+
+  // combine all three alignments into a single array for printing together in
+  // a single list
+  $alignments = array();
+  foreach ($pfeaturelocs as $featureloc) {
+    // if type is a 'match' then ignore it. We will handle those below
+    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
+      continue;
+    }
+    $alignment = new stdClass();
+    $alignment->record = $featureloc;
+    $alignment->name = $featureloc->feature_id->name;
+    $alignment->type = $featureloc->feature_id->type_id->name;
+    $alignment->fmin = $featureloc->fmin;
+    $alignment->fmax = $featureloc->fmax;
+    $alignment->phase = $featureloc->phase;
+    $alignment->strand = $featureloc->strand;
+    $alignments[] = $alignment;
+    if (property_exists($featureloc->feature_id, 'nid')) {
+      $alignment->nid = $featureloc->feature_id->nid;
+    }
+  }
+  foreach ($cfeaturelocs as $featureloc) {
+    // if type is a 'match' then ignore it. We will handle those below
+    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
+      continue;
+    }
+    $alignment = new stdClass();
+    $alignment->record = $featureloc;
+    $alignment->name = $featureloc->srcfeature_id->name;
+    $alignment->type = $featureloc->srcfeature_id->type_id->name;
+    $alignment->fmin = $featureloc->fmin;
+    $alignment->is_fmin_partial = $featureloc->is_fmin_partial;
+    $alignment->fmax = $featureloc->fmax;
+    $alignment->is_fmax_partial = $featureloc->is_fmax_partial;
+    $alignment->phase = $featureloc->phase;
+    $alignment->strand = $featureloc->strand;
+    $alignments[] = $alignment;
+    if (property_exists($featureloc->srcfeature_id, 'nid')) {
+      $alignment->nid = $featureloc->srcfeature_id->nid;
+    }
+  }
+  // in matching features, the left feature is always the feature
+  // provided to this function.
+  foreach ($mfeaturelocs as $featureloc) {
+    // get more information about the right feature
+    $select = array('feature_id' => $featureloc->right_srcfeature_id);
+    $rfeature = tripal_core_generate_chado_var('feature', $select);
+    // now add to the list
+    $alignment = new stdClass();
+    $alignment->record = $featureloc;
+    $alignment->right_feature = $rfeature;
+    $alignment->name = $rfeature->name;
+    $alignment->type = $rfeature->type_id->name;
+    $alignment->fmin = $featureloc->left_fmin;
+    $alignment->is_fmin_partial = $featureloc->left_is_fmin_partial;
+    $alignment->fmax = $featureloc->left_fmax;
+    $alignment->is_fmax_partial = $featureloc->left_is_fmax_partial;
+    $alignment->phase = $featureloc->left_phase;
+    $alignment->strand = $featureloc->left_strand;
+    $alignment->right_fmin = $featureloc->right_fmin;
+    $alignment->right_is_fmin_partial = $featureloc->right_is_fmin_partial;
+    $alignment->right_fmax = $featureloc->right_fmax;
+    $alignment->right_is_fmax_partial = $featureloc->right_is_fmax_partial;
+    $alignment->right_phase = $featureloc->right_phase;
+    $alignment->right_strand = $featureloc->right_strand;
+    $alignments[] = $alignment;
+    if (property_exists($rfeature, 'nid')) {
+      $alignment->nid = $rfeature->nid;
+    }
+  }
+  $feature->all_featurelocs = $alignments;
+}
+/**
+ *
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables, $hook) {
+  $organism = $variables['node']->organism;
+  $organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
+}

+ 2 - 2
tripal_feature/theme/tripal_feature/tripal_feature_base.tpl.php

@@ -43,9 +43,9 @@ $feature  = $variables['node']->feature;  ?>
     $feature->type_id->name
   );
   // Organism row
-  $organism = $feature->organism_id->genus ." " . $feature->organism_id->species ." (" .$feature->organism_id->common_name .")";
+  $organism = $feature->organism_id->genus ." " . $feature->organism_id->species ." (" . $feature->organism_id->common_name .")";
   if ($feature->organism_id->nid) {
-    $organism = l("<i>" . $feature->organism_id->genus . " " . $feature->organism_id->species . "</i> (" .$feature->organism_id->common_name .")", "node/".$feature->organism_id->nid, array('html' => TRUE));
+    $organism = l("<i>" . $feature->organism_id->genus . " " . $feature->organism_id->species . "</i> (" . $feature->organism_id->common_name .")", "node/".$feature->organism_id->nid, array('html' => TRUE));
   } 
   $rows[] = array(
     array(

+ 85 - 0
tripal_feature/theme/tripal_feature/tripal_feature_publications.tpl.php

@@ -0,0 +1,85 @@
+<?php
+$feature = $variables['node']->feature;
+
+// expand feature to include pubs 
+$options = array('return_array' => 1);
+$feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_pub', $options);
+$feature_pubs = $feature->feature_pub; 
+
+
+if (count($feature_pubs) > 0) { ?>
+  <div id="tripal_feature_pub-pub-box" class="tripal_feature_pub-info-box tripal-info-box">
+    <div class="tripal_feature_pub-info-box-title tripal-info-box-title">Publications</div>
+    <div class="tripal_feature_pub-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Year', 'Publication');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($feature_pubs as $feature_pub) {
+      $pub = $feature_pub->pub_id;
+      $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+      $citation = $pub->title;  // use the title as the default citation
+      
+      // get the citation for this pub if it exists
+      $values = array(
+        'pub_id' => $pub->pub_id, 
+        'type_id' => array(
+          'name' => 'Citation',
+        ),
+      );
+      $options = array('return_array' => 1);
+      $citation_prop = tripal_core_generate_chado_var('pubprop', $values, $options); 
+      if (count($citation_prop) == 1) {
+        $citation_prop = tripal_core_expand_chado_vars($citation_prop, 'field', 'pubprop.value');
+        $citation = $citation_prop[0]->value;
+      }
+      
+      // if the publication is synced then link to it
+      if ($pub->nid) {
+        // replace the title with a link
+        $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
+        $patterns = array(
+          '/(\()/', '/(\))/',
+          '/(\])/', '/(\[)/',
+          '/(\{)/', '/(\})/',
+          '/(\+)/', '/(\.)/', '/(\?)/',
+        );
+        $fixed_title = preg_replace($patterns, "\\\\$1", $pub->title);
+        $citation = preg_replace('/' . $fixed_title . '/', $link, $citation);
+      }
+      
+      $rows[] = array(
+        $pub->pyear,
+        $citation,
+      );
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-publications',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php 
+}

+ 7 - 4
tripal_feature/theme/tripal_feature/tripal_feature_terms.tpl.php

@@ -1,14 +1,17 @@
 <?php
 
-$feature = $node->feature;
+$feature = $variables['node']->feature;
+
 $options = array('return_array' => 1);
 $feature = tripal_core_expand_chado_vars($feature, 'table', 'feature_cvterm', $options);
 $terms = $feature->feature_cvterm;
 
 // order the terms by CV
 $s_terms = array();
-foreach ($terms as $term) {
-  $s_terms[$term->cvterm_id->cv_id->name][] = $term;  
+if ($terms) {
+  foreach ($terms as $term) {
+    $s_terms[$term->cvterm_id->cv_id->name][] = $term;  
+  }
 }
 
 if (count($s_terms) > 0) { ?>
@@ -56,7 +59,7 @@ if (count($s_terms) > 0) { ?>
           'id' => "tripal_feature-table-terms-$i",
         ),
         'sticky' => FALSE,
-        'caption' => ucwords(preg_replace('/_/', ' ', $cv)),
+        'caption' => '<b>Vocabulary: ' . ucwords(preg_replace('/_/', ' ', $cv)) . '</b>',
         'colgroups' => array(),
         'empty' => '',
       );

+ 10 - 174
tripal_feature/tripal_feature.module

@@ -15,7 +15,7 @@
 
 require_once "api/tripal_feature.api.inc";
 require_once "api/tripal_feature.schema.api.inc";
-
+require_once "theme/tripal_feature.theme.inc";
 require_once "includes/tripal_feature.admin.inc";
 require_once "includes/tripal_feature.sync_features.inc";
 require_once "includes/tripal_feature.fasta_loader.inc";
@@ -277,7 +277,7 @@ function tripal_feature_menu() {
     'title' => 'Enable feature Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_feature_admin_features', 'admin/tripal/chado/tripal_feature'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal feature'),
     'type' => MENU_CALLBACK,
   );
 
@@ -330,6 +330,11 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
       'template' => 'tripal_feature_proteins',
       'path' => "$path/theme/tripal_feature",
     ),
+    'tripal_feature_publications' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_feature_publications',
+      'path' => "$path/theme/tripal_feature",
+    ),
     'tripal_feature_synonyms' => array(
       'variables' => array('node' => NULL),
       'template' => 'tripal_feature_synonyms',
@@ -1387,6 +1392,9 @@ function tripal_feature_node_view($node, $view_mode, $langcode) {
         $node->content['tripal_feature_properties'] = array(
           '#value' => theme('tripal_feature_properties', array('node' => $node)),
         );
+        $node->content['tripal_feature_publications'] = array(
+          '#value' => theme('tripal_feature_properties', array('node' => $node)),
+        );
         $node->content['tripal_feature_references'] = array(
           '#value' => theme('tripal_feature_references', array('node' => $node)),
         );
@@ -1449,178 +1457,6 @@ function tripal_feature_node_update($node) {
   }
 }
 
-/**
- * @ingroup tripal_feature
- */
-function tripal_feature_preprocess_tripal_feature_sequence(&$variables) {
-  // we want to provide a new variable that contains the matched features.
-  $feature = $variables['node']->feature;
-
-  // get the featureloc src features
-  $options = array(
-    'return_array' => 1,
-    'include_fk' => array(
-      'srcfeature_id' => array(
-        'type_id' => 1
-      ),
-    ),
-  );
-
-  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
-
-  // because there are two foriegn keys in the featureloc table with the feature table
-  // we have to access the records for each by specifying the field name after the table name:
-  $ffeaturelocs = $feature->featureloc->feature_id;
-
-  // now extract the sequences
-  $featureloc_sequences = tripal_feature_load_featureloc_sequences($feature->feature_id, $ffeaturelocs);
-  $feature->featureloc_sequences = $featureloc_sequences;
-}
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_preprocess_tripal_feature_relationships(&$variables) {
-  // we want to provide a new variable that contains the matched features.
-  $feature = $variables['node']->feature;
-
-  if (!property_exists($feature, 'all_relationships')) {
-    $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
-  }
-}
-
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_preprocess_tripal_feature_proteins(&$variables) {
-  // we want to provide a new variable that contains the matched features.
-  $feature = $variables['node']->feature;
-
-  if (!property_exists($feature, 'all_relationships')) {
-    $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
-  }
-}
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
-
-  // we want to provide a new variable that contains the matched features.
-  $feature = $variables['node']->feature;
-  $options = array(
-    'return_array' => 1,
-    'include_fk' => array(
-      'srcfeature_id' => array(
-        'type_id' => 1,
-      ),
-      'feature_id' => array(
-        'type_id' => 1
-      ),
-    )
-  );
-  $feature = tripal_core_expand_chado_vars($feature, 'table', 'featureloc', $options);
-
-  // get alignments as child
-  $cfeaturelocs = $feature->featureloc->feature_id;
-  if (!$cfeaturelocs) {
-    $cfeaturelocs = array();
-  }
-  // get alignment as parent
-  $pfeaturelocs = $feature->featureloc->srcfeature_id;
-  if (!$pfeaturelocs) {
-    $pfeaturelocs = array();
-  }
-
-  // get matched alignments (those with an itermediate 'match' or 'EST_match', etc
-  $mfeaturelocs = tripal_feature_get_matched_alignments($feature);
-  $feature->matched_featurelocs = $mfeaturelocs;
-
-  // combine all three alignments into a single array for printing together in
-  // a single list
-  $alignments = array();
-  foreach ($pfeaturelocs as $featureloc) {
-    // if type is a 'match' then ignore it. We will handle those below
-    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
-       continue;
-    }
-    $alignment = new stdClass();
-    $alignment->record = $featureloc;
-    $alignment->name = $featureloc->feature_id->name;
-    $alignment->type = $featureloc->feature_id->type_id->name;
-    $alignment->fmin = $featureloc->fmin;
-    $alignment->fmax = $featureloc->fmax;
-    $alignment->phase = $featureloc->phase;
-    $alignment->strand = $featureloc->strand;
-    $alignments[] = $alignment;
-    if (property_exists($featureloc->feature_id, 'nid')) {
-      $alignment->nid = $featureloc->feature_id->nid;
-    }
-  }
-  foreach ($cfeaturelocs as $featureloc) {
-    // if type is a 'match' then ignore it. We will handle those below
-    if (preg_match('/(^match$|^.*?_match|match_part)$/', $featureloc->feature_id->type_id->name)) {
-      continue;
-    }
-    $alignment = new stdClass();
-    $alignment->record = $featureloc;
-    $alignment->name = $featureloc->srcfeature_id->name;
-    $alignment->type = $featureloc->srcfeature_id->type_id->name;
-    $alignment->fmin = $featureloc->fmin;
-    $alignment->is_fmin_partial = $featureloc->is_fmin_partial;
-    $alignment->fmax = $featureloc->fmax;
-    $alignment->is_fmax_partial = $featureloc->is_fmax_partial;
-    $alignment->phase = $featureloc->phase;
-    $alignment->strand = $featureloc->strand;
-    $alignments[] = $alignment;
-    if (property_exists($featureloc->srcfeature_id, 'nid')) {
-      $alignment->nid = $featureloc->srcfeature_id->nid;
-    }
-  }
-  // in matching features, the left feature is always the feature
-  // provided to this function.
-  foreach ($mfeaturelocs as $featureloc) {
-     // get more information about the right feature
-     $select = array('feature_id' => $featureloc->right_srcfeature_id);
-     $rfeature = tripal_core_generate_chado_var('feature', $select);
-     // now add to the list
-     $alignment = new stdClass();
-     $alignment->record = $featureloc;
-     $alignment->right_feature = $rfeature;
-     $alignment->name = $rfeature->name;
-     $alignment->type = $rfeature->type_id->name;
-     $alignment->fmin = $featureloc->left_fmin;
-     $alignment->is_fmin_partial = $featureloc->left_is_fmin_partial;
-     $alignment->fmax = $featureloc->left_fmax;
-     $alignment->is_fmax_partial = $featureloc->left_is_fmax_partial;
-     $alignment->phase = $featureloc->left_phase;
-     $alignment->strand = $featureloc->left_strand;
-     $alignment->right_fmin = $featureloc->right_fmin;
-     $alignment->right_is_fmin_partial = $featureloc->right_is_fmin_partial;
-     $alignment->right_fmax = $featureloc->right_fmax;
-     $alignment->right_is_fmax_partial = $featureloc->right_is_fmax_partial;
-     $alignment->right_phase = $featureloc->right_phase;
-     $alignment->right_strand = $featureloc->right_strand;
-     $alignments[] = $alignment;
-     if (property_exists($rfeature, 'nid')) {
-       $alignment->nid = $rfeature->nid;
-     }
-  }
-  $feature->all_featurelocs = $alignments;
-}
-/**
- *
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables, $hook) {
-  $organism = $variables['node']->organism;
-  $organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
-}
 
 /**
  *

+ 3 - 358
tripal_featuremap/includes/tripal_featuremap.admin.inc

@@ -41,374 +41,19 @@ function tripal_featuremap_admin_featuremaps_listing() {
 function tripal_featuremap_admin() {
   $form = array();
 
-  // before proceeding check to see if we have any
-  // currently processing jobs. If so, we don't want
-  // to give the opportunity to sync maps
-  $active_jobs = FALSE;
-  if (tripal_get_module_active_jobs('tripal_featuremap')) {
-    $active_jobs = TRUE;
-  }
-
-  // add the field set for syncing maps
-  if (!$active_jobs) {
-    get_tripal_featuremap_admin_form_sync_set($form);
-    get_tripal_featuremap_admin_form_cleanup_set($form);
-// TODO: complete coding of indexing and taxonomy assignment to features.
-//    get_tripal_featuremap_admin_form_reindex_set($form);
-//    get_tripal_featuremap_admin_form_taxonomy_set($form);
-  }
-  else {
-    $form['notice'] = array(
-     '#type' => 'fieldset',
-     '#title' => t('Feature Map Management Temporarily Unavailable')
-    );
-    $form['notice']['message'] = array(
-        '#value' => t('Currently, feature map management jobs are waiting or are running. Managemment features have been hidden until these jobs complete.  Please check back later once these jobs have finished.  You can view the status of pending jobs in the Tripal jobs page.'),
-    );
-  }
-
-  return system_settings_form($form);
-}
-/**
- *
- *
- * @ingroup tripal_featuremap
- */
-function get_tripal_featuremap_admin_form_cleanup_set(&$form) {
-  $form['cleanup'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Clean Up')
-  );
-  $form['cleanup']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("With Drupal and chado residing in different databases ".
-        "it is possible that nodes in Drupal and maps in Chado become ".
-        "\"orphaned\".  This can occur if an map node in Drupal is ".
-        "deleted but the corresponding chado map is not and/or vice ".
-        "versa. Click the button below to resolve these discrepancies."),
-     '#weight' => 1,
-  );
-  $form['cleanup']['button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Clean up orphaned maps'),
-    '#weight' => 2,
-  );
-}
-
-/**
- *
- *
- * @ingroup tripal_featuremap
- */
-function get_tripal_featuremap_admin_form_taxonomy_set(&$form) {
-  $form['taxonify'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Assign Drupal Taxonomy to Map Features')
-  );
-
-  // get the list of maps
-  $sql = "SELECT * FROM {featuremap} ORDER BY name";
-  $lib_rset = chado_query($sql);
-
-  // iterate through all of the maps
-  $lib_boxes = array();
-  while ($featuremap = $lib_rset->fetchObject()) {
-    $lib_boxes[$featuremap->featuremap_id] = "$featuremap->name";
-  }
-
-  $form['taxonify']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("Drupal allows for assignment of \"taxonomy\" or catagorical terms to " .
-                   "nodes. These terms allow for advanced filtering during searching. This option allows ".
-                   "for setting taxonomy only for features that belong to the selected maps below.  All other features will be unaffected.  To set taxonomy for all features in the site see the Feature Administration page."),
-   '#weight' => 1,
+  $form['nothing'] = array(
+    '#markup' => t('There are currently no settings to configure.')
   );
 
-  $form['taxonify']['tx-maps'] = array(
-   '#title'       => t('Maps'),
-   '#type'        => t('checkboxes'),
-   '#description' => t("Check the maps whose features you want to reset taxonomy.  Note: this list contains all maps, even those that may not be synced."),
-   '#required'    => FALSE,
-   '#prefix'      => '<div id="lib_boxes">',
-   '#suffix'      => '</div>',
-   '#options'     => $lib_boxes,
-   '#weight'      => 2
-  );
-  $form['taxonify']['tx-button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Set Feature Taxonomy'),
-    '#weight'      => 3
-  );
-}
-/**
- *
- * @ingroup tripal_featuremap
- */
-function get_tripal_featuremap_admin_form_reindex_set(&$form) {
-   // define the fieldsets
-  $form['reindex'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Reindex Map Features')
-  );
-
-  // get the list of maps
-  $sql = "SELECT * FROM {featuremap} ORDER BY name";
-  $lib_rset = chado_query($sql);
-
-  // iterate through all of the maps
-  $lib_boxes = array();
-  while ($featuremap = $lib_rset->fetchObject()) {
-    $lib_boxes[$featuremap->featuremap_id] = "$featuremap->name";
-  }
-  $form['reindex']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("This option allows for reindexing of only those features that belong to the selected maps below. All other features will be unaffected.  To reindex all features in the site see the Feature Administration page."),
-   '#weight' => 1,
-  );
-
-  $form['reindex']['re-maps'] = array(
-   '#title'       => t('Maps'),
-   '#type'        => t('checkboxes'),
-   '#description' => t("Check the maps whoee features you want to reindex. Note: this list contains all maps, even those that may not be synced."),
-   '#required'    => FALSE,
-   '#prefix'      => '<div id="lib_boxes">',
-   '#suffix'      => '</div>',
-   '#options'     => $lib_boxes,
-   '#weight' => 2,
-  );
-  $form['reindex']['re-button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reindex Features'),
-    '#weight' => 3,
-  );
+  return system_settings_form($form);
 }
-/**
- *
- * @ingroup tripal_featuremap
- */
-function get_tripal_featuremap_admin_form_sync_set(&$form) {
-   // define the fieldsets
-  $form['sync'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Sync Maps')
-  );
-
 
-  // get the list of maps
-  $sql = "SELECT * FROM {featuremap} ORDER BY name";
-  $lib_rset = chado_query($sql);
 
-  // if we've added any maps to the list that can be synced
-  // then we want to build the form components to allow the user
-  // to select one or all of them.  Otherwise, just present
-  // a message stating that all maps are currently synced.
-  $lib_boxes = array();
-  $added = 0;
-  while ($featuremap = $lib_rset->fetchObject()) {
-    // check to see if the map is already present as a node in drupal.
-    // if so, then skip it.
-    $sql = "SELECT * FROM {chado_featuremap} WHERE featuremap_id = :featuremap_id";
-    if (!db_query($sql, array(':featuremap_id' => $featuremap->featuremap_id))->fetchObject()) {
-      $lib_boxes[$featuremap->featuremap_id] = "$featuremap->name";
-      $added++;
-    }
-  }
-
-  // if we have maps we need to add to the checkbox then
-  // build that form element
-  if ($added > 0) {
-    $lib_boxes['all'] = "All Maps";
-
-    $form['reindex']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("This option allows for the creation of Drupal content for maps in chado. Only the selected maps will be synced."),
-   '#weight' => 1,
-    );
-
-
-    $form['sync']['featuremaps'] = array(
-      '#title'       => t('Available Maps'),
-      '#type'        => t('checkboxes'),
-      '#description' => t("Check the maps you want to sync.  Drupal content will be created for each of the maps listed above.  Select 'All Maps' to sync all of them."),
-      '#required'    => FALSE,
-      '#prefix'      => '<div id="lib_boxes">',
-      '#suffix'      => '</div>',
-      '#options'     => $lib_boxes,
-    '#weight' => 2,
-    );
-    $form['sync']['button'] = array(
-       '#type' => 'submit',
-       '#value' => t('Sync Maps'),
-     '#weight' => 3,
-    );
-  }
-   // we don't have any maps to select from
-  else {
-    $form['sync']['value'] = array(
-       '#value' => t('All maps in Chado are currently synced with Drupal.')
-    );
-  }
-}
 /**
  *
  * @ingroup tripal_featuremap
  */
 function tripal_featuremap_admin_validate($form, &$form_state) {
-  global $user;  // we need access to the user info
-  $job_args = array();
-
-  // Submit the Sync Job if selected
-  if ($form_state['values']['op'] == t('Sync Maps')) {
-
-    // check to see if the user wants to sync chado and drupal.  If
-    // so then we need to register a job to do so with tripal
-    $featuremaps = $form_state['values']['featuremaps'];
-    $do_all = FALSE;
-    $to_sync = array();
-
-  foreach ($featuremaps as $featuremap_id) {
-    if (preg_match("/^all$/i", $featuremap_id)) {
-      $do_all = TRUE;
-    }
-    if ($featuremap_id and preg_match("/^\d+$/i", $featuremap_id)) {
-      // get the map info
-      $sql = "SELECT * FROM {featuremap} WHERE featuremap_id = :featuremap_id";
-      $featuremap = chado_query($sql, array(':featuremap_id' => $featuremap_id))->fetchObject();
-      $to_sync[$featuremap_id] = $featuremap->name;
-    }
-  }
-
-  // submit the job to the tripal job manager
-  if ($do_all) {
-    tripal_add_job('Sync all maps', 'tripal_featuremap', 'tripal_featuremap_sync_featuremaps', $job_args, $user->uid);
-  }
-  else{
-    foreach ($to_sync as $featuremap_id => $name) {
-      $job_args[0] = $featuremap_id;
-      tripal_add_job("Sync map: $name", 'tripal_featuremap', 'tripal_featuremap_sync_featuremaps', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Reindex Job if selected
-  if ($form_state['values']['op'] == t('Reindex Features')) {
-    $featuremaps = $form_state['values']['re-maps'];
-    foreach ($featuremaps as $featuremap_id) {
-      if ($featuremap_id and preg_match("/^\d+$/i", $featuremap_id)) {
-        // get the map info
-        $sql = "SELECT * FROM {featuremap} WHERE featuremap_id = :featuremap_id";
-        $featuremap = chado_query($sql, array(':featuremap_id' => $featuremap_id))->fetchObject();
-        $job_args[0] = $featuremap_id;
-        tripal_add_job("Reindex features for map: $featuremap->name", 'tripal_featuremap',
-         'tripal_featuremap_reindex_features', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Taxonomy Job if selected
-  if ($form_state['values']['op'] == t('Set Feature Taxonomy')) {
-    $featuremaps = $form_state['values']['tx-maps'];
-    foreach ($featuremaps as $featuremap_id) {
-      if ($featuremap_id and preg_match("/^\d+$/i", $featuremap_id)) {
-        // get the map info
-        $sql = "SELECT * FROM {featuremap} WHERE featuremap_id = :featuremap_id";
-        $featuremap = chado_query($sql, array(':featuremap_id' => $featuremap_id))->fetchObject();
-        $job_args[0] = $featuremap_id;
-        tripal_add_job("Set taxonomy for features in map: $featuremap->name", 'tripal_featuremap',
-         'tripal_featuremap_taxonify_features', $job_args, $user->uid);
-      }
-    }
-  }
-    // -------------------------------------
-    // Submit the Cleanup Job if selected
-    if ($form_state['values']['op'] == t('Clean up orphaned maps')) {
-      tripal_add_job('Cleanup orphaned maps', 'tripal_featuremap',
-         'tripal_featuremap_cleanup', $job_args, $user->uid);
-    }
-}
-
-/**
- *
- *
- * @ingroup tripal_featuremap
- */
-function tripal_featuremap_sync_featuremaps($featuremap_id = NULL, $job_id = NULL) {
-
-  global $user;
-  $page_content = '';
-
-  // get the list of featuremaps and create new nodes
-  if (!$featuremap_id) {
-    $sql = "SELECT * FROM {featuremap} F";
-    $results = chado_query($sql);
-  }
-  else {
-    $sql = "SELECT * FROM {featuremap} F WHERE featuremap_id = :featuremap_id";
-    $results = chado_query($sql, array(':featuremap_id' => $featuremap_id));
-  }
 
-  // We'll use the following SQL statement for checking if the map
-  // already exists as a drupal node.
-  $sql = "SELECT * FROM {chado_featuremap} ".
-        "WHERE featuremap_id = :featuremap_id";
-
-  while ($featuremap = $results->fetchObject()) {
-
-    // check if this map already exists in the drupal database. if it
-    // does then skip this map and go to the next one.
-    if (!db_query($sql, array(':featuremap_id' => $featuremap->featuremap_id))->fetchObject()) {
-
-    $new_node = new stdClass();
-    $new_node->type = 'chado_featuremap';
-    $new_node->uid = $user->uid;
-    $new_node->title = "$featuremap->name";
-    $new_node->featuremap_id = $featuremap->featuremap_id;
-
-    node_validate($new_node);
-    $errors = form_get_errors();
-    if (!$errors) {
-      $node = node_submit($new_node);
-      node_save($node);
-      if ($node->nid) {
-        print "Added " . $featuremap->name . "\n";
-      }
-      else {
-        print "ERROR: Unable to create " . $featuremap->name . "\n";
-      }
-    }
-    else {
-      print "ERROR: Unable to create " . $featuremap->name . "\n" . print_r($errors, TRUE) . "\n";
-    }
-    }
-    else {
-      print "Skipped " . $featuremap->name . "\n";
-    }
-  }
-  return $page_content;
 }
 
-/**
- * Remove orphaned drupal nodes
- *
- * @param $dummy
- *   Not Used -kept for backwards compatibility
- * @param $job_id
- *   The id of the tripal job executing this function
- *
- * @ingroup tripal_featuremap
- */
-function tripal_featuremap_cleanup($dummy = NULL, $job_id = NULL) {
-
-  return tripal_core_clean_orphaned_nodes('featuremap', $job_id);
-
-}
-/**
- * Add the map as a taxonomy term for associating with map_features
- *
- * @ingroup tripal_featuremap
- */
-function tripal_featuremap_add_taxonomy($node, $featuremap_id) {
-
-}

+ 397 - 0
tripal_featuremap/includes/tripal_featuremap.chado_node.inc

@@ -0,0 +1,397 @@
+<?php
+/**
+ *  When editing or creating a new node of type 'chado_featuremap' we need
+ *  a form.  This function creates the form that will be used for this.
+ *
+ * @ingroup tripal_featuremap
+ */
+function chado_featuremap_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 library
+  // 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
+  $featuremap_id = NULL;
+  $title = '';
+  $description = '';
+  $unittype_id = '';
+  
+  // if we are editing an existing node then the featuremap is already part of the node
+  if (property_exists($node, 'featuremap')) {
+    $featuremap = $node->featuremap;
+    $featuremap = tripal_core_expand_chado_vars($featuremap, 'field', 'featuremap.description');
+    $featuremap_id = $featuremap->featuremap_id;
+    
+    // get form defaults
+    $title       = $featuremap->name;
+    $description = $featuremap->description;
+    $unittype_id = $featuremap->unittype_id->cvterm_id;
+    
+    // set the featuremap_id in the form
+    $form['featuremap_id'] = array(
+      '#type' => 'hidden',
+      '#value' => $featuremap_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)) {
+    $title       = $form_state['values']['title'];
+    $description = $form_state['values']['description'];
+    $unittype_id = $form_state['values']['unittype_id'];
+  }
+  // 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'])) {
+    $title       = $form_state['input']['title'];
+    $description = $form_state['input']['description'];
+    $unittype_id = $form_state['input']['unittype_id'];
+  }
+  
+  $form['title']= array(
+    '#type'          => 'textfield',
+    '#title'         => t('Map Name'),
+    '#description'   => t('Please enter a name for this map'),
+    '#required'      => TRUE,
+    '#default_value' => $title,
+    '#maxlength'     => 255
+  );
+  $form['description']= array(
+    '#type'          => 'textarea',
+    '#title'         => t('Map Description'),
+    '#description'   => t('A description of the map.'),
+    '#required'      => TRUE,
+    '#default_value' => $description,
+  );
+
+  // get the list of unit types
+  $values = array(
+    'cv_id' => array(
+      'name' => 'featuremap_units',
+    )
+  );
+  $columns = array('cvterm_id','name');
+  $options = array('order_by' => array('name' => 'ASC'));
+  $featuremap_units = tripal_core_chado_select('cvterm', $columns, $values, $options);
+  $units = array();
+  $units[''] = '';
+  foreach($featuremap_units as $unit) {
+    $units[$unit->cvterm_id] = $unit->name;
+  }
+  $form['unittype_id'] = array(
+    '#title'       => t('Map Units'),
+    '#type'        => t('select'),
+    '#description' => t("Chose the units for this map"),
+    '#required'    => TRUE,
+    '#default_value' => $unittype_id,
+    '#options'     => $units,
+  );
+
+  // get the featuremap properties
+  $properties = array();
+  $properties[] = 'Select a Property';
+  $sql = "
+    SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
+    FROM  {cvterm} CVT
+      INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
+    WHERE 
+      CV.name = 'featuremap_property' AND 
+      NOT CVT.is_obsolete = 1
+    ORDER BY CVT.name ASC 
+  ";
+  $prop_types = chado_query($sql);
+  while ($prop = $prop_types->fetchObject()) {
+    $properties[$prop->cvterm_id] = $prop->name;
+  }
+
+  $exclude = array();
+  $include = array();
+  $instructions = t('To add additional properties to the drop down. ' . l("Add terms to the featuremap_property vocabulary", "admin/tripal/chado/tripal_cv/cvterm/add") . ".");
+  tripal_core_properties_form($form, $form_state, 'featuremapprop', 'featuremap_id', 'featuremap_property',
+    $properties, $featuremap_id, $exclude, $include, $instructions, 'Properties');
+
+  return $form;
+}
+/**
+ *  validates submission of form when adding or updating a map node
+ *
+ * @ingroup tripal_featuremap
+ */
+function chado_featuremap_validate($node, $form, &$form_state) {
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+  
+  // if this is a delete then don't validate
+  if($node->op == 'Delete') {
+    return;
+  }
+  
+  // we are syncing if we do not have a node ID but we do have a featuremap_id. We don't
+  // need to validate during syncing so just skip it.
+  if (is_null($node->nid) and property_exists($node, 'featuremap_id') and $node->featuremap_id != 0) {
+    return;
+  }
+
+  $featuremap = 0;
+  // check to make sure the unique name on the map is unique
+  // before we try to insert into chado. If this is an update then we will
+  // have a featuremap_id, therefore we want to look for another map with this
+  // name but with a different featuremap_id. If this is an insert, just look
+  // for a case where the name already exists.
+  if (property_exists($node, 'featuremap_id')) {
+    $sql = "
+      SELECT * FROM {featuremap} 
+      WHERE name = :name AND NOT featuremap_id = :featuremap_id
+    ";
+    $featuremap = chado_query($sql, array(':name' => $node->title, ':featuremap_id' => $node->featuremap_id))->fetchObject();
+  }
+  else {
+    $sql = "SELECT * FROM {featuremap} WHERE name = :name";
+    $featuremap = chado_query($sql, array(':name' => $node->title))->fetchObject();
+  }
+  if ($featuremap) {
+    form_set_error('title', t('The unique map name already exists. Please choose another'));
+  }
+}
+
+
+/**
+ * Implement hook_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_featuremap
+ */
+function chado_featuremap_node_access($node, $op, $account) {
+  if ($op == 'create') {
+    if (!user_access('create chado_featuremap content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  if ($op == 'update') {
+    if (!user_access('edit any chado_featuremap content', $account) &&
+    !user_access('edit own chado_featuremap content', $account)) {
+      return FALSE;
+    }
+    if (user_access('edit own chado_featuremap content', $account) &&
+    $account->uid != $node->uid) {
+      return FALSE;
+    }
+  }
+
+  if ($op == 'delete') {
+    if (!user_access('delete any chado_featuremap content', $account) &&
+    !user_access('delete own chado_featuremap content', $account)) {
+      return FALSE;
+    }
+    if (user_access('delete own chado_featuremap content', $account) &&
+    $account->uid != $node->uid) {
+      return FALSE;
+    }
+  }
+  return NULL;
+}
+
+/**
+ *  When a new chado_featuremap node is created we also need to add information
+ *  to our chado_featuremap table.  This function is called on insert of a new node
+ *  of type 'chado_featuremap' and inserts the necessary information.
+ *
+ * @ingroup tripal_featuremap
+ */
+function chado_featuremap_insert($node) {
+
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+  
+  // if there is an featuremap_id in the $node object then this must be a sync so
+  // we can skip adding the featuremap as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'featuremap_id')) {
+    
+    $values = array(
+      'name'        => $node->title,
+      'description' => $node->description,
+      'unittype_id' => $node->unittype_id
+    );
+    $featuremap = tripal_core_chado_insert('featuremap', $values);
+    if(!$featuremap) {
+      drupal_set_message(t('Unable to add featuremap.', 'warning'));
+      watchdog('tripal_featuremap', 'Unable to create feature map where values: %values',
+      array('%values' => print_r($values, TRUE)), WATCHDOG_WARNING);
+      return;
+    }
+    $featuremap_id = $featuremap['featuremap_id'];
+
+    // get the properties from the form
+    $properties = tripal_core_properties_form_retreive($node, 'featuremap_property');
+    
+    // now add in the properties
+    $properties = tripal_core_properties_form_retreive($node, 'featuremap_property');
+    foreach ($properties as $property => $elements) {
+      foreach ($elements as $rank => $value) {
+        // if the property name is 'Map Dbxref' then save this as a Dbxref record not a property
+        if ($property == 'Map Dbxref') {
+          $featuremap_dbxref = tripal_featuremap_add_featuremap_dbxref($featuremap_id, $value);
+          if (!$featuremap_dbxref) {
+            drupal_set_message("Error cannot add featuremap cross reference: $value", "error");
+            watchdog('t_featuremap', "Error cannot add featuremap cross reference: %ref",
+            array('%ref' => $value), WATCHDOG_ERROR);
+          }
+        }
+        // this is a property so add it 
+        else {
+          $status = tripal_featuremap_insert_property($featuremap_id, $property, $value, FALSE, 'featuremap_property');
+          if (!$status) {
+            drupal_set_message("Error cannot add property: $property", "error");
+            watchdog('t_featuremap', "Error cannot add property: %prop",
+            array('%property' => $property), WATCHDOG_ERROR);
+          }
+        }
+      }
+    }
+  }
+  else {
+    $featuremap_id = $node->featuremap_id;
+  }
+
+  // Make sure the entry for this featuremap doesn't already exist in the
+  // chado_featuremap table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('featuremap', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->featuremap_id = $featuremap_id;
+    drupal_write_record('chado_featuremap', $record);
+  }
+}
+/**
+ * Update nodes
+ *
+ * @ingroup tripal_featuremap
+ */
+function chado_featuremap_update($node) {
+  
+  $node->title          = trim($node->title);
+  $node->description    = trim($node->description);
+  
+  $featuremap_id = chado_get_id_for_node('featuremap', $node->nid) ;
+
+  // update the map record
+  $match = array(
+    'featuremap_id' => $featuremap_id,
+  );
+  $values = array(
+    'name' => $node->title,
+    'description' => $node->description,
+    'unittype_id' => $node->unittype_id
+  );
+  $status = tripal_core_chado_update('featuremap', $match, $values);
+  if (!$status) {
+    drupal_set_message("Error updating map", "error");
+    watchdog('t_featuremap', "Error updating map", array(), WATCHDOG_ERROR);
+    return;
+  }
+
+  // get the properties from the form
+  $properties = tripal_core_properties_form_retreive($node, 'featuremap_property');
+  
+  tripal_core_chado_delete('featuremapprop', array('featuremap_id' => $featuremap_id));
+  foreach ($properties as $property => $elements) {
+    foreach ($elements as $rank => $value) {
+      // if the property name is 'Map Dbxref' then save this as a Dbxref record not a property
+      if ($property == 'Map Dbxref') {
+        $featuremap_dbxref = tripal_featuremap_add_featuremap_dbxref($featuremap_id, $value);
+        if (!$featuremap_dbxref) {
+          drupal_set_message("Error cannot add featuremap cross reference: $value", "error");
+          watchdog('t_featuremap', "Error cannot add featuremap cross reference: %ref",
+          array('%ref' => $value), WATCHDOG_ERROR);
+        }
+      }
+      // this is a property so add it
+      else {
+        $status = tripal_featuremap_insert_property($featuremap_id, $property, $value, FALSE, 'featuremap_property');
+        if (!$status) {
+          drupal_set_message("Error cannot add property: $property", "error");
+          watchdog('t_featuremap', "Error cannot add property: %prop",
+          array('%property' => $property), WATCHDOG_ERROR);
+        }
+      }
+    }
+  }
+}
+/**
+ *  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_featuremap
+ */
+function chado_featuremap_load($nodes) {
+  foreach ($nodes as $nid => $node) {
+    // get the feature details from chado
+    $featuremap_id = chado_get_id_for_node('featuremap', $node->nid);
+  
+    $values = array('featuremap_id' => $featuremap_id);
+    $featuremap = tripal_core_generate_chado_var('featuremap', $values);
+  
+    // expand the description field as it is needed by the form
+    $featuremap = tripal_core_expand_chado_vars($featuremap, 'field', 'featuremap.description');
+  
+    $nodes[$nid]->featuremap = $featuremap;
+  }
+
+}
+/**
+ * Delete data from drupal and chado databases when a node is deleted
+ * @ingroup tripal_featuremap
+ */
+function chado_featuremap_delete(&$node) {
+
+  $featuremap_id = chado_get_id_for_node('featuremap', $node->nid);
+
+  // if we don't have a map id for this node then this isn't a node of
+  // type chado_featuremap or the entry in the chado_featuremap table was lost.
+  if (!$featuremap_id) {
+    return;
+  }
+
+  // Remove data from {chado_featuremap}, {node} and {node_revisions} tables of
+  // drupal database
+  $sql_del = "DELETE FROM {chado_featuremap} 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));
+  $sql_del = "DELETE FROM {node_revisions} WHERE nid = :nid AND vid = :vid";
+  db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
+
+  // Remove data from map and mapprop tables of chado database as well
+  chado_query("DELETE FROM {featuremapprop}    WHERE featuremap_id = :featuremap_id", array(':featuremap_id' => $featuremap_id));
+  chado_query("DELETE FROM {featuremap_dbxref} WHERE featuremap_id = :featuremap_id", array(':featuremap_id' => $featuremap_id));
+  chado_query("DELETE FROM {featuremap}        WHERE featuremap_id = :featuremap_id", array(':featuremap_id' => $featuremap_id));
+  
+}

+ 0 - 533
tripal_featuremap/includes/tripal_featuremap.form.inc

@@ -1,533 +0,0 @@
-<?php
-/**
- *  When editing or creating a new node of type 'chado_featuremap' we need
- *  a form.  This function creates the form that will be used for this.
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_form($node) {
-  tripal_core_ahah_init_form();
-  $form = array();
-  
-  $featuremap = $node->featuremap;
-  $featuremap_id = $featuremap->featuremap_id;
-  
-  $d_title        = $form_state['values']['title']       ? $form_state['values']['title']       : $featuremap->name;
-  $d_description  = $form_state['values']['description'] ? $form_state['values']['description'] : $featuremap->description;
-  $d_unittype_id  = $form_state['values']['unittype_id'] ? $form_state['values']['unittype_id'] : $featuremap->unittype_id->cvterm_id;
-
-  // on AHAH callbacks we want to keep a list of all the properties that have been removed
-  // we'll store this info in a hidden field and retrieve it here
-  $d_removed = $form_state['values']['removed'];
-
-  // get the number of new fields that have been aded via AHAH callbacks
-  $num_new = $form_state['values']['num_new'] ? $form_state['values']['num_new'] : 0;
-
-  // initialze default properties array. This is where we store the property defaults
-  $d_properties = array();
-  
-  // get the list of unit types
-  $values = array(
-    'cv_id' => array(
-      'name' => 'featuremap_units',
-    )
-  );
-  $columns = array('cvterm_id','name');
-  $options = array('order_by' => array('name' => 'ASC'));
-  $featuremap_units = tripal_core_chado_select('cvterm', $columns, $values, $options);
-  $units = array();
-  $units[''] = '';
-  foreach($featuremap_units as $unit) {
-    $units[$unit->cvterm_id] = $unit->name;
-  }
-  
-  // get the featuremap properties
-  $properties_select = array();
-  $properties_select[] = 'Select a Property';
-  $properties_list = array();
-  $sql = "
-    SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
-    FROM  {cvterm} CVT
-      INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
-    WHERE 
-      CV.name = 'featuremap_property' AND 
-      NOT CVT.is_obsolete = 1
-    ORDER BY CVT.name ASC 
-  ";
-  $prop_types = chado_query($sql);
-  while ($prop = $prop_types->fetchObject()) {
-    $properties_select[$prop->cvterm_id] = $prop->name;
-    $properties_list[$prop->cvterm_id] = $prop;
-  }
-  
-  // keep track of the map id if we have.  If we do have one then
-  // this is an update as opposed to an insert.
-  $form['featuremap_id'] = array(
-    '#type' => 'hidden',
-    '#value' => $featuremap_id,
-  );
-
-  $form['title']= array(
-    '#type'          => 'textfield',
-    '#title'         => t('Map Name'),
-    '#description'   => t('Please enter a name for this map'),
-    '#required'      => TRUE,
-    '#default_value' => $d_title,
-    '#maxlength'     => 255
-  );
-
-  $form['description']= array(
-    '#type'          => 'textarea',
-    '#title'         => t('Map Description'),
-    '#description'   => t('A description of the map.'),
-    '#required'      => TRUE,
-    '#default_value' => $d_description,
-  );
-  
-
-  $form['unittype_id'] = array(
-    '#title'       => t('Map Units'),
-    '#type'        => t('select'),
-    '#description' => t("Chose the units for this map"),
-    '#required'    => TRUE,
-    '#default_value' => $d_unittype_id,
-    '#options'     => $units,
-  );
-
-  
-  // add in the properties from the featuremapprop table
-  $num_properties += chado_featuremap_node_form_add_featuremapprop_table_props($form, $form_state, $featuremap_id, $d_properties, $d_removed);
-
-  // add in any new properties that have been added by the user through an AHAH callback
-  $num_new = chado_featuremap_node_form_add_new_props($form, $form_state, $d_properties, $d_removed);
-
-  // add an empty row of field to allow for addition of a new property
-  chado_featuremap_node_form_add_new_empty_props($form, $properties_select);
-  
-
-  return $form;
-}
-/**
- *  validates submission of form when adding or updating a map node
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_validate($node, $form, &$form_state) {
-  $name          = trim($node->title);
-  $featuremap_id = trim($node->featuremap_id);
-  $unittype_id   = trim($node->unittype_id);
-  $description   = trim($node->description);
-  $num_properties = $node->num_properties;
-  $num_new = $node->num_new;
-  
-  $featuremap = 0;
-  // check to make sure the unique name on the map is unique
-  // before we try to insert into chado. If this is an update then we will
-  // have a featuremap_id, therefore we want to look for another map with this
-  // name but with a different featuremap_id. If this is an insert, just look
-  // for a case where the name already exists.
-  if ($node->featuremap_id) {
-    $sql = "
-      SELECT * FROM {featuremap} 
-      WHERE name = :name AND NOT featuremap_id = :featuremap_id
-    ";
-    $featuremap = chado_query($sql, array(':name' => $node->title, ':featurempa_id' => $node->featuremap_id))->fetchObject();
-  }
-  else {
-    $sql = "SELECT * FROM {featuremap} WHERE name = :name";
-    $featuremap = chado_query($sql, array(':name' => $node->title))->fetchObject();
-  }
-  if ($featuremap) {
-    form_set_error('name', t('The unique map name already exists. Please choose another'));
-  }
-  
-}
-/*
- *
- */
-function chado_featuremap_node_form_add_new_empty_props(&$form, $properties_select) {
-
-  // add one more blank set of property fields
-  $form['properties']['new']["new_id"] = array(
-    '#type'          => 'select',
-    '#options'       => $properties_select,
-    '#ahah' => array(
-      'path'    => "tripal_featuremap/properties/description",
-      'wrapper' => 'tripal-featuremap-new_value-desc',
-      'event'   => 'change',
-      'method'  => 'replace',          
-  ),
-  );
-  $form['properties']['new']["new_value"] = array(
-    '#type'          => 'textarea',
-    '#default_value' => '',
-    '#cols'          => 5,
-    '#rows'          => $rows,
-    '#description'   => '<div id="tripal-featuremap-new_value-desc"></div>'
-    );
-    $form['properties']['new']["add"] = array(
-    '#type'         => 'image_button',      
-    '#value'        => t('Add'),
-    '#src'          => drupal_get_path('theme', 'tripal') . '/images/add.png',
-    '#ahah' => array(
-      'path'    => "tripal_featuremap/properties/add",
-      'wrapper' => 'tripal-featuremap-edit-properties-table',
-      'event'   => 'click',
-      'method'  => 'replace',          
-    ),
-    '#attributes' => array('onClick' => 'return false;'),
-    );
-}
-/*
- *
- */
-function chado_featuremap_node_form_add_new_props(&$form, $form_state, &$d_properties, &$d_removed) {
-   
-  // first, add in all of the new properties that were added through a previous AHAH callback
-  $j = 0;
-  $num_properties++;
-
-  // we need to find the
-  if ($form_state['values']) {
-    foreach ($form_state['values'] as $element_name => $value) {
-      if (preg_match('/new_value-(\d+)-(\d+)/', $element_name, $matches)) {
-        $new_id = $matches[1];
-        $rank = $matches[2];
-
-        // skip any properties that the user requested to delete through a previous
-        // AHAH callback or through the current AHAH callback
-        if($d_removed["$new_id-$rank"]) {
-          continue;
-        }
-        if($form_state['post']['remove-' . $new_id . '-' . $rank]) {
-          $d_removed["$new_id-$rank"] = 1;
-          continue;
-        }
-
-        // get this new_id information
-        $cvterm = tripal_core_chado_select('cvterm', array('name', 'definition'), array('cvterm_id' => $new_id));
-
-        // add it to the $d_properties array
-        $d_properties[$new_id][$rank]['name']  = $cvterm->name;
-        $d_properties[$new_id][$rank]['id']    = $new_id;
-        $d_properties[$new_id][$rank]['value'] = $value;
-        $d_properties[$new_id][$rank]['definition']  = $cvterm->definition;
-        $num_properties++;
-
-        // determine how many rows we need in the textarea
-        $rows = 1;
-        if (preg_match('/Abstract/', $cvterm[0]->name)) {
-          $rows = 10;
-        }
-        if ($cvterm[0]->name == 'Authors') {
-          $rows = 2;
-        }
-
-        // add the new fields
-        $form['properties']['new'][$new_id][$rank]["new_id-$new_id-$rank"] = array(
-          '#type'          => 'item',
-          '#value'         => $cvterm[0]->name
-        );
-        $form['properties']['new'][$new_id][$rank]["new_value-$new_id-$rank"] = array(
-          '#type'          => 'textarea',
-          '#default_value' => $value,
-          '#cols'          => 50,
-          '#rows'          => $rows,
-          '#description'   => $cvterm->definition,
-        );
-
-        $form['properties']['new'][$new_id][$rank]["remove-$new_id-$rank"] = array(
-          '#type'         => 'image_button',
-          '#value'        => t('Remove'),
-          '#src'          => drupal_get_path('theme', 'tripal') . '/images/minus.png',
-          '#ahah' => array(
-            'path'    => "tripal_featuremap/properties/minus/$new_id/$rank",
-            'wrapper' => 'tripal-featuremap-edit-properties-table',
-            'event'   => 'click',
-            'method'  => 'replace',
-        ),
-          '#attributes' => array('onClick' => 'return false;'),
-        );
-      }
-    }
-  }
-
-
-  // second add in any new properties added during this callback
-  if($form_state['post']['add']) {
-    $new_id = $form_state['values']['new_id'];
-    $new_value = $form_state['values']['new_value'];
-
-    // get the rank by counting the number of entries
-    $rank = count($d_properties[$new_id]);
-
-    // get this new_id information
-    $cvterm = tripal_core_chado_select('cvterm', array('name', 'definition'), array('cvterm_id' => $new_id));
-
-    // add it to the $d_properties array
-    $d_properties[$new_id][$rank]['name']  = $cvterm->name;
-    $d_properties[$new_id][$rank]['id']    = $new_id;
-    $d_properties[$new_id][$rank]['value'] = $value;
-    $d_properties[$new_id][$rank]['definition']  = $cvterm->definition;
-    $num_properties++;
-
-    // determine how many rows we need in the textarea
-    $rows = 1;
-    if (preg_match('/Abstract/', $cvterm[0]->name)) {
-      $rows = 10;
-    }
-    if ($cvterm[0]->name == 'Authors') {
-      $rows = 2;
-    }
-
-    // add the new fields
-    $form['properties']['new'][$new_id][$rank]["new_id-$new_id-$rank"] = array(
-      '#type'          => 'item',
-      '#value'         => $cvterm[0]->name
-    );
-    $form['properties']['new'][$new_id][$rank]["new_value-$new_id-$rank"] = array(
-      '#type'          => 'textarea',
-      '#default_value' => $new_value,
-      '#cols'          => 50,
-      '#rows'          => $rows,
-      '#description'   => $cvterm->definition,
-    );
-
-    $form['properties']['new'][$new_id][$rank]["remove-$new_id-$rank"] = array(
-      '#type'         => 'image_button',
-      '#value'        => t('Remove'),
-      '#src'          => drupal_get_path('theme', 'tripal') . '/images/minus.png',
-      '#ahah' => array(
-        'path'    => "tripal_featuremap/properties/minus/$new_id/$rank",
-        'wrapper' => 'tripal-featuremap-edit-properties-table',
-        'event'   => 'click',
-        'method'  => 'replace',
-    ),
-      '#attributes' => array('onClick' => 'return false;'),
-    );
-
-  }
-
-  return $num_properties;
-}
-/*
- *
- */
-function chado_featuremap_node_form_add_featuremapprop_table_props(&$form, $form_state, $featuremap_id, &$d_properties, &$d_removed) {
-
-  // get the properties for this featuremap
-  $num_properties = 0;
-
-  if(!$featuremap_id) {
-    return $num_properties;
-  }
-
-  $sql = "
-    SELECT CVT.cvterm_id, CVT.name, CVT.definition, PP.value, PP.rank
-    FROM {featuremapprop} PP
-      INNER JOIN {cvterm} CVT on CVT.cvterm_id = PP.type_id
-    WHERE PP.featuremap_id = :featuremap_id
-    ORDER BY CVT.name, PP.rank
-  ";
-  $featuremap_props = chado_query($sql, array(':featuremap_id' => $featuremap_id));
-  while ($prop = $featuremap_props->fetchObject()) {
-
-    $type_id = $prop->cvterm_id;
-    $rank = count($d_properties[$type_id]);
-
-    // skip any properties that the user requested to delete through a previous
-    // AHAH callback or through the current AHAH callback
-    if($d_removed["$type_id-$rank"]) {
-      continue;
-    }
-    if($form_state['post']['remove-' . $type_id . '-' . $rank]) {
-      $d_removed["$type_id-$rank"] = 1;
-      continue;
-    }
-
-    $d_properties[$type_id][$rank]['name']  = $prop->name;
-    $d_properties[$type_id][$rank]['id']    = $type_id;
-    $d_properties[$type_id][$rank]['value'] = $prop->value;
-    $d_properties[$type_id][$rank]['definition']  = $prop->definition;
-    $num_properties++;
-
-    $form['properties'][$type_id][$rank]["prop_id-$type_id-$rank"] = array(
-      '#type'          => 'item',
-      '#value'         => $prop->name,
-    );
-    $form['properties'][$type_id][$rank]["prop_value-$type_id-$rank"] = array(
-      '#type'          => 'textarea',
-      '#default_value' => $prop->value,
-      '#cols'          => 50,
-      '#rows'          => $rows,
-      '#description'   => $prop->definition,
-    );
-
-    $form['properties'][$type_id][$rank]["remove-$type_id-$rank"] = array(
-      '#type'         => 'image_button',
-      '#value'        => t('Remove'),
-      '#src'          => drupal_get_path('theme', 'tripal') . '/images/minus.png',
-      '#ahah' => array(
-        'path'    => "tripal_featuremap/properties/minus/$type_id/$rank",
-        'wrapper' => 'tripal-featuremap-edit-properties-table',
-        'event'   => 'click',
-        'method'  => 'replace',
-    ),
-      '#attributes' => array('onClick' => 'return false;'),
-    );
-  }
-  return $num_properties;
-}
-/*
- *
- */
-function tripal_featuremap_theme_node_form_properties($form) {
-  $rows = array();
-
-  if ($form['properties']) {
-
-    // first add in the properties derived from the featuremapprop table
-    // the array tree for these properties looks like this:
-    // $form['properties'][$type_id][$rank]["prop_id-$type_id-$rank"]
-    foreach ($form['properties'] as $type_id => $elements) {
-      // there are other fields in the properties array so we only
-      // want the numeric ones those are our type_id
-      if (is_numeric($type_id)) {
-        foreach ($elements as $rank => $element) {
-          if (is_numeric($rank)) {
-            $rows[] = array(
-            drupal_render($element["prop_id-$type_id-$rank"]),
-            drupal_render($element["prop_value-$type_id-$rank"]),
-            drupal_render($element["remove-$type_id-$rank"]),
-            );
-          }
-        }
-      }
-    }
-
-    // second, add in any new properties added by the user through AHAH callbacks
-    // the array tree for these properties looks like this:
-    // $form['properties']['new'][$type_id][$rank]["new_id-$new_id-$rank"]
-    foreach ($form['properties']['new'] as $type_id => $elements) {
-      if (is_numeric($type_id)) {
-        foreach ($elements as $rank => $element) {
-          if (is_numeric($rank)) {
-            $rows[] = array(
-            drupal_render($element["new_id-$type_id-$rank"]),
-            drupal_render($element["new_value-$type_id-$rank"]),
-            drupal_render($element["remove-$type_id-$rank"]),
-            );
-          }
-        }
-      }
-    }
-
-    // finally add in a set of blank field for adding a new property
-    $rows[] = array(
-    drupal_render($form['properties']['new']['new_id']),
-    drupal_render($form['properties']['new']['new_value']),
-    drupal_render($form['properties']['new']['add']),
-    );
-  }
-
-  $headers = array('Property Type','Value', '');
-  return theme('table', $headers, $rows, array('id'=> "tripal-featuremap-edit-properties-table"));
-}
-
-/*
- *
- */
-function tripal_featuremap_property_add() {
-  $status = TRUE;
-
-  // prepare and render the form
-  $form = tripal_core_ahah_prepare_form();
-
-  // we only want to return the properties as that's all we'll replace with this AHAh callback
-  $data = tripal_featuremap_theme_node_form_properties($form);
-
-  // bind javascript events to the new objects that will be returned
-  // so that AHAH enabled elements will work.
-  $settings = tripal_core_ahah_bind_events();
-
-  // return the updated JSON
-  drupal_json(
-  array(
-      'status'   => $status, 
-      'data'     => $data,
-      'settings' => $settings,
-  )
-  );
-}
-/*
- *
- */
-function tripal_featuremap_property_delete() {
-  $status = TRUE;
-
-  // prepare and render the form
-  $form = tripal_core_ahah_prepare_form();
-
-  // we only want to return the properties as that's all we'll replace with this AHAh callback
-  $data = tripal_featuremap_theme_node_form_properties($form);
-
-  // bind javascript events to the new objects that will be returned
-  // so that AHAH enabled elements will work.
-  $settings = tripal_core_ahah_bind_events();
-
-  // return the updated JSON
-  drupal_json(
-  array(
-      'status'   => $status, 
-      'data'     => $data,
-      'settings' => $settings,
-  )
-  );
-}
-/*
- *
- */
-function tripal_featuremap_property_get_description() {
-  $new_id = $_POST['new_id'];
-
-  $values = array('cvterm_id' => $new_id);
-  $cvterm = tripal_core_chado_select('cvterm', array('definition'), $values);
-
-  $description = '&nbsp;';
-  if ($cvterm[0]->definition) {
-    $description = $cvterm[0]->definition;
-  }
-  drupal_json(
-    array(
-      'status' => TRUE,
-      'data'   => '<div id="tripal-featuremap-new_value-desc">' . $description . '</div>',
-    )
-  );
-}
-/*
- *
- */
-function theme_chado_featuremap_node_form($form) {
-
-  $properties_table = tripal_featuremap_theme_node_form_properties($form);
-
-  $markup  = drupal_render($form['featuremap_id']);
-  $markup .= drupal_render($form['title']);
-  $markup .= drupal_render($form['unittype_id']);
-  $markup .= drupal_render($form['description']);
-  $markup .= "<b>Include Additional Details</b><br>You may add additional 
-    properties to this map by scrolling to the bottom of this table, selecting 
-    a property type from the dropdown and adding text.  You may add as many 
-    properties as desired by clicking the plus button on the right.  To 
-    remove a property, click the minus button. If a property is not available
-    you may add it by " . l('adding the term', 'admin/tripal/tripal_cv/cvterm/add') . "
-    to the <b>featuremap_property</b> vocabulary within the <b>tripal</b> database.";
-  $markup .= $properties_table;
-  $markup .= drupal_render($form['is_obsolete']);
-
-  $form['properties'] = array(
-    '#type' => 'markup',
-    '#value' =>  $markup,
-  );
-  return drupal_render($form);
-}

+ 0 - 142
tripal_featuremap/theme/node--chado-featuremap.tpl.php

@@ -1,142 +0,0 @@
-<?php
-// Purpose: This template provides the layout of the featuremap node (page)
-//   using the same templates used for the various featuremap content blocks.
-//
-// To Customize the Libray Node Page:
-//   - This Template: customize basic layout and which elements are included
-//   - Using Panels: Override the node page using Panels3 and place the blocks
-//       of content as you please. This method requires no programming. See
-//       the Tripal User Guide for more details
-//   - Block Templates: customize the content/layout of each block of stock 
-//       content. These templates are found in the tripal_stock subdirectory
-//
-// Variables Available:
-//   - $node: a standard object which contains all the fields associated with
-//       nodes including nid, type, title, taxonomy. It also includes stock
-//       specific fields such as stock_name, uniquename, stock_type, synonyms,
-//       properties, db_references, object_relationships, subject_relationships,
-//       organism, etc.
-//   NOTE: For a full listing of fields available in the node object the
-//       print_r $node line below or install the Drupal Devel module which 
-//       provides an extra tab at the top of the node page labelled Devel
-
-$featuremap  = $variables['node']->featuremap;
-
-// get the template settings
-$template_settings = theme_get_setting('tripal');
-
-// toggle the sidebar if desired
-$no_sidebar = 0;
-if (is_array($template_settings['tripal_no_sidebar']) and 
-   $template_settings['tripal_no_sidebar']['featuremap']) {
-  $no_sidebar = 1;
-}
-
-if ($teaser) { 
-  print theme('tripal_featuremap_teaser',$variables); 
-} 
-else { ?>
-
-<script type="text/javascript">
-(function ($) {
-  Drupal.behaviors.featuremapBehavior = {
-    attach: function (context, settings){ <?php 
-      if ($no_sidebar) { ?>    
-        // hide the resource side bar and strech the details section    
-        $(".tripal_toc").hide();
-        $(".tripal_details").addClass("tripal_details_full");
-        $(".tripal_details_full").removeClass("tripal_details"); <?php
-      } else { ?>
-        // use default resource sidebar
-        $(".tripal-info-box").hide(); <?php
-      } ?>
- 
-      // iterate through all of the info boxes and add their titles
-      // to the table of contents
-      $(".tripal-info-box-title").each(function(){
-        var parent = $(this).parent();
-        var id = $(parent).attr('id');
-        var title = $(this).text();
-        $('#tripal_featuremap_toc_list').append('<li><a href="#'+id+'" class="tripal_featuremap_toc_item">'+title+'</a></li>');
-      });
-
-      // when a title in the table of contents is clicked, then
-      // show the corresponding item in the details box
-      $(".tripal_featuremap_toc_item").click(function(){
-         $(".tripal-info-box").hide();
-         href = $(this).attr('href');
-         $(href).fadeIn('slow');
-         // we want to make sure our table of contents and the details
-         // box stay the same height
-         $("#tripal_featuremap_toc").height($(href).parent().height());
-         return false;
-      }); 
-
-      // we want the base details to show up when the page is first shown 
-      // unless the user specified a specific block
-      var block = window.location.href.match(/[\?|\&]block=(.+?)\&/)
-      if(block == null){
-         block = window.location.href.match(/[\?|\&]block=(.+)/)
-      }
-      if(block != null){
-         $("#tripal_featuremap-"+block[1]+"-box").show();
-      } else {
-         $("#tripal_featuremap-base-box").show();
-      }
-
-      $("#tripal_featuremap_toc").height($("#tripal_featuremap-base-box").parent().height());
-    }     
-  };
-})(jQuery);
-</script>
-
-<div id="tripal_featuremap_details" class="tripal_details">
-
-   <!-- Basic Details Theme -->
-   <?php print theme('tripal_featuremap_base',$node); ?>
-   
-   <!-- Map Features -->
-   <?php print theme('tripal_featuremap_featurepos',$node); ?>
-
-   <!-- Properties -->
-   <?php print theme('tripal_featuremap_properties',$node); ?>
-   
-   <!-- Publications -->
-   <?php print theme('tripal_featuremap_publications',$node); ?>
-   
-   <!-- Cross References -->
-   <?php print theme('tripal_featuremap_references',$node); ?>
-
-   <!-- Resource Blocks CCK elements --><?php
-   for($i = 0; $i < count($node->field_resource_titles); $i++){
-     if($node->field_resource_titles[$i]['value']){ ?>
-       <div id="tripal_featuremap-resource_<?php print $i?>-box" class="tripal_featuremap-info-box tripal-info-box">
-         <div class="tripal_featuremap-info-box-title tripal-info-box-title"><?php print $node->field_resource_titles[$i]['value'] ?></div>
-         <?php print $node->field_resource_blocks[$i]['value']; ?>
-       </div><?php
-     }
-   }?>
-   
-   <!-- Let modules add more content -->
-
-   <?php print $content ?>
-</div>
-
-<!-- Table of contents -->
-<div id="tripal_featuremap_toc" class="tripal_toc">
-   <div id="tripal_featuremap_toc_title" class="tripal_toc_title">Resources</div>
-   <ul id="tripal_featuremap_toc_list" class="tripal_toc_list">
-   
-     <!-- Resource Links CCK elements --><?php
-     for($i = 0; $i < count($node->field_resource_links); $i++){
-       if($node->field_resource_links[$i]['value']){
-         $matches = preg_split("/\|/",$node->field_resource_links[$i]['value']);?>
-         <li><a href="<?php print $matches[1] ?>" target="_blank"><?php print $matches[0] ?></a></li><?php
-       }
-     }?>
-     
-     <?php // ADD CUSTOMIZED <li> LINKS HERE ?>
-   </ul>
-</div>
-
-<?php } ?>

+ 0 - 5
tripal_featuremap/theme/tripal_featuremap_help.tpl.php → tripal_featuremap/theme/tripal_featuremap.help.tpl.php

@@ -1,8 +1,3 @@
-<h3>Tripal Feature Map Quick Links:</h3>
-<ul>
-  <li><a href="<?php print url('admin/tripal/tripal_featuremap/configuration') ?>">Map Configuration</a></li>
-</ul>
-
 <h3>Module Description:</h3>
 <p>The Tripal Map module is an interface for the Chado Map module which groups features (sequences) into 
    maps (typically genetic maps).

+ 0 - 0
tripal_featuremap/theme/tripal_featuremap.theme.inc


+ 76 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.base.tpl.php

@@ -0,0 +1,76 @@
+<?php
+
+$featuremap  = $variables['node']->featuremap;
+
+// expand the description field
+$featuremap = tripal_core_expand_chado_vars($featuremap, 'field', 'featuremap.description');
+
+?>
+<div id="tripal_featuremap-base-box" class="tripal_featuremap-info-box tripal-info-box">
+  <div class="tripal_featuremap-info-box-title tripal-info-box-title">Map Details</div>
+  <div class="tripal_featuremap-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+  // the $headers array is an array of fields to use as the colum headers. 
+  // additional documentation can be found here 
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  // This table for the analysis has a vertical header (down the first column)
+  // so we do not provide headers here, but specify them in the $rows array below.
+  $headers = array();
+  
+  // the $rows array contains an array of rows where each row is an array
+  // of values for each column of the table in that row.  Additional documentation
+  // can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+  $rows = array();
+  
+  // Map Name row
+  $rows[] = array(
+    array(
+      'data' => 'Map Name',
+      'header' => TRUE
+    ),
+    $featuremap->name
+  );
+  // Map Units
+  $rows[] = array(
+    array(
+      'data' => 'Map Units',
+      'header' => TRUE
+    ),
+    $featuremap->unittype_id->name
+  );
+  // allow site admins to see the feature ID
+  if (user_access('access administration pages')) {
+    // Feature Map ID
+    $rows[] = array(
+      array(
+        'data' => 'Feature Map ID',
+        'header' => TRUE
+      ),
+      $featuremap->featuremap_id
+    );
+  }
+
+  // the $table array contains the headers and rows array as well as other
+  // options for controlling the display of the table.  Additional
+  // documentation can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  $table = array(
+    'header' => $headers,
+    'rows' => $rows,
+    'attributes' => array(
+      'id' => 'tripal_featuremap-table-base',
+    ),
+    'sticky' => FALSE,
+    'caption' => '',
+    'colgroups' => array(),
+    'empty' => '',
+  );
+  
+  // once we have our table array structure defined, we call Drupal's theme_table()
+  // function to generate the table.
+  print theme_table($table);
+  if (property_exists($featuremap, 'description')) { ?>
+    <div style="text-align: justify"><?php print $featuremap->description; ?></div> <?php  
+  } ?>
+</div>

+ 158 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.featurepos.tpl.php

@@ -0,0 +1,158 @@
+<?php
+$featuremap = $variables['node']->featuremap;
+$feature_positions = array();
+
+// expand the featuremap object to include the records from the featurepos table
+// specify the number of features to show by default and the unique pager ID
+$num_results_per_page = 25; 
+$featurepos_pager_id = 0;
+
+// get the features aligned on this map
+$options = array(  
+  'return_array' => 1,
+  'order_by' => array('map_feature_id' => 'ASC'),
+  'pager' => array(
+    'limit' => $num_results_per_page, 
+    'element' => $featurepos_pager_id
+  ),
+  'include_fk' => array(
+    'map_feature_id' => array(
+      'type_id' => 1,
+      'organism_id' => 1,
+    ),
+    'feature_id' => array(
+      'type_id' => 1,
+    ),
+    'featuremap_id' => array(
+       'unittype_id' => 1,
+    ),
+  ),
+);
+
+$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featurepos', $options);
+$feature_positions = $featuremap->featurepos;
+
+
+// the total number of records for the paged query is stored in a session variable
+$total_features = $_SESSION['chado_pager'][$featurepos_pager_id]['total_records'];
+
+
+if(count($feature_positions) > 0){ ?>
+  <div id="tripal_featuremap-featurepos-box" class="tripal_featuremap-info-box tripal-info-box">
+    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Map Features</div>
+    <div class="tripal_featuremap-info-box-desc tripal-info-box-desc">This map contains <?php print number_format($total_features) ?> features:</div> <?php 
+    
+        // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Landmark', 'Type', 'Organism', 'Feature Name', 'Type', 'Position');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($feature_positions as $position){
+      $map_feature = $position->map_feature_id;
+      $feature     = $position->feature_id;  
+      $organism    = $map_feature->organism_id; 
+
+      // check if there are any values in the featureposprop table for the start and stop
+      $mappos = $position->mappos;
+      $options = array(
+        'return_array' => 1,
+        'include_fk' => array(
+          'type_id' => 1,            
+        ),
+      );
+      $position = tripal_core_expand_chado_vars($position, 'table', 'featureposprop', $options);
+      $featureposprop = $position->featureposprop;
+      $start = 0;
+      $stop = 0;
+      if (is_array($featureposprop)) {
+        foreach ($featureposprop as $index => $property) {
+           if ($property->type_id->name == 'start') {
+             $start = $property->value;
+           }
+           if ($property->type_id->name == 'stop') {
+             $stop = $property->value;
+           }
+        }      
+      }  
+      if ($start and $stop and $start != $stop) {
+        $mappos = "$start-$stop";
+      }
+      if ($start and !$stop) {
+        $mappos = $start;
+      } 
+      if ($start and $stop and $start == $stop) {
+        $mappos = $start;
+      }
+      
+      $mfname = $map_feature->name;
+      if (property_exists($map_feature, 'nid')) {
+        $mfname =  l($mfname, 'node/' . $map_feature->nid, array('attributes' => array('target' => '_blank')));
+      }
+      $orgname = $organism->genus ." " . $organism->species ." (" . $organism->common_name .")";
+      if (property_exists($organism, 'nid')) {
+        $orgname = l(
+          "<i>" . $organism->genus . " " . $organism->species . "</i> (" . $organism->common_name .")", 
+          "node/". $organism->nid, 
+          array('html' => TRUE, 'attributes' => array('target' => '_blank'))
+        );
+      }
+      $organism =  $organism->genus . ' ' . $organism->species;
+      
+      $fname = $feature->name;
+      if (property_exists($feature, 'nid')) {
+        $fname = l($fname, 'node/' . $feature->nid, array('attributes' => array('target' => '_blank')));
+      }
+        
+      $rows[] = array(
+        $mfname,
+        $map_feature->type_id->name,
+        $orgname,
+        $fname,
+        $feature->type_id->name,
+        $mappos . ' ' . $position->featuremap_id->unittype_id->name
+      );
+    } 
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_featuremap-table-featurepos',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table);
+
+    // the $pager array values that control the behavior of the pager.  For
+    // documentation on the values allows in this array see:
+    // https://api.drupal.org/api/drupal/includes!pager.inc/function/theme_pager/7
+    // here we add the paramter 'block' => 'features'. This is because
+    // the pager is not on the default block that appears. When the user clicks a
+    // page number we want the browser to re-appear with the page is loaded.
+    $pager = array(
+      'tags' => array(),
+      'element' => $featurepos_pager_id,
+      'parameters' => array(
+        'block' => 'featurepos'
+      ),
+      'quantity' => $num_results_per_page,
+    );
+    print theme_pager($pager); ?>
+  </div><?php 
+}?>
+

+ 52 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.properties.tpl.php

@@ -0,0 +1,52 @@
+<?php
+
+$featuremap = $variables['node']->featuremap;
+$options = array('return_array' => 1);
+$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremapprop', $options);
+$properties = $featuremap->featuremapprop;
+
+if(count($properties) > 0){ ?>
+
+  <div id="tripal_featuremap-properties-box" class="tripal_featuremap-info-box tripal-info-box">
+    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Properties</div> <?php
+
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Property Name', 'Value');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($properties as $property){
+      $property = tripal_core_expand_chado_vars($property,'field','featuremapprop.value');
+      $rows[] = array(
+        ucfirst(preg_replace('/_/', ' ', $property->type_id->name)),
+        urldecode($property->value)
+      );
+    }
+     
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_featuremap-table-properties',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php
+}

+ 85 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.publication.tpl.php

@@ -0,0 +1,85 @@
+<?php
+$featuremap = $variables['node']->featuremap;
+
+// expand featuremap to include pubs 
+$options = array('return_array' => 1);
+$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremap_pub', $options);
+$featuremap_pubs = $featuremap->featuremap_pub; 
+
+
+if (count($featuremap_pubs) > 0) { ?>
+  <div id="tripal_featuremap_pub-pub-box" class="tripal_featuremap_pub-info-box tripal-info-box">
+    <div class="tripal_featuremap_pub-info-box-title tripal-info-box-title">Publications</div>
+    <div class="tripal_featuremap_pub-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Year', 'Publication');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($featuremap_pubs as $featuremap_pub) {
+      $pub = $featuremap_pub->pub_id;
+      $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+      $citation = $pub->title;  // use the title as the default citation
+      
+      // get the citation for this pub if it exists
+      $values = array(
+        'pub_id' => $pub->pub_id, 
+        'type_id' => array(
+          'name' => 'Citation',
+        ),
+      );
+      $options = array('return_array' => 1);
+      $citation_prop = tripal_core_generate_chado_var('pubprop', $values, $options); 
+      if (count($citation_prop) == 1) {
+        $citation_prop = tripal_core_expand_chado_vars($citation_prop, 'field', 'pubprop.value');
+        $citation = $citation_prop[0]->value;
+      }
+      
+      // if the publication is synced then link to it
+      if (property_exists($pub, 'nid')) {
+        // replace the title with a link
+        $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
+        $patterns = array(
+          '/(\()/', '/(\))/', 
+          '/(\])/', '/(\[)/',
+          '/(\{)/', '/(\})/',
+          '/(\+)/', '/(\.)/', '/(\?)/', 
+        );
+        $fixed_title = preg_replace($patterns, "\\\\$1", $pub->title);
+        $citation = preg_replace('/' . $fixed_title . '/', $link, $citation);
+      }
+      
+      $rows[] = array(
+        $pub->pyear,
+        $citation,
+      );
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_featuremap-table-publications',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php 
+}

+ 69 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.references.tpl.php

@@ -0,0 +1,69 @@
+<?php
+$featuremap = $variables['node']->featuremap;
+$references = array();
+
+// expand the featuremap object to include the records from the featuremap_dbxref table
+$options = array('return_array' => 1);
+$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremap_dbxref', $options);
+$featuremap_dbxrefs = $featuremap->featuremap_dbxref;
+if (count($featuremap_dbxrefs) > 0 ) {
+  foreach ($featuremap_dbxrefs as $featuremap_dbxref) {    
+    $references[] = $featuremap_dbxref->dbxref_id;
+  }
+}
+
+
+if(count($references) > 0){ ?>
+  <div id="tripal_featuremap-references-box" class="tripal_featuremap-info-box tripal-info-box">
+    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Cross References</div>
+    <div class="tripal_featuremap-info-box-desc tripal-info-box-desc">External references for this map</div><?php
+     
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Dababase', 'Accession');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+ 
+    foreach ($references as $dbxref){
+      $dbname = $dbxref->db_id->name; 
+      if ($dbxref->db_id->url) { 
+        $dbname = l($dbname, $dbxref->db_id->url, array('attributes' => array('target' => '_blank')));
+      } 
+      
+      $accession = $dbxref->accession; 
+      if ($dbxref->db_id->urlprefix) { 
+        $accession = l($accession, $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
+      } 
+      $rows[] = array(
+        $dbname,
+        $accession
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_featuremap-table-references',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div><?php 
+}?>
+

+ 16 - 0
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap.teaser.tpl.php

@@ -0,0 +1,16 @@
+<?php
+$node = $variables['node'];
+$featuremap = $variables['node']->featuremap;
+$featuremap = tripal_core_expand_chado_vars($featuremap,'field','featuremap.description'); ?>
+
+<div class="tripal_featuremap-teaser tripal-teaser"> 
+  <div class="tripal-featuremap-teaser-title tripal-teaser-title"><?php 
+    print l($node->title, "node/$node->nid", array('html' => TRUE));?>
+  </div>
+  <div class="tripal-featuremap-teaser-text tripal-teaser-text"><?php 
+    print substr($featuremap->description, 0, 650);
+    if (strlen($featuremap->description) > 650) {
+      print "... " . l("[more]", "node/$node->nid");
+    } ?>
+  </div>
+</div>

+ 0 - 39
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_base.tpl.php

@@ -1,39 +0,0 @@
-<?php
-
-$featuremap  = $variables['node']->featuremap;
-
-// expand the description field
-$featuremap = tripal_core_expand_chado_vars($featuremap, 'field', 'featuremap.description');
-
-?>
-<div id="tripal_featuremap-base-box" class="tripal_featuremap-info-box tripal-info-box">
-  <div class="tripal_featuremap-info-box-title tripal-info-box-title">Map Details</div>
-  <div class="tripal_featuremap-info-box-desc tripal-info-box-desc"></div>
-
-   <table id="tripal_featuremap-base-table" class="tripal_featuremap-table tripal-table tripal-table-vert">
-      <tr class="tripal_featuremap-table-even-row tripal-table-even-row">
-        <th nowrap>Name</th>
-        <td><?php print $featuremap->name; ?></td>
-      </tr>
-      <tr class="tripal_featuremap-table-odd-row tripal-table-odd-row">
-        <th>Map Units</th>
-        <td><?php print $featuremap->unittype_id->name; ?></td>
-      </tr>
-      <tr class="tripal_featuremap-table-even-row tripal-table-even-row">
-        <th>Description</th>
-        <td><?php
-           // right now we only have one property for featuremaps. So we can just
-           // refernece it directly.  If we had more than one property
-           // we would need to convert this to an if statment and loop
-           // until we found the right one.
-           print $featuremap->description?>
-        </td>
-     	</tr>
-     	<!--     
-     	<tr class="tripal_featuremap-table-odd-row tripal-table-odd-row">
-        <th>Internal ID</th>
-        <td><?php print $featuremap->featuremap_id; ?></td>
-      </tr>  
-       -->     	                                
-   </table>
-</div>

+ 0 - 126
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_featurepos.tpl.php

@@ -1,126 +0,0 @@
-<?php
-$featuremap = $variables['node']->featuremap;
-$feature_positions = array();
-
-// expand the featuremap object to include the records from the featurepos table
-// specify the number of features to show by default and the unique pager ID
-$num_results_per_page = 25; 
-$featurepos_pager_id = 0;
-
-// get the features aligned on this map
-$options = array(  
-  'return_array' => 1,
-  'order_by' => array('map_feature_id' => 'ASC'),
-  'pager' => array('limit' => $num_results_per_page, 'element' => $featurepos_pager_id),
-  'include_fk' => array(
-    'map_feature_id' => array(
-      'type_id' => 1,
-      'organism_id' => 1,
-    ),
-    'feature_id' => array(
-      'type_id' => 1,
-    ),
-    'featuremap_id' => array(
-       'unittype_id' => 1,
-    ),
-  ),
-);
-
-$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featurepos', $options);
-$feature_positions = $featuremap->featurepos;
-
-// create the pager.  
-global $pager_total_items;
-$featurepos_pager = theme('pager', array(), $num_results_per_page, $featurepos_pager_id, array('block' => 'featurepos'));
-$total_features = $pager_total_items[$featurepos_pager_id];
-
-
-if(count($feature_positions) > 0){ ?>
-  <div id="tripal_featuremap-featurepos-box" class="tripal_featuremap-info-box tripal-info-box">
-    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Map Features</div>
-    <div class="tripal_featuremap-info-box-desc tripal-info-box-desc">This Map contains <?php print number_format($total_features) ?> features:</div>
-    <table id="tripal_featuremap-featurepos-table" class="tripal_featuremap-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Landmark</th>
-        <th>Type</th>
-        <th>Organism</th>
-        <th>Feature Name</th>
-        <th>Type</th>
-        <th>Position</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($feature_positions as $position){
-        $map_feature = $position->map_feature_id;
-        $feature = $position->feature_id;  
-        $organism = $map_feature->organism_id; 
-
-        // check if there are any values in the featureposprop table for the start and stop
-        $mappos = $position->mappos;
-        $options = array(
-          'return_array' => 1,
-          'include_fk' => array(
-            'type_id' => 1,            
-          ),
-        );
-        $position = tripal_core_expand_chado_vars($position, 'table', 'featureposprop', $options);
-        $featureposprop = $position->featureposprop;
-        if (is_array($featureposprop)) {
-          foreach ($featureposprop as $index => $property) {
-             if ($property->type_id->name == 'start') {
-               $start = $property->value;
-             }
-             if ($property->type_id->name == 'stop') {
-               $stop = $property->value;
-             }
-          }      
-        }  
-        if ($start and $stop and $start != $stop) {
-          $mappos = "$start-$stop";
-        }
-        if ($start and !$stop) {
-          $mappos = $start;
-        } 
-        if ($start and $stop and $start == $stop) {
-          $mappos = $start;
-        }
-        
-        $class = 'tripal_featuremap-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_featuremap-table-even-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td> <?php 
-            if ($map_feature->nid) { 
-              print l($map_feature->name, 'node/' . $map_feature->nid, array('attributes' => array('target' => '_blank')));
-            } 
-            else { 
-              print $map_feature->name;
-            } ?>
-          </td>          
-          <td><?php print $map_feature->type_id->name ?></td>
-          <td><?php 
-            if ($organism->nid) { 
-              print l($organism->genus . ' ' . $organism->species, 'node/' . $organism->nid, array('attributes' => array('target' => '_blank')));
-            } 
-            else { 
-              print $organism->genus . ' ' . $organism->species;
-            } ?>
-          </td>
-          <td> <?php 
-            if ($feature->nid) { 
-              print l($feature->name, 'node/' . $feature->nid, array('attributes' => array('target' => '_blank')));
-            } 
-            else { 
-              print $feature->name;
-            } ?>
-          </td>
-          <td><?php print $feature->type_id->name ?></td>
-          <td><?php print $mappos ?>&nbsp;<?php print $position->featuremap_id->unittype_id->name ?> </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table> <?php 
-    print $featurepos_pager ?>
-  </div><?php 
-}?>
-

+ 0 - 50
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_properties.tpl.php

@@ -1,50 +0,0 @@
-<?php
-
-$featuremap = $node->featuremap;
-
-// expand the featuremap to include the properties.
-$options = array(
-  'return_array' => 1,
-  'order_by' => array('rank' => 'ASC'),
-);
-$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremapprop', $options);
-$featuremapprops = $featuremap->featuremapprop;
-$properties = array();
-if (is_array($featuremapprops)) {
-  foreach ($featuremapprops as $property) {
-    // skip the following properties as those are already on other templates
-    if ($property->type_id->name == 'Map Dbxref')  {
-      continue;
-    }
-    $property = tripal_core_expand_chado_vars($property,'field','featuremapprop.value');
-    $properties[] = $property;
-  }
-}
-if(count($properties) > 0){ ?>
-
-  <div id="tripal_featuremap-properties-box" class="tripal_featuremap-info-box tripal-info-box">
-    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Properties</div>
-    <div class="tripal_featuremap-info-box-desc tripal-info-box-desc">Properties for the featuremap '<?php print $node->featuremap->name ?>' include:</div>
-
-    <table class="tripal_featuremap-table tripal-table tripal-table-horz">
-    <tr>
-      <th>Property Name</th>
-      <th>Value</th>
-    </tr>
-	  <?php	// iterate through each property
-		  $i = 0;
-		  foreach ($properties as $result){
-		    $result = tripal_core_expand_chado_vars($result,'field','featuremapprop.value');
-		    $class = 'tripal_featuremap-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_featuremap-table-odd-row tripal-table-even-row';
-        } ?>
-			  <tr class="<?php print $class ?>">
-  			  <td><?php print $result->type_id->name ?></td>
-  			  <td><?php print urldecode($result->value) ?></td>
-  			</tr> <?php
-			  $i++;
-		  } ?>
-		</table>
-  </div> <?php
-}

+ 0 - 33
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_publication.tpl.php

@@ -1,33 +0,0 @@
-<?php
-$featuremap  = $variables['node']->featuremap;
-
-// expand featuremap to include pubs 
-$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremap_pub');
-$pubs = $featuremap->featuremap_pub;
-$pubs = tripal_core_expand_chado_vars($pubs, 'field', 'pub.title', array('return_array' => 1));
-?>
-
-<div id="tripal_featuremap-pub-box" class="tripal_featuremap-info-box tripal-info-box">
-  <div class="tripal_featuremap-info-box-title tripal-info-box-title">Publications</div>
-  <div class="tripal_featuremap-info-box-desc tripal-info-box-desc"></div>
-
-  <table id="tripal_featuremap-pub-table" class="tripal_featuremap-table tripal-table tripal-table-vert" style="border-bottom:solid 2px #999999">
-    <tr>
-      <th>Year</th>
-      <th>Reference</th>
-      <th>Title</th></tr> <?php
-      $i = 0;
-      foreach ($pubs AS $pub) {
-        $class = 'tripal_featuremap-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_featuremap-table-odd-row tripal-table-even-row';
-        } ?>
-    	  <tr class="<?php print $class ?>">
-    	    <td><?php print $pub->pub_id->pyear ?></td>
-    	    <td><?php print $pub->pub_id->uniquename ?></td>
-    	    <td><?php print $pub->pub_id->title ?></td>
-    	  </tr><?php 
-    	  $i++;
-      }  ?>
-  </table>
-</div>

+ 0 - 56
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_references.tpl.php

@@ -1,56 +0,0 @@
-<?php
-$featuremap = $variables['node']->featuremap;
-$references = array();
-
-// expand the featuremap object to include the records from the featuremap_dbxref table
-$options = array('return_array' => 1);
-$featuremap = tripal_core_expand_chado_vars($featuremap, 'table', 'featuremap_dbxref', $options);
-$featuremap_dbxrefs = $featuremap->featuremap_dbxref;
-if (count($featuremap_dbxrefs) > 0 ) {
-  foreach ($featuremap_dbxrefs as $featuremap_dbxref) {    
-    $references[] = $featuremap_dbxref->dbxref_id;
-  }
-}
-
-if(count($references) > 0){ ?>
-  <div id="tripal_featuremap-references-box" class="tripal_featuremap-info-box tripal-info-box">
-    <div class="tripal_featuremap-info-box-title tripal-info-box-title">Cross References</div>
-    <div class="tripal_featuremap-info-box-desc tripal-info-box-desc">This Map is also available in the following databases:</div>
-    <table id="tripal_featuremap-references-table" class="tripal_featuremap-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Dababase</th>
-        <th>Accession</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($references as $dbxref){         
-        $class = 'tripal_featuremap-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_featuremap-table-even-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td> <?php 
-            if ($dbxref->db_id->url) { 
-              print l($dbxref->db_id->name, $dbxref->db_id->url, array('attributes' => array('target' => '_blank'))) . '<br> ' . $dbxref->db_id->description;             
-            } 
-            else { 
-              print $dbxref->db_id->name . '<br>' . $dbxref->db_id->description;
-            } ?>
-          </td>
-          <td> <?php 
-            if ($dbxref->db_id->urlprefix) { 
-              print l($dbxref->db_id->name . ':' . $dbxref->accession, $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
-            } 
-            else { 
-              print $dbxref->db_id->name . ':' . $dbxref->accession; 
-            }
-            if ($dbxref->is_primary) {
-              print " <i>(primary cross-reference)</i>";
-            } ?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
-  </div><?php 
-}?>
-

+ 0 - 60
tripal_featuremap/theme/tripal_featuremap/tripal_featuremap_teaser.tpl.php

@@ -1,60 +0,0 @@
-<?php
-
-$featuremap  = $variables['node']->featuremap;
-
-// expand the featuremap to include the properties.
-$featuremap = tripal_core_expand_chado_vars($featuremap,'table','featuremapprop');
-$featuremap = tripal_core_expand_chado_vars($featuremap,'field','featuremapprop.value');
-
-?>
-<div id="tripal_featuremap-base-box" class="tripal_featuremap-info-box tripal-info-box">
-  <div class="tripal_featuremap-info-box-title tripal-info-box-title">featuremap Details</div>
-  <div class="tripal_featuremap-info-box-desc tripal-info-box-desc"></div>
-
-   <?php if(strcmp($featuremap->is_obsolete,'t')==0){ ?>
-      <div class="tripal_featuremap-obsolete">This featuremap is obsolete</div>
-   <?php }?>
-   <table id="tripal_featuremap-base-table" class="tripal_featuremap-table tripal-table tripal-table-vert">
-      <tr class="tripal_featuremap-table-even-row tripal-table-even-row">
-        <th nowrap>Unique Name</th>
-        <td><?php print $featuremap->uniquename; ?></td>
-      </tr>
-      <tr class="tripal_featuremap-table-odd-row tripal-table-odd-row">
-        <th>Internal ID</th>
-        <td><?php print $featuremap->featuremap_id; ?></td>
-      </tr>
-      <tr class="tripal_featuremap-table-even-row tripal-table-even-row">
-        <th>Organism</th>
-        <td>
-          <?php if ($featuremap->organism_id->nid) { 
-      	   print "<a href=\"".url("node/".$featuremap->organism_id->nid)."\">".$featuremap->organism_id->genus ." " . $featuremap->organism_id->species ." (" .$featuremap->organism_id->common_name .")</a>";      	 
-          } else { 
-            print $featuremap->organism_id->genus ." " . $featuremap->organism_id->species ." (" .$featuremap->organism_id->common_name .")";
-          } ?>
-        </td>
-      </tr>      
-      <tr class="tripal_featuremap-table-odd-row tripal-table-odd-row">
-        <th>Type</th>
-        <td><?php 
-            if ($featuremap->type_id->name == 'cdna_featuremap') {
-               print 'cDNA';
-            } else if ($featuremap->type_id->name == 'bac_featuremap') {
-               print 'BAC';
-            } else {
-               print $featuremap->type_id->name;
-            }
-          ?>
-        </td>
-      </tr>
-      <tr class="tripal_featuremap-table-even-row tripal-table-even-row">
-        <th>Description</th>
-        <td><?php
-           // right now we only have one property for libraries. So we can just
-           // refernece it directly.  If we had more than one property
-           // we would need to convert this to an if statment and loop
-           // until we found the right one.
-           print $featuremap->featuremapprop->value?>
-        </td>
-     	</tr>           	                                
-   </table>
-</div>

+ 129 - 33
tripal_featuremap/tripal_featuremap.install

@@ -49,6 +49,7 @@ function tripal_featuremap_install() {
   tripal_featuremap_add_custom_tables();
 
   // Add cvterms
+  tripal_featuremap_add_cvs();
   tripal_featuremap_add_cvterms();
 
 }
@@ -100,47 +101,142 @@ function tripal_featuremap_schema() {
   return $schema;
 }
 
+/**
+ *
+ */
+function tripal_featuremap_add_cvs() {
+  
+  tripal_cv_add_cv(
+    'featuremap_units', 
+    'Contains map unit types for the unittype_id column of the featuremap table.'
+  );
+  
+  tripal_cv_add_cv(
+    'featurepos_property', 
+    'Contains terms map properties.'
+  );
+  
+  tripal_cv_add_cv(
+    'featuremap_property',
+    'Contains positional types for the feature positions'
+  );
+}
 
-
-/*
+/**
  *
  */
 function tripal_featuremap_add_cvterms() {
 
    // add cvterms for the map unit types
-   tripal_cv_add_cvterm(array('name' => 'cM','def' => 'Centimorgan units'),
-     'featuremap_units', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'bp','def' => 'Base pairs units'),
-     'featuremap_units', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'bin_unit','def' => 'The bin unit'),
-     'featuremap_units', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'marker_order','def' => 'Units simply to define marker order.'),
-     'featuremap_units', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'undefined','def' => 'A catch-all for an undefined unit type'),
-     'featuremap_units', 0, 1, 'tripal');
-
-   tripal_cv_add_cvterm(array('name' => 'start','def' => 'The start coordinate for a map feature.'),
-     'featurepos_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'stop','def' => 'The end coordinate for a map feature'),
-     'featurepos_property', 0, 1, 'tripal');
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'cM',
+       'def' => 'Centimorgan units'
+     ),
+     'featuremap_units', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'bp',
+       'def' => 'Base pairs units'
+     ),
+     'featuremap_units', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'bin_unit',
+       'def' => 'The bin unit'
+     ),
+     'featuremap_units', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'marker_order',
+       'def' => 'Units simply to define marker order.'
+     ),
+     'featuremap_units', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'undefined',
+       'def' => 'A catch-all for an undefined unit type'
+     ),
+     'featuremap_units', 0, 1, 'tripal'
+   );
+   
+   // featurepos properties
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'start',
+       'def' => 'The start coordinate for a map feature.'
+     ),
+     'featurepos_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'stop',
+       'def' => 'The end coordinate for a map feature'
+     ),
+     'featurepos_property', 0, 1, 'tripal'
+   );
 
    // add cvterms for map properties
-   tripal_cv_add_cvterm(array('name' => 'Map Dbxref','def' => 'A unique identifer for the map in a remote database.  The format is a database abbreviation and a unique accession separated by a colon.  (e.g. Gramene:tsh1996a)'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Map Type','def' => 'The type of Map (e.g. QTL, Physical, etc.)'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Genome Group','def' => ''),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'URL','def' => 'A univeral resource locator (URL) reference where the publication can be found.  For maps found online, this would be the web address for the map.'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Population Type','def' => 'A brief descriptoin of the population type used to generate the map (e.g. RIL, F2, BC1, etc).'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Population Size','def' => 'The size of the population used to construct the map.'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Methods','def' => 'A brief description of the methods used to construct the map.'),
-     'featuremap_property', 0, 1, 'tripal');
-   tripal_cv_add_cvterm(array('name' => 'Software','def' => 'The software used to construct the map.'),
-     'featuremap_property', 0, 1, 'tripal');
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Map Dbxref',
+       'def' => 'A unique identifer for the map in a remote database.  The format is a database abbreviation and a unique accession separated by a colon.  (e.g. Gramene:tsh1996a)'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Map Type',
+       'def' => 'The type of Map (e.g. QTL, Physical, etc.)'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Genome Group',
+       'def' => ''
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'URL',
+       'def' => 'A univeral resource locator (URL) reference where the publication can be found.  For maps found online, this would be the web address for the map.'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Population Type',
+       'def' => 'A brief description of the population type used to generate the map (e.g. RIL, F2, BC1, etc).'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Population Size',
+       'def' => 'The size of the population used to construct the map.'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Methods',
+       'def' => 'A brief description of the methods used to construct the map.'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
+   tripal_cv_add_cvterm(
+     array(
+       'name' => 'Software',
+       'def' => 'The software used to construct the map.'
+     ),
+     'featuremap_property', 0, 1, 'tripal'
+   );
 
 }
 

+ 113 - 422
tripal_featuremap/tripal_featuremap.module

@@ -9,8 +9,9 @@
  */
 
 require('api/tripal_featuremap.api.inc');
+require('theme/tripal_featuremap.theme.inc');
 require('includes/tripal_featuremap.admin.inc');
-require('includes/tripal_featuremap.form.inc');
+require('includes/tripal_featuremap.chado_node.inc');
 
 /**
  *
@@ -52,14 +53,26 @@ function tripal_featuremap_help($path, $arg) {
 function tripal_featuremap_node_info() {
   $nodes = array();
   $nodes['chado_featuremap'] = array(
-      'name' => t('Map'),
-      'base' => 'chado_featuremap',
-      'description' => t('A feature map from the chado database (e.g. genetic map)'),
-      'has_title' => FALSE,
-      'title_label' => t('Feature Map'),
-      'has_body' => FALSE,
-      'body_label' => t('Feature Map Description'),
-      'locked' => TRUE
+    'name' => t('Feature Map'),
+    'base' => 'chado_featuremap',
+    'description' => t('A map of features from the chado database (e.g. genetic map)'),
+    'has_title' => FALSE,
+    'title_label' => t('Feature Map'),
+    'has_body' => FALSE,
+    'body_label' => t('Feature Map Description'),
+    'locked' => TRUE,
+    'chado_node_api' => array(
+      'base_table' => 'featuremap',
+      'hook_prefix' => 'chado_featuremap',
+      'record_type_title' => array(
+        'singular' => t('Feature Map'),
+        'plural' => t('Feature Maps')
+      ),
+      'sync_filters' => array(
+        'type_id' => FALSE,
+        'organism_id' => FALSE
+      ),
+    )
   );
   return $nodes;
 }
@@ -95,34 +108,7 @@ function tripal_featuremap_permissions() {
     ),
   );
 }
-/**
- *  Set the permission types that the module uses.
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_access($op, $node, $account) {
-  if ($op == 'create') {
-    if (!user_access('create chado_featuremap content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'update') {
-    if (!user_access('edit chado_featuremap content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'delete') {
-    if (!user_access('delete chado_featuremap content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'view') {
-    if (!user_access('access chado_featuremap content', $account)) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
+
 /**
  * Menu items are automatically added for the new node types created
  * by this module to the 'Create Content' Navigation menu item.  This function
@@ -135,8 +121,8 @@ function tripal_featuremap_menu() {
 
   // The administative settings menu
   $items['admin/tripal/chado/tripal_featuremap'] = array(
-    'title' => 'Maps',
-    'description' => 'Genetic Maps of Features',
+    'title' => 'Feature Maps',
+    'description' => 'A map of features from the chado database (e.g. genetic map)',
     'page callback' => 'tripal_featuremap_admin_featuremaps_listing',
     'access arguments' => array('administer tripal featuremap'),
     'type' => MENU_NORMAL_ITEM,
@@ -161,6 +147,16 @@ function tripal_featuremap_menu() {
     'type' => MENU_LOCAL_TASK,
     'weight' => 2
   );
+  
+  $items['admin/tripal/chado/tripal_featuremap/sync'] = array(
+    'title' => ' Sync',
+    'description' => 'Sync featuremaps from Chado with Drupal',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_core_chado_node_sync_form', 'tripal_featuremap', 'chado_featuremap'),
+    'access arguments' => array('administer tripal featuremaps'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 0
+  );
 
   // Synchronizing maps from Chado to Drupal
   $items['chado_sync_featuremaps'] = array(
@@ -192,7 +188,7 @@ function tripal_featuremap_menu() {
     'title' => 'Enable featuremap Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_featuremap_admin_featuremaps', 'admin/tripal/chado/tripal_featuremap'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal featuremap'),
     'type' => MENU_CALLBACK,
   );
 
@@ -220,47 +216,87 @@ function tripal_featuremap_views_api() {
  *
  * @ingroup tripal_featuremap
  */
-function tripal_featuremap_theme() {
-  return array(
-    'tripal_featuremap_search_index' => array(
-       'arguments' => array('node'),
-    ),
-    'tripal_featuremap_search_result' => array(
-       'arguments' => array('node'),
+function tripal_featuremap_theme($existing, $type, $theme, $path) {
+  $core_path = drupal_get_path('module', 'tripal_core');
+
+  $items = array(
+    'node__chado_featuremap' => array(
+      'template' => 'node--chado-generic',
+      'render element' => 'node',
+      'base hook' => 'node',
+      'path' => "$core_path/theme",
     ),
     'tripal_featuremap_base' => array(
-       'arguments' => array('node' => NULL),
-       'template' => 'tripal_featuremap_base',
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_featuremap.base',
+      'path' => "$path/theme/tripal_featuremap",
     ),
     'tripal_featuremap_properties' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_featuremap_properties',
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_featuremap.properties',
+      'path' => "$path/theme/tripal_featuremap",
     ),
     'tripal_featuremap_featurepos' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_featuremap_featurepos',
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_featuremap.featurepos',
+      'path' => "$path/theme/tripal_featuremap",
     ),
     'tripal_featuremap_publication' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_featuremap_publication',
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_featuremap.publication',
+      'path' => "$path/theme/tripal_featuremap",
     ),
     'tripal_featuremap_references' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_featuremap_references',
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_featuremap.references',
+      'path' => "$path/theme/tripal_featuremap",
     ),
     'tripal_featuremap_help' => array(
-      'template' => 'tripal_featuremap_help',
-      'arguments' =>  array(NULL),
-      'path' => drupal_get_path('module', 'tripal_featuremap') . '/theme'
+      'template' => 'tripal_featuremap.help',
+      'variables' =>  array(NULL),
+      'path' => "$path/theme",
     ),
-
-    // Themed Forms
-    'chado_featuremap_node_form' => array(
-     'arguments' => array('form'),
+    'tripal_featuremap_teaser' => array(
+      'template' => 'tripal_featuremap.teaser',
+      'variables' =>  array(NULL),
+      'path' => "$path/theme/tripal_featuremap",
     ),
   );
+  return $items;
+}
+/**
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_featuremap_node_view($node, $view_mode, $langcode) {
+  switch ($node->type) {
+    case 'chado_featuremap':
+      // Show feature browser and counts
+      if ($view_mode == 'full') {
+        $node->content['tripal_featuremap_base'] = array(
+          '#value' => theme('tripal_featuremap_base', array('node' => $node)),
+        );
+        $node->content['tripal_featuremap_featurepos'] = array(
+          '#value' => theme('tripal_featuremap_featurepos', array('node' => $node)),
+        );
+        $node->content['tripal_featuremap_properties'] = array(
+          '#value' => theme('tripal_featuremap_properties', array('node' => $node)),
+        );
+        $node->content['tripal_featuremap_publication'] = array(
+          '#value' => theme('tripal_featuremap_publication', array('node' => $node)),
+        );
+        $node->content['tripal_featuremap_references'] = array(
+          '#value' => theme('tripal_featuremap_references', array('node' => $node)),
+        );
+      }
+      if ($view_mode == 'teaser') {
+        $node->content['tripal_featuremap_teaser'] = array(
+          '#value' => theme('tripal_featuremap_teaser', array('node' => $node)),
+        );
+      }
+      break;
+  }
 }
-
 /**
  * @ingroup tripal_library
  */
@@ -319,15 +355,6 @@ function tripal_featuremap_block_view($delta = '') {
     return $block;
   }
 }
-/**
- * This function is an extension of the chado_feature_view and
- * chado_organism_view by providing the markup for the map object
- * THAT WILL BE INDEXED.
- *
- * @ingroup tripal_featuremap
- */
-function theme_tripal_featuremap_search_index($node) {
-}
 
 /**
  *
@@ -336,355 +363,7 @@ function theme_tripal_featuremap_search_index($node) {
 function tripal_featuremap_cron() {
 
 }
-/**
- * Implement hook_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_featuremap
- */
-function chado_featuremap_node_access($node, $op, $account) {
-  if ($op == 'create') {
-    if (!user_access('create chado_featuremap content', $account)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-
-  if ($op == 'update') {
-    if (!user_access('edit any chado_featuremap content', $account) &&
-        !user_access('edit own chado_featuremap content', $account)) {
-        return FALSE;
-    }
-    if (user_access('edit own chado_featuremap content', $account) &&
-      $account->uid != $node->uid) {
-      return FALSE;
-    }
-  }
-
-  if ($op == 'delete') {
-    if (!user_access('delete any chado_featuremap content', $account) &&
-      !user_access('delete own chado_featuremap content', $account)) {
-      return FALSE;
-    }
-    if (user_access('delete own chado_featuremap content', $account) &&
-      $account->uid != $node->uid) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
-
-
-
-/**
- *  When a new chado_featuremap node is created we also need to add information
- *  to our chado_featuremap table.  This function is called on insert of a new node
- *  of type 'chado_featuremap' and inserts the necessary information.
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_insert($node) {
-
-  // if the featuremap_id already exists then we got to the insert via
-  // a syncing operation.  We do not need to add the feature map
-  if ($node->featuremap_id) {
-    $featuremap['featuremap_id'] = $node->featuremap_id;
-  }
-  else {
-    $values = array(
-      'name' => $node->title,
-      'description' => $node->description,
-      'unittype_id' => $node->unittype_id
-    );
-    $featuremap = tripal_core_chado_insert('featuremap', $values);
-    if(!$featuremap) {
-      drupal_set_message(t('Unable to add featuremap.', 'warning'));
-      watchdog('tripal_featuremap', 'Unable to create feature map where values: %values',
-        array('%values' => print_r($values, TRUE)), WATCHDOG_WARNING);
-      return;
-    }
-
-    // now add the properties
-    $properties = array(); // stores all of the properties we need to add
-    $cross_refs = array(); // stores any cross references for this featuremap
-
-    // get the list of properties for easy lookup (without doing lots of database queries
-    $properties_list = array();
-    $sql = "
-      SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
-      FROM  {cvterm} CVT
-        INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
-      WHERE
-        CV.name = 'featuremap_property' AND
-        NOT CVT.is_obsolete = 1
-      ORDER BY CVT.name ASC
-    ";
-    $prop_types = chado_query($sql);
-    while ($prop = $prop_types->fetchObject()) {
-      $properties_list[$prop->cvterm_id] = $prop->name;
-    }
-
-    // get the properties that should be added. Properties are in one of two forms:
-    //  1) prop_value-[type id]-[index]
-    //  2) new_value-[type id]-[index]
-    //  3) new_id, new_value
-    foreach ($node as $name => $value) {
-      if (preg_match('/^new_value-(\d+)-(\d+)/', $name, $matches)) {
-        $type_id = $matches[1];
-        $index = $matches[2];
-        $name = $properties_list[$type_id];
-        $properties[$name][$index] = trim($value);
-      }
-    }
-    if ($node->new_id and $node->new_value) {
-      $type_id = $node->new_id;
-      $index = count($properties[$name]);
-      $name = $properties_list[$type_id];
-      $properties[$name][$index] = trim($node->new_value);
-    }
-
-    // iterate through all of the properties to see if the Map dbxref is set,
-    // if so, add it to the $cross_refs array
-    foreach ($properties as $name => $element) {
-      foreach ($element as $index => $value) {
-        if ($name == "Map Dbxref") {
-          // we will add the cross-references to the featuremap_dbxref table
-          // but we also want to keep the property in the featuremapprop table so don't unset it
-          $cross_refs[] = $value;
-        }
-      }
-    }
-
-    // now add in the properties
-    foreach ($properties as $property => $elements) {
-      foreach ($elements as $rank => $value) {
-
-        $status = tripal_featuremap_insert_property($featuremap['featuremap_id'], $property, $value, FALSE);
-        if (!$status) {
-          drupal_set_message("Error cannot add property: $property", "error");
-          watchdog('t_featuremap', "Error cannot add property: %prop",
-          array('%property' => $property), WATCHDOG_ERROR);
-        }
-      }
-    }
-
-    // add in any database cross-references
-    foreach ($cross_refs as $index => $ref) {
-      $featuremap_dbxref = tripal_featuremap_add_featuremap_dbxref($featuremap['featuremap_id'], trim($ref));
-      if (!$featuremap_dbxref) {
-        drupal_set_message("Error cannot add map cross reference: $ref", "error");
-        watchdog('t_featuremap', "Error cannot add map cross reference: %ref",
-        array('%ref' => $ref), WATCHDOG_ERROR);
-      }
-    }
-  }
-
-  // add the record to the chado_featuremap table in Drupal
-  if ($featuremap) {
-    // make sure the entry for this feature doesn't already exist in the chado_featuremap table
-    // if it doesn't exist then we want to add it.
-    $featuremap_id = chado_get_id_for_node('featuremap', $node->nid) ;
-    if (!$featuremap_id) {
-       // next add the item to the drupal table
-      $sql = "
-        INSERT INTO {chado_featuremap} (nid, vid, featuremap_id)
-        VALUES (:nid, :vid, :featuremap_id)
-      ";
-      db_query($sql, array(':nid' => $node->nid, ':vid' => $node->vid, ':featuremap_id' => $featuremap['featuremap_id']));
-    }
-  }
-}
-/**
- * Update nodes
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_update($node) {
-  if ($node->revision) {
-    // there is no way to handle revisions in Chado but leave
-    // this here just to make not we've addressed it.
-  }
-  $featuremap_id = chado_get_id_for_node('featuremap', $node->nid) ;
-
-  // update the map record
-  $match = array(
-    'featuremap_id' => $featuremap_id,
-  );
-  $values = array(
-    'name' => $node->title,
-    'description' => $node->description,
-    'unittype_id' => $node->unittype_id
-  );
-  $status = tripal_core_chado_update('featuremap', $match, $values);
-  if (!$status) {
-    drupal_set_message("Error updating map", "error");
-    watchdog('t_featuremap', "Error updating map", array(), WATCHDOG_ERROR);
-    return;
-  }
-
-  // now update the properties
-  $properties = array(); // stores all of the properties we need to add
-  $cross_refs = array(); // stores any cross references for this map
-
-  // get the list of properties for easy lookup (without doing lots of database queries
-  $properties_list = array();
-  $sql = "
-    SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
-    FROM  {cvterm} CVT
-      INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
-    WHERE
-      CV.name = 'featuremap_property' AND
-      NOT CVT.is_obsolete = 1
-    ORDER BY CVT.name ASC
-  ";
-  $prop_types = chado_query($sql);
-  while ($prop = $prop_types->fetchObject()) {
-    $properties_list[$prop->cvterm_id] = $prop->name;
-  }
-
-  // get the properties that should be added. Properties are in one of three forms:
-  //  1) prop_value-[type id]-[index]
-  //  2) new_value-[type id]-[index]
-  //  3) new_id, new_value
-  //  dpm($node);
-  foreach ($node as $key => $value) {
-    if (preg_match('/^prop_value-(\d+)-(\d+)/', $key, $matches)) {
-      $type_id = $matches[1];
-      $index = $matches[2];
-      $name = $properties_list[$type_id];
-      $properties[$name][$index] = trim($value);
-    }
-    if (preg_match('/^new_value-(\d+)-(\d+)/', $key, $matches)) {
-      $type_id = $matches[1];
-      $index = $matches[2];
-      $name = $properties_list[$type_id];
-      $properties[$name][$index] = trim($value);
-    }
-  }
-  if ($node->new_id and $node->new_value) {
-    $type_id = $node->new_id;
-    $name = $properties_list[$type_id];
-    $index = count($properties[$name]);
-    $properties[$name][$index] = trim($node->new_value);
-  }
-
-  // iterate through all of the properties to see if the Map dbxref is set,
-  // if so, add it to the $cross_refs array
-  foreach ($properties as $name => $element) {
-    foreach ($element as $index => $value) {
-      if ($name == "Map Dbxref") {
-        // we will add the cross-references to the featuremap_dbxref table
-        // but we also want to keep the property in the featuremapprop table so don't unset it
-        $cross_refs[] = $value;
-      }
-    }
-  }
-
-  // now add in the properties by first removing any the featuremap
-  // already has and adding the ones we have
-  tripal_core_chado_delete('featuremapprop', array('featuremap_id' => $featuremap_id));
-  foreach ($properties as $property => $elements) {
-    foreach ($elements as $rank => $value) {
-      $status = tripal_featuremap_insert_property($featuremap_id, $property, $value, FALSE);
-      if (!$status) {
-        drupal_set_message("Error cannot add property: '$property'", "error");
-        watchdog('t_featuremap', "Error cannot add property: '%prop'",
-        array('%prop' => $property), WATCHDOG_ERROR);
-      }
-    }
-  }
-
-  // add in any database cross-references after first removing
-  tripal_core_chado_delete('featuremap_dbxref', array('featuremap_id' => $featuremap_id));
-  foreach ($cross_refs as $index => $ref) {
-    $featuremap_dbxref = tripal_featuremap_add_featuremap_dbxref($featuremap_id, trim($ref));
-    if (!$featuremap_dbxref) {
-      drupal_set_message("Error cannot add map cross reference: $ref", "error");
-      watchdog('t_featuremap', "Error cannot add map cross reference: %ref",
-      array('%ref' => $ref), WATCHDOG_ERROR);
-    }
-  }
-}
-/**
- *  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_featuremap
- */
-function chado_featuremap_load($node) {
-  // get the feature details from chado
-  $featuremap_id = chado_get_id_for_node('featuremap', $node->nid);
 
-  $values = array('featuremap_id' => $featuremap_id);
-  $featuremap = tripal_core_generate_chado_var('featuremap', $values);
-
-  // expand the description field as it is needed by the form
-  $featuremap = tripal_core_expand_chado_vars($featuremap, 'field', 'featuremap.description');
-
-  $additions = new stdClass();
-  $additions->featuremap = $featuremap;
-  return $additions;
-
-}
-/**
- *  This function customizes the view of the chado_featuremap node.  It allows
- *  us to generate the markup. This function is required for node [Preview]
- *
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_view($node, $teaser = FALSE, $page = FALSE) {
-   // use drupal's default node view:
-  if (!$teaser) {
-
-    $node = node_prepare($node, $teaser);
-  }
-  return $node;
-}
-
-/**
- * Delete data from drupal and chado databases when a node is deleted
- * @ingroup tripal_featuremap
- */
-function chado_featuremap_delete(&$node) {
-
-  $featuremap_id = chado_get_id_for_node('featuremap', $node->nid);
-
-  // if we don't have a map id for this node then this isn't a node of
-  // type chado_featuremap or the entry in the chado_featuremap table was lost.
-  if (!$featuremap_id) {
-    return;
-  }
-
-  // Remove data from {chado_featuremap}, {node} and {node_revisions} tables of
-  // drupal database
-  $sql_del = "DELETE FROM {chado_featuremap} 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));
-  $sql_del = "DELETE FROM {node_revisions} WHERE nid = :nid AND vid = :vid";
-  db_query($sql_del, array(':nid' => $node->nid, ':vid' => $node->vid));
-
-  // Remove data from map and mapprop tables of chado database as well
-  chado_query("DELETE FROM {featuremap} WHERE featuremap_id = :featuremap_id", array(':featuremap_id' => $featuremap_id));
-  chado_query("DELETE FROM {featuremapprop} WHERE featuremap_id = :featuremap_id", array(':featuremap_id' => $featuremap_id));
-}
 
 /**
  * Implementation of hook_form_alter()
@@ -698,4 +377,16 @@ function tripal_featuremap_form_alter(&$form, &$form_state, $form_id) {
   if ($form_id == "chado_featuremap_node_form") {
     $form['actions']['preview']['#access'] = FALSE;
   }
+}
+
+/**
+ *
+ * @param $node
+ */
+function tripal_featuremap_node_presave($node) {
+  // if this is a chado_featuremap and the $node->featuremap object is set then we
+  // are syncing and we want to set the node title to be the same as the node name
+  if ($node->type == 'chado_featuremap' and property_exists($node, 'featuremap')) {
+    $node->title = $node->featuremap->name;
+  }
 }

+ 4 - 4
tripal_library/api/tripal_library.api.inc

@@ -21,7 +21,7 @@
  * @ingroup tripal_library_api
  */
 function tripal_library_get_property($library_id, $property) {
-  return tripal_core_get_property('library', $library_id, $property, 'tripal');
+  return tripal_core_get_property('library', $library_id, $property, 'library_property');
 }
 
 /**
@@ -42,7 +42,7 @@ function tripal_library_get_property($library_id, $property) {
  * @ingroup tripal_library_api
  */
 function tripal_library_insert_property($library_id, $property, $value, $update_if_present = 0) {
-  return tripal_core_insert_property('library', $library_id, $property, 'tripal', $value, $update_if_present);
+  return tripal_core_insert_property('library', $library_id, $property, 'library_property', $value, $update_if_present);
 }
 
 /**
@@ -66,7 +66,7 @@ function tripal_library_insert_property($library_id, $property, $value, $update_
  * @ingroup tripal_library_api
  */
 function tripal_library_update_property($library_id, $property, $value, $insert_if_missing = 0) {
-  return tripal_core_update_property('library', $library_id, $property, 'tripal', $value, $insert_if_missing);
+  return tripal_core_update_property('library', $library_id, $property, 'library_property', $value, $insert_if_missing);
 }
 /**
  * Delete a given property
@@ -85,5 +85,5 @@ function tripal_library_update_property($library_id, $property, $value, $insert_
  * @ingroup tripal_library_api
  */
 function tripal_library_delete_property($library_id, $property) {
-  return tripal_core_delete_property('library', $library_id, $property, 'tripal');
+  return tripal_core_delete_property('library', $library_id, $property, 'library_property');
 }

+ 4 - 565
tripal_library/includes/tripal_library.admin.inc

@@ -38,581 +38,20 @@ function tripal_library_admin_libraries_listing() {
 function tripal_library_admin() {
   $form = array();
 
-  // before proceeding check to see if we have any
-  // currently processing jobs. If so, we don't want
-  // to give the opportunity to sync libraries
-  $active_jobs = FALSE;
-  if (tripal_get_module_active_jobs('tripal_library')) {
-    $active_jobs = TRUE;
-  }
-
-  // add the field set for syncing libraries
-  if (!$active_jobs) {
-    get_tripal_library_admin_form_sync_set($form);
-    get_tripal_library_admin_form_reindex_set($form);
-    get_tripal_library_admin_form_taxonomy_set($form);
-    get_tripal_library_admin_form_cleanup_set($form);
-  }
-  else {
-    $form['notice'] = array(
-     '#type' => 'fieldset',
-     '#title' => t('Library Management Temporarily Unavailable')
-    );
-    $form['notice']['message'] = array(
-        '#value' => t('Currently, library management jobs are waiting or are running. . Managemment features have been hidden until these jobs complete.  Please check back later once these jobs have finished.  You can view the status of pending jobs in the Tripal jobs page.'),
-    );
-  }
-
-  return system_settings_form($form);
-}
-
-
-/**
- *
- *
- * @ingroup tripal_library
- */
-function get_tripal_library_admin_form_cleanup_set(&$form) {
-  $form['cleanup'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Clean Up')
-  );
-  $form['cleanup']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("With Drupal and chado residing in different databases ".
-        "it is possible that nodes in Drupal and libraries in Chado become ".
-        "\"orphaned\".  This can occur if an library node in Drupal is ".
-        "deleted but the corresponding chado library is not and/or vice ".
-        "versa. Click the button below to resolve these discrepancies."),
-     '#weight' => 1,
-  );
-  $form['cleanup']['button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Clean up orphaned libraries'),
-    '#weight' => 2,
-  );
-}
-
-/**
- *
- *
- * @ingroup tripal_library
- */
-function get_tripal_library_admin_form_taxonomy_set(&$form) {
-  $form['taxonify'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Assign Drupal Taxonomy to Library Features')
-  );
-
-  // get the list of libraries
-  $sql = "SELECT * FROM {library} ORDER BY uniquename";
-  $lib_rset = chado_query($sql);
-
-  // iterate through all of the libraries
-  $lib_boxes = array();
-  foreach ($lib_rset as $library) {
-    $lib_boxes[$library->library_id] = "$library->name";
-  }
-
-  $form['taxonify']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("Drupal allows for assignment of \"taxonomy\" or catagorical terms to " .
-                   "nodes. These terms allow for advanced filtering during searching. This option allows ".
-                   "for setting taxonomy only for features that belong to the selected libraries below.  All other features will be unaffected.  To set taxonomy for all features in the site see the Feature Administration page."),
-   '#weight' => 1,
-  );
-
-  $form['taxonify']['tx-libraries'] = array(
-   '#title'       => t('Libraries'),
-   '#type'        => t('checkboxes'),
-   '#description' => t("Check the libraries whose features you want to reset taxonomy.  Note: this list contains all libraries, even those that may not be synced."),
-   '#required'    => FALSE,
-   '#prefix'      => '<div id="lib_boxes">',
-   '#suffix'      => '</div>',
-   '#options'     => $lib_boxes,
-   '#weight'      => 2
-  );
-  $form['taxonify']['tx-button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Set Feature Taxonomy'),
-    '#weight'      => 3
-  );
-}
-/**
- *
- * @ingroup tripal_library
- */
-function get_tripal_library_admin_form_reindex_set(&$form) {
-   // define the fieldsets
-  $form['reindex'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Reindex Library Features')
+  $form['nothing'] = array(
+    '#markup' => t('There are currently no settings to configure.')
   );
 
-  // get the list of libraries
-  $sql = "SELECT * FROM {Library} ORDER BY uniquename";
-  $lib_rset = chado_query($sql);
-
-  // iterate through all of the libraries
-  $lib_boxes = array();
-  while ($library = $lib_rset->fetchObject()) {
-    $lib_boxes[$library->library_id] = "$library->name";
-  }
-  $form['reindex']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("This option allows for reindexing of only those features that belong to the selected libraries below. All other features will be unaffected.  To reindex all features in the site see the Feature Administration page."),
-   '#weight' => 1,
-  );
-
-  $form['reindex']['re-libraries'] = array(
-   '#title'       => t('Libraries'),
-   '#type'        => t('checkboxes'),
-   '#description' => t("Check the libraries whoee features you want to reindex. Note: this list contains all libraries, even those that may not be synced."),
-   '#required'    => FALSE,
-   '#prefix'      => '<div id="lib_boxes">',
-   '#suffix'      => '</div>',
-   '#options'     => $lib_boxes,
-   '#weight' => 2,
-  );
-  $form['reindex']['re-button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reindex Features'),
-    '#weight' => 3,
-  );
+  return system_settings_form($form);
 }
-/**
- *
- * @ingroup tripal_library
- */
-function get_tripal_library_admin_form_sync_set(&$form) {
-   // define the fieldsets
-  $form['sync'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Sync Libraries')
-  );
-
-
-  // get the list of libraries
-  $sql = "SELECT * FROM {library} ORDER BY uniquename";
-  $lib_rset = chado_query($sql);
-
-  // if we've added any libraries to the list that can be synced
-  // then we want to build the form components to allow the user
-  // to select one or all of them.  Otherwise, just present
-  // a message stating that all libraries are currently synced.
-  $lib_boxes = array();
-  $added = 0;
-  foreach ($lib_rset as $libary) {
-    // check to see if the library is already present as a node in drupal.
-    // if so, then skip it.
-    $sql = "SELECT * FROM {chado_library} WHERE library_id = :library_id";
-    $chado_library = db_query($sql, array(':library_id' => $library->library_id))->fetchObject();
-    if (!$chado_library) {
-      $lib_boxes[$library->library_id] = "$library->name";
-      $added++;
-    }
-  }
-
-  // if we have libraries we need to add to the checkbox then
-  // build that form element
-  if ($added > 0) {
-    $lib_boxes['all'] = "All Libraries";
 
-    $form['reindex']['description'] = array(
-     '#type' => 'item',
-     '#value' => t("This option allows for the creation of Drupal content for libraries in chado. Only the selected libraries will be synced."),
-   '#weight' => 1,
-    );
 
 
-    $form['sync']['libraries'] = array(
-      '#title'       => t('Available Libraries'),
-      '#type'        => t('checkboxes'),
-      '#description' => t("Check the libraries you want to sync.  Drupal content will be created for each of the libraries listed above.  Select 'All Libraries' to sync all of them."),
-      '#required'    => FALSE,
-      '#prefix'      => '<div id="lib_boxes">',
-      '#suffix'      => '</div>',
-      '#options'     => $lib_boxes,
-    '#weight' => 2,
-    );
-    $form['sync']['button'] = array(
-       '#type' => 'submit',
-       '#value' => t('Sync Libraries'),
-     '#weight' => 3,
-    );
-  }
-   // we don't have any libraries to select from
-  else {
-    $form['sync']['value'] = array(
-       '#value' => t('All libraries in Chado are currently synced with Drupal.')
-    );
-  }
-}
 /**
  *
  * @ingroup tripal_library
  */
 function tripal_library_admin_validate($form, &$form_state) {
-  global $user;  // we need access to the user info
-  $job_args = array();
-
-  // Submit the Sync Job if selected
-  if ($form_state['values']['op'] == t('Sync Libraries')) {
-
-    // check to see if the user wants to sync chado and drupal.  If
-    // so then we need to register a job to do so with tripal
-    $libraries = $form_state['values']['libraries'];
-    $do_all = FALSE;
-    $to_sync = array();
-
-  foreach ($libraries as $library_id) {
-    if (preg_match("/^all$/i", $library_id)) {
-      $do_all = TRUE;
-    }
-    if ($library_id and preg_match("/^\d+$/i", $library_id)) {
-      // get the library info
-      $sql = "SELECT * FROM {library} WHERE library_id = :library_id";
-      $library = chado_query($sql, array(':library_id' => $library_id))->fetchObject();
-      $to_sync[$library_id] = $library->name;
-    }
-  }
-
-  // submit the job to the tripal job manager
-  if ($do_all) {
-    tripal_add_job('Sync all libraries', 'tripal_library', 'tripal_library_sync_libraries', $job_args, $user->uid);
-  }
-  else{
-    foreach ($to_sync as $library_id => $name) {
-      $job_args[0] = $library_id;
-      tripal_add_job("Sync library: $name", 'tripal_library', 'tripal_library_sync_libraries', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Reindex Job if selected
-  if ($form_state['values']['op'] == t('Reindex Features')) {
-    $libraries = $form_state['values']['re-libraries'];
-    foreach ($libraries as $library_id) {
-      if ($library_id and preg_match("/^\d+$/i", $library_id)) {
-        // get the library info
-        $sql = "SELECT * FROM {Library} WHERE library_id = :library_id";
-        $library = chado_query($sql, array(':library_id' => $library_id))->fetchObject();
-        $job_args[0] = $library_id;
-        tripal_add_job("Reindex features for library: $library->name", 'tripal_library',
-         'tripal_library_reindex_features', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Taxonomy Job if selected
-  if ($form_state['values']['op'] == t('Set Feature Taxonomy')) {
-    $libraries = $form_state['values']['tx-libraries'];
-    foreach ($libraries as $library_id) {
-      if ($library_id and preg_match("/^\d+$/i", $library_id)) {
-        // get the library info
-        $sql = "SELECT * FROM {Library} WHERE library_id = :libary_id";
-        $library = chado_query($sql, array(':library_id' => $library_id))->fetchObject();
-        $job_args[0] = $library_id;
-        tripal_add_job("Set taxonomy for features in library: $library->name", 'tripal_library',
-         'tripal_library_taxonify_features', $job_args, $user->uid);
-      }
-    }
-  }
-    // -------------------------------------
-    // Submit the Cleanup Job if selected
-    if ($form_state['values']['op'] == t('Clean up orphaned libraries')) {
-      tripal_add_job('Cleanup orphaned libraries', 'tripal_library',
-         'tripal_library_cleanup', $job_args, $user->uid);
-    }
-}
-
-
-/**
- * Add the library as a taxonomy term for associating with library_features
- *
- * @ingroup tripal_library
- */
-function tripal_library_add_taxonomy($node, $library_id) {
-
-  //include the file containing the required functions.  We only have to
-  // do this because Drupal 6 fails to do this globally for us and
-  // the drupal_execute function below won't work
-  module_load_include('inc', 'taxonomy', 'taxonomy.admin');
-
-   // add the vocabulary
-  $vocab_form['values']['name'] = 'DNA Libraries';
-  $vocab_form['values']['description'] = 'Allows for associating/searching of library features by library name';
-  $vocab_form['values']['help'] = '';
-  $vocab_form['values']['module'] = 'taxonomy';
-  drupal_form_submit('taxonomy_form_vocabulary', $vocab_form);
-  return;
-
-   // make sure this term doesn't already exist.  If it doesn't then add it
-  if ($vid) {
-    $tree = taxonomy_get_tree($vid);
-    $found = 0;
-    foreach ($tree as $term) {
-      if ($term->name == $node->title) {
-        $found = 1;
-      }
-    }
-
-      // add the term to the vocabulary
-    if (!$found) {
-      $form_state = array();
-      $form_state['values']['name'] = $node->title;
-      $form_state['values']['description'] = $library_id;
-      drupal_form_submit('taxonomy_form_term', $form_state, $vid);
-    }
-  }
-}
-
-
-/**
- *
- *
- * @ingroup tripal_library
- */
-function tripal_library_sync_libraries($library_id = NULL, $job_id = NULL) {
-
-  global $user;
-  $page_content = '';
-
-  // get the list of libraries and create new nodes
-  if (!$library_id) {
-    $sql = "SELECT * FROM {library} L";
-    $results = chado_query($sql);
-  }
-  else {
-    $sql = "SELECT * FROM {library} L WHERE library_id = :library_id";
-    $results = chado_query($sql, array(':library_id' => $library_id));
-  }
-
-  // We'll use the following SQL statement for checking if the library
-  // already exists as a drupal node.
-  $sql = "SELECT * FROM {chado_library} ".
-        "WHERE library_id = :libary_id";
-
-  while ($library = $results->fetchObject()) {
-
-    // check if this library already exists in the drupal database. if it
-    // does then skip this library and go to the next one.
-    if (!db_query($sql, array(':libary_id' => $library->library_id))->fetchObject()) {
-
-    $new_node = new stdClass();
-    $new_node->type = 'chado_library';
-    $new_node->uid = $user->uid;
-    $new_node->title = "$library->name";
-    $new_node->library_id = $library->library_id;
-    $new_node->organism_id = $library->organism_id;
-    $new_node->uniquename = $library->uniquename;
-    $new_node->type_id = $library->type_id;
-
-    node_validate($new_node);
-    $errors = form_get_errors();
-    if (!$errors) {
-      $node = node_submit($new_node);
-      node_save($node);
-      if ($node->nid) {
-        print "Added " . $library->name . "\n";
-      }
-      else {
-        print "ERROR: Unable to create " . $library->name . "\n";
-      }
-    }
-    else {
-      print "ERROR: Unable to create " . $library->name . "\n" . print_r($errors, TRUE) . "\n";
-    }
-    }
-    else {
-      print "Skipped " . $library->name . "\n";
-    }
-  }
-  return $page_content;
-}
-
-
-/**
- *
- * @ingroup tripal_library
- */
-function tripal_library_feature_set_taxonomy($library_id = NULL) {
-
-   //TO DO : return usable error if vocabs don't exist
-   // get the list of vocabularies and find our two vocabularies of interest
-  $vocabularies = taxonomy_get_vocabularies();
-  $vid = NULL;
-  foreach ($vocabularies as $vocab) {
-    if ($vocab->name == 'Library') {
-      $vid = $vocab->vid;
-    }
-  }
-  if (!$vid) {
-    return;
-  }
-
-  // We'll use the following SQL statement for getting the node info
-  if ($library_id) {
-    print "Finding features for library with ID: $library_id\n";
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      WHERE L.library_id = :library_id
-      ORDER BY LF.feature_id
-    ";
-    $features = chado_query($sql, array(':library_id' => $library_id));
-  }
-  else {
-    print "Finding features for all libraries\n";
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      ORDER BY LF.feature_id
-    ";
-    $features = chado_query($sql);
-  }
-
-  $node_sql = "
-    SELECT *
-    FROM {chado_feature} CF
-      INNER JOIN {node} N ON CF.nid = N.nid
-    WHERE feature_id = :feature_id
-  ";
-  // iterate through the features and add the taxonomy
-  while ($feature = $features->fetchObject()) {
-    $node = db_query($node_sql, array(':feature_id' => $feature->feature_id))->fetchObject();
-    $tags["$vid"] = $feature->libname;
-    $terms['tags'] = $tags;
-    taxonomy_node_save($node, $terms);
-    print "Updated $feature->feature_id as $feature->libname\n";
-  }
-}
-/**
- *
- * @ingroup tripal_library
- */
-function tripal_library_reindex_features($library_id = NULL, $job_id = NULL) {
-  $i = 0;
-
-  // if the caller provided a library_id then get all of the features
-  // associated with the library. Otherwise get all sequences assoicated
-  // with all libraries.
-  if ($library_id) {
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      WHERE L.library_id = :library_id
-      ORDER BY LF.feature_id
-    ";
-    $results = chado_query($sql, array(':library_id' => $library_id));
-  }
-  else {
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      ORDER BY LF.feature_id
-    ";
-    $results = chado_query($sql);
-  }
-
-   // load into ids array
-  $count = 0;
-  $ids = array();
-  while ($id = $results->fetchObject()) {
-    $ids[$count] = $id->feature_id;
-    $count++;
-  }
-
-  $interval = intval($count * 0.01);
-  foreach ($ids as $feature_id) {
-    // update the job status every 1% features
-    if ($job_id and $i % interval == 0) {
-      tripal_job_set_progress($job_id, intval(($i/$count)*100));
-    }
-    $i++;
-  }
-}
-/**
- *
- * @ingroup tripal_library
- */
-function tripal_library_taxonify_features($library_id = NULL, $job_id = NULL) {
-  $i = 0;
-
-  // if the caller provided a library_id then get all of the features
-  // associated with the library. Otherwise get all sequences assoicated
-  // with all libraries.
-  if ($library_id) {
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      WHERE L.library_id = :library_id
-      ORDER BY LF.feature_id
-    ";
-    $results = chado_query($sql, array(':library_id' => $library_id));
-  }
-  else {
-    $sql = "
-      SELECT LF.feature_id, L.library_id, L.name as libname
-      FROM {library_feature} LF
-        INNER JOIN {library} L ON LF.library_id = L.library_id
-      ORDER BY LF.feature_id
-    ";
-    $results = chado_query($sql);
-  }
-
-  // load into ids array
-  $count = 0;
-  $ids = array();
-  while ($id = $results->fetchObject()) {
-    $ids[$count] = $id->feature_id;
-    $count++;
-  }
-
-  // make sure our vocabularies are set before proceeding
-  tripal_feature_set_vocabulary();
-
-  // use this SQL for getting the nodes
-  $nsql =  "
-    SELECT *
-    FROM {chado_feature} CF
-      INNER JOIN {node} N ON N.nid = CF.nid
-    WHERE feature_id = :feature_id
-  ";
-   // iterate through the features and set the taxonomy
-  $interval = intval($count * 0.01);
-  foreach ($ids as $feature_id) {
-    // update the job status every 1% features
-    if ($job_id and $i % interval == 0) {
-      tripal_job_set_progress($job_id, intval(($i/$count)*100));
-    }
-      $node = db_query($nsql, array(':feature_id' => $feature_id))->fetchObject();
-      tripal_feature_set_taxonomy($node, $feature_id);
-      $i++;
-  }
-}
-
-
-/**
- * Remove orphaned drupal nodes
- *
- * @param $dummy
- *   Not Used -kept for backwards compatibility
- * @param $job_id
- *   The id of the tripal job executing this function
- *
- * @ingroup tripal_library
- */
-function tripal_library_cleanup($dummy = NULL, $job_id = NULL) {
-
-  return tripal_core_clean_orphaned_nodes('library', $job_id);
-
+  
 }
 

+ 350 - 0
tripal_library/includes/tripal_library.chado_node.inc

@@ -0,0 +1,350 @@
+<?php
+/**
+ *  When editing or creating a new node of type 'chado_library' we need
+ *  a form.  This function creates the form that will be used for this.
+ *
+ * @ingroup tripal_library
+ */
+function chado_library_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 library
+  // 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
+  $library_id = NULL;
+  $title = '';
+  $uniquename = '';
+  $library_type = '';
+  $organism_id = '';
+  $description = '';
+  
+  // if we are editing an existing node then the library is already part of the node
+  if (property_exists($node, 'library')) {
+    $library = $node->library;
+    $library_id = $library->library_id;
+    
+    $title        = $library->name;
+    $uniquename   = $library->uniquename;
+    $library_type = $library->type_id->cvterm_id;
+    $organism_id  = $library->organism_id->organism_id;
+    
+    $libprop = tripal_library_get_property($library->library_id, 'Library Description');
+    $description = $libprop->value;
+    
+    // keep track of the library id if we have.  If we do have one then
+    // this is an update as opposed to an insert.
+    $form['library_id'] = array(
+      '#type' => 'value',
+      '#value' => $library_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)) {
+    $title        = $form_state['values']['title'];
+    $uniquename   = $form_state['values']['uniquename'];
+    $library_type = $form_state['values']['library_type'];
+    $organism_id  = $form_state['values']['organism_id'];
+    $description  = $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'])) {
+    $title        = $form_state['input']['title'];
+    $uniquename   = $form_state['input']['uniquename'];
+    $library_type = $form_state['input']['library_type'];
+    $organism_id  = $form_state['input']['organism_id'];
+    $description  = $form_state['input']['description'];
+  }
+
+  $form['title']= array(
+    '#type'          => 'textfield',
+    '#title'         => t('Library Name'),
+    '#description'   => t('Please enter the name for this library. Library names should be recognizable but do not need to be unique.'),
+    '#required'      => TRUE,
+    '#default_value' => $title,
+    '#weight'        => 1
+  );
+
+  $form['uniquename']= array(
+    '#type'          => 'textfield',
+    '#title'         => t('Unique Name'),
+    '#description'   => t('Please enter a unique name for this library. This can be any value used to uniquely identify a library.'),
+    '#required'      => TRUE,
+    '#default_value' => $uniquename,
+    '#weight'        => 2
+  );
+
+  // get the list of library types
+  $values = array(
+    'cv_id' => array(
+      'name' => 'library_type',
+    )
+  );
+  $columns = array('cvterm_id','name');
+  $options = array('order_by' => array('name' => 'ASC'));
+  $lib_types = tripal_core_chado_select('cvterm', $columns, $values, $options);
+  $types = array();
+  $types[''] = '';
+  foreach($lib_types as $type) {
+    $types[$type->cvterm_id] = $type->name;
+  }
+
+  $form['library_type'] = array(
+    '#title'       => t('Library Type'),
+    '#type'        => t('select'),
+    '#description' => t("Choose the library type."),
+    '#required'    => TRUE,
+    '#default_value' => $library_type,
+    '#options'     => $types,
+    '#weight'      => 3
+  );
+
+  // get the list of organisms
+  $sql = "SELECT * FROM {organism}";
+  $org_rset = chado_query($sql);
+
+  $organisms = array();
+  $organisms[''] = '';
+  while ($organism = $org_rset->fetchObject()) {
+    $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 library is associated."),
+    '#required'    => TRUE,
+    '#default_value' => $organism_id,
+    '#options'     => $organisms,
+    '#weight'      => 4,
+  );
+
+  $form['description']= array(
+    '#type'          => 'textarea',
+    '#title'         => t('Library Description'),
+    '#description'   => t('A brief description of the library'),
+    '#required'      => TRUE,
+    '#default_value' => $description,
+    '#weight'        => 5
+  );
+
+  return $form;
+}
+/**
+ *  validates submission of form when adding or updating a library node
+ *
+ * @ingroup tripal_library
+ */
+function chado_library_validate($node, $form, &$form_state) {
+  
+  $node->title       = trim($node->title);
+  $node->uniquename  = trim($node->uniquename);
+  $node->description = trim($node->description);
+  
+  $lib = 0;
+  // check to make sure the unique name on the library is unique
+  // before we try to insert into chado.
+  if (property_exists($node, 'library_id')) {
+    $sql = "
+      SELECT *
+      FROM {library}
+      WHERE uniquename = :uname AND NOT library_id = :library_id
+    ";
+    $lib = chado_query($sql, array(':uname' => $node->uniquename, ':library_id' => $node->library_id))->fetchObject();
+  }
+  else {
+    $sql = "SELECT * FROM {library} WHERE uniquename = :uname";
+    $lib = chado_query($sql, array(':uname' => $node->uniquename))->fetchObject();
+  }
+  if ($lib) {
+    form_set_error('uniquename', t('The unique library name already exists. Please choose another'));
+  }
+}
+/**
+ *  When a new chado_library node is created we also need to add information
+ *  to our chado_library table.  This function is called on insert of a new node
+ *  of type 'chado_library' and inserts the necessary information.
+ *
+ * @ingroup tripal_library
+ */
+function chado_library_insert($node) {
+  
+  $node->title       = trim($node->title);
+  $node->uniquename  = trim($node->uniquename);
+  $node->description = trim($node->description);
+
+  // if there is an library_id in the $node object then this must be a sync so
+  // we can skip adding the library as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'library_id')) {
+    $values = array(
+      'name' => $node->title,
+      'uniquename' => $node->uniquename,
+      'organism_id' => $node->organism_id,
+      'type_id' => $node->library_type,
+    );
+    $library = tripal_core_chado_insert('library', $values);
+    if (!$library) {
+      drupal_set_message(t('Unable to add library.', 'warning'));
+      watchdog('tripal_library', 'Insert library: Unable to create library where values: %values',
+        array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+      return;
+    }
+    $library_id = $library['library_id'];
+    
+    // add the description property
+    tripal_library_insert_property($library_id, 'Library Description', $node->description);
+    
+  }
+  else {
+    $library_id = $node->library_id;
+  }
+
+  // Make sure the entry for this library doesn't already exist in the
+  // chado_library table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('library', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->library_id = $library_id;
+    drupal_write_record('chado_library', $record);
+  }
+}
+/**
+ * Update nodes
+ *
+ * @ingroup tripal_library
+ */
+function chado_library_update($node) {
+  
+  $node->title       = trim($node->title);
+  $node->uniquename  = trim($node->uniquename);
+  $node->description = trim($node->description);
+
+  // update the library record
+  $library_id = chado_get_id_for_node('library', $node->nid);
+  $match = array(
+    'library_id' => $library_id,
+  );
+  $values = array(
+    'name'        => $node->title,
+    'uniquename'  => $node->uniquename,
+    'organism_id' => $node->organism_id,
+    'type_id'     => $node->library_type,
+  );
+  $status = tripal_core_chado_update('library', $match, $values);
+  if (!$status) {
+    drupal_set_message(t('Unable to update library.', 'warning'));
+    watchdog('tripal_library', 'Update library: Unable to update library where values: %values',
+    array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+  }
+  
+  // add in the library description as a property
+  tripal_library_update_property($library_id, 'Library Description', $node->description, 1);
+}
+/**
+ *  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_library
+ */
+function chado_library_load($nodes) {
+  
+  foreach ($nodes as $nid => $node) {
+    // get the feature details from chado
+    $library_id = chado_get_id_for_node('library', $node->nid);
+  
+    $values = array('library_id' => $library_id);
+    $library = tripal_core_generate_chado_var('library', $values);
+  
+    // the uniquename field is a text field so we need to expand it
+    $library = tripal_core_expand_chado_vars($library, 'field', 'library.uniquename');
+    
+    $nodes[$nid]->library = $library;
+  }
+}
+
+/**
+ * Delete data from drupal and chado databases when a node is deleted
+ * @ingroup tripal_library
+ */
+function chado_library_delete(&$node) {
+
+  $library_id = chado_get_id_for_node('library', $node->nid);
+
+  // if we don't have a library id for this node then this isn't a node of
+  // type chado_library or the entry in the chado_library table was lost.
+  if (!$library_id) {
+    return;
+  }
+
+  // Remove data from {chado_library}, {node} and {node_revisions} tables of
+  // drupal database
+  $sql_del = "DELETE FROM {chado_library} 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 library and libraryprop tables of chado database as well
+  chado_query("DELETE FROM {libraryprop} WHERE library_id = :library_id", array(':library_id' => $library_id));
+  chado_query("DELETE FROM {library} WHERE library_id = :library_id", array(':library_id' => $library_id));
+}
+
+/**
+ * Implement hook_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_library
+ */
+function chado_library_node_access($node, $op, $account) {
+  if ($op == 'create') {
+    if (!user_access('create chado_library content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+  if ($op == 'update') {
+    if (!user_access('edit chado_library content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'delete') {
+    if (!user_access('delete chado_library content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'view') {
+    if (!user_access('access chado_library content', $account)) {
+      return FALSE;
+    }
+  }
+  return NULL;
+}

+ 0 - 142
tripal_library/theme/node--chado-library.tpl.php

@@ -1,142 +0,0 @@
-<?php
-// Purpose: This template provides the layout of the library node (page)
-//   using the same templates used for the various library content blocks.
-//
-// To Customize the Libray Node Page:
-//   - This Template: customize basic layout and which elements are included
-//   - Using Panels: Override the node page using Panels3 and place the blocks
-//       of content as you please. This method requires no programming. See
-//       the Tripal User Guide for more details
-//   - Block Templates: customize the content/layout of each block of stock 
-//       content. These templates are found in the tripal_stock subdirectory
-//
-// Variables Available:
-//   - $node: a standard object which contains all the fields associated with
-//       nodes including nid, type, title, taxonomy. It also includes stock
-//       specific fields such as stock_name, uniquename, stock_type, synonyms,
-//       properties, db_references, object_relationships, subject_relationships,
-//       organism, etc.
-//   NOTE: For a full listing of fields available in the node object the
-//       print_r $node line below or install the Drupal Devel module which 
-//       provides an extra tab at the top of the node page labelled Devel
-
-$library  = $variables['node']->library;
-
-// get the template settings
-$template_settings = theme_get_setting('tripal');
-
-// toggle the sidebar if desired
-$no_sidebar = 0;
-if (is_array($template_settings['tripal_no_sidebar']) and 
-   $template_settings['tripal_no_sidebar']['library']) {
-  $no_sidebar = 1;
-}
-
-if ($teaser) { 
-  print theme('tripal_library_teaser',$variables); 
-} 
-else { ?>
-
-<script type="text/javascript">
-(function ($) {
-  Drupal.behaviors.libraryBehavior = {
-	attach: function (context, settings){ <?php 
-	  if ($no_sidebar) { ?>    
-        // hide the resource side bar and strech the details section    
-        $(".tripal_toc").hide();
-        $(".tripal_details").addClass("tripal_details_full");
-        $(".tripal_details_full").removeClass("tripal_details"); <?php
-      } else { ?>
-        // use default resource sidebar
-        $(".tripal-info-box").hide(); <?php
-      } ?>
- 
-      // iterate through all of the info boxes and add their titles
-      // to the table of contents
-      $(".tripal-info-box-title").each(function(){
-        var parent = $(this).parent();
-        var id = $(parent).attr('id');
-        var title = $(this).text();
-        $('#tripal_library_toc_list').append('<li><a href="#'+id+'" class="tripal_library_toc_item">'+title+'</a></li>');
-      });
-
-      // when a title in the table of contents is clicked, then
-      // show the corresponding item in the details box
-      $(".tripal_library_toc_item").click(function(){
-         $(".tripal-info-box").hide();
-         href = $(this).attr('href');
-         $(href).fadeIn('slow');
-         // we want to make sure our table of contents and the details
-         // box stay the same height
-         $("#tripal_library_toc").height($(href).parent().height());
-         return false;
-      }); 
-
-      // we want the base details to show up when the page is first shown 
-      // unless the user specified a specific block
-      var block = window.location.href.match(/[\?|\&]block=(.+?)\&/)
-      if(block == null){
-         block = window.location.href.match(/[\?|\&]block=(.+)/)
-      }
-      if(block != null){
-         $("#tripal_library-"+block[1]+"-box").show();
-      } else {
-         $("#tripal_library-base-box").show();
-      }
-
-      $("#tripal_library_toc").height($("#tripal_library-base-box").parent().height());
-    }     
-  };
-})(jQuery);
-</script>
-
-<div id="tripal_library_details" class="tripal_details">
-
-   <!-- Basic Details Theme -->
-   <?php print theme('tripal_library_base',$node); ?>
-
-   <!-- External References -->
-   <?php print theme('tripal_library_references',$node); ?>
-
-   <!-- Properties -->
-   <?php print theme('tripal_library_properties',$node); ?>
-   
-   <!-- Terms -->
-   <?php print theme('tripal_library_terms',$node); ?>
-
-   <!-- Synonyms -->
-   <?php print theme('tripal_library_synonyms',$node); ?>
-
-   <!-- Resource Blocks CCK elements --><?php
-   for($i = 0; $i < count($node->field_resource_titles); $i++){
-     if($node->field_resource_titles[$i]['value']){ ?>
-       <div id="tripal_library-resource_<?php print $i?>-box" class="tripal_library-info-box tripal-info-box">
-         <div class="tripal_library-info-box-title tripal-info-box-title"><?php print $node->field_resource_titles[$i]['value'] ?></div>
-         <?php print $node->field_resource_blocks[$i]['value']; ?>
-       </div><?php
-     }
-   }?>
-   
-   <!-- Let modules add more content -->
-
-   <?php print $content ?>
-</div>
-
-<!-- Table of contents -->
-<div id="tripal_library_toc" class="tripal_toc">
-   <div id="tripal_library_toc_title" class="tripal_toc_title">Resources</div>
-   <ul id="tripal_library_toc_list" class="tripal_toc_list">
-   
-     <!-- Resource Links CCK elements --><?php
-     for($i = 0; $i < count($node->field_resource_links); $i++){
-       if($node->field_resource_links[$i]['value']){
-         $matches = preg_split("/\|/",$node->field_resource_links[$i]['value']);?>
-         <li><a href="<?php print $matches[1] ?>" target="_blank"><?php print $matches[0] ?></a></li><?php
-       }
-     }?>
-     
-     <?php // ADD CUSTOMIZED <li> LINKS HERE ?>
-   </ul>
-</div>
-
-<?php } ?>

+ 69 - 0
tripal_library/theme/tripal_feature/tripal_feature.libraries.tpl.php

@@ -0,0 +1,69 @@
+<?php
+$feature = $variables['node']->feature;
+
+// expand the feature object to include the libraries from the library
+// table in chado.
+$options = array('return_array' => 1);
+$feature = tripal_core_expand_chado_vars($feature, 'table', 'library_feature', $options);
+$library_features = $feature->library_feature;
+
+
+if (count($library_features) > 0) {?>
+  <div id="tripal_feature-library_list-box" class="tripal_feature-info-box tripal-info-box">
+    <div class="tripal_feature-info-box-title tripal-info-box-title">Libraries</div>
+    <div class="tripal_feature-info-box-desc tripal-info-box-desc">The following libraries are associated with this feature.</div> <?php 
+    
+    // the $headers array is an array of fields to use as the colum headers. 
+    // additional documentation can be found here 
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    // This table for the analysis has a vertical header (down the first column)
+    // so we do not provide headers here, but specify them in the $rows array below.
+    $headers = array('Library Name', 'Type');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+    $rows = array();
+    foreach ($library_features as $library_feature){ 
+      
+      $libname = $library_feature->library_id->name;
+      if ($library_feature->library_id->nid) {
+        $libname = l($libname, "node/" . $library_feature->library_id->nid, array('attributes' => array('target' => '_blank')));
+      }
+      
+      $typename = $library_feature->library_id->type_id->name;
+      if ($typename == 'cdna_library') {
+        $typename = 'cDNA';
+      }
+      else if ($typename == 'bac_library') {
+        $typename = 'BAC';
+      }
+      
+      $rows[] = array(
+        $libname,
+        $typename
+      );      
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_feature-table-libraries',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>  
+  </div><?php
+}

+ 0 - 57
tripal_library/theme/tripal_feature/tripal_feature_libraries.tpl.php

@@ -1,57 +0,0 @@
-<?php
-$feature = $variables['node']->feature;
-
-// expand the feature object to include the libraries from the library_feature
-// table in chado.
-$feature = tripal_core_expand_chado_vars($feature,'table','library_feature');
-
-// get the references. if only one reference exists then we want to convert
-// the object into an array, otherwise the value is an array
-$library_features = $feature->library_feature;
-if (!$library_features) {
-   $library_features = array();
-} 
-elseif (!is_array($library_features)) { 
-   $library_features = array($library_features); 
-}
-
-// don't show this page if there are no libraries
-if (count($library_features) > 0) { ?>
-  <div id="tripal_feature-libraries-box" class="tripal_feature-info-box tripal-info-box">
-    <div class="tripal_feature-info-box-title tripal-info-box-title">Libraries</div>
-    <div class="tripal_feature-info-box-desc tripal-info-box-desc">This <?php print $feature->type_id->name ?> is derived, or can be located in the following libraries</div>
-    <table id="tripal_feature-libraries-table" class="tripal_feature-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Library Name</th>
-        <th>Type</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($library_features as $library_feature) {
-        $class = 'tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-           $class = 'tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td><?php 
-            if ($library_feature->library_id->nid) {
-               print "<a href=\"". url("node/".$library_feature->library_id->nid) . "\">".$library_feature->library_id->name."</a>";
-            } else {
-               print $library_feature->library_id->name;
-            } ?>
-          </td>
-          <td> <?php 
-              if ($library_feature->library_id->type_id->name == 'cdna_library') {
-                 print 'cDNA';
-              } else if ($library_feature->library_id->type_id->name == 'bac_library') {
-                 print 'BAC';
-              } else {
-                 print $library_feature->library_id->type_id->name;
-              } ?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table> 
-  </div><?php 
-} 
-

+ 0 - 4
tripal_library/theme/tripal_library_admin.tpl.php → tripal_library/theme/tripal_library.help.tpl.php

@@ -1,7 +1,3 @@
-<h3>Tripal Library Administrative Tools Quick Links:</h3>
-<ul>
- <li><a href="<?php print url("admin/tripal/tripal_library/configuration") ?>">Library Configuration</a></li>
-</ul>
 <h3>Module Description:</h3>
 <p>The Tripal Library module is an interface for the Chado Library module which groups features (sequences) into genetic libraries.
     This module provides support for visualization of "library" pages, editing and updating.</p>

+ 1 - 0
tripal_library/theme/tripal_library.theme.inc

@@ -0,0 +1 @@
+<?php

+ 105 - 0
tripal_library/theme/tripal_library/tripal_library.base.tpl.php

@@ -0,0 +1,105 @@
+<?php
+
+$library  = $variables['node']->library;
+
+// get the library description. IT uses a tern name of 'Library Description'
+$libprop = tripal_library_get_property($library->library_id, 'Library Description');
+$description = $libprop->value;
+
+
+?>
+<div id="tripal_library-base-box" class="tripal_library-info-box tripal-info-box">
+  <div class="tripal_library-info-box-title tripal-info-box-title">Library Details</div>
+  <div class="tripal_library-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+  // the $headers array is an array of fields to use as the colum headers. 
+  // additional documentation can be found here 
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  // This table for the library has a vertical header (down the first column)
+  // so we do not provide headers here, but specify them in the $rows array below.
+  $headers = array();
+  
+  // the $rows array contains an array of rows where each row is an array
+  // of values for each column of the table in that row.  Additional documentation
+  // can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+  $rows = array();
+
+  // Name row
+  $rows[] = array(
+    array(
+      'data' => 'Library Name',
+      'header' => TRUE
+    ),
+    $library->name
+  );
+
+  // Unique row
+  $rows[] = array(
+    array(
+      'data' => 'Unique Name',
+      'header' => TRUE
+    ),
+    $library->uniquename
+  );
+  
+  // Organism row
+  $organism = $library->organism_id->genus ." " . $library->organism_id->species ." (" .$library->organism_id->common_name .")";
+  if ($library->organism_id->nid) {
+    $organism = l("<i>" . $library->organism_id->genus . " " . $library->organism_id->species . "</i> (" .$library->organism_id->common_name .")", "node/".$library->organism_id->nid, array('html' => TRUE));
+  } 
+  $rows[] = array(
+    array(
+      'data' => 'Organism',
+      'header' => TRUE
+    ),
+    $organism
+  );
+
+  // Library Type row
+  $rows[] = array(
+    array(
+      'data' => 'Type',
+      'header' => TRUE
+    ),
+    $library->type_id->name,
+  );
+  
+  // allow site admins to see the library ID
+  if (user_access('access administration pages')) {
+    // Library ID
+    $rows[] = array(
+      array(
+        'data' => 'Library ID',
+        'header' => TRUE
+      ),
+      $library->library_id,
+    );
+  }
+  
+  // the $table array contains the headers and rows array as well as other
+  // options for controlling the display of the table.  Additional
+  // documentation can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  $table = array(
+    'header' => $headers,
+    'rows' => $rows,
+    'attributes' => array(
+      'id' => 'tripal_library-table-base',
+    ),
+    'sticky' => FALSE,
+    'caption' => '',
+    'colgroups' => array(),
+    'empty' => '',
+  );
+  
+  // once we have our table array structure defined, we call Drupal's theme_table()
+  // function to generate the table.
+  print theme_table($table); 
+  
+  // now add in the description below the table if one exists
+  if ($description) { ?>
+    <div style="text-align: justify"><?php print $description; ?></div> <?php  
+  }
+  ?>
+</div>

+ 62 - 0
tripal_library/theme/tripal_library/tripal_library.properties.tpl.php

@@ -0,0 +1,62 @@
+<?php
+
+$library = $variables['node']->library;
+$options = array('return_array' => 1);
+$library = tripal_core_expand_chado_vars($library, 'table', 'libraryprop', $options);
+$props = $library->libraryprop;
+
+// iterate through the properties and remove the 'library_description' as it is
+// already displayed on the base template.
+$properties = array();
+foreach ($props as $prop) {
+  if ($prop->type_id->name == 'Library Description') {
+    continue;
+  }
+  $properties[] = $prop;
+}
+
+if(count($properties) > 0){ ?>
+
+  <div id="tripal_library-properties-box" class="tripal_library-info-box tripal-info-box">
+    <div class="tripal_library-info-box-title tripal-info-box-title">Properties</div> <?php
+
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Property Name', 'Value');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($properties as $property){
+      $property = tripal_core_expand_chado_vars($property,'field','libraryprop.value');
+      $rows[] = array(
+        ucfirst(preg_replace('/_/', ' ', $property->type_id->name)),
+        urldecode($property->value)
+      );
+    }
+     
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_library-table-properties',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php
+}

+ 85 - 0
tripal_library/theme/tripal_library/tripal_library.publications.tpl.php

@@ -0,0 +1,85 @@
+<?php
+$library = $variables['node']->library;
+
+// expand library to include pubs 
+$options = array('return_array' => 1);
+$library = tripal_core_expand_chado_vars($library, 'table', 'library_pub', $options);
+$library_pubs = $library->library_pub; 
+
+
+if (count($library_pubs) > 0) { ?>
+  <div id="tripal_library_pub-pub-box" class="tripal_library_pub-info-box tripal-info-box">
+    <div class="tripal_library_pub-info-box-title tripal-info-box-title">Publications</div>
+    <div class="tripal_library_pub-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Year', 'Publication');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($library_pubs as $library_pub) {
+      $pub = $library_pub->pub_id;
+      $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+      $citation = $pub->title;  // use the title as the default citation
+      
+      // get the citation for this pub if it exists
+      $values = array(
+        'pub_id' => $pub->pub_id, 
+        'type_id' => array(
+          'name' => 'Citation',
+        ),
+      );
+      $options = array('return_array' => 1);
+      $citation_prop = tripal_core_generate_chado_var('pubprop', $values, $options); 
+      if (count($citation_prop) == 1) {
+        $citation_prop = tripal_core_expand_chado_vars($citation_prop, 'field', 'pubprop.value');
+        $citation = $citation_prop[0]->value;
+      }
+      
+      // if the publication is synced then link to it
+      if ($pub->nid) {
+        // replace the title with a link
+        $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
+        $patterns = array(
+          '/(\()/', '/(\))/',
+          '/(\])/', '/(\[)/',
+          '/(\{)/', '/(\})/',
+          '/(\+)/', '/(\.)/', '/(\?)/',
+        );
+        $fixed_title = preg_replace($patterns, "\\\\$1", $pub->title);
+        $citation = preg_replace('/' . $fixed_title . '/', $link, $citation);
+      }
+      
+      $rows[] = array(
+        $pub->pyear,
+        $citation,
+      );
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_library-table-publications',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php 
+}

+ 70 - 0
tripal_library/theme/tripal_library/tripal_library.references.tpl.php

@@ -0,0 +1,70 @@
+<?php
+$library = $variables['node']->library;
+$references = array();
+
+// Second, expand the library object to include the records from the library_dbxref table
+$options = array('return_array' => 1);
+$library = tripal_core_expand_chado_vars($library, 'table', 'library_dbxref', $options);
+$library_dbxrefs = $library->library_dbxref;
+if (count($library_dbxrefs) > 0 ) {
+  foreach ($library_dbxrefs as $library_dbxref) {    
+    $references[] = $library_dbxref->dbxref_id;
+  }
+}
+
+
+if(count($references) > 0){ ?>
+  <div id="tripal_library-references-box" class="tripal_library-info-box tripal-info-box">
+    <div class="tripal_library-info-box-title tripal-info-box-title">Cross References</div>
+    <div class="tripal_library-info-box-desc tripal-info-box-desc">External references for this <?php print $library->type_id->name ?></div><?php
+     
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Dababase', 'Accession');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+ 
+    foreach ($references as $dbxref){
+     
+      $dbname = $dbxref->db_id->name; 
+      if ($dbxref->db_id->url) { 
+        $dbname = l($dbname, $dbxref->db_id->url, array('attributes' => array('target' => '_blank')));
+      } 
+      
+      $accession = $dbxref->accession; 
+      if ($dbxref->db_id->urlprefix) { 
+        $accession = l($accession, $dbxref->db_id->urlprefix . $dbxref->accession, array('attributes' => array('target' => '_blank')));
+      } 
+      $rows[] = array(
+        $dbname,
+        $accession
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_library-table-references',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div><?php 
+}?>
+

+ 53 - 0
tripal_library/theme/tripal_library/tripal_library.synonyms.tpl.php

@@ -0,0 +1,53 @@
+<?php
+$library = $variables['node']->library;
+
+// expand the library object to include the synonyms from the library_synonym 
+// table in chado.
+$options = array('return_array' => 1);
+$library = tripal_core_expand_chado_vars($library, 'table', 'library_synonym', $options);
+$synonyms = $library->library_synonym;
+
+if(count($synonyms) > 0){ ?>
+  <div id="tripal_library-synonyms-box" class="tripal_library-info-box tripal-info-box">
+    <div class="tripal_library-info-box-title tripal-info-box-title">Synonyms</div>
+    <div class="tripal_library-info-box-desc tripal-info-box-desc">The library '<?php print $library->name ?>' has the following synonyms</div><?php
+    
+    // the $headers array is an array of fields to use as the colum headers. 
+    // additional documentation can be found here 
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    // This table for the analysis has a vertical header (down the first column)
+    // so we do not provide headers here, but specify them in the $rows array below.
+    $headers = array('Synonym');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+    $rows = array();
+    foreach ($synonyms as $library_synonym){
+      $rows[] = array(
+        $library_synonym->synonym_id->name
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_library-table-synonyms',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+      print theme_table($table); ?>
+  </div><?php
+}

+ 19 - 0
tripal_library/theme/tripal_library/tripal_library.teaser.tpl.php

@@ -0,0 +1,19 @@
+<?php
+$node    = $variables['node'];
+$library = $variables['node']->library;
+
+// get the library description. IT uses a tern name of 'Library Description'
+$libprop = tripal_library_get_property($library->library_id, 'Library Description');
+$description = $libprop->value; ?>
+
+<div class="tripal_library-teaser tripal-teaser"> 
+  <div class="tripal-library-teaser-title tripal-teaser-title"><?php 
+    print l($node->title, "node/$node->nid", array('html' => TRUE));?>
+  </div>
+  <div class="tripal-library-teaser-text tripal-teaser-text"><?php 
+    print substr($description, 0, 650);
+    if (strlen($description) > 650) {
+      print "... " . l("[more]", "node/$node->nid");
+    } ?>
+  </div>
+</div>

+ 71 - 0
tripal_library/theme/tripal_library/tripal_library.terms.tpl.php

@@ -0,0 +1,71 @@
+<?php
+
+$library = $variables['node']->library;
+
+$options = array('return_array' => 1);
+$library = tripal_core_expand_chado_vars($library, 'table', 'library_cvterm', $options);
+$terms = $library->library_cvterm;
+
+// order the terms by CV
+$s_terms = array();
+foreach ($terms as $term) {
+  $s_terms[$term->cvterm_id->cv_id->name][] = $term;  
+}
+
+if (count($s_terms) > 0) { ?>
+  <div id="tripal_library-terms-box" class="tripal_library-info-box tripal-info-box">
+    <div class="tripal_library-info-box-title tripal-info-box-title">Annotated Terms</div>
+    <div class="tripal_library-info-box-desc tripal-info-box-desc">The following terms have been associated with this <?php print $node->library->type_id->name ?>:</div>  <?php
+    
+    // iterate through each term
+    $i = 0;
+    foreach ($s_terms as $cv => $terms) {  
+      // the $headers array is an array of fields to use as the colum headers.
+      // additional documentation can be found here
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $headers = array('Term', 'Definition');
+      
+      // the $rows array contains an array of rows where each row is an array
+      // of values for each column of the table in that row.  Additional documentation
+      // can be found here:
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $rows = array();
+      
+      foreach ($terms as $term) { 
+
+        $accession = $term->cvterm_id->dbxref_id->accession;
+        if (is_numeric($term->cvterm_id->dbxref_id->accession)) {
+          $accession = $term->cvterm_id->dbxref_id->db_id->name . ":" . $term->cvterm_id->dbxref_id->accession;
+        }
+        if ($term->cvterm_id->dbxref_id->db_id->urlprefix) {
+          $accession = l($accession, $term->cvterm_id->dbxref_id->db_id->urlprefix . $accession, array('attributes' => array("target" => '_blank')));
+        } 
+        
+        $rows[] = array(
+          $accession,
+          $term->cvterm_id->name
+        );
+      } 
+      // the $table array contains the headers and rows array as well as other
+      // options for controlling the display of the table.  Additional
+      // documentation can be found here:
+      // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+      $table = array(
+        'header' => $headers,
+        'rows' => $rows,
+        'attributes' => array(
+          'id' => "tripal_library-table-terms-$i",
+        ),
+        'sticky' => FALSE,
+        'caption' => '<b>Vocabulary: ' . ucwords(preg_replace('/_/', ' ', $cv)) . '</b>',
+        'colgroups' => array(),
+        'empty' => '',
+      );
+      
+      // once we have our table array structure defined, we call Drupal's theme_table()
+      // function to generate the table.
+      print theme_table($table);
+      $i++;
+    } ?>
+  </div> <?php
+} ?>

+ 0 - 54
tripal_library/theme/tripal_library/tripal_library_base.tpl.php

@@ -1,54 +0,0 @@
-<?php
-
-$library  = $variables['node']->library;
-
-// expand the library to include the properties so that we can get the description
-$library = tripal_core_expand_chado_vars($library,'table','libraryprop', array('return_array' => 1));  
-$libraryprops = $library->libraryprop;
-if (count($libraryprops) > 0){ 
-  foreach ($libraryprops as $property) {
-    if($property->type_id->name == 'library_description') {
-      $property = tripal_core_expand_chado_vars($property,'field','libraryprop.value');
-      $library_description = $property->value;      
-    }
-  }
-}
-
-?>
-<div id="tripal_library-base-box" class="tripal_library-info-box tripal-info-box">
-  <div class="tripal_library-info-box-title tripal-info-box-title">Library Details</div>
-  <div class="tripal_library-info-box-desc tripal-info-box-desc"></div>
-
-   <?php if(strcmp($library->is_obsolete,'t')==0){ ?>
-      <div class="tripal_library-obsolete">This library is obsolete</div>
-   <?php }?>
-   <table id="tripal_library-base-table" class="tripal_library-table tripal-table tripal-table-vert">
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th nowrap>Unique Name</th>
-        <td><?php print $library->uniquename; ?></td>
-      </tr>
-      <tr class="tripal_library-table-odd-row tripal-table-odd-row">
-        <th>Internal ID</th>
-        <td><?php print $library->library_id; ?></td>
-      </tr>
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th>Organism</th>
-        <td>
-          <?php if ($library->organism_id->nid) { 
-      	   print "<a href=\"".url("node/".$library->organism_id->nid)."\">".$library->organism_id->genus ." " . $library->organism_id->species ." (" .$library->organism_id->common_name .")</a>";      	 
-          } else { 
-            print $library->organism_id->genus ." " . $library->organism_id->species ." (" .$library->organism_id->common_name .")";
-          } ?>
-        </td>
-      </tr>      
-      <tr class="tripal_library-table-odd-row tripal-table-odd-row">
-        <th>Type</th>
-        <td><?php print $library->type_id->definition ?></td>
-      </tr>
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th>Description</th>
-        <td><?php print $library_description ?>
-        </td>
-     	</tr>           	                                
-   </table>
-</div>

+ 0 - 44
tripal_library/theme/tripal_library/tripal_library_properties.tpl.php

@@ -1,44 +0,0 @@
-<?php
-$library = $node->library;
-
-// expand the library to include the properties.
-$library = tripal_core_expand_chado_vars($library, 'table', 'libraryprop', array('return_array' => 1));
-$libraryprops = $library->libraryprop;
-$properties = array();
-
-if (count($libraryprops) > 0) {
-  foreach ($libraryprops as $property) {
-    // we want to keep all properties but the library_description as that
-    // property is shown on the base template page.
-    if($property->type_id->name != 'library_description') {
-      $property = tripal_core_expand_chado_vars($property,'field','libraryprop.value');
-      $properties[] = $property;
-    }
-  }
-}
-
-if (count($properties) > 0) { ?>
-  <div id="tripal_library-properties-box" class="tripal_library-info-box tripal-info-box">
-    <div class="tripal_library-info-box-title tripal-info-box-title">Properties</div>
-    <div class="tripal_library-info-box-desc tripal-info-box-desc">Properties for this library include:</div>
-    <table class="tripal_library-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Property Name</th>
-        <th>Value</th>
-      </tr> <?php
-      $i = 0;
-      foreach ($properties as $property) {
-        $class = 'tripal_library-table-odd-row tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-           $class = 'tripal_library-table-odd-row tripal-table-even-row';
-        }
-        $i++; 
-        ?>
-        <tr class="<?php print $class ?>">
-          <td><?php print ucfirst(preg_replace('/_/', ' ', $property->type_id->name)) ?></td>
-          <td><?php print $property->value ?></td>
-        </tr><?php 
-      } ?>
-    </table>
-  </div> <?php
-}

+ 0 - 49
tripal_library/theme/tripal_library/tripal_library_references.tpl.php

@@ -1,49 +0,0 @@
-<?php
-$library = $variables['node']->library;
-
-// expand the library object to include the external references stored
-// in the library_dbxref table
-$options = array('return_array' => 1);
-$library = tripal_core_expand_chado_vars($library,'table','library_dbxref', $options);
-$references = $library->library_dbxref;
-
-
-if(count($references) > 0){ ?>
-  <div id="tripal_library-references-box" class="tripal_library-info-box tripal-info-box">
-    <div class="tripal_library-info-box-title tripal-info-box-title">Cross References</div>
-    <div class="tripal_library-info-box-desc tripal-info-box-desc">External references for this <?php print $library->type_id->name ?> library</div>
-    <table id="tripal_library-references-table" class="tripal_library-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Dababase</th>
-        <th>Accession</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($references as $library_dbxref) { 
-        $dbxref = $library_dbxref->dbxref_id;
-        $class = 'tripal_library-table-odd-row tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-           $class = 'tripal_library-table-odd-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td> <?php 
-            if ($dbxref->db_id->url) { 
-              print l($dbxref->db_id->name, $dbxref->db_id->url);
-            } 
-            else { 
-              print $dbxref->db_id->name; 
-            } ?>
-          </td>
-          <td> <?php 
-            if ($dbxref->db_id->urlprefix) { 
-              print l($dbxref->accession, $dbxref->db_id->urlprefix.$dbxref->accession);
-            } 
-            else { 
-              print $dbxref->accession; 
-            } ?>
-          </td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
-  </div><?
-}

+ 0 - 31
tripal_library/theme/tripal_library/tripal_library_synonyms.tpl.php

@@ -1,31 +0,0 @@
-<?php
-$library = $variables['node']->library;
-
-// expand the library object to include the synonyms from the library_synonym 
-// table in chado.
-$options = array('return_array' => 1); 
-$library = tripal_core_expand_chado_vars($library,'table','library_synonym', $options);
-$synonyms = $library->library_synonym;
-
-if (count($synonyms) > 0) { ?>
-  <div id="tripal_library-synonyms-box" class="tripal_library-info-box tripal-info-box">
-    <div class="tripal_library-info-box-title tripal-info-box-title">Synonyms</div>
-    <div class="tripal_library-info-box-desc tripal-info-box-desc">The library '<?php print $library->name ?>' has the following synonyms</div>
-    <table id="tripal_library-synonyms-table" class="tripal_library-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Synonym</th>
-      </tr> <?php
-      $i = 0; 
-      foreach ($synonyms as $library_synonym) {
-        $class = 'tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-          $class = 'tripal-table-even-row';
-        }?>
-        <tr class="<?php print $class ?>">
-          <td> <?php print $library_synonym->synonym_id->name?></td>
-        </tr> <?php
-        $i++;  
-      } ?>
-    </table>
-  </div> <?php 
-}

+ 0 - 54
tripal_library/theme/tripal_library/tripal_library_teaser.tpl.php

@@ -1,54 +0,0 @@
-<?php
-
-$library  = $variables['node']->library;
-
-// expand the library to include the properties so that we can get the description
-$library = tripal_core_expand_chado_vars($library,'table','libraryprop', array('return_array' => 1));  
-$libraryprops = $library->libraryprop;
-if (count($libraryprops) > 0){ 
-  foreach ($libraryprops as $property) {
-    if($property->type_id->name == 'library_description') {
-      $property = tripal_core_expand_chado_vars($property,'field','libraryprop.value');
-      $library_description = $property->value;      
-    }
-  }
-}
-
-?>
-<div id="tripal_library-base-box" class="tripal_library-info-box tripal-info-box">
-  <div class="tripal_library-info-box-title tripal-info-box-title">Library Details</div>
-  <div class="tripal_library-info-box-desc tripal-info-box-desc"></div>
-
-   <?php if(strcmp($library->is_obsolete,'t')==0){ ?>
-      <div class="tripal_library-obsolete">This library is obsolete</div>
-   <?php }?>
-   <table id="tripal_library-base-table" class="tripal_library-table tripal-table tripal-table-vert">
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th nowrap>Unique Name</th>
-        <td><?php print $library->uniquename; ?></td>
-      </tr>
-      <tr class="tripal_library-table-odd-row tripal-table-odd-row">
-        <th>Internal ID</th>
-        <td><?php print $library->library_id; ?></td>
-      </tr>
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th>Organism</th>
-        <td>
-          <?php if ($library->organism_id->nid) { 
-           print "<a href=\"".url("node/".$library->organism_id->nid)."\">".$library->organism_id->genus ." " . $library->organism_id->species ." (" .$library->organism_id->common_name .")</a>";         
-          } else { 
-            print $library->organism_id->genus ." " . $library->organism_id->species ." (" .$library->organism_id->common_name .")";
-          } ?>
-        </td>
-      </tr>      
-      <tr class="tripal_library-table-odd-row tripal-table-odd-row">
-        <th>Type</th>
-        <td><?php print $library->type_id->definition ?></td>
-      </tr>
-      <tr class="tripal_library-table-even-row tripal-table-even-row">
-        <th>Description</th>
-        <td><?php print $library_description ?>
-        </td>
-      </tr>                                             
-   </table>
-</div>

+ 0 - 51
tripal_library/theme/tripal_library/tripal_library_terms.tpl.php

@@ -1,51 +0,0 @@
-<?php
-
-$library = $node->library;
-
-// expand the library object to inlucde the records from the library_cvterm table
-$options = array('return_array' => 1);
-$library = tripal_core_expand_chado_vars($library, 'table', 'library_cvterm', $options);
-$terms = $library->library_cvterm;
-
-// re-organize the terms by CV
-$s_terms = array();
-if (count($terms) > 0) {
-  foreach ($terms as $term) {
-    $s_terms[$term->cvterm_id->cv_id->name][] = $term;  
-  }
-}
-
-if (count($s_terms) > 0) { ?>
-  <div id="tripal_library-terms-box" class="tripal_library-info-box tripal-info-box">
-    <div class="tripal_library-info-box-title tripal-info-box-title">Annotated Terms</div>
-    <div class="tripal_library-info-box-desc tripal-info-box-desc">The following terms have been associated with this <?php print $node->library->type_id->name ?>:</div>  <?php
-    // iterate through each term
-    foreach ($s_terms as $cv => $terms) {  ?>
-      <p><?php print ucwords(preg_replace('/_/', ' ', $cv)) ?></p>
-      <table class="tripal_library-table tripal-table tripal-table-horz">
-        <tr>
-          <th>Term</th>
-          <th>Definition</th>
-        </tr> <?php
-        $i = 0;
-        foreach ($terms as $term) { 
-          $class = 'tripal_library-table-odd-row tripal-table-odd-row';
-          if($i % 2 == 0 ){
-            $class = 'tripal_library-table-even-row tripal-table-even-row';
-          }
-          $accession = $term->cvterm_id->dbxref_id->accession;
-          if (is_numeric($term->cvterm_id->dbxref_id->accession)) {
-            $accession = $term->cvterm_id->dbxref_id->db_id->name . ":" . $term->cvterm_id->dbxref_id->accession;
-          }
-          if ($term->cvterm_id->dbxref_id->db_id->urlprefix) {
-            $accession =  "<a href=\"" . $term->cvterm_id->dbxref_id->db_id->urlprefix . "$accession\" target=\"_blank\">$accession</a>";
-          } ?>
-          <tr class="<?php print $class ?>">
-            <td><?php print $accession ?></td>
-            <td><?php print $term->cvterm_id->name ?></td>
-          </tr> <?php
-        } ?>
-      </table> <?php
-  } ?>
-  </div> <?php
-} ?>

+ 73 - 0
tripal_library/theme/tripal_organism/tripal_organism.libraries.tpl.php

@@ -0,0 +1,73 @@
+<?php
+$organism = $variables['node']->organism;
+
+// expand the organism object to include the libraries from the library
+// table in chado.
+$options = array('return_array' => 1);
+$organism = tripal_core_expand_chado_vars($organism, 'table', 'library', $options);
+$libraries = $organism->library;
+
+
+if (count($libraries) > 0) {?>
+  <div id="tripal_organism-library_list-box" class="tripal_organism-info-box tripal-info-box">
+    <div class="tripal_organism-info-box-title tripal-info-box-title">Libraries</div>
+    <div class="tripal_organism-info-box-desc tripal-info-box-desc">The following libraries are associated with this organism.</div> <?php 
+    
+    // the $headers array is an array of fields to use as the colum headers. 
+    // additional documentation can be found here 
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    // This table for the analysis has a vertical header (down the first column)
+    // so we do not provide headers here, but specify them in the $rows array below.
+    $headers = array('Library Name', 'Type');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+    $rows = array();
+    foreach ($libraries as $library){ 
+      
+      $libname = $library->name;
+      if ($library->nid) {
+        $libname = l($libname, "node/".$library->nid, array('attributes' => array('target' => '_blank')));
+      }
+      
+      $typename = $library->type_id->name;
+      if ($typename == 'cdna_library') {
+        $typename = 'cDNA';
+      }
+      else if ($typename == 'bac_library') {
+        $typename = 'BAC';
+      }
+      
+      $rows[] = array(
+        $libname,
+        $typename
+      );      
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_organism-table-libraries',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>  
+  </div><?php
+}
+
+
+
+

+ 0 - 74
tripal_library/theme/tripal_organism/tripal_organism_libraries.tpl.php

@@ -1,74 +0,0 @@
-<?php
-$organism = $variables['node']->organism;
-
-// expand the organism object to include the libraries from the library
-// table in chado.
-$organism = tripal_core_expand_chado_vars($organism,'table','library');
-
-
-// get the references. if only one reference exists then we want to convert
-// the object into an array, otherwise the value is an array
-$libraries = $organism->library;
-if (!$libraries) {
-   $libraries = array();
-} 
-elseif (!is_array($libraries)) { 
-   $libraries = array($libraries); 
-}
-
-if (count($libraries) > 0) {?>
-  <div id="tripal_organism-library_list-box" class="tripal_organism-info-box tripal-info-box">
-    <div class="tripal_organism-info-box-title tripal-info-box-title">Libraries</div>
-    <div class="tripal_organism-info-box-desc tripal-info-box-desc">The following libraries are associated with this organism.</div>
-    <table id="tripal_organism-table-library_list" class="tripal_organism-table tripal-table tripal-table-horz">     
-      <tr class="tripal_organism-table-odd-row tripal-table-even-row">
-        <th>Library Name</th>
-        <th>Description</th>
-        <th>Type</th>
-      </tr> <?php
-      foreach ($libraries as $library){ 
-        // expand the library to include the properties.
-        $library = tripal_core_expand_chado_vars($library,'table','libraryprop');
-        $library = tripal_core_expand_chado_vars($library,'field','libraryprop.value');
-        $class = 'tripal_organism-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-          $class = 'tripal_organism-table-odd-row tripal-table-even-row';
-        } ?>
-        <tr class="<?php print $class ?>">
-          <td><?php 
-            if($library->nid){    
-              $link =  url("node/$library->nid");        
-              print "<a href=\"$link\">$library->name</a>";
-            } 
-            else {
-              print $library->name;
-            } ?>
-          </td>
-          <td><?php 
-            // right now we only have one property for libraries. So we can just
-            // refernece it directly.  If we had more than one property
-            // we would need to convert this to an if statment and loop
-            // until we found the right one.
-            print $library->libraryprop->value?>
-          </td>
-          <td> <?php 
-            if ($library->type_id->name == 'cdna_library') {
-              print 'cDNA';
-            } 
-            else if ($library->type_id->name == 'bac_library') {
-              print 'BAC';
-            } 
-            else {
-              print $library->type_id->name;
-            }?>
-          </td>
-        </tr> <?php
-        $i++; 
-      }?>  
-    </table> 
-  </div><?php
-}
-
-
-
-

+ 96 - 14
tripal_library/tripal_library.install

@@ -49,6 +49,7 @@ function tripal_library_install() {
   tripal_library_add_mview_library_feature_count();
 
   // add cvterms
+  tripal_library_add_cvs();
   tripal_library_add_cvterms();
 }
 
@@ -152,6 +153,13 @@ function tripal_library_add_mview_library_feature_count(){
   tripal_add_mview($view_name, 'tripal_library', $schema, $sql, $comment);
 }
 
+/**
+ * Adds new CV's used by this module
+ */
+function tripal_library_add_cvs(){
+  tripal_cv_add_cv('library_property', 'Contains properties for libraries');
+  tripal_cv_add_cv('library_type', 'Contains terms for types of libraries (e.g. BAC, cDNA, FOSMID, etc).');
+}
 /**
  * @ingroup tripal_library
  */
@@ -160,20 +168,94 @@ function tripal_library_add_cvterms() {
   // Insert cvterm 'library_description' into cvterm table of chado
   // database. This CV term is used to keep track of the library
   // description in the libraryprop table.
-  tripal_cv_add_cvterm(array('name' => 'library_description', 'def' => 'Description of a library'),
-    'tripal', 0, 1, 'tripal');
+  tripal_cv_add_cvterm(
+     array(
+       'name' => 'Library Description', 
+       'def' => 'Description of a library'
+     ),
+    'library_property', 0, 1, 'tripal'
+   );
 
   // add cvterms for the map unit types
-  tripal_cv_add_cvterm(array('name' => 'cdna_library','def' => 'cDNA library'),
-    'tripal_library_types', 0, 1, 'tripal');
-  tripal_cv_add_cvterm(array('name' => 'bac_library','def' => 'Bacterial Artifical Chromsome (BAC) library'),
-    'tripal_library_types', 0, 1, 'tripal');
-  tripal_cv_add_cvterm(array('name' => 'fosmid_library','def' => 'Fosmid library'),
-    'tripal_library_types', 0, 1, 'tripal');
-  tripal_cv_add_cvterm(array('name' => 'cosmid_library','def' => 'Cosmid library'),
-    'tripal_library_types', 0, 1, 'tripal');
-  tripal_cv_add_cvterm(array('name' => 'yac_library','def' => 'Yeast Artificial Chromosome (YAC) library'),
-    'tripal_library_types', 0, 1, 'tripal');
-  tripal_cv_add_cvterm(array('name' => 'genomic_library','def' => 'Genomic Library'),
-    'tripal_library_types', 0, 1, 'tripal');
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'cdna_library',
+      'def' => 'cDNA library'
+    ),
+    'library_type', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'bac_library',
+      'def' => 'Bacterial Artifical Chromsome (BAC) library'
+    ),
+    'library_type', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'fosmid_library',
+      'def' => 'Fosmid library'
+    ),
+    'library_type', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'cosmid_library',
+      'def' => 'Cosmid library'
+    ),
+    'library_type', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'yac_library',
+      'def' => 'Yeast Artificial Chromosome (YAC) library'
+    ),
+    'library_type', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'genomic_library',
+      'def' => 'Genomic Library'),
+    'library_type', 0, 1, 'tripal'
+  );
+}
+
+/**
+ * This is the required update for tripal_library when upgrading from Drupal core API 6.x. 
+ */
+function tripal_library_update_7000() {
+  
+  // the library types were formerly in a vocabulary named 'tripal_library_types'.
+  // rename that to just be 'library_type'
+  $cv = tripal_cv_get_cv_by_name('tripal_library_types');
+  $match = array(
+    'cv_id' => $cv->cv_id
+  );
+  $values = array(
+    'name' => 'library_type'
+  );
+  $success = tripal_core_chado_update('cv', $match, $values);
+  if (!$success) {
+    throw new DrupalUpdateException('Failed to rename tripal_library_types CV.');
+  }
+  
+  
+  // For Tripal in Drupal 6 the library_description cvterm was stored in the 
+  // 'tripal' CV.  It should be stored in the new library_property CV that
+  // is added by this module for Tripal 2.0 and Drupal 7.  So, we need to 
+  // reset the CV ID for that term and rename the term to 'Library Description'
+  tripal_library_add_cvs();
+  $cv = tripal_cv_get_cv_by_name('library_property');
+  $cvterm = tripal_cv_get_cvterm_by_name('library_description');
+  $match = array(
+    'cvterm_id' => $cvterm->cvterm_id,
+  );
+  $values = array(
+    'cv_id' => $cv->cv_id,
+    'name' => 'Library Description',
+  );
+  tripal_core_chado_update('cvterm', $match, $values);
+  if (!$success) {
+    throw new DrupalUpdateException('Failed to move library properties to new library_property CV.');
+  }
 }

+ 132 - 498
tripal_library/tripal_library.module

@@ -9,7 +9,9 @@
  */
 
 require('api/tripal_library.api.inc');
+require('theme/tripal_library.theme.inc');
 require('includes/tripal_library.admin.inc');
+require('includes/tripal_library.chado_node.inc');
 
 /**
  * Provide information to drupal about the node types that we're creating
@@ -26,11 +28,24 @@ function tripal_library_node_info() {
     'has_title' => FALSE,
     'title_label' => t('Library'),
     'has_body' => FALSE,
-    'locked' => TRUE
+    'locked' => TRUE,
+    'chado_node_api' => array(
+      'base_table' => 'library',
+      'hook_prefix' => 'chado_library',
+      'record_type_title' => array(
+        'singular' => t('Library'),
+        'plural' => t('Libraries')
+      ),
+      'sync_filters' => array(
+        'type_id' => TRUE,
+        'organism_id' => TRUE
+      ),
+    )
   );
   return $nodes;
 }
 
+
 /**
  * Set the permission types that the chado module uses.  Essentially we
  * want permissionis that protect creation, editing and deleting of chado
@@ -62,53 +77,7 @@ function tripal_library_permisssions() {
     ),
   );
 }
-/**
- * Implement hook_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_library
- */
-function chado_library_node_access($node, $op, $account) {
-  if ($op == 'create') {
-    if (!user_access('create chado_library content', $account)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-  if ($op == 'update') {
-    if (!user_access('edit chado_library content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'delete') {
-    if (!user_access('delete chado_library content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'view') {
-    if (!user_access('access chado_library content', $account)) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
+
 /**
  * Menu items are automatically added for the new node types created
  * by this module to the 'Create Content' Navigation menu item.  This function
@@ -121,21 +90,20 @@ function tripal_library_menu() {
   // The administative settings menu
   $items['admin/tripal/chado/tripal_library'] = array(
     'title' => 'Libraries',
-    'description' => 'A grouping of genetic data',
+    'description' => 'Any biological library. Examples of genomic libraries include BAC, cDNA, FOSMID, etc.',
     'page callback' => 'tripal_library_admin_libraries_listing',
     'access arguments' => array('administer tripal libraries'),
     'type' => MENU_NORMAL_ITEM,
-    'weight' => 0
   );
 
   $items['admin/tripal/chado/tripal_library/help'] = array(
     'title' => 'Help',
     'description' => 'Basic Description of Tripal Library Module Functionality',
     'page callback' => 'theme',
-    'page arguments' => array('tripal_library_admin'),
+    'page arguments' => array('tripal_library_help'),
     'access arguments' => array('administer tripal libraries'),
     'type' => MENU_LOCAL_TASK,
-    'weight' => 4
+    'weight' => 10
   );
 
   $items['admin/tripal/chado/tripal_library/configuration'] = array(
@@ -145,8 +113,18 @@ function tripal_library_menu() {
     'page arguments' => array('tripal_library_admin'),
     'access arguments' => array('administer tripal libraries'),
     'type' => MENU_LOCAL_TASK,
-    'weight' => 2
+    'weight' => 5
   );
+  $items['admin/tripal/chado/tripal_library/sync'] = array(
+    'title' => ' Sync',
+    'description' => 'Create pages on this site for libraries stored in Chado',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_core_chado_node_sync_form', 'tripal_library', 'chado_library'),
+    'access arguments' => array('administer tripal libraries'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 0
+  );
+  return $items;
 
   // Synchronizing libraries from Chado to Drupal
   $items['chado_sync_libraries'] = array(
@@ -184,20 +162,47 @@ function tripal_library_views_api() {
 /**
  * @ingroup tripal_library
  */
-function tripal_library_node_view(&$node, $view_mode, $langcode) {
+function tripal_library_node_view($node, $view_mode, $langcode) {
 
   switch ($node->type) {
+    case 'chado_library':
+      if ($view_mode == 'full') {
+        $node->content['tripal_library_base'] = array(
+          '#value' => theme('tripal_library_base', array('node' => $node)),
+        );      
+        $node->content['tripal_library_properties'] = array(
+          '#value' => theme('tripal_library_properties', array('node' => $node)),
+        );
+        $node->content['tripal_library_publications'] = array(
+          '#value' => theme('tripal_library_publications', array('node' => $node)),
+        );
+        $node->content['tripal_library_references'] = array(
+          '#value' => theme('tripal_library_references', array('node' => $node)),
+        );      
+        $node->content['tripal_library_synonyms'] = array(
+          '#value' => theme('tripal_library_synonyms', array('node' => $node)),
+        );
+        $node->content['tripal_library_terms'] = array(
+          '#value' => theme('tripal_library_terms', array('node' => $node)),
+        );
+      }
+      if ($view_mode == 'teaser') {
+        $node->content['tripal_library_teaser'] = array(
+          '#value' => theme('tripal_library_teaser', array('node' => $node)),
+        );
+      }
+      break;
     case 'chado_organism':
       if ($view_mode == 'full') {
-        $node->content['tripal_organism_libraries'] = array(
-          '#value' => theme('tripal_organism_libraries', $node),
+        $node->content['tripal_organism.libraries'] = array(
+          '#value' => theme('tripal_organism.libraries', array('node' => $node)),
         );
       }
       break;
     case 'chado_feature':
       if ($view_mode == 'full') {
-        $node->content['tripal_feature_libraries'] = array(
-          '#value' => theme('tripal_feature_libraries', $node),
+        $node->content['tripal_feature.libraries'] = array(
+          '#value' => theme('tripal_feature.libraries', array('node' => $node)),
         );
       }
       break;
@@ -210,63 +215,75 @@ function tripal_library_node_view(&$node, $view_mode, $langcode) {
  *
  * @ingroup tripal_library
  */
-function tripal_library_theme() {
-  $theme_path = drupal_get_path('module', 'tripal_library') . '/theme';
+function tripal_library_theme($existing, $type, $theme, $path) {
+  $core_path = drupal_get_path('module', 'tripal_core');
+  
   $items = array(
-    // themed functions
-    'tripal_library_library_table' => array(
-      'arguments' => array('libraries'),
-    ),
-    'tripal_library_search_index' => array(
-      'arguments' => array('node'),
-    ),
-    'tripal_library_search_result' => array(
-      'arguments' => array('node'),
-    ),
-    // tripal_organism templates
-    'tripal_organism_libraries' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_organism_libraries',
-      'path' => "$theme_path/tripal_organism",
-    ),
-    // tripal_feature templates
-    'tripal_feature_libraries' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_feature_libraries',
-      'path' => "$theme_path/tripal_feature",
+    'node__chado_library' => array(
+      'template' => 'node--chado-generic',
+      'render element' => 'node',
+      'base hook' => 'node',
+      'path' => "$core_path/theme",
     ),
+
     // tripal_library templates
     'tripal_library_base' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_library_base',
-      'path' => "$theme_path/tripal_library",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.base',
+      'path' => "$path/theme/tripal_library",
     ),
-    'tripal_library_synonyms' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_library_synonyms',
-      'path' => "$theme_path/tripal_library",
+    'tripal_library_properties' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.properties',
+      'path' => "$path/theme/tripal_library",
+    ),
+    'tripal_library_publications' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.publications',
+      'path' => "$path/theme/tripal_library",
     ),
     'tripal_library_references' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_library_references',
-      'path' => "$theme_path/tripal_library",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.references',
+      'path' => "$path/theme/tripal_library",
     ),
-    'tripal_library_properties' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_library_properties',
-      'path' => "$theme_path/tripal_library",
+    'tripal_library_synonyms' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.synonyms',
+      'path' => "$path/theme/tripal_library",
     ),
     'tripal_library_terms' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_library_terms',
-      'path' => "$theme_path/tripal_library",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.terms',
+      'path' => "$path/theme/tripal_library",
     ),
-    // help template
-    'tripal_library_admin' => array(
-      'template' => 'tripal_library_admin',
-      'arguments' =>  array(NULL),
-      'path' => $theme_path,
+    'tripal_library_help' => array(
+      'template' => 'tripal_library.help',
+      'variables' =>  array(NULL),
+      'path' => "$path/theme",
     ),
+    
+    // teaser
+    'tripal_library_teaser' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_library.teaser',
+      'path' => "$path/theme/tripal_library",
+    ),
+    
+    // tripal_organism templates
+    'tripal_organism_libraries' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_organism.libraries',
+      'path' => "$path/theme/tripal_organism",
+    ),
+    
+    // tripal_feature templates
+    'tripal_feature_libraries' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_feature.libraries',
+      'path' => "$path/theme/tripal_feature",
+    ),
+    
   );
   return $items;
 }
@@ -352,117 +369,6 @@ function tripal_library_block_view($delta = '') {
     return $block;
   }
 }
-/**
- * This function is an extension of the chado_feature_view and
- * chado_organism_view by providing the markup for the library object
- * THAT WILL BE INDEXED.
- *
- * @ingroup tripal_library
- */
-function theme_tripal_library_search_index($node) {
-
-  if ($node->type == 'chado_organism') {
-    $content = "";
-    // get the libraries for the organism
-    $sql = "SELECT * FROM {library} L WHERE L.organism_id = :organism_id";
-    $libraries = array();
-    $results = chado_query($sql, array(':organism_id' => $node->organism->organism_id));
-    while ($library = $results->fetchObject()) {
-      // get the description
-      $sql = "
-        SELECT *
-        FROM {libraryprop} LP
-          INNER JOIN {cvterm} CVT ON CVT.cvterm_id = LP.type_id
-        WHERE LP.library_id = :library_id
-          AND CVT.name = 'library_description'
-      ";
-      $desc = chado_query($sql, array(':library_id' => $library->library_id))->fetchObject();
-      $library->description = $desc->value;
-      $libraries[] = $library;
-    }
-    if (count($libraries) > 0) {
-      foreach ($libraries as $library) {
-        $content .= "$library->name ";
-        $content .= "$library->description";
-      };
-    }
-    // Provide library names to show in a feature page
-  }
-  elseif ($node->type == 'chado_feature') {
-    $content = "";
-    $organism_id = $node->feature->organism_id;
-    $sql = "
-      SELECT *
-      FROM {library} L
-        INNER JOIN {library_feature} LF ON L.library_id = LF.library_id
-      WHERE LF.feature_id = :feature_id
-    ";
-    $libraries = array();
-    $results = chado_query($sql, array(':feature_id' => $node->feature->feature_id));
-    while ($library = $results->fetchObject()) {
-      $libraries[] = $library;
-    }
-    if (count($libraries) > 0) {
-      $lib_additions = array();
-      foreach ($libraries as $library) {
-        $content .= $library->name;
-      };
-    }
-  }
-  return $content;
-}
-
-/**
- * This function shows library information on an organism/feature node
- *
- * @ingroup tripal_library
- */
-function theme_tripal_library_node_libraries($node) {
-  $content = "";
-
-  // Show library information in a expandable box for a organism page.
-  // Make sure we have $node->organism_id. In the case of creating a new
-  // organism, the organism_id is not created until we save. This will cause
-  // an error when users preview the creation without a $node->organism_id
-  if ($node->type == 'chado_organism' && $node->organism_id) {
-    $box_status = variable_get("tripal_library-box-libraries", "menu_off");
-
-    if (strcmp($box_status, "menu_off")==0) {
-      return get_tripal_library_organism_libraries($node->nid);
-    }
-  }
-  // Provide library names to show in a feature page.
-  // Make sure we have $node->feature->feature_id or there will be an error
-  // when a feature is previewed at its creation
-  elseif ($node->type == 'chado_feature' && $node->feature->feature_id) {
-    $organism_id = $node->feature->organism_id;
-    $sql = "
-      SELECT *
-      FROM {library} L
-        INNER JOIN Library_feature LF ON L.library_id = LF.library_id
-      WHERE LF.feature_id = :feature_id
-    ";
-    $libraries = array();
-    $results = chado_query($sql, array(':feature_id' => $node->feature->feature_id));
-    while ($library = $results->fetchObject()) {
-      $libraries[] = $library;
-  }
-  if (count($libraries) > 0) {
-    $lib_additions = array();
-    foreach ($libraries as $library) {
-      $sql = "SELECT nid FROM {chado_library} WHERE library_id = :library_id";
-      $lib_nid = db_query($sql, array(':library_id' => $library->library_id))->fetchField();
-      if ($lib_nid) {
-        $lib_url = url("node/$lib_nid");
-      }
-      $lib_additions[$lib_url] = $library->name;
-    };
-    $node->lib_additions = $lib_additions;
-  }
-  }
-  return $content;
-}
-
 
 /**
  *
@@ -473,290 +379,6 @@ function tripal_library_cron() {
 }
 
 
-/**
- *  When editing or creating a new node of type 'chado_library' we need
- *  a form.  This function creates the form that will be used for this.
- *
- * @ingroup tripal_library
- */
-function chado_library_form($node) {
-  $form = array();
-
-  $library = $node->library;
-
-  // get the default values
-  $uniquename = $node->uniquename;
-  if (!$uniquename) {
-    $uniquename = $library->uniquename;
-  }
-  $library_type = $node->library_type;
-  if (!$library_type) {
-    $library_type = $library->type_id->cvterm_id;
-  }
-  $organism_id = $node->organism_id;
-  if (!$organism_id) {
-    $organism_id = $library->organism_id->organism_id;
-  }
-  $library_description = $node->library_description;
-  if (!$library_description) {
-    $libprop = tripal_library_get_property($library->library_id, 'library_description');
-    $library_description = $libprop->value;
-  }
-
-  // keep track of the library id if we have.  If we do have one then
-  // this is an update as opposed to an insert.
-  $form['library_id'] = array(
-    '#type' => 'value',
-    '#value' => $library->library_id,
-  );
-
-  $form['title']= array(
-    '#type'          => 'textfield',
-    '#title'         => t('Library Title'),
-    '#description'   => t('Please enter the title for this library. '.
-                          'This appears at the top of the library page.'),
-    '#required'      => TRUE,
-    '#default_value' => $node->title,
-    '#weight'        => 1
-  );
-
-  $form['uniquename']= array(
-    '#type'          => 'textfield',
-    '#title'         => t('Unique Library Name'),
-    '#description'   => t('Please enter a unique name for this library'),
-    '#required'      => TRUE,
-    '#default_value' => $uniquename,
-    '#weight'        => 2
-  );
-
-  // get the list of library types
-  $values = array(
-    'cv_id' => array(
-      'name' => 'tripal_library_types',
-    )
-  );
-  $columns = array('cvterm_id','name');
-  $options = array('order_by' => array('name' => 'ASC'));
-  $lib_types = tripal_core_chado_select('cvterm', $columns, $values, $options);
-  $types = array();
-  $types[''] = '';
-  foreach($lib_types as $type) {
-    $types[$type->cvterm_id] = $type->name;
-  }
-
-  $form['library_type'] = array(
-    '#title'       => t('Library Type'),
-    '#type'        => t('select'),
-    '#description' => t("Choose the library type."),
-    '#required'    => TRUE,
-    '#default_value' => $library_type,
-    '#options'     => $types,
-    '#weight'      => 3
-  );
-
-  // get the list of organisms
-  $sql = "SELECT * FROM {organism}";
-  $org_rset = chado_query($sql);
-
-  $organisms = array();
-  $organisms[''] = '';
-  while ($organism = $org_rset->fetchObject()) {
-    $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 library is ".
-                       "associated."),
-   '#required'    => TRUE,
-   '#default_value' => $organism_id,
-   '#options'     => $organisms,
-   '#weight'      => 4,
-  );
-
-  $form['library_description']= array(
-    '#type'          => 'textarea',
-    '#title'         => t('Library Description'),
-    '#description'   => t('A brief description of the library'),
-    '#required'      => TRUE,
-    '#default_value' => $library_description,
-    '#weight'        => 5
-  );
-
-  return $form;
-}
-/**
- *  validates submission of form when adding or updating a library node
- *
- * @ingroup tripal_library
- */
-function chado_library_validate($node, $form, &$form_state) {
-  $lib = 0;
-  // check to make sure the unique name on the library is unique
-  // before we try to insert into chado.
-  if ($node->library_id) {
-    $sql = "
-      SELECT *
-      FROM {library}
-      WHERE uniquename = :uname AND NOT library_id = :library_id
-    ";
-    $lib = chado_query($sql, array(':uname' => $node->uniquename, ':library_id' => $node->library_id))->fetchObject();
-  }
-  else {
-    $sql = "SELECT * FROM {library} WHERE uniquename = :uname";
-    $lib = chado_query($sql, array(':uname' => $node->uniquename))->fetchObject();
-  }
-  if ($lib) {
-    form_set_error('uniquename', t('The unique library name already exists. Please choose another'));
-  }
-}
-/**
- *  When a new chado_library node is created we also need to add information
- *  to our chado_library table.  This function is called on insert of a new node
- *  of type 'chado_library' and inserts the necessary information.
- *
- * @ingroup tripal_library
- */
-function chado_library_insert($node) {
-
-  if ($node->library_id) {
-    $library['library_id'] = $node->library_id;
-  }
-  else {
-    $values = array(
-      'name' => $node->title,
-      'uniquename' => $node->uniquename,
-      'organism_id' => $node->organism_id,
-      'type_id' => $node->library_type,
-    );
-    $library = tripal_core_chado_insert('library', $values);
-  }
-
-  if ($library) {
-     // add the description property
-    tripal_library_insert_property($library['library_id'], 'library_description',
-      $node->library_description);
-
-    // make sure the entry for this feature doesn't already exist in the chado_library table
-    // if it doesn't exist then we want to add it.
-    $library_id = chado_get_id_for_node('library', $node->nid) ;
-    if (!$library_id) {
-       // next add the item to the drupal table
-      $sql = "
-        INSERT INTO {chado_library} (nid, vid, library_id)
-        VALUES (:nid, :vid, :library_id)
-      ";
-      db_query($sql, array(':nid' => $node->nid, ':vid' => $node->vid, ':library_id' => $library['library_id']));
-    }
-  }
-  else {
-    drupal_set_message(t('Unable to add library.', 'warning'));
-    watchdog('tripal_library', 'Insert feature: Unable to create library where values: %values',
-      array('%values' => print_r($values, TRUE)), WATCHDOG_WARNING);
-  }
-}
-/**
- * Update nodes
- *
- * @ingroup tripal_library
- */
-function chado_library_update($node) {
-  if ($node->revision) {
-    // there is no way to handle revisions in Chado but leave
-    // this here just to make not we've addressed it.
-  }
-
-  $library_id = chado_get_id_for_node('library', $node->nid);
-  // update the library record
-  $match = array(
-     'library_id' => $library_id,
-  );
-  $values = array(
-     'name' => $node->title,
-     'uniquename' => $node->uniquename,
-     'organism_id' => $node->organism_id,
-     'type_id' => $node->library_type,
-  );
-  $status = tripal_core_chado_update('library', $match, $values);
-
-  tripal_library_update_property($library_id, 'library_description', $node->library_description, 1);
-
-}
-/**
- *  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_library
- */
-function chado_library_load($node) {
-  // get the feature details from chado
-  $library_id = chado_get_id_for_node('library', $node->nid);
-
-  $values = array('library_id' => $library_id);
-  $library = tripal_core_generate_chado_var('library', $values);
-
-  $additions = new stdClass();
-  $additions->library = $library;
-  return $additions;
-
-}
-/**
- *  This function customizes the view of the chado_library node.  It allows
- *  us to generate the markup. This function is required for node [Preview]
- *
- * @ingroup tripal_library
- */
-function chado_library_view($node, $teaser = FALSE, $page = FALSE) {
-   // use drupal's default node view:
-  if (!$teaser) {
-
-    $node = node_prepare($node, $teaser);
-
-    // If Hook_view() is called by Hook_form(), we'll only have orgnism_id
-    // but not genus/species/common_name. We need to get those from chado
-    // database so they will show up in preview
-    if (!$node->genus) {
-      $sql = "SELECT * FROM {organism} WHERE organism_id = :organism_id";
-      $data = chado_query($sql, array(':organism_id' => $node->organism_id))->fetchObject();
-      $node->genus = $data->genus;
-      $node->species = $data->species;
-      $node->common_name = $data->common_name;
-    }
-  }
-  return $node;
-}
-
-/**
- * Delete data from drupal and chado databases when a node is deleted
- * @ingroup tripal_library
- */
-function chado_library_delete(&$node) {
-
-  $library_id = chado_get_id_for_node('library', $node->nid);
-
-  // if we don't have a library id for this node then this isn't a node of
-  // type chado_library or the entry in the chado_library table was lost.
-  if (!$library_id) {
-    return;
-  }
-
-  // Remove data from {chado_library}, {node} and {node_revisions} tables of
-  // drupal database
-  $sql_del = "DELETE FROM {chado_library} 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 library and libraryprop tables of chado database as well
-  chado_query("DELETE FROM {libraryprop} WHERE library_id = :library_id", array(':library_id' => $library_id));
-  chado_query("DELETE FROM {library} WHERE library_id = :library_id", array(':library_id' => $library_id));
-}
-
-
 /**
  * Implementation of hook_form_alter()
  *
@@ -769,4 +391,16 @@ function tripal_library_form_alter(&$form, &$form_state, $form_id) {
   if ($form_id == "chado_library_node_form") {
     $form['actions']['preview']['#access'] = FALSE;
   }
+}
+
+/**
+ *
+ * @param $node
+ */
+function tripal_library_node_presave($node) {
+  // if this is a chado_library and the $node->library object is set then we
+  // are syncing and we want to set the node title to be the same as the node name
+  if ($node->type == 'chado_library' and property_exists($node, 'library')) {
+    $node->title = $node->library->name;
+  }
 }

+ 1 - 1
tripal_natural_diversity/tripal_natural_diversity.module

@@ -48,7 +48,7 @@ function tripal_natural_diversity_menu() {
     'title' => 'Enable Natural Diversity Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_natural_diversity_admin_natdiv_exp', 'admin/tripal/chado/tripal_natdiv'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal natural_diversity'),
     'type' => MENU_CALLBACK,
   );
 

+ 1 - 1
tripal_organism/includes/organism_sync.inc

@@ -207,5 +207,5 @@ function tripal_organism_sync_organisms($organism_id = NULL, $job_id = NULL) {
  */
 function tripal_organism_cleanup($dummy = NULL, $job_id = NULL) {
 
-  return tripal_core_clean_orphaned_nodes('organism', $job_id);
+  return tripal_core_chado_node_cleanup_orphaned('organism', $job_id);
 }

+ 1 - 1
tripal_organism/tripal_organism.module

@@ -140,7 +140,7 @@ function tripal_organism_menu() {
     'title' => 'Enable Organism Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_organism_admin_organisms', 'admin/tripal/chado/tripal_organism'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal organism'),
     'type' => MENU_CALLBACK,
   );
   

+ 1 - 1
tripal_phenotype/tripal_phenotype.module

@@ -44,7 +44,7 @@ function tripal_phenotype_menu() {
     'title' => 'Enable Phenotype Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_phenotype_admin_phenotypes', 'admin/tripal/chado/tripal_phenotype'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal phenotype'),
     'type' => MENU_CALLBACK,
   );
 

+ 4 - 4
tripal_project/api/tripal_project.api.inc

@@ -23,7 +23,7 @@
  * @ingroup tripal_project_api
  */
 function tripal_project_get_property($project_id, $property) {
-  return tripal_core_get_property('project', $project_id, $property, 'tripal');
+  return tripal_core_get_property('project', $project_id, $property, 'project_property');
 }
 
 /**
@@ -44,7 +44,7 @@ function tripal_project_get_property($project_id, $property) {
  * @ingroup tripal_project_api
  */
 function tripal_project_insert_property($project_id, $property, $value, $update_if_present = 0) {
-  return tripal_core_insert_property('project', $project_id, $property, 'tripal', $value, $update_if_present);
+  return tripal_core_insert_property('project', $project_id, $property, 'project_property', $value, $update_if_present);
 }
 
 /**
@@ -68,7 +68,7 @@ function tripal_project_insert_property($project_id, $property, $value, $update_
  * @ingroup tripal_project_api
  */
 function tripal_project_update_property($project_id, $property, $value, $insert_if_missing = 0) {
-  return tripal_core_update_property('project', $project_id, $property, 'tripal', $value, $insert_if_missing);
+  return tripal_core_update_property('project', $project_id, $property, 'project_property', $value, $insert_if_missing);
 }
 /**
  * Delete a given property
@@ -87,5 +87,5 @@ function tripal_project_update_property($project_id, $property, $value, $insert_
  * @ingroup tripal_project_api
  */
 function tripal_project_delete_property($project_id, $property) {
-  return tripal_core_delete_property('project', $project_id, $property, 'tripal');
+  return tripal_core_delete_property('project', $project_id, $property, 'project_property');
 }

+ 8 - 333
tripal_project/includes/tripal_project.admin.inc

@@ -36,349 +36,24 @@ function tripal_project_admin_project_view() {
 
   return $output;
 }
-
-
-function tripal_project_admin($form_state = NULL) {
+/**
+ * 
+ * @param $form_state
+ */
+function tripal_project_admin($form_state) {
   $form = array();
 
-  // before proceeding check to see if we have any
-  // currently processing jobs. If so, we don't want
-  // to give the opportunity to sync libraries
-  $active_jobs = FALSE;
-  if (tripal_get_module_active_jobs('tripal_project')) {
-    $active_jobs = TRUE;
-  }
-
-  // add the field set for syncing libraries
-  if (!$active_jobs) {
-    get_tripal_project_admin_form_sync_set($form);
-    get_tripal_project_admin_form_cleanup_set($form);
-//    get_tripal_project_admin_form_reindex_set($form);
-
-  }
-  else {
-    $form['notice'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Project Management Temporarily Unavailable')
-    );
-    $form['notice']['message'] = array(
-      '#value' => t('Currently, project management jobs are waiting or are running. . Managemment features have been hidden until these jobs complete.  Please check back later once these jobs have finished.  You can view the status of pending jobs in the Tripal jobs page.'),
-    );
-  }
+  $form['nothing'] = array(
+    '#markup' => t('There are currently no settings to configure.')
+  );
 
   return system_settings_form($form);
 }
-/**
- *
- *
- * @ingroup tripal_project
- */
-function get_tripal_project_admin_form_cleanup_set(&$form) {
-  $form['cleanup'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Clean Up')
-  );
-  $form['cleanup']['description'] = array(
-    '#type' => 'item',
-    '#value' => t("With Drupal and chado residing in different databases ".
-    "it is possible that nodes in Drupal and projects in Chado become ".
-    "\"orphaned\".  This can occur if an project node in Drupal is ".
-    "deleted but the corresponding chado project is not and/or vice ".
-    "versa. Click the button below to resolve these discrepancies."),
-    '#weight' => 1,
-  );
-  $form['cleanup']['button'] = array(
-    '#type' => 'submit',
-    '#value' => t('Clean up orphaned projects'),
-    '#weight' => 2,
-  );
-}
-/**
- *
- * @ingroup tripal_project
- */
-function get_tripal_project_admin_form_sync_set(&$form) {
-  // define the fieldsets
-  $form['sync'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Sync Projects')
-  );
-
-  // before proceeding check to see if we have any
-  // currently processing jobs. If so, we don't want
-  // to give the opportunity to sync libraries
-  $active_jobs = FALSE;
-  if (tripal_get_module_active_jobs('tripal_project')) {
-    $active_jobs = TRUE;
-  }
-
-  if (!$active_jobs) {
 
-    // get the list of projects
-    $sql = "SELECT * FROM {project} ORDER BY name";
-    $org_rset = chado_query($sql);
-
-    // if we've added any projects to the list that can be synced
-    // then we want to build the form components to allow the user
-    // to select one or all of them.  Otherwise, just present
-    // a message stating that all projects are currently synced.
-    $proj_boxes = array();
-    $added = 0;
-    while ($project = $org_rset->fetchObject()) {
-      // check to see if the project is already present as a node in drupal.
-      // if so, then skip it.
-      $sql = "SELECT * FROM {chado_project} WHERE project_id = :project_id";
-      if (!db_query($sql, array(':project_id' => $project->project_id))->fetchObject()) {
-        $proj_boxes[$project->project_id] = $project->name;
-        $added++;
-      }
-    }
-
-    // if we have projects we need to add to the checkbox then
-    // build that form element
-    if ($added > 0) {
-      $proj_boxes['all'] = "All Projects";
-
-      $form['sync']['projects'] = array(
-        '#title'       => t('Available Projects'),
-        '#type'        => t('checkboxes'),
-        '#description' => t("Check the projects you want to sync.  Drupal content will be created for each of the projects listed above.  Select 'All Projects' to sync all of them."),
-        '#required'    => FALSE,
-        '#prefix'      => '<div id="org_boxes">',
-        '#suffix'      => '</div>',
-        '#options'     => $proj_boxes,
-      );
-      $form['sync']['button'] = array(
-        '#type' => 'submit',
-        '#value' => t('Submit Sync Job')
-      );
-    }
-    // we don't have any projects to select from
-    else {
-    $form['sync']['value'] = array(
-        '#value' => t('All projects in Chado are currently synced with Drupal.')
-    );
-    }
-  }
-  // we don't want to present a form since we have an active job running
-  else {
-    $form['sync']['value'] = array(
-        '#value' => t('Currently, jobs exist related to chado projects. Please check back later for projects that can by synced once these jobs have finished.  You can view the status of pending jobs in the Tripal jobs page.')
-    );
-  }
-}
 /**
  *
  * @ingroup tripal_project
  */
 function tripal_project_admin_validate($form, &$form_state) {
-  global $user;  // we need access to the user info
-  $job_args = array();
-
-  if ($form_state['values']['op'] == t('Submit Sync Job')) {
-
-    // check to see if the user wants to sync chado and drupal.  If
-    // so then we need to register a job to do so with tripal
-    $projects = $form_state['values']['projects'];
-    $do_all = FALSE;
-    $to_sync = array();
-
-    foreach ($projects as $project_id) {
-      if (preg_match("/^all$/i" , $project_id)) {
-        $do_all = TRUE;
-      }
-      if ($project_id and preg_match("/^\d+$/i" , $project_id)) {
-        // get the list of projects
-        $sql = "SELECT * FROM {project} WHERE project_id = :project_id";
-        $project = chado_query($sql, array(':project_id' => $project_id))->fetchObject();
-        $to_sync[$project_id] = "$project->genus $project->species";
-      }
-    }
-
-    // submit the job the tripal job manager
-    if ($do_all) {
-      tripal_add_job('Sync all projects' , 'tripal_project',
-      'tripal_project_sync_projects' , $job_args , $user->uid);
-    }
-    else{
-      foreach ($to_sync as $project_id => $name) {
-        $job_args[0] = $project_id;
-        tripal_add_job("Sync project: $name" , 'tripal_project',
-          'tripal_project_sync_projects' , $job_args , $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Reindex Job if selected
-  if ($form_state['values']['op'] == t('Reindex Features')) {
-    $projects = $form_state['values']['re-projects'];
-    foreach ($projects as $project_id) {
-      if ($project_id and preg_match("/^\d+$/i" , $project_id)) {
-        // get the project info
-        $sql = "SELECT * FROM {project} WHERE project_id = :project_id";
-        $project = chado_query($sql , array(':project_id' => $project_id))->fetchObject();
-        $job_args[0] = $project_id;
-        tripal_add_job("Reindex features for project: $project->genus ".
-         "$project->species", 'tripal_project' ,
-         'tripal_project_reindex_features', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the taxonomy Job if selected
-  if ($form_state['values']['op'] == t('Set Feature Taxonomy')) {
-    $projects = $form_state['values']['tx-projects'];
-    foreach ($projects as $project_id) {
-      if ($project_id and preg_match("/^\d+$/i", $project_id)) {
-        // get the project info
-        $sql = "SELECT * FROM {project} WHERE project_id = :project_id";
-        $project = chado_query($sql , array(':project_id' => $project_id))->fetchObject();
-        $job_args[0] = $project_id;
-        tripal_add_job("Set taxonomy for features in project: ".
-          "$project->genus $project->species" , 'tripal_project',
-          'tripal_project_taxonify_features', $job_args, $user->uid);
-      }
-    }
-  }
-
-  // -------------------------------------
-  // Submit the Cleanup Job if selected
-  if ($form_state['values']['op'] == t('Clean up orphaned projects')) {
-    tripal_add_job('Cleanup orphaned projects', 'tripal_project',
-      'tripal_project_cleanup', $job_args, $user->uid);
-  }
-}
-/**
- * Synchronize projects from chado to drupal
- *
- * @ingroup tripal_project
- */
-function tripal_project_sync_projects($project_id = NULL, $job_id = NULL) {
-  global $user;
-  $page_content = '';
-
-  if (!$project_id) {
-    $sql = "SELECT * FROM {project} P";
-    $results = chado_query($sql);
-  }
-  else {
-    $sql = "SELECT * FROM {project} P WHERE project_id = :project_id";
-    $results = chado_query($sql, array(':project_id' => $project_id));
-  }
-
-  // We'll use the following SQL statement for checking if the project
-  // already exists as a drupal node.
-  $sql = "SELECT * FROM {chado_project} WHERE project_id = :project_id";
-
-  while ($project = $results->fetchObject()) {
-
-    // check if this project already exists in the drupal database. if it
-    // does then skip this project and go to the next one.
-    if (!db_query($sql, array(':project_id' => $project->project_id))->fetchObject()) {
-
-      $new_node = new stdClass();
-      $new_node->type = 'chado_project';
-      $new_node->uid = $user->uid;
-      $new_node->title = "$project->name";
-      $new_node->project_id = $project->project_id;
-      $new_node->name = $project->name;
-      $new_node->description = $project->description;
-      node_validate($new_node);
-      if (!form_get_errors()) {
-        $node = node_submit($new_node);
-        node_save($node);
-        if ($node->nid) {
-          print "Added $project->name\n";
-        }
-      }
-      else {
-        print "Failed to insert project $project->name\n";
-      }
-    }
-    else {
-      print "Skipped $project->name\n";
-    }
-  }
-  return $page_content;
-}
-/*
- *
- */
-function tripal_project_sync_projects_form_submit($form, &$form_state) {
-  global $user;
-
-  //sync'ing is done by a tripal_job that is added here
-  $job_id = tripal_add_job('Sync Projects', 'tripal_project',
-  'tripal_project_sync_all_projects', array(), $user->uid);
-
-}
-
-/*
- *
- */
-function tripal_project_sync_all_projects() {
-
-  //retrieve all projects in drupal
-  $resource = db_query('SELECT project_id FROM {chado_project}');
-  $drupal_projects = array();
-  while ($r = $resource->fetchObject()) {
-    $drupal_projects[$r->project_id] = $r->project_id;
-  }
-
-  // retrieve all projects in chado
-  $chado_projects = array();
-  $resource = chado_query('SELECT project_id FROM {project}');
-  while ($r = $resource->fetchObject()) {
-    // if not already in drupal add to list to be sync'd
-    if (!isset($drupal_projects[$r->project_id])) {
-      $chado_projects[$r->project_id] = $r->project_id;
-    }
-  }
-
-  print 'Number of Projects to Sync: ' . sizeof($chado_projects) . "\n";
-
-  foreach ($chado_projects as $project_id) {
-    $project = tripal_core_chado_select('project', array('name', 'description'), array('project_id' => $project_id));
-
-    // create node
-    $new_node = new stdClass();
-    $new_node->type = 'chado_project';
-    $new_node->uid = $user->uid;
-    $new_node->title = $project[0]->name;
-    $new_node->project_id = $project_id;
-    $new_node->description = $project[0]->description;
-    node_validate($new_node);
-    $errors = form_get_errors();
-    if (!$errors) {
-      $node = node_submit($new_node);
-      node_save($node);
-      if ($node->nid) {
-        print "Added " . $project[0]->name . " (Node ID:" . $node->nid . ")\n";
-      }
-    }
-    else {
-      print "Failed to insert project: " . $project[0]->name . "\n";
-      print "Errors: " . print_r($errors, TRUE) . "\n";
-    }
-
-  }
-
-
-}
-
-/**
- * Remove orphaned drupal nodes
- *
- * @param $dummy
- *   Not Used -kept for backwards compatibility
- * @param $job_id
- *   The id of the tripal job executing this function
- *
- * @ingroup tripal_project
- */
-function tripal_project_cleanup($dummy = NULL, $job_id = NULL) {
 
-  return tripal_core_clean_orphaned_nodes('project', $job_id);
 }

+ 395 - 0
tripal_project/includes/tripal_project.chado_node.inc

@@ -0,0 +1,395 @@
+<?php
+
+/**
+ * Implementation of hook_form().
+ *
+ *  This form takes the Project Title information and description from the user.
+ *
+ *  @parm $node
+ *    The initialized node
+ *
+ *  @parm $form_state
+ *    The state of the form, that has the user entered information that is neccessary for adding
+ *    information to the project
+ *
+ *  @return $form
+ *    An array as described by the Drupal Form API
+ *
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_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 project
+  // 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
+  $project_id = null;
+  $title = '';
+  $description = '';
+  
+  // if we are editing an existing node then the project is already part of the node
+  if (property_exists($node, 'project')) {
+    $project = $node->project;
+    // get the project default values.  When this module was first created
+    // the project description was incorrectly stored in the $node->body field.
+    // It is better to store it in the Chado tables.  However, the 'description'
+    // field of the project table is only 255 characters.  So, we are going
+    // to follow the same as the project module and store the description in
+    // the projectprop table and leave the project.description field blank.
+    // however, for backwards compatibitily, we check to see if the description
+    // is in the $node->body field. If it is we'll use that.  When the node is
+    // edited the text will be moved out of the body and into the projectprop
+    // table where it should belong.
+    if (property_exists($node, 'body')) {
+      $description = $node->body;
+    }
+    else {
+      $description = $project->description;
+    }
+    if (!$description) {
+      $projectprop = tripal_project_get_property($project->project_id, 'Project Description');
+      $description = $projectprop->value;
+    }
+    
+    $title = $project->name;
+    $project_id = $project->project_id;
+    
+    // keep track of the project id if we have.  If we do have one then
+    // this is an update as opposed to an insert.
+    $form['project_id'] = array(
+      '#type' => 'value',
+      '#value' => $project_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)) {
+    $title       = $form_state['values']['title'];
+    $description = $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'])) {
+    $title       = $form_state['input']['title'];
+    $description = $form_state['input']['description'];
+  }
+
+  $form['title']= array(
+    '#type'          => 'textfield',
+    '#title'         => t('Project Title'),
+    '#description'   => t('Please enter the title for this project. This appears at the top of the project page.'),
+    '#required'      => TRUE,
+    '#default_value' => $node->title,
+  );
+
+  $form['description']= array(
+    '#type'          => 'textarea',
+    '#title'         => t('Project Description'),
+    '#description'   => t('A brief description of the project'),
+    '#required'      => TRUE,
+    '#default_value' => $description,
+  );
+
+  // get the project properties
+  $properties = array();
+  $properties[] = 'Select a Property';
+  $sql = "
+    SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
+    FROM  {cvterm} CVT
+      INNER JOIN {cv} ON CVT.cv_id = CV.cv_id
+    WHERE
+      CV.name = 'project_property' AND
+      NOT CVT.is_obsolete = 1
+    ORDER BY CVT.name ASC
+  ";
+  $prop_types = chado_query($sql);
+  while ($prop = $prop_types->fetchObject()) {
+    // because we are using the project description property as
+    // a replacement for the project.description field and we want the 
+    // user to add a description in the field above, we remove the property
+    // from the list.
+    if (strcmp($prop->name, "Project Description")==0) {
+      continue;
+    }
+    $properties[$prop->cvterm_id] = $prop->name;
+  }
+  
+  // we want to exclude the project description from being loaded as a stored property 
+  // because we want to use the property to replace the project.description field as it is
+  // only 255 characters which isn't large enough. We don't want the user to set it 
+  // as a property even though it will be stored as a property. 
+  $exclude = array('Project Description');
+  $include = array();
+  $instructions = t('To add properties to the drop down list, you must ' . l("add terms to the project_property vocabulary", "admin/tripal/chado/tripal_cv/cvterm/add") . ".");
+  tripal_core_properties_form($form, $form_state, 'projectprop', 'project_id', 'project_property',
+    $properties, $project_id, $exclude, $include, $instructions, 'Properties');
+  
+  return $form;
+
+}
+/**
+ *  validates submission of form when adding or updating a project node
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_validate($node, $form, &$form_state) {
+  
+  $node->title = trim($node->title);
+  $node->description = trim($node->description);
+  
+  // if this is a delete then don't validate
+  if($node->op == 'Delete') {
+    return;
+  }
+  
+  // we are syncing if we do not have a node ID but we do have a project_id. We don't
+  // need to validate during syncing so just skip it.
+  if (is_null($node->nid) and property_exists($node, 'project_id') and $node->project_id != 0) {
+    return;
+  }
+  
+  $project = 0;
+  // check to make sure the name on the project is unique
+  // before we try to insert into chado.
+  if (property_exists($node, 'project_id')) {
+    $sql = "SELECT * FROM {project} WHERE name = :name AND NOT project_id = :project_id";
+    $project = chado_query($sql, array(':name' => $node->title, ':project_id' => $node->project_id))->fetchObject();
+  }
+  else {
+    $sql = "SELECT * FROM {project} WHERE name = :name";
+    $project = chado_query($sql, array(':name' => $node->title))->fetchObject();
+  }
+  if ($project) {
+    form_set_error('title', t('The unique project name already exists. Please choose another'));
+  }
+}
+/**
+ * Implementation of hook_insert().
+ *
+ *  @parm $node
+ *    Then node that has the information stored within, accessed given the nid
+ *
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_insert($node) {
+
+  $node->title = trim($node->title);
+  $node->description = trim($node->description);
+  
+  // if there is an project_id in the $node object then this must be a sync so
+  // we can skip adding the project as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'project_id')) {
+    $values = array(
+      'name' => $node->title,
+      'description' => '',
+    );
+    $project = tripal_core_chado_insert('project', $values);
+    if (!$project) {
+      drupal_set_message(t('Unable to add project.', 'warning'));
+      watchdog('tripal_project', 'Insert project: Unable to create project where values:%values',
+      array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+      return;
+    }
+    $project_id = $project['project_id'];
+    
+    // now add in the properties
+    $properties = tripal_core_properties_form_retreive($node, 'project_property');
+    foreach ($properties as $property => $elements) {
+      foreach ($elements as $rank => $value) {
+    
+        $status = tripal_project_insert_property($project_id, $property, $value, FALSE, 'project_property');
+        if (!$status) {
+          drupal_set_message("Error cannot add property: $property", "error");
+          watchdog('t_project', "Error cannot add property: %prop",
+          array('%property' => $property), WATCHDOG_ERROR);
+        }
+      }
+    }
+    
+    // add in the description as a separate property
+    tripal_project_insert_property($project_id, 'Project Description', $node->description, FALSE);
+  }
+  else {
+    $project_id = $node->project_id;
+  }
+
+  // Make sure the entry for this project doesn't already exist in the
+  // chado_project table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('project', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->project_id = $project_id;
+    drupal_write_record('chado_project', $record);
+  }
+}
+
+/**
+ *
+ * Implementation of hook_delete().
+ *
+ * @param $node
+ * The node which is to be deleted, only chado project and chado_project need to be dealt with
+ * since the drupal node is deleted automagically
+ *
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_delete($node) {
+
+  $project_id = chado_get_id_for_node('project', $node->nid);
+
+  // if we don't have a project id for this node then this isn't a node of
+  // type chado_project or the entry in the chado_project table was lost.
+  if (!$project_id) {
+    return;
+  }
+
+  // Remove data from {chado_project}, {node} and {node_revisions} tables of
+  // drupal database
+  $sql_del = "DELETE FROM {chado_project} 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 = :vod";
+  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 project and projectprop tables of chado database as well
+  chado_query("DELETE FROM {projectprop} WHERE project_id = :project_id", array(':project_id' => $project_id));
+  chado_query("DELETE FROM {project} WHERE project_id = :project_id", array(':project_id' => $project_id));
+}
+
+/**
+ * Implements hook_update().
+ *
+ * @param $node
+ *  The node which is to have its containing information updated when the user modifies information
+ *  pertaining to the specific project
+ *
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_update($node) {
+  
+  $node->title = trim($node->title);
+  $node->description = trim($node->description);
+
+  // update the project and the description
+  $project_id = chado_get_id_for_node('project', $node->nid) ;
+  $match = array('project_id' => $project_id);
+  $values = array(
+    'name' => $node->title,
+    'description' => '',
+  );
+  $status = tripal_core_chado_update('project', $match, $values);
+  if (!$status) {
+    drupal_set_message(t('Unable to update project.', 'warning'));
+    watchdog('tripal_project', 'Update project: Unable to update project where values: %values',
+    array('%values' => print_r($values, TRUE)), WATCHDOG_ERROR);
+  }
+  
+  // now add in the properties by first removing any the project
+  // already has and adding the ones we have
+  tripal_core_chado_delete('projectprop', array('project_id' => $project_id));
+  $properties = tripal_core_properties_form_retreive($node, 'project_property');
+  foreach ($properties as $property => $elements) {
+    foreach ($elements as $rank => $value) {
+      $status = tripal_project_insert_property($project_id, $property, $value, FALSE, 'project_property');
+      if (!$status) {
+        drupal_set_message("Error cannot add property: '$property'", "error");
+        watchdog('t_project', "Error cannot add property: '%prop'",
+        array('%prop' => $property), WATCHDOG_ERROR);
+      }
+    }
+  }
+  
+  // add the project description as a property
+  tripal_project_update_property($project_id, 'Project Description', $node->description, 1);
+}
+
+/**
+ * Implementation of node_load().
+ *
+ * @param $node
+ *   The node that is to have its containing information loaded
+ *
+ * @return $node
+ *   The node, containing the loaded project with the current nid
+ *
+ *
+ * @ingroup tripal_project
+ */
+function chado_project_load($nodes) {
+
+  foreach ($nodes as $nid => $node) {
+    // get the feature details from chado
+    $project_id = chado_get_id_for_node('project', $node->nid);
+  
+    $values = array('project_id' => $project_id);
+    $project = tripal_core_generate_chado_var('project', $values);
+  
+    $nodes[$nid]->project = $project;
+  }
+
+}
+
+/**
+ * Implement hook_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_project
+ */
+function chado_project_node_access($node, $op, $account) {
+
+  if ($op == 'create') {
+    if (!user_access('create chado_projects content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+  if ($op == 'update') {
+    if (!user_access('edit chado_projects content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'delete') {
+    if (!user_access('delete chado_projects content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'view') {
+    if (!user_access('access chado_projects content', $account)) {
+      return FALSE;
+    }
+  }
+  return NULL;
+}

+ 0 - 142
tripal_project/theme/node--chado-project.tpl.php

@@ -1,142 +0,0 @@
-<?php
-// Purpose: This template provides the layout of the project node (page)
-//   using the same templates used for the various project content blocks.
-//
-// To Customize the Libray Node Page:
-//   - This Template: customize basic layout and which elements are included
-//   - Using Panels: Override the node page using Panels3 and place the blocks
-//       of content as you please. This method requires no programming. See
-//       the Tripal User Guide for more details
-//   - Block Templates: customize the content/layout of each block of stock 
-//       content. These templates are found in the tripal_stock subdirectory
-//
-// Variables Available:
-//   - $node: a standard object which contains all the fields associated with
-//       nodes including nid, type, title, taxonomy. It also includes stock
-//       specific fields such as stock_name, uniquename, stock_type, synonyms,
-//       properties, db_references, object_relationships, subject_relationships,
-//       organism, etc.
-//   NOTE: For a full listing of fields available in the node object the
-//       print_r $node line below or install the Drupal Devel module which 
-//       provides an extra tab at the top of the node page labelled Devel
-
-$project  = $variables['node']->project;
-
-// get the template settings
-$template_settings = theme_get_setting('tripal');
-
-// toggle the sidebar if desired
-$no_sidebar = 0;
-if (is_array($template_settings['tripal_no_sidebar']) and 
-   $template_settings['tripal_no_sidebar']['project']) {
-  $no_sidebar = 1;
-}
-
-if ($teaser) { 
-  print theme('tripal_project_teaser',$node); 
-} 
-else { ?>
-
-<script type="text/javascript">
-(function ($) {
-  Drupal.behaviors.projectBehavior = {
-    attach: function (context, settings){ <?php 
-      if ($no_sidebar) { ?>    
-        // hide the resource side bar and strech the details section    
-        $(".tripal_toc").hide();
-        $(".tripal_details").addClass("tripal_details_full");
-        $(".tripal_details_full").removeClass("tripal_details"); <?php
-      } else { ?>
-        // use default resource sidebar
-        $(".tripal-info-box").hide(); <?php
-      } ?>
- 
-      // iterate through all of the info boxes and add their titles
-      // to the table of contents
-      $(".tripal-info-box-title").each(function(){
-        var parent = $(this).parent();
-        var id = $(parent).attr('id');
-        var title = $(this).text();
-        $('#tripal_project_toc_list').append('<li><a href="#'+id+'" class="tripal_project_toc_item">'+title+'</a></li>');
-      });
-
-      // when a title in the table of contents is clicked, then
-      // show the corresponding item in the details box
-      $(".tripal_project_toc_item").click(function(){
-         $(".tripal-info-box").hide();
-         href = $(this).attr('href');
-         $(href).fadeIn('slow');
-         // we want to make sure our table of contents and the details
-         // box stay the same height
-         $("#tripal_project_toc").height($(href).parent().height());
-         return false;
-      }); 
-
-      // we want the base details to show up when the page is first shown 
-      // unless the user specified a specific block
-      var block = window.location.href.match(/[\?|\&]block=(.+?)\&/)
-      if(block == null){
-         block = window.location.href.match(/[\?|\&]block=(.+)/)
-      }
-      if(block != null){
-         $("#tripal_project-"+block[1]+"-box").show();
-      } else {
-         $("#tripal_project-base-box").show();
-      }
-
-      $("#tripal_project_toc").height($("#tripal_project-base-box").parent().height());
-    }     
-  };
-})(jQuery);
-</script>
-
-<div id="tripal_project_details" class="tripal_details">
-
-   <!-- Basic Details Theme -->
-   <?php print theme('tripal_project_base',$node); ?>
-   
-   <!-- Properties Theme -->
-   <?php print theme('tripal_project_properties',$node); ?>
-   
-   <!-- Contact Theme -->
-   <?php print theme('tripal_project_contact',$node); ?>
-   
-   <!-- Relationships Theme -->
-   <?php print theme('tripal_project_relationships',$node); ?>
-   
-   <!-- Publications Theme -->
-   <?php print theme('tripal_project_publications',$node); ?>
-
-   <!-- Resource Blocks CCK elements --><?php
-   for($i = 0; $i < count($node->field_resource_titles); $i++){
-     if($node->field_resource_titles[$i]['value']){ ?>
-       <div id="tripal_project-resource_<?php print $i?>-box" class="tripal_project-info-box tripal-info-box">
-         <div class="tripal_project-info-box-title tripal-info-box-title"><?php print $node->field_resource_titles[$i]['value'] ?></div>
-         <?php print $node->field_resource_blocks[$i]['value']; ?>
-       </div><?php
-     }
-   }?>
-   
-   <!-- Let modules add more content -->
-
-   <?php print $content ?>
-</div>
-
-<!-- Table of contents -->
-<div id="tripal_project_toc" class="tripal_toc">
-   <div id="tripal_project_toc_title" class="tripal_toc_title">Resources</div>
-   <ul id="tripal_project_toc_list" class="tripal_toc_list">
-   
-     <!-- Resource Links CCK elements --><?php
-     for($i = 0; $i < count($node->field_resource_links); $i++){
-       if($node->field_resource_links[$i]['value']){
-         $matches = preg_split("/\|/",$node->field_resource_links[$i]['value']);?>
-         <li><a href="<?php print $matches[1] ?>" target="_blank"><?php print $matches[0] ?></a></li><?php
-       }
-     }?>
-     
-     <?php // ADD CUSTOMIZED <li> LINKS HERE ?>
-   </ul>
-</div>
-
-<?php } ?>

+ 0 - 0
tripal_project/theme/tripal_project_help.tpl.php → tripal_project/theme/tripal_project.help.tpl.php


+ 75 - 0
tripal_project/theme/tripal_project.theme.inc

@@ -0,0 +1,75 @@
+<?php
+/**
+ *
+ *
+ * @ingroup tripal_project
+ */
+function tripal_project_preprocess_tripal_project_relationships(&$variables) {
+  $project = $variables['node']->project;
+  
+  // expand the project object to include the project relationships.
+  $options = array(
+    'return_array' => 1,
+    // we don't want to fully recurse we only need information about the 
+    // relationship type and the object and subject projects
+    'include_fk' => array(
+      'type_id'    => 1,
+      'object_project_id'  => 1,
+      'subject_project_id' => 1,
+    ),
+  );
+  $project = tripal_core_expand_chado_vars($project, 'table', 'project_relationship', $options);
+  
+  // get the subject relationships
+  $srelationships = $project->project_relationship->subject_project_id;
+  $orelationships = $project->project_relationship->object_project_id;
+  
+  // combine both object and subject relationshisp into a single array
+  $relationships = array();
+  $relationships['object'] = array();
+  $relationships['subject'] = array();
+  
+  // iterate through the object relationships
+  if ($orelationships) {
+    foreach ($orelationships as $relationship) {      
+       $rel = new stdClass(); 
+       $rel->record = $relationship;
+       
+       // get the relationship and child types
+       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
+
+       // get the node id of the subject
+       $sql = "SELECT nid FROM {chado_project} WHERE project_id = :project_id";
+       $n = db_query($sql, array(':project_id' => $relationship->subject_project_id->project_id))->fetchObject();
+       if ($n) {
+          $rel->record->nid = $n->nid;
+       }
+  
+       if (!array_key_exists($rel_type, $relationships['object'])) {
+         $relationships['object'][$rel_type][] = $rel;
+       }
+    }
+  }
+  
+  // now add in the subject relationships
+  if ($srelationships) {
+    foreach ($srelationships as $relationship) {
+       $rel = new stdClass(); 
+       $rel->record = $relationship;
+       
+       $rel_type = t(preg_replace('/_/', " ", $relationship->type_id->name));
+       
+       // get the node id of the subject
+       $sql = "SELECT nid FROM {chado_project} WHERE project_id = :project_id";
+       $n = db_query($sql, array(':project_id' => $relationship->object_project_id->project_id))->fetchObject();
+       if ($n) {
+          $rel->record->nid = $n->nid;
+       }
+       
+       if (!array_key_exists($rel_type, $relationships['subject'])) {
+         $relationships['subject'][$rel_type][] = $rel;
+       }
+    }
+  }
+  $project->all_relationships = $relationships;
+}

+ 84 - 0
tripal_project/theme/tripal_project/tripal_project.base.tpl.php

@@ -0,0 +1,84 @@
+<?php
+$project = $variables['node']->project;
+
+// get the project description.  The first iteration of the project
+// module incorrectly stored the project description in the Drupal 
+// node->body field.  Also, the project.descriptin field is only 255
+// characters which is not large neough. Therefore, we store the description
+// in the  chado.projectprop table.  For backwards compatibility, we 
+// will check if the node->body is empty and if not we'll use that instead.
+// If there is data in the project.description field then we will use that, but
+// if there is data in the projectprop table for a descrtion then that takes 
+// precedence 
+$description = '';
+if (property_exists($node, 'body')) {
+  $description = $node->body;
+}
+if ($project->description) {
+  $description = $project->description;
+}
+else {
+  $projectprop = tripal_project_get_property($project->project_id, 'Project Description');
+  $description = $projectprop->value;
+}
+
+?>
+<div id="tripal_project-base-box" class="tripal_project-info-box tripal-info-box">
+  <div class="tripal_project-info-box-title tripal-info-box-title">Project Details</div>
+  <div class="tripal_project-info-box-desc tripal-info-box-desc"></div><?php 
+
+  // the $headers array is an array of fields to use as the colum headers. 
+  // additional documentation can be found here 
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  // This table for the project has a vertical header (down the first column)
+  // so we do not provide headers here, but specify them in the $rows array below.
+  $headers = array();
+  
+  // the $rows array contains an array of rows where each row is an array
+  // of values for each column of the table in that row.  Additional documentation
+  // can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7 
+  $rows = array();
+
+  // Project Name row
+  $rows[] = array(
+    array(
+      'data' => 'Project Name',
+      'header' => TRUE
+    ),
+    $project->name
+  );
+  // allow site admins to see the feature ID
+  if (user_access('access administration pages')) {
+    // Project ID
+    $rows[] = array(
+      array(
+        'data' => 'Project ID',
+        'header' => TRUE
+      ),
+      $project->project_id
+    );
+  }
+  // the $table array contains the headers and rows array as well as other
+  // options for controlling the display of the table.  Additional
+  // documentation can be found here:
+  // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+  $table = array(
+    'header' => $headers,
+    'rows' => $rows,
+    'attributes' => array(
+      'id' => 'tripal_project-table-base',
+    ),
+    'sticky' => FALSE,
+    'caption' => '',
+    'colgroups' => array(),
+    'empty' => '',
+  );
+  
+  // once we have our table array structure defined, we call Drupal's theme_table()
+  // function to generate the table.
+  print theme_table($table);
+  if ($description) { ?>
+    <div style="text-align: justify"><?php print $description; ?></div> <?php  
+  } ?>
+</div>

+ 80 - 0
tripal_project/theme/tripal_project/tripal_project.contact.tpl.php

@@ -0,0 +1,80 @@
+<?php
+$project = $variables['node']->project;
+
+// expand the project object to include the contacts from the project_contact
+// table in chado.
+$project = tripal_core_expand_chado_vars($project,'table','project_contact', array('return_array' => 1));
+$project_contacts = $project->project_contact;
+
+if (count($project_contacts) > 0) { ?>
+  <div id="tripal_project-contacts-box" class="tripal_project-info-box tripal-info-box">
+    <div class="tripal_project-info-box-title tripal-info-box-title">Participants</div>
+    <div class="tripal_project-info-box-desc tripal-info-box-desc">The following indivuals or groups have particpated in development or execution of this project</div><?php     
+    
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('', 'Details');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    $i = 1;
+    foreach ($project_contacts as $project_contact) {
+      $contact = $project_contact->contact_id;
+      $contact_name = $contact->name;
+      if (property_exists($contact, 'nid')) {
+        $contact_name = l($contact_name, 'node/' . $contact->nid, array('attributes' => array('target' => '_blank')));
+      }
+      
+      // Get some additional details about this contact if they exists.
+      $details = '';
+      $options = array('return_array' => 1);
+      $contact = tripal_core_expand_chado_vars($contact, 'table', 'contactprop', $options);
+      $properties = $contact->contactprop;
+      $options = array('order_by' => array('rank' => 'ASC'));
+      $properties = tripal_core_expand_chado_vars($properties, 'field', 'contactprop.value', $options);
+      
+      if (is_array($properties)) {
+        foreach ($properties as $property) {
+          // skip the description and name properties
+          if ($property->type_id->name == "contact_description" or
+              $property->type_id->name == "Surname" or
+              $property->type_id->name == "Given Name" or
+              $property->type_id->name == "First Initials" or
+              $property->type_id->name == "Suffix") {
+            continue;
+          }
+          $details .= "<br>" . $property->type_id->name . " : " .  $property->value;
+        }
+      }
+      
+      $rows[] = array(
+        $i,
+        $contact_name . $details,
+      );
+      $i++;
+    } 
+        // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_pub-table-contacts',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table);?>    
+  </div> <?php 
+}

+ 65 - 0
tripal_project/theme/tripal_project/tripal_project.properties.tpl.php

@@ -0,0 +1,65 @@
+<?php
+
+// expand the project to include the properties.
+$project = $variables['node']->project;
+$project = tripal_core_expand_chado_vars($project,'table', 'projectprop', array('return_array' => 1));
+$projectprops = $project->projectprop;
+
+// put the properties in an array so we can remove the project_description property
+$properties = array();
+if ($projectprops) {
+  foreach ($projectprops as $property) {
+    // we want to keep all properties but the project_description as that
+    // property is shown on the base template page.
+    if($property->type_id->name != 'Project Description') {
+      $property = tripal_core_expand_chado_vars($property,'field','projectprop.value');
+      $properties[] = $property;
+    }
+  }
+}
+
+
+if (count($properties) > 0) { ?>
+  <div id="tripal_project-properties-box" class="tripal_project-info-box tripal-info-box">
+    <div class="tripal_project-info-box-title tripal-info-box-title">More Details</div>
+    <div class="tripal_project-info-box-desc tripal-info-box-desc">Additional information about this project:</div><?php
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Property Name', 'Value');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    // add the properties as individual rows
+    foreach ($properties as $property) {
+      $rows[] = array(
+        ucfirst(preg_replace('/_/', ' ', $property->type_id->name)),
+        $property->value
+      );
+    } 
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_project-table-properties',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php
+}

+ 85 - 0
tripal_project/theme/tripal_project/tripal_project.publications.tpl.php

@@ -0,0 +1,85 @@
+<?php
+$project = $variables['node']->project;
+
+// expand project to include pubs 
+$options = array('return_array' => 1);
+$project = tripal_core_expand_chado_vars($project, 'table', 'project_pub', $options);
+$project_pubs = $project->project_pub; 
+
+
+if (count($project_pubs) > 0) { ?>
+  <div id="tripal_project_pub-pub-box" class="tripal_project_pub-info-box tripal-info-box">
+    <div class="tripal_project_pub-info-box-title tripal-info-box-title">Publications</div>
+    <div class="tripal_project_pub-info-box-desc tripal-info-box-desc"></div> <?php 
+  
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Year', 'Publication');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    foreach ($project_pubs as $project_pub) {
+      $pub = $project_pub->pub_id;
+      $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+      $citation = $pub->title;  // use the title as the default citation
+      
+      // get the citation for this pub if it exists
+      $values = array(
+        'pub_id' => $pub->pub_id, 
+        'type_id' => array(
+          'name' => 'Citation',
+        ),
+      );
+      $options = array('return_array' => 1);
+      $citation_prop = tripal_core_generate_chado_var('pubprop', $values, $options); 
+      if (count($citation_prop) == 1) {
+        $citation_prop = tripal_core_expand_chado_vars($citation_prop, 'field', 'pubprop.value');
+        $citation = $citation_prop[0]->value;
+      }
+      
+      // if the publication is synced then link to it
+      if ($pub->nid) {
+        // replace the title with a link
+        $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
+        $patterns = array(
+          '/(\()/', '/(\))/',
+          '/(\])/', '/(\[)/',
+          '/(\{)/', '/(\})/',
+          '/(\+)/', '/(\.)/', '/(\?)/',
+        );
+        $fixed_title = preg_replace($patterns, "\\\\$1", $pub->title);
+        $citation = preg_replace('/' . $fixed_title . '/', $link, $citation);
+      }
+      
+      $rows[] = array(
+        $pub->pyear,
+        $citation,
+      );
+    }
+    
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_project-table-publications',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php 
+}

+ 88 - 0
tripal_project/theme/tripal_project/tripal_project.relationships.tpl.php

@@ -0,0 +1,88 @@
+<?php
+/* Typically in a Tripal template, the data needed is retrieved using a call to
+ * tripal_core_expand_chado_vars function.  For example, to retrieve all 
+ * of the project relationships for this node, the following function call would be made:
+ * 
+ *   $project = tripal_core_expand_chado_vars($project,'table','project_relationship');
+ * 
+ * However, this function call can be extremely slow when there are numerous relationships.
+ * This is because the tripal_core_expand_chado_vars function is recursive and expands 
+ * all data following the foreign key relationships tree.  Therefore, to speed retrieval
+ * of data, a special variable is provided to this template:
+ * 
+ *   $project->all_relationships;
+ *   
+ * This variable is an array with two sub arrays with the keys 'object' and 'subject'.  The array with
+ * key 'object' contains relationships where the project is the object, and the array with
+ * the key 'subject' contains relationships where the project is the subject
+ */
+$project = $variables['node']->project;
+
+$all_relationships = $project->all_relationships;
+$object_rels = $all_relationships['object'];
+$subject_rels = $all_relationships['subject'];
+
+if (count($object_rels) > 0 or count($subject_rels) > 0) { ?>
+  <div id="tripal_project-relationships-box" class="tripal_project-info-box tripal-info-box">
+    <div class="tripal_project-info-box-title tripal-info-box-title">Relationships</div>
+    <div class="tripal_project-info-box-desc tripal-info-box-desc">This project is related to the following other projects:</div> <?php
+
+    // the $headers array is an array of fields to use as the colum headers.
+    // additional documentation can be found here
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $headers = array('Relationship');
+    
+    // the $rows array contains an array of rows where each row is an array
+    // of values for each column of the table in that row.  Additional documentation
+    // can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $rows = array();
+    
+    // first add in the subject relationships.  
+    foreach ($subject_rels as $rel_type => $objects){ 
+      foreach ($objects as $object){
+        // link the project to it's node
+        $object_name = $object->record->object_project_id->name;
+        if (property_exists($object->record, 'nid')) {
+          $object_name = l($object_name, "node/" . $object->record->nid, array('attributes' => array('target' => "_blank")));
+        }
+        $rows[] = array(
+          "$project->name is a \"$rel_type\" of $object_name",
+        ); 
+      }
+    }
+    
+    // second add in the object relationships.  
+    foreach ($object_rels as $rel_type => $subjects){
+      foreach ($subjects as $subject){
+        // link the project to it's node
+        $subject_name = $subject->record->subject_project_id->name;
+        if (property_exists($subject->record, 'nid')) {
+          $subject_name = l($subject_name, "node/" . $subject->record->nid, array('attributes' => array('target' => "_blank")));
+        }
+        $rows[] = array(
+          "$subject_name is a \"$rel_type\" of $project->name",
+        ); 
+      }
+    }
+    // the $table array contains the headers and rows array as well as other
+    // options for controlling the display of the table.  Additional
+    // documentation can be found here:
+    // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => 'tripal_project-table-relationship-subject',
+      ),
+      'sticky' => FALSE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+     
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    print theme_table($table); ?>
+  </div> <?php
+}

+ 36 - 0
tripal_project/theme/tripal_project/tripal_project.teaser.tpl.php

@@ -0,0 +1,36 @@
+<?php
+$node    = $variables['node'];
+$project = $variables['node']->project;
+
+// get the project description.  The first iteration of the project
+// module incorrectly stored the project description in the Drupal 
+// node->body field.  Also, the project.descriptin field is only 255
+// characters which is not large neough. Therefore, we store the description
+// in the  chado.projectprop table.  For backwards compatibility, we 
+// will check if the node->body is empty and if not we'll use that instead.
+// If there is data in the project.description field then we will use that, but
+// if there is data in the projectprop table for a descrtion then that takes 
+// precedence 
+$description = '';
+if ($node->body) {
+  $description = $node->body;
+}
+if ($node->description) {
+  $description = $project->description;
+}
+else {
+  $projectprop = tripal_project_get_property($project->project_id, 'Project Description');
+  $description = $projectprop->value;
+} ?>
+
+<div class="tripal_project-teaser tripal-teaser"> 
+  <div class="tripal-project-teaser-title tripal-teaser-title"><?php 
+    print l($node->title, "node/$node->nid", array('html' => TRUE));?>
+  </div>
+  <div class="tripal-project-teaser-text tripal-teaser-text"><?php 
+    print substr($description, 0, 650);
+    if (strlen($description) > 650) {
+      print "... " . l("[more]", "node/$node->nid");
+    } ?>
+  </div>
+</div>

+ 0 - 53
tripal_project/theme/tripal_project/tripal_project_base.tpl.php

@@ -1,53 +0,0 @@
-<?php
-$node = $variables['node'];
-$project = $variables['node']->project;
-
-// get the project description.  The first iteration of the project
-// module incorrectly stored the project description in the Drupal 
-// node->body field.  It should have been in the chado.projectprop 
-// table.  Therefore, for backwards compatibility, we will check if the
-// node->body is empty and if not we'll use that instead. Otherwise,
-// we'll pull from the projectprop table.
-$project_description = '';
-if ($node->body) {
-  $project_description = $node->body;
-}
-else {
-  // expand the project to include the properties.
-  $project = tripal_core_expand_chado_vars($project,'table','projectprop', array('return_array' => 1));  
-  $projectprops = $project->projectprop;
-  foreach ($projectprops as $property) {
-    if($property->type_id->name == 'project_description') {
-      $property = tripal_core_expand_chado_vars($property,'field','projectprop.value');
-      $project_description = $property->value;      
-    }
-  }
-  // if there is no project_description property then see if
-  // there is anything in the project.description field.  This field is only 255
-  // characters and isn't large enough for some project description, which is why
-  // the description is stored as a property.  But if we have no property then
-  // use the field
-  if (!$project_description) {
-    // we expect the project.description field will one day get changed to
-    // a text field so, we'll expand it now so that the template won't break if the field ever does change.
-    tripal_core_expand_chado_vars($project,'field','project.description');
-    $project_description = $project->description;
-  }
-}
-
-?>
-<div id="tripal_project-base-box" class="tripal_project-info-box tripal-info-box">
-  <div class="tripal_project-info-box-title tripal-info-box-title">Project Details</div>
-  <div class="tripal_project-info-box-desc tripal-info-box-desc"></div>   
-
-  <table id="tripal_project-table-base" class="tripal_project-table tripal-table tripal-table-vert">
-    <tr class="tripal_project-table-even-row tripal-table-even-row">
-      <th>Project Name</th>
-      <td><?php print $project->name; ?></td>
-    </tr>
-    <tr class="tripal_project-table-odd-row tripal-table-odd-row">
-      <th>Description</th>
-      <td><?php print $project_description?></td>
-    </tr>
-  </table> 
-</div>

+ 0 - 50
tripal_project/theme/tripal_project/tripal_project_contact.tpl.php

@@ -1,50 +0,0 @@
-<?php
-$project = $variables['node']->project;
-
-// expand the project object to include the contacts from the project_contact
-// table in chado.
-$project = tripal_core_expand_chado_vars($project,'table','project_contact', array('return_array' => 1));
-$contacts = $project->project_contact;
-
-if (count($contacts) > 0) { ?>
-  <div id="tripal_project-contacts-box" class="tripal_project-info-box tripal-info-box">
-    <div class="tripal_project-info-box-title tripal-info-box-title">People</div>
-    <div class="tripal_project-info-box-desc tripal-info-box-desc">The following people particpated in development or execution of this project</div><?php     
-    $i = 0; 
-    foreach ($contacts as $contact) { ?>
-      <b><?php print $contact->contact_id->name ?></b>, <?php print $contact->contact_id->description ?>
-      <table id="tripal_project-contacts-table" class="tripal_project-table tripal-table tripal-table-horz"> <?php
-      
-        // expand the contact to include the properties.  This table doesn't
-        // actually exist in Chado v1.11 or Chado v1.2. But, for some sites it has been
-        // added manually, and it is expected that this table will be added to fiture
-        // versions of Chado, so the code is included below to handle contact properties.
-        $contact = tripal_core_expand_chado_vars($contact,'table','contactprop');       
-        if ($contact->contactprop) {
-          foreach ($contact->contactprop as $prop) {
-             $class = 'tripal-table-odd-row';
-             if ($i % 2 == 0 ) {
-               $class = 'tripal-table-even-row';
-             }
-             # make the type a bit more reader friendly
-             $type = $prop->type_id->name;
-             $type = preg_replace("/_/", " ", $type);
-             $type = ucwords($type);
-             ?>
-             <tr class="<?php print $class ?>">
-               <td> <?php print $type ?></td>
-               <td> <?php print $prop->value ?></td>
-             </tr> <?php
-             $i++;  
-          } 
-        }
-        /* else { ?>
-          <tr class="tripal-table-odd-row">
-            <td>No contact information available for <?php print $contact->contact_id->name ?></td>
-          </tr> <?php
-        } */
-        ?>
-      </table> <?php 
-    } ?>    
-  </div> <?php 
-}

+ 0 - 41
tripal_project/theme/tripal_project/tripal_project_properties.tpl.php

@@ -1,41 +0,0 @@
-<?php
-$project = $node->project;
-
-// expand the project to include the properties.
-$project = tripal_core_expand_chado_vars($project,'table', 'projectprop', array('return_array' => 1));
-$projectprops = $project->projectprop;
-$properties = array();
-foreach ($projectprops as $property) {
-  // we want to keep all properties but the project_description as that
-  // property is shown on the base template page.
-  if($property->type_id->name != 'project_description') {
-    $property = tripal_core_expand_chado_vars($property,'field','projectprop.value');
-    $properties[] = $property;
-  }
-}
-
-if (count($properties) > 0) { ?>
-  <div id="tripal_project-properties-box" class="tripal_project-info-box tripal-info-box">
-    <div class="tripal_project-info-box-title tripal-info-box-title">Properties</div>
-    <div class="tripal_project-info-box-desc tripal-info-box-desc">Properties for this project include:</div>
-    <table class="tripal_project-table tripal-table tripal-table-horz">
-      <tr>
-        <th>Property Name</th>
-        <th>Value</th>
-      </tr> <?php
-      $i = 0;
-      foreach ($properties as $property) {
-        $class = 'tripal_project-table-odd-row tripal-table-odd-row';
-        if ($i % 2 == 0 ) {
-           $class = 'tripal_project-table-odd-row tripal-table-even-row';
-        }
-        $i++; 
-        ?>
-        <tr class="<?php print $class ?>">
-          <td><?php print ucfirst(preg_replace('/_/', ' ', $property->type_id->name)) ?></td>
-          <td><?php print $property->value ?></td>
-        </tr><?php 
-      } ?>
-    </table>
-  </div> <?php
-}

+ 0 - 58
tripal_project/theme/tripal_project/tripal_project_publications.tpl.php

@@ -1,58 +0,0 @@
-<?php
-$project  = $variables['node']->project;
-
-// expand project to include pubs 
-$project = tripal_core_expand_chado_vars($project, 'table', 'project_pub', array('return_array' => 1));
-$project_pubs = $project->project_pub;
-
-if (count($project_pubs) > 0) { ?>
-  <div id="tripal_project-pub-box" class="tripal_project-info-box tripal-info-box">
-    <div class="tripal_project-info-box-title tripal-info-box-title">Publications</div>
-    <div class="tripal_project-info-box-desc tripal-info-box-desc"></div>
-  
-    <table id="tripal_project-pub-table" class="tripal_project-table tripal-table tripal-table-vert" style="border-bottom:solid 2px #999999">
-      <tr>
-        <th>Year</th>
-        <th>Publication</th>
-      </tr> <?php
-      $i = 0;
-      foreach ($project_pubs AS $project_pubs) {
-        $pub = $project_pubs->pub_id;
-        $class = 'tripal_project-table-odd-row tripal-table-odd-row';
-        if($i % 2 == 0 ){
-           $class = 'tripal_project-table-odd-row tripal-table-even-row';
-        }
-        $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title'); 
-        $citation = $pub->title;  // use the title as the default citation
-        
-        // get the citation for this pub if it exists
-        $values = array(
-          'pub_id' => $pub->pub_id, 
-          'type_id' => array(
-            'name' => 'Citation',
-          ),
-        );
-
-        $options = array('return_array' => 1);
-        $citation_prop = tripal_core_generate_chado_var('pubprop', $values, $options); 
-        if (count($citation_prop) == 1) {
-          $citation_prop = tripal_core_expand_chado_vars($citation_prop, 'field', 'pubprop.value');
-          $citation = $citation_prop[0]->value;
-        }
-        
-        // if the publication is synced then link to it
-        if ($pub->nid) {
-          // replace the title with a link
-          $link = l($pub->title, 'node/' . $pub->nid ,array('attributes' => array('target' => '_blank')));
-          $citation = preg_replace('/' . $pub->title . '/', $link, $citation);
-        }
-        ?>
-        <tr class="<?php print $class ?>">
-          <td><?php print $pub->pyear ?></td>
-          <td><?php print $citation ?></td>
-        </tr><?php 
-        $i++;
-      }  ?>
-    </table>
-  </div><?php 
-}

+ 0 - 81
tripal_project/theme/tripal_project/tripal_project_relationships.tpl.php

@@ -1,81 +0,0 @@
-<?php
-// this template does not follow the typical Tripal API. Normally
-// variables are expanded using the tripal_core_expand_chado_vars API
-// function call, but expanding the relationships table does not yeild
-// a meaningful order to the data.  Therefore, relationships are preprocessed
-// into an array named 'all_relationships', which is used in the template below.
-
-$project = $variables['node']->project;
-
-$all_relationships = $project->all_relationships;
-$object_rels = $all_relationships['object'];
-$subject_rels = $all_relationships['subject'];
-
-// make the project type a bit more human readable
-$project_type =  preg_replace("/_/", ' ', $project->type_id->name);
-
-if (count($object_rels) > 0 or count($subject_rels) > 0) {
-?>
-  <div id="tripal_project-relationships-box" class="tripal_project-info-box tripal-info-box">
-    <div class="tripal_project-info-box-title tripal-info-box-title">Relationships</div>
-    <!--  <div class="tripal_project-info-box-desc tripal-info-box-desc"></div> --><?php
-    
-      // first add in the subject relationships.  
-      foreach ($subject_rels as $rel_type => $rels){
-         // make the type a bit more human readable
-         $rel_type = preg_replace("/_/", ' ', $rel_type);
-         $rel_type = preg_replace("/^is/", '', $rel_type);
-         // iterate through each parent   
-         foreach ($rels as $obj_type => $objects){?>
-           <p>This project is a <b><?php print $rel_type ?></b> of the following project(s):
-           <table id="tripal_project-relationships_as_object-table" class="tripal_project-table tripal-table tripal-table-horz">
-             <tr>
-               <th>Project Name</th>
-             </tr> <?php
-             foreach ($objects as $object){ ?>
-               <tr>
-                 <td><?php 
-                    if ($object->nid) {
-                      print "<a href=\"" . url("node/" . $object->nid) . "\" target=\"_blank\">" . $object->name . "</a>";
-                    }
-                    else {
-                      print $object->name;
-                    } ?>
-                 </td>
-               </tr> <?php
-             } ?>
-             </table>
-             </p><br><?php
-         }
-      }
-      
-      // second add in the object relationships.  
-      foreach ($object_rels as $rel_type => $rels){
-         // make the type more human readable
-         $rel_type = preg_replace('/_/', ' ', $rel_type);
-         $rel_type = preg_replace("/^is/", '', $rel_type);
-         // iterate through the children         
-         foreach ($rels as $subject_type => $subjects){?>
-           <p>The following projects are a <b><?php print $rel_type ?></b> of this project:
-           <table id="tripal_project-relationships_as_object-table" class="tripal_project-table tripal-table tripal-table-horz">
-             <tr>
-               <th>Project Name</th>
-             </tr> <?php
-             foreach ($subjects as $subject){ ?>
-               <tr>
-                 <td><?php 
-                    if ($subject->nid) {
-                      print "<a href=\"" . url("node/" . $subject->nid) . "\" target=\"_blank\">" . $subject->name . "</a>";
-                    }
-                    else {
-                      print $subject->name;
-                    } ?>
-                 </td>
-               </tr> <?php
-             } ?>
-             </table>
-             </p><br><?php
-         }
-      } ?>
-  </div> <?php
-}

+ 0 - 20
tripal_project/theme/tripal_project/tripal_project_teaser.tpl.php

@@ -1,20 +0,0 @@
-<?php
-$node = $variables['node'];
-$project = $variables['node']->project;
-
-?>
-<div id="tripal_project-base-box" class="tripal_project-info-box tripal-info-box">
-  <div class="tripal_project-info-box-title tripal-info-box-title">Project Details</div>
-  <div class="tripal_project-info-box-desc tripal-info-box-desc"></div>   
-
-  <table id="tripal_project-table-base" class="tripal_project-table tripal-table tripal-table-vert">
-    <tr class="tripal_project-table-even-row tripal-table-even-row">
-      <th>Project Name</th>
-      <td><?php print $project->name; ?></td>
-    </tr>
-    <tr class="tripal_project-table-odd-row tripal-table-odd-row">
-      <th>Description</th>
-      <td><i><?php print $project->description; ?></i></td>
-    </tr>
-  </table> 
-</div>

+ 59 - 6
tripal_project/tripal_project.install

@@ -86,14 +86,67 @@ function tripal_project_schema() {
   return $schema;
 }
 
-/*
+/**
+ * 
+ */
+function tripal_project_add_cvs() {
+  tripal_cv_add_cv('project_property', 'Contains properties for projects');
+}
+/**
  *
  */
 function tripal_project_add_cvterms() {
 
-  // Insert cvterm 'library_description' into cvterm table of chado
-  // database. This CV term is used to keep track of the library
-  // description in the libraryprop table.
-  tripal_cv_add_cvterm(array('name' => 'project_description', 'def' => 'Description of a project'),
-    'tripal', 0, 1, 'tripal');
+  // Insert cvterm 'Project Description' into cvterm table of chado
+  // database. This CV term is used to keep track of the project
+  // description in the projectprop table.
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'Project Description', 
+      'def'  => 'Description of a project'
+    ),
+    'project_property', 0, 1, 'tripal'
+  );
+  
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'Project Type',
+      'def'  => 'The short few word description of the type of project.'
+    ),
+   'project_property', 0, 1, 'tripal'
+  );
+  tripal_cv_add_cvterm(
+    array(
+      'name' => 'Funding Source',
+      'def'  => 'The funding source for this project.'
+    ),
+    'project_property', 0, 1, 'tripal'
+  );
+}
+
+/**
+ * This is the required update for tripal_project when upgrading from Drupal core API 6.x.
+ */
+function tripal_project_update_7000() {
+
+  // For Tripal in Drupal 6 the project_description cvterm was stored in the
+  // 'tripal' CV.  It should be stored in the new project_property CV that
+  // is added by this module for Tripal 2.0 and Drupal 7.  So, we need to
+  // reset the CV ID for that term and rename the term to 'Project Description'
+  tripal_project_add_cvs();
+  $cv = tripal_cv_get_cv_by_name('project_property');
+  $cvterm = tripal_cv_get_cvterm_by_name('project_description', $cv->cv_id);
+  $match = array(
+    'cvterm_id' => $cvterm->cvterm_id,
+  );
+  $values = array(
+    'name'  => 'Project Description',
+  );
+  tripal_core_chado_update('cvterm', $match, $values);
+  if (!$success) {
+    throw new DrupalUpdateException('Failed to move project properties to new project_property CV.');
+  }
+  
+  // add in new CVterms
+  tripal_project_add_cvterms();
 }

+ 92 - 371
tripal_project/tripal_project.module

@@ -1,7 +1,8 @@
 <?php
-
-require('includes/tripal_project.admin.inc');
 require('api/tripal_project.api.inc');
+require('theme/tripal_project.theme.inc');
+require('includes/tripal_project.admin.inc');
+require('includes/tripal_project.chado_node.inc');
 
 /**
  *  @file
@@ -30,12 +31,24 @@ function tripal_project_node_info() {
     'chado_project' => array(
       'name' => t('Project'),
       'base' => 'chado_project',
-      'description' => t('A module for interfacing the GMOD chado database with Drupal, providing viewing of projects'),
+      'description' => t('A project from the Chado database'),
       'has_title' => TRUE,
       'title_label' => t('Project Name'),
       'had_body' => TRUE,
       'body_label' => t('Full Description'),
-    )
+      'chado_node_api' => array(
+        'base_table' => 'project',
+        'hook_prefix' => 'chado_project',
+        'record_type_title' => array(
+          'singular' => t('Project'),
+          'plural' => t('Projects')
+        ),
+        'sync_filters' => array(
+          'type_id' => FALSE,
+          'organism_id' => FALSE
+        ),
+      ),
+    ),
   );
 }
 
@@ -63,15 +76,15 @@ function tripal_project_views_api() {
 function tripal_project_menu() {
   $items[ 'admin/tripal/chado/tripal_project' ]= array(
     'title' => 'Projects',
-    'description' => ('A grouping of a variety of data (ie: group natural diversity experiment).'),
+    'description' => ('A project. Can be used for grouping data such as with the natural diversity module data.'),
     'page callback' => 'tripal_project_admin_project_view',
     'access arguments' => array('adminster tripal projects'),
     'type' => MENU_NORMAL_ITEM
   );
 
-  $items[ 'admin/tripal/chado/tripal_project/help' ]= array(
+  $items['admin/tripal/chado/tripal_project/help']= array(
     'title' => 'Help',
-    'description' => ("A description of the Tripal Project module including a short description of it's usage."),
+    'description' => ("Basic Description of Tripal Project Module Functionality."),
     'page callback' => 'theme',
     'page arguments' => array('tripal_project_help'),
     'access arguments' => array('adminster tripal projects'),
@@ -79,7 +92,7 @@ function tripal_project_menu() {
     'weight' => 6
   );
 
-  $items[ 'admin/tripal/chado/tripal_project/configuration' ]= array(
+  $items['admin/tripal/chado/tripal_project/configuration']= array(
     'title' => 'Settings',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('tripal_project_admin'),
@@ -88,11 +101,21 @@ function tripal_project_menu() {
     'weight' => 4
   );
 
+  $items['admin/tripal/chado/tripal_project/sync'] = array(
+    'title' => ' Sync',
+    'description' => 'Create pages on this site for projects stored in Chado',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('tripal_core_chado_node_sync_form', 'tripal_project', 'chado_project'),
+    'access arguments' => array('administer tripal projects'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 0
+  );
+  
   $items['admin/tripal/chado/tripal_project/views/projects/enable'] = array(
     'title' => 'Enable Project Administrative View',
     'page callback' => 'tripal_views_admin_enable_view',
     'page arguments' => array('tripal_project_admin_projects', 'admin/tripal/chado/tripal_project'),
-    'access arguments' => array('administer tripal_bulk_loader'),
+    'access arguments' => array('administer tripal projects'),
     'type' => MENU_CALLBACK,
   );
 
@@ -143,55 +166,7 @@ function tripal_project_permission() {
   );
 }
 
-/**
- * Implement hook_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_project
- */
-function chado_project_node_access($node, $op, $account) {
 
-  if ($op == 'create') {
-    if (!user_access('create chado_projects content', $account)) {
-      return FALSE;
-    }
-    return TRUE;
-  }
-  if ($op == 'update') {
-    if (!user_access('edit chado_projects content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'delete') {
-    if (!user_access('delete chado_projects content', $account)) {
-      return FALSE;
-    }
-  }
-  if ($op == 'view') {
-    if (!user_access('access chado_projects content', $account)) {
-      return FALSE;
-    }
-  }
-  return NULL;
-}
 
 /**
  *  We need to let drupal know about our theme functions and their arguments.
@@ -200,270 +175,88 @@ function chado_project_node_access($node, $op, $account) {
  *
  * @ingroup tripal_project
  */
-function tripal_project_theme() {
-  $theme_path = drupal_get_path('module', 'tripal_project') . '/theme';
+function tripal_project_theme($existing, $type, $theme, $path) {
+  $core_path = drupal_get_path('module', 'tripal_core');
 
   $items = array(
+    'node__chado_project' => array(
+      'template' => 'node--chado-generic',
+      'render element' => 'node',
+      'base hook' => 'node',
+      'path' => "$core_path/theme",
+    ),
     'tripal_project_base' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_project_base',
-      'path' => "$theme_path/tripal_project",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.base',
+      'path' => "$path/theme/tripal_project",
     ),
     'tripal_project_contact' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_project_contact',
-      'path' => "$theme_path/tripal_project",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.contact',
+      'path' => "$path/theme/tripal_project",
+    ),
+    'tripal_project_properties' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.properties',
+      'path' => "$path/theme/tripal_project",
     ),
     'tripal_project_publications' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_project_publications',
-      'path' => "$theme_path/tripal_project",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.publications',
+      'path' => "$path/theme/tripal_project",
     ),
     'tripal_project_relationships' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_project_relationships',
-      'path' => "$theme_path/tripal_project",
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.relationships',
+      'path' => "$path/theme/tripal_project",
     ),
-    'tripal_project_properties' => array(
-      'arguments' => array('node' => NULL),
-      'template' => 'tripal_project_properties',
-      'path' => "$theme_path/tripal_project",
+    'tripal_project_teaser' => array(
+      'variables' => array('node' => NULL),
+      'template' => 'tripal_project.teaser',
+      'path' => "$path/theme/tripal_project",
     ),
     'tripal_project_help' => array(
-      'template' => 'tripal_project_help',
-      'arguments' =>  array(NULL),
-      'path' => $theme_path,
+      'variables' => 'tripal_project.help',
+      'variables' =>  array(NULL),
+      'path' => "$path/theme",
     ),
   );
   return $items;
 }
-/**
- * Implementation of hook_form().
- *
- *  This form takes the Project Title information and description from the user.
- *
- *  @parm $node
- *    The initialized node
- *
- *  @parm $form_state
- *    The state of the form, that has the user entered information that is neccessary for adding
- *    information to the project
- *
- *  @return $form
- *    An array as described by the Drupal Form API
- *
- *
- * @ingroup tripal_project
- */
-function chado_project_form(&$node, $form_state) {
-  $form = array();
-
-  $project = $node->project;
-
-  // get the project default values.  When this module was first created
-  // the project description was incorrectly stored in the $node->body field.
-  // It is better to store it in the Chado tables.  However, the 'description'
-  // field of the project table is only 255 characters.  So, we are going
-  // to follow the same as the project module and store the description in
-  // the projectprop table and leave the project.description field blank.
-  // however, for backwards compatibitily, we check to see if the description
-  // is in the $node->body field. If it is we'll use that.  When the node is
-  // edited the text will be moved out of the body and into the projectprop
-  // table where it should belong.
-  if ($node->body) {
-    $project_description = $node->body;
-  }
-  else {
-    $project_description = $node->project_description;
-  }
-  if (!$project_description) {
-    $projectprop = tripal_project_get_property($project->project_id, 'project_description');
-    $project_description = $projectprop->value;
-  }
-
-  // keep track of the project id if we have.  If we do have one then
-  // this is an update as opposed to an insert.
-  $form['project_id'] = array(
-    '#type' => 'value',
-    '#value' => $project->project_id,
-  );
-
-  $form['title']= array(
-    '#type'          => 'textfield',
-    '#title'         => t('Project Title'),
-    '#description'   => t('Please enter the title for this project. This appears at the top of the project page.'),
-    '#required'      => TRUE,
-    '#default_value' => $node->title,
-    '#weight'        => 1
-  );
 
-  $form['project_description']= array(
-    '#type'          => 'textarea',
-    '#title'         => t('Project Description'),
-    '#description'   => t('A brief description of the project'),
-    '#required'      => TRUE,
-    '#default_value' => $project_description,
-    '#weight'        => 5
-  );
-
-  return $form;
-
-}
 /**
- *  validates submission of form when adding or updating a project node
  *
- * @ingroup tripal_project
+ * @ingroup tripal_feature
  */
-function chado_project_validate($node, $form, &$form_state) {
-  $project = 0;
-  // check to make sure the name on the project is unique
-  // before we try to insert into chado.
-  if ($node->project_id) {
-    $sql = "SELECT * FROM {project} WHERE name = :name AND NOT project_id = :project_id";
-    $project = chado_query($sql, array(':name' => $node->title, ':project_id' => $node->project_id))->fetchObject();
-  }
-  else {
-    $sql = "SELECT * FROM {project} WHERE name = :name";
-    $project = chado_query($sql, array(':name' => $node->title))->fetchObject();
-  }
-  if ($project) {
-    form_set_error('title', t('The unique project name already exists. Please choose another'));
+function tripal_project_node_view($node, $view_mode, $langcode) {
+  switch ($node->type) {
+    case 'chado_project':
+      // Show feature browser and counts
+      if ($view_mode == 'full') {
+        $node->content['tripal_project_base'] = array(
+          '#value' => theme('tripal_project_base', array('node' => $node)),
+        );
+        $node->content['tripal_project_contact'] = array(
+          '#value' => theme('tripal_project_contact', array('node' => $node)),
+        );
+        $node->content['tripal_project_properties'] = array(
+          '#value' => theme('tripal_project_properties', array('node' => $node)),
+        );
+        $node->content['tripal_project_publications'] = array(
+          '#value' => theme('tripal_project_publications', array('node' => $node)),
+        );
+        $node->content['tripal_project_relationships'] = array(
+          '#value' => theme('tripal_project_relationships', array('node' => $node)),
+        );
+      }
+      if ($view_mode == 'teaser') {
+        $node->content['tripal_project_teaser'] = array(
+          '#value' => theme('tripal_project_teaser', array('node' => $node)),
+        );
+      }
+      break;
   }
 }
-/**
- * Implementation of hook_insert().
- *
- *  @parm $node
- *    Then node that has the information stored within, accessed given the nid
- *
- *
- * @ingroup tripal_project
- */
-function chado_project_insert($node) {
-
-  if ($node->project_id) {
-    $project['project_id'] = $node->project_id;
-  }
-  else {
-    $values = array(
-      'name' => $node->title,
-      'description' => '',
-    );
-    $project = tripal_core_chado_insert('project', $values);
-  }
-
-  if ($project) {
-     // add the description property
-    tripal_project_insert_property($project['project_id'], 'project_description',
-      $node->project_description);
-
-    // make sure the entry for this feature doesn't already exist in the chado_project table
-    // if it doesn't exist then we want to add it.
-    $project_id = chado_get_id_for_node('project', $node->nid) ;
-    if (!$project_id) {
-       // next add the item to the drupal table
-      $sql = "
-        INSERT INTO {chado_project} (nid, vid, project_id)
-        VALUES (:nid, :vid, :project_id)
-      ";
-      db_query($sql, array(':nid' => $node->nid, ':vid' => $node->vid, ':project_id' => $project['project_id']));
-    }
-  }
-  else {
-    drupal_set_message(t('Unable to add project.', 'warning'));
-    watchdog('tripal_project', 'Insert feature: Unable to create project where values: %values',
-      array('%values' => print_r($values, TRUE)), WATCHDOG_WARNING);
-  }
-}
-
-/**
- *
- * Implementation of hook_delete().
- *
- * @param $node
- * The node which is to be deleted, only chado project and chado_project need to be dealt with
- * since the drupal node is deleted automagically
- *
- *
- * @ingroup tripal_project
- */
-function chado_project_delete($node) {
-
-  $project_id = chado_get_id_for_node('project', $node->nid);
-
-  // if we don't have a project id for this node then this isn't a node of
-  // type chado_project or the entry in the chado_project table was lost.
-  if (!$project_id) {
-    return;
-  }
-
-  // Remove data from {chado_project}, {node} and {node_revisions} tables of
-  // drupal database
-  $sql_del = "DELETE FROM {chado_project} 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 = :vod";
-  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 project and projectprop tables of chado database as well
-  chado_query("DELETE FROM {projectprop} WHERE project_id = :project_id", array(':project_id' => $project_id));
-  chado_query("DELETE FROM {project} WHERE project_id = :project_id", array(':project_id' => $project_id));
-}
-
-/**
- * Implements hook_update().
- *
- * @param $node
- *  The node which is to have its containing information updated when the user modifies information
- *  pertaining to the specific project
- *
- *
- * @ingroup tripal_project
- */
-function chado_project_update($node) {
- if ($node->revision) {
-    // there is no way to handle revisions in Chado but leave
-    // this here just to make note we've addressed it.
-  }
-
-  // update the project and the description
-  $project_id = chado_get_id_for_node('project', $node->nid) ;
-  $match = array('project_id' => $project_id);
-  $values = array(
-    'name' => $node->title,
-    'description' => '',
-  );
-  $status = tripal_core_chado_update('project', $match, $values);
-  tripal_project_update_property($project_id, 'project_description', $node->project_description, 1);
-}
-
-/**
- * Implementation of node_load().
- *
- * @param $node
- *   The node that is to have its containing information loaded
- *
- * @return $node
- *   The node, containing the loaded project with the current nid
- *
- *
- * @ingroup tripal_project
- */
-function chado_project_load($node) {
-
-  // get the feature details from chado
-  $project_id = chado_get_id_for_node('project', $node->nid);
-
-  $values = array('project_id' => $project_id);
-  $project = tripal_core_generate_chado_var('project', $values);
-
-  $additions = new stdClass();
-  $additions->project = $project;
-  return $additions;
-
-}
-
 /**
  *
  * @ingroup tripal_project
@@ -524,79 +317,7 @@ function tripal_project_block_view($delta = '') {
     return $block;
   }
 }
-/**
- *
- *
- * @ingroup tripal_project
- */
-function tripal_project_preprocess_tripal_project_relationships(&$variables) {
-  // we want to provide a new variable that contains the matched projects.
-  $project = $variables['node']->project;
-
-  // normally we would use tripal_core_expand_chado_vars to expand our
-  // organism object and add in the relationships, however whan a large
-  // number of relationships are present this significantly slows the
-  // query, therefore we will manually perform the query
-  $sql = "
-    SELECT P.name, P.project_id, CP.nid, CVT.name as rel_type
-    FROM project_relationship PR
-      INNER JOIN {project} P            ON PR.object_project_id = P.project_id
-      INNER JOIN {cvterm} CVT           ON PR.type_id           = CVT.cvterm_id
-      LEFT JOIN public.chado_project CP ON P.project_id         = CP.project_id
-    WHERE PR.subject_project_id = :project_id
-  ";
-  $as_subject = chado_query($sql, array(':project_id' => $project->project_id));
-  $sql = "
-    SELECT P.name, P.project_id, CP.nid, CVT.name as rel_type
-    FROM project_relationship PR
-      INNER JOIN {project} P            ON PR.subject_project_id = P.project_id
-      INNER JOIN {cvterm} CVT           ON PR.type_id            = CVT.cvterm_id
-      LEFT JOIN public.chado_project CP ON P.project_id          = CP.project_id
-    WHERE PR.object_project_id = :project_id
-  ";
-  $as_object = chado_query($sql, array(':project_id' => $project->project_id));
-
-  // combine both object and subject relationshisp into a single array
-  $relationships = array();
-  $relationships['object'] = array();
-  $relationships['subject'] = array();
-
-  // iterate through the object relationships
-  while ($relationship = $as_object->fetchObject()) {
-
-     // get the relationship and child types
-     $rel_type = t(preg_replace('/_/', " ", $relationship->rel_type));
-     $sub_type = t(preg_replace('/_/', " ", $relationship->sub_type));
-
-     if (!array_key_exists($rel_type, $relationships['object'])) {
-       $relationships['object'][$rel_type] = array();
-     }
-     if (!array_key_exists($sub_type, $relationships['object'][$rel_type])) {
-       $relationships['object'][$rel_type][$sub_type] = array();
-     }
-     $relationships['object'][$rel_type][$sub_type][] = $relationship;
-  }
 
-  // now add in the subject relationships
-  while ($relationship = $as_subject->fetchObject()) {
-
-     // get the relationship and child types
-     $rel_type = t(preg_replace('/_/', " ", $relationship->rel_type));
-     $obj_type = t(preg_replace('/_/', " ", $relationship->obj_type));
-
-     if (!array_key_exists($rel_type, $relationships['subject'])) {
-       $relationships['subject'][$rel_type] = array();
-     }
-     if (!array_key_exists($obj_type, $relationships['subject'][$rel_type])) {
-       $relationships['subject'][$rel_type][$obj_type] = array();
-     }
-     $relationships['subject'][$rel_type][$obj_type][] = $relationship;
-  }
-
-
-  $project->all_relationships = $relationships;
-
-}
 /**
  * Implementation of hook_form_alter()
  *

+ 242 - 180
tripal_pub/api/tripal_pub.api.inc

@@ -99,92 +99,148 @@ function tripal_pub_get_raw_data($dbxref) {
  */
 function tripal_pub_update_publications($do_contact = FALSE, $dbxref = NULL, $db = NULL) {
 
-  // get a persistent connection
-  $connection = tripal_db_persistent_chado();
-  if (!$connection) {
-    print "A persistant connection was not obtained. Loading will be slow\n";
-  }
-
-  // if we cannot get a connection then let the user know the loading will be slow
-  tripal_db_start_transaction();
-  if ($connection) {
-    print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
-           "If the load fails or is terminated prematurely then the entire set of \n" .
-           "insertions/updates is rolled back and will not be found in the database\n\n";
-  }
+  print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
+      "If the load fails or is terminated prematurely then the entire set of \n" .
+      "insertions/updates is rolled back and will not be found in the database\n\n";
+  $transaction = db_transaction();
+  try {
 
-  // get a list of all publications by their Dbxrefs that have supported databases
-  $sql = "
-    SELECT DB.name as db_name, DBX.accession
-    FROM pub P
-      INNER JOIN pub_dbxref PDBX ON P.pub_id = PDBX.pub_id
-      INNER JOIN dbxref DBX      ON DBX.dbxref_id = PDBX.dbxref_id
-      INNER JOIN db DB           ON DB.db_id = DBX.db_id
-  "; 
-  $args = array();
-  if ($dbxref and preg_match('/^(.*?):(.*?)$/', $dbxref, $matches)) {
-    $dbname = $matches[1];
-    $accession = $matches[2];
-    $sql .= "WHERE DBX.accession = :accession and DB.name = :dbname ";
-    $args[':accession'] = $accession;
-    $args[':dbname'] = $dbname;
+    // get a list of all publications by their Dbxrefs that have supported databases
+    $sql = "
+      SELECT DB.name as db_name, DBX.accession
+      FROM pub P
+        INNER JOIN pub_dbxref PDBX ON P.pub_id = PDBX.pub_id
+        INNER JOIN dbxref DBX      ON DBX.dbxref_id = PDBX.dbxref_id
+        INNER JOIN db DB           ON DB.db_id = DBX.db_id
+    "; 
+    $args = array();
+    if ($dbxref and preg_match('/^(.*?):(.*?)$/', $dbxref, $matches)) {
+      $dbname = $matches[1];
+      $accession = $matches[2];
+      $sql .= "WHERE DBX.accession = :accession and DB.name = :dbname ";
+      $args[':accession'] = $accession;
+      $args[':dbname'] = $dbname;
+    }
+    elseif ($db) {
+      $sql .= " WHERE DB.name = :dbname ";
+      $args[':dbname'] = $db;
+    }
+    $sql .= "ORDER BY DB.name, P.pub_id";
+    $results = chado_query($sql, $args);
+  
+    $num_to_retrieve = 100;
+    $i = 0;                 // count the number of IDs. When we hit $num_to_retrieve we'll do the query
+    $curr_db = '';          // keeps track of the current current database
+    $ids = array();         // the list of IDs for the database
+    $search = array();      // the search array passed to the search function
+  
+    // iterate through the pub IDs
+    while ($pub = $results->fetchObject()) {
+      $accession = $pub->accession;
+      $remote_db = $pub->db_name;
+  
+      // here we need to only update publications for databases we support
+      $supported_dbs = variable_get('tripal_pub_supported_dbs', array());
+      if(!in_array($remote_db, $supported_dbs)) {
+        continue;
+      }
+      $search = array(
+        'num_criteria' => 1,
+        'remote_db' => $remote_db,
+        'criteria' => array(
+          '1' => array(
+            'search_terms' => "$remote_db:$accession",
+            'scope' => 'id',
+            'operation' => '',
+            'is_phrase' => 0,
+          ),
+        ),
+      );
+      $pubs = tripal_pub_get_remote_search_results($remote_db, $search, 1, 0);
+      tripal_pub_add_publications($pubs, $do_contact, TRUE);
+  
+      $i++;
+    }
+  
+    // sync the newly added publications with Drupal
+    print "Syncing publications with Drupal...\n";
+    tripal_pub_sync_pubs();
+  
+    // if the caller wants to create contacts then we should sync them
+    if ($do_contact) {
+      print "Syncing contacts with Drupal...\n";
+      tripal_contact_sync_contacts();
+    }
   }
-  elseif ($db) {
-    $sql .= " WHERE DB.name = :dbname ";
-    $args[':dbname'] = $db;
+  catch (Exception $e) {
+    print "\n"; // make sure we start errors on new line
+    watchdog_exception('T_pub_import', $e);
+    $transaction->rollback();
+    print "FAILED: Rolling back database changes...\n";
+    return;
   }
-  $sql .= "ORDER BY DB.name, P.pub_id";
-  $results = chado_query($sql, $args);
-
-  $num_to_retrieve = 100;
-  $i = 0;                 // count the number of IDs. When we hit $num_to_retrieve we'll do the query
-  $curr_db = '';          // keeps track of the current current database
-  $ids = array();         // the list of IDs for the database
-  $search = array();      // the search array passed to the search function
-
-  // iterate through the pub IDs
-  while ($pub = $results->fetchObject()) {
-    $accession = $pub->accession;
-    $remote_db = $pub->db_name;
-
-    // here we need to only update publications for databases we support
-    $supported_dbs = variable_get('tripal_pub_supported_dbs', array());
-    if(!in_array($remote_db, $supported_dbs)) {
-      continue;
-    }
-    $search = array(
-      'num_criteria' => 1,
-      'remote_db' => $remote_db,
-      'criteria' => array(
-        '1' => array(
-          'search_terms' => "$remote_db:$accession",
-          'scope' => 'id',
-          'operation' => '',
-          'is_phrase' => 0,
-        ),
-      ),
-    );
-    $pubs = tripal_pub_get_remote_search_results($remote_db, $search, 1, 0);
-    tripal_pub_add_publications($pubs, $do_contact, TRUE);
+  print "Done.\n";
+}
+/**
+ *
+ * @param $pub_importer_id
+ */
+function tripal_pub_import_publications_by_import_id($import_id, $job_id = NULL) {
+  print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
+        "If the load fails or is terminated prematurely then the entire set of \n" .
+        "insertions/updates is rolled back and will not be found in the database\n\n";
 
-    $i++;
-  }
+  // start the transaction
+  $transaction = db_transaction();
 
-  // transaction is complete
-  tripal_db_commit_transaction();
+  try {
+    $page = 0;
+    $do_contact = FALSE;
+    $num_to_retrieve = 100;
 
-  print "Transaction Complete\n";
+    // get all of the loaders
+    $args = array(':import_id' => $import_id);
+    $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :import_id ";
+    $import = db_query($sql, $args)->fetchObject();
 
-  // sync the newly added publications with Drupal
-  print "Syncing publications with Drupal...\n";
-  tripal_pub_sync_pubs();
+    print "Importing: " . $import->name . "\n";
 
-  // if the caller wants to create contacts then we should sync them
-  if ($do_contact) {
-    print "Syncing contacts with Drupal...\n";
-    tripal_contact_sync_contacts();
+    $criteria = unserialize($import->criteria);
+    $remote_db = $criteria['remote_db'];
+    $total_pubs = 0;
+    do {
+      // retrieve the pubs for this page. We'll retreive 100 at a time
+      $results  = tripal_pub_get_remote_search_results($remote_db, $criteria, $num_to_retrieve, $page);
+      $pubs     = $results['pubs'];
+      $num_pubs = $rseults['total_records'];
+      $total_pubs += $num_pubs;
+      tripal_pub_add_publications($pubs, $import->do_contact);
+      $page++;
+    }
+    // continue looping until we have a $pubs array that does not have
+    // our requested numer of records.  This means we've hit the end
+    while (count($pubs) == $num_to_retrieve);
+
+    // sync the newly added publications with Drupal. If the user
+    // requested a report then we don't want to print any syncing information
+    // so pass 'FALSE' to the sync call
+    print "Syncing publications with Drupal...\n";
+    tripal_pub_sync_pubs();
+
+    // if any of the importers wanted to create contacts from the authors then sync them
+    if($import->do_contact) {
+      print "Syncing contacts with Drupal...\n";
+      tripal_contact_sync_contacts();
+    }
+    tripal_job_set_progress($job_id, '100');
+  }
+  catch (Exception $e) {
+    print "\n"; // make sure we start errors on new line
+    watchdog_exception('T_pub_import', $e);
+    $transaction->rollback();
+    print "FAILED: Rolling back database changes...\n";
+    return;
   }
-
   print "Done.\n";
 }
 /*
@@ -194,6 +250,10 @@ function tripal_pub_import_publications($report_email = FALSE, $do_update = FALS
   $num_to_retrieve = 100;
   $page = 0;
   
+  print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
+      "If the load fails or is terminated prematurely then the entire set of \n" .
+      "insertions/updates is rolled back and will not be found in the database\n\n";
+  
   // start the transaction
   $transaction = db_transaction();
   
@@ -224,53 +284,51 @@ function tripal_pub_import_publications($report_email = FALSE, $do_update = FALS
       // our requested numer of records.  This means we've hit the end
       while (count($pubs) == $num_to_retrieve);
     }
+    
+    // sync the newly added publications with Drupal. If the user
+    // requested a report then we don't want to print any syncing information
+    // so pass 'FALSE' to the sync call
+    print "Syncing publications with Drupal...\n";
+    tripal_pub_sync_pubs();
+  
+    // iterate through each of the reports and generate a final report with HTML links
+    $HTML_report = '';
+    if ($report_email) {
+      $HTML_report .= "<html>";
+      global $base_url;
+      foreach ($reports as $importer => $report) {
+        $total = count($report['inserted']);
+        $HTML_report .= "<b>$total new publications from importer: $importer</b><br><ol>\n";
+        foreach ($report['inserted'] as $pub) {
+          $item = $pub['Title'];
+          if (array_key_exists('pub_id', $pub)) {
+            $item = l($pub['Title'], "$base_url/pub/" . $pub['pub_id']);
+          }
+          $HTML_report .= "<li>$item</li>\n";
+        }
+        $HTML_report .= "</ol>\n";
+      }
+      $HTML_report .= "</html>";
+      $site_email = variable_get('site_mail', '');
+      $params = array(
+        'message' => $HTML_report
+      );
+      drupal_mail('tripal_pub', 'import_report', $report_email, language_default(), $params, $site_email, TRUE);
+    }
+  
+    // if any of the importers wanted to create contacts from the authors then sync them
+    if($do_contact) {
+      print "Syncing contacts with Drupal...\n";
+      tripal_contact_sync_contacts();
+    }
   }
   catch (Exception $e) {
     print "\n"; // make sure we start errors on new line
     watchdog_exception('T_pub_import', $e);
-    $transaction->rollback();
-    print "FAILED: Rolling back database changes...\n";
+      $transaction->rollback();
+      print "FAILED: Rolling back database changes...\n";
     return;
   }
-  print "Transaction Complete\n";
-
-  // sync the newly added publications with Drupal. If the user
-  // requested a report then we don't want to print any syncing information
-  // so pass 'FALSE' to the sync call
-  print "Syncing publications with Drupal...\n";
-  tripal_pub_sync_pubs();
-
-  // iterate through each of the reports and generate a final report with HTML links
-  $HTML_report = '';
-  if ($report_email) {
-    $HTML_report .= "<html>";
-    global $base_url;
-    foreach ($reports as $importer => $report) {
-      $total = count($report['inserted']);
-      $HTML_report .= "<b>$total new publications from importer: $importer</b><br><ol>\n";
-      foreach ($report['inserted'] as $pub) {
-        $item = $pub['Title'];
-        if (array_key_exists('pub_id', $pub)) {
-          $item = l($pub['Title'], "$base_url/pub/" . $pub['pub_id']);
-        }
-        $HTML_report .= "<li>$item</li>\n";
-      }
-      $HTML_report .= "</ol>\n";
-    }
-    $HTML_report .= "</html>";
-    $site_email = variable_get('site_mail', '');
-    $params = array(
-      'message' => $HTML_report
-    );
-    drupal_mail('tripal_pub', 'import_report', $report_email, language_default(), $params, $site_email, TRUE);
-  }
-
-  // if any of the importers wanted to create contacts from the authors then sync them
-  if($do_contact) {
-    print "Syncing contacts with Drupal...\n";
-    tripal_contact_sync_contacts();
-  }
-   
   print "Done.\n";
 }
 /*
@@ -282,61 +340,61 @@ function tripal_pub_import_by_dbxref($pub_dbxref, $do_contact = FALSE, $do_updat
   $page = 0;
   $num_pubs = 0;
 
-  // get a persistent connection
-  $connection = tripal_db_persistent_chado();
-  if (!$connection) {
-    print "A persistant connection was not obtained. Loading will be slow\n";
-  }
-
-  // if we cannot get a connection then let the user know the loading will be slow
-  tripal_db_start_transaction();
-  if ($connection) {
-    print "\nNOTE: Loading of the publication is performed using a database transaction. \n" .
-           "If the load fails or is terminated prematurely then the entire set of \n" .
-           "insertions/updates is rolled back and will not be found in the database\n\n";
-  }
-
-  if(preg_match('/^(.*?):(.*?)$/', $pub_dbxref, $matches)) {
-    $dbname = $matches[1];
-    $accession = $matches[2];
-
-    $criteria = array(
-      'num_criteria' => 1,
-      'remote_db' => $dbname,
-      'criteria' => array(
-        '1' => array(
-          'search_terms' => "$dbname:$accession",
-          'scope' => 'id',
-          'operation' => '',
-          'is_phrase' => 0,
+  print "\nNOTE: Loading of publications is performed using a database transaction. \n" .
+      "If the load fails or is terminated prematurely then the entire set of \n" .
+      "insertions/updates is rolled back and will not be found in the database\n\n";
+  
+  $transaction = db_transaction();
+  try {
+    if(preg_match('/^(.*?):(.*?)$/', $pub_dbxref, $matches)) {
+      $dbname = $matches[1];
+      $accession = $matches[2];
+  
+      $criteria = array(
+        'num_criteria' => 1,
+        'remote_db' => $dbname,
+        'criteria' => array(
+          '1' => array(
+            'search_terms' => "$dbname:$accession",
+            'scope' => 'id',
+            'operation' => '',
+            'is_phrase' => 0,
+          ),
         ),
-      ),
-    );
-    $remote_db = $criteria['remote_db'];
-    $pubs = tripal_pub_get_remote_search_results($remote_db, $criteria, $num_to_retrieve, $page);
-    $pub_id = tripal_pub_add_publications($pubs, $do_contact, $do_update);
+      );
+      $remote_db = $criteria['remote_db'];
+      $results = tripal_pub_get_remote_search_results($remote_db, $criteria, $num_to_retrieve, $page);
+      $pubs          = $results['pubs'];
+      $search_str    = $results['search_str'];
+      $total_records = $results['total_records'];
+      $pub_id = tripal_pub_add_publications($pubs, $do_contact, $do_update);
+    }
 
+    // sync the newly added publications with Drupal
+    print "Syncing publications with Drupal...\n";
+    tripal_pub_sync_pubs();
+  
+    // if any of the importers wanted to create contacts from the authors then sync them
+    if($do_contact) {
+      print "Syncing contacts with Drupal...\n";
+      tripal_contact_sync_contacts();
+    }
   }
-
-  // transaction is complete
-  tripal_db_commit_transaction();
-
-  print "Transaction Complete\n";
-
-  // sync the newly added publications with Drupal
-  print "Syncing publications with Drupal...\n";
-  tripal_pub_sync_pubs();
-
-  // if any of the importers wanted to create contacts from the authors then sync them
-  if($do_contact) {
-    print "Syncing contacts with Drupal...\n";
-    tripal_contact_sync_contacts();
+  catch (Exception $e) {
+    print "\n"; // make sure we start errors on new line
+    watchdog_exception('T_pub_import', $e);
+        $transaction->rollback();
+        print "FAILED: Rolling back database changes...\n";
+      return;
   }
    
   print "Done.\n";
 }
-/*
- *
+/**
+ * 
+ * @param $pubs
+ * @param $do_contact
+ * @param $update
  */
 function tripal_pub_add_publications($pubs, $do_contact, $update = FALSE) {
   $report = array();
@@ -344,7 +402,7 @@ function tripal_pub_add_publications($pubs, $do_contact, $update = FALSE) {
   $report['inserted'] = array();
   $report['skipped'] = array();
   $total_pubs = count($pubs);
-
+  
   // iterate through the publications and add each one
   $i = 1;
   foreach ($pubs as $pub) {
@@ -381,8 +439,8 @@ function tripal_pub_add_publications($pubs, $do_contact, $update = FALSE) {
   print "\n";
   return $report;
 }
-/*
- *
+/**
+ * Adds a dbxref record to a publication
  */
 function tripal_pub_add_pub_dbxref($pub_id, $pub_dbxref) {
 
@@ -614,18 +672,21 @@ function tripal_pub_get_pub_by_uniquename($name) {
  *
  */
 function tripal_pub_add_publication($pub_details, &$action, $do_contact = FALSE, $update_if_exists = FALSE) {
-
   $pub_id = 0;
+  
+  if (!is_array($pub_details)) {
+    return FALSE;
+  }
 
   // first try to find the publication using the accession number. It will have
   // one if the pub has already been loaded for the publication database
-  if ($pub_details['Publication Dbxref']) {
+  if (array_key_exists('Publication Dbxref', $pub_details)) {
     $results = tripal_pub_get_pubs_by_dbxref($pub_details['Publication Dbxref']);
     if(count($results) == 1) {
       $pub_id = $results[0];
       if ($pub_id and !$update_if_exists) {
-        watchdog('tripal_pub', "A publication with this Dbxref already exists... Skipping: %dbxref",
-        array('%dbxref' => $pub_details['Publication Dbxref']), WATCHDOG_WARNING);
+        //watchdog('tripal_pub', "A publication with this Dbxref already exists... Skipping: %dbxref",
+        //array('%dbxref' => $pub_details['Publication Dbxref']), WATCHDOG_WARNING);
         $action = 'skipped';
         return $pub_id;
       }
@@ -641,7 +702,7 @@ function tripal_pub_add_publication($pub_details, &$action, $do_contact = FALSE,
   // if we couldn't find a publication by the accession (which means it doesn't
   // yet exist or it has been added using a different publication database) then
   // try to find it using the title and publication year.
-  if (!$pub_id and $pub_details['Title']) {
+  if (!$pub_id and array_key_exists('Title', $pub_details)) {
 
     $results = tripal_pub_get_pubs_by_title_type_pyear_series($pub_details['Title'], NULL, $pub_details['Year']);
     if (count($results) == 1) {
@@ -662,13 +723,14 @@ function tripal_pub_add_publication($pub_details, &$action, $do_contact = FALSE,
       return FALSE;
     }
   }
-
   // get the publication type (use the first publication type, any others will get stored as properties)
-  if (is_array($pub_details['Publication Type'])) {
-    $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'][0], NULL, 'tripal_pub');
-  }
-  elseif ($pub_details['Publication Type']) {
-    $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'], NULL, 'tripal_pub');
+  if (array_key_exists('Publication Type', $pub_details)) {
+    if(is_array($pub_details['Publication Type'])) {
+      $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'][0], NULL, 'tripal_pub');
+    }
+    else {
+      $pub_type = tripal_cv_get_cvterm_by_name($pub_details['Publication Type'], NULL, 'tripal_pub');
+    }
   }
   else {
     watchdog('tripal_pub', "The Publication Type is a required property but is missing", array(), WATCHDOG_ERROR);

+ 0 - 0
tripal_pub/includes/importers/AGL.inc → tripal_pub/includes/importers/tripal_pub.AGL.inc


+ 0 - 0
tripal_pub/includes/importers/PMID.inc → tripal_pub/includes/importers/tripal_pub.PMID.inc


+ 0 - 413
tripal_pub/includes/pub_form.inc

@@ -1,413 +0,0 @@
-<?php
-
-/**
- * This is the chado_pub node form callback. The arguments
- * are out of order from a typical form because it's a defined callback
- */
-
-function chado_pub_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 pub
-  // 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
-  $pub_id      = null;
-  $title       = '';
-  $pyear       = '';
-  $uniquename  = '';
-  $type_id     = '';
-  $is_obsolete = '';
-  
-  // some of the fields in the pub table should show up in the properties 
-  // form elements to make the form more seemless.  We will add them
-  // to this array.
-  $more_props = array();
-
-  // if we are editing an existing node then the pub is already part of the node
-  if (property_exists($node, 'pub')) {
-    $pub = $node->pub;
-    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
-    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.volumetitle');
-    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.uniquename');
-    $pub_id = $pub->pub_id;
-    
-    $title       = $pub->title;
-    $pyear       = $pub->pyear;
-    $uniquename  = $pub->uniquename;
-    $type_id     = $pub->type_id->cvterm_id;
-    $is_obsolete = $pub->is_obsolete;
-    
-    // if the obsolete value is set by the database then it is in the form of
-    // 't' or 'f', we need to convert to 1 or 0
-    $is_obsolete = $is_obsolete == 't' ? 1 : $is_obsolete;
-    $is_obsolete = $is_obsolete == 'f' ? 0 : $is_obsolete;
-    
-    // set the organism_id in the form
-    $form['pub_id'] = array(
-      '#type' => 'value',
-      '#value' => $pub->pub_id,
-    );
-    
-    // get fields from the pub table and convert them to properties. We will add these to the $more_props
-    // array which gets passed in to the tripal_core_properties_form() API call further down
-    if ($pub->volumetitle) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Volume Title', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->volumetitle);
-    }
-    if ($pub->volume) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Volume', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->volume);
-    }
-    if ($pub->series_name) {
-      switch ($pub->type_id->name) {
-        case 'Journal Article':
-          $cvterm = tripal_cv_get_cvterm_by_name('Journal Name', NULL, 'tripal_pub');
-          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
-          break;
-        case 'Conference Proceedings':
-          $cvterm = tripal_cv_get_cvterm_by_name('Conference Name', NULL, 'tripal_pub');
-          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
-          break;
-        default:
-          $cvterm = tripal_cv_get_cvterm_by_name('Series Name', NULL, 'tripal_pub');
-          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
-      }
-    }
-    if ($pub->issue) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Issue', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->issue);
-    }
-    if ($pub->pages) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Pages', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->pages);
-    }
-    if ($pub->miniref) {
-      // not sure what to do with this one
-    }
-    if ($pub->publisher) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Publisher', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->publisher);
-    }
-    if ($pub->pubplace) {
-      $cvterm = tripal_cv_get_cvterm_by_name('Published Location', NULL, 'tripal_pub');
-      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->pages);
-    }
-  }
-  // 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)) {
-    $title        = $form_state['values']['pubtitle'];
-    $pyear        = $form_state['values']['pyear'];
-    $uniquename   = $form_state['values']['uniquename'];
-    $type_id      = $form_state['values']['type_id'];
-    $is_obsolete  = $form_state['values']['is_obsolete'];
-  }
-  // 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'])) {
-    $title        = $form_state['input']['pubtitle'];
-    $uniquename   = $form_state['input']['uniquename'];
-    $type_id      = $form_state['input']['type_id'];
-    $is_obsolete  = $form_state['input']['is_obsolete'];
-  }
- 
-  // a drupal title can only be 255 characters, but the Chado title can be much longer.
-  // we use the publication title as the drupal title, but we'll need to truncate it.
-  $form['title'] = array(
-    '#type' => 'hidden',
-    '#value' => substr($title, 0, 255),
-  );
-  $form['pubtitle'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Publication Title'),
-    '#default_value' => $title,
-    '#required' => TRUE,
-  );
-  // get the list of publication types.  In the Tripal publication
-  // ontologies these are all grouped under the term 'Publication Type'
-  // we want the default to be 'Journal Article'
-  $sql = "
-    SELECT
-      CVTS.cvterm_id, CVTS.name
-    FROM {cvtermpath} CVTP
-      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
-      INNER JOIN {cvterm} CVTO ON CVTP.object_id  = CVTO.cvterm_id
-      INNER JOIN {cv}          ON CVTO.cv_id      = CV.cv_id
-    WHERE
-      CV.name = 'tripal_pub' AND CVTO.name = 'Publication Type' AND
-      NOT CVTS.is_obsolete = 1
-    ORDER BY CVTS.name ASC
-  ";
-  $results = chado_query($sql);
-  $pub_types = array();
-  while ($pub_type = $results->fetchObject()) {
-    $pub_types[$pub_type->cvterm_id] = $pub_type->name;
-    // if we don't have a default type then set the default to be 'Journal Article'
-    if (strcmp($pub_type->name,"Journal Article") == 0 and !$type_id) {
-      $type_id = $pub_type->cvterm_id;
-    }
-  }
-  
-  $form['type_id'] = array(
-    '#type' => 'select',
-    '#title' => t('Publication Type'),
-    '#options' => $pub_types,
-    '#required' => TRUE,
-    '#default_value' => $type_id,
-  );
-  $form['pyear'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Publication Year'),
-    '#default_value' => $pyear,
-    '#required' => TRUE,
-    '#size' => 5,
-    '#description' => t('Enter the year of publication. Also, if available, please add a <b>Publication Date</b> property to specify the full date of publication.'),
-  );
-  $form['uniquename'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Citation'),
-    '#default_value' => $uniquename,
-    '#description' => t('All publications must have a unique citation. 
-      <b>Please enter the full citation for this publication or leave blank and one will be generated 
-      automatically if possible</b>.  For PubMed style citations list 
-      the last name of the author followed by initials. Each author should be separated by a comma. Next comes 
-      the title, followed by the series title (e.g. journal name), publication date (4 digit year, 3 character Month, day), volume, issue and page numbers. You may also use HTML to provide a link in the citation.  
-      Below is an example: <pre>Medeiros PM, Ladio AH, Santos AM, Albuquerque UP. <a href="http://www.ncbi.nlm.nih.gov/pubmed/23462414" target="_blank">Does the selection of medicinal plants by Brazilian local populations 
-        suffer taxonomic influence?</a> J Ethnopharmacol. 2013 Apr 19; 146(3):842-52.</pre>'),
-  );
-  $form['is_obsolete'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Is Obsolete? (Check for Yes)'),
-    '#default_value' => $is_obsolete,
-  );
- 
-  // get publication properties list
-  $properties_select = array();
-  $properties_select[] = 'Select a Property';
-  $sql = "
-    SELECT
-      DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
-    FROM {cvtermpath} CVTP
-      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
-      INNER JOIN {cvterm} CVTO ON CVTP.object_id  = CVTO.cvterm_id
-      INNER JOIN {cv}          ON CVTO.cv_id      = CV.cv_id
-    WHERE CV.name = 'tripal_pub' and
-      (CVTO.name = 'Publication Details' OR CVTS.name = 'Publication Type') AND
-      NOT CVTS.is_obsolete = 1
-    ORDER BY CVTS.name ASC
-  ";
-  $prop_types = chado_query($sql);
-  while ($prop = $prop_types->fetchObject()) {
-    // add all properties except the Citation. That property is set via the uniquename field
-    if ($prop->name != 'Citation') {
-      $properties[$prop->cvterm_id] = $prop->name;
-    }
-  }
-  
-  // add in the properties fields. The 'Citation' term is special because it serves
-  // both as a property and as the uniquename for the publiation table so we exclude it
-  // as it shouldn't be selected as a property
-  $exclude = array("Citation"); 
-  $instructions = '';
-  tripal_core_properties_form($form, $form_state, 'pubprop', 'pub_id', 'tripal_pub',
-    $properties, $pub_id, $exclude, $more_props, $instructions, 'Properties');
-
-  return $form;
-
-}
-/*
- *
- */
-function chado_pub_validate($node, $form, &$form_state) {
-
-  // get the submitted values
-  $title        = trim($node->pubtitle);
-  $pyear        = trim($node->pyear);
-  $uniquename   = trim($node->uniquename);
-  $is_obsolete  = $node->is_obsolete;
-  $type_id      = $node->type_id;  
-
-  // if this is a delete then don't validate
-  if($node->op == 'Delete') {
-    return;
-  }
-
-  // we are syncing if we do not have a node ID but we do have a pub_id. We don't
-  // need to validate during syncing so just skip it.
-  if (is_null($node->nid) and property_exists($node, 'pub_id') and $node->pub_id != 0) {
-    return;
-  }
-  
-  $pub = array();
-  
-  // make sure the year is four digits
-  if(!preg_match('/^\d{4}$/', $pyear)){
-    form_set_error('pyear', t('The publication year should be a 4 digit year.'));
-    return;
-  }
-
-  // get the type of publication
-  $values = array('cvterm_id' => $type_id);
-  $options = array('statement_name' => 'sel_pub_ty');
-  $cvterm = tripal_core_chado_select('cvterm', array('name'), $values, $options);
-  if (count($cvterm) == 0) {
-    $message = t('Invalid publication type.');
-    form_set_error('type_id', $message);
-    return;
-  }  
-
-  // get the media name looking at the properties
-  $series_name = '';
-  foreach ($node as $element => $value) {
-    // if this is an existing property (either previously in the database or
-    // added via AHAH/AJAX callback)
-    if (preg_match('/^prop_value-(\d+)-(\d+)$/', $element, $matches)) {
-      $prop_type_id = $matches[1];
-      $prop_type = tripal_cv_get_cvterm_by_id($prop_type_id);
-      if($prop_type->name == 'Conference Name' or $prop_type->name == 'Journal Name') {
-        $series_name = $value;
-      }
-      if($prop_type->name == 'Citation') {
-        $uniquename = $value;
-      }
-      $pub[$prop_type->name] = $value;
-    }
-    // if this is a new property (added by this submit of the form)
-    elseif ($element == 'new_id') {       
-      $prop_type = tripal_cv_get_cvterm_by_id($value);
-      if($prop_type->name == 'Conference Name' or $prop_type->name == 'Journal Name') {
-        $series_name = $node->new_value;
-      }
-      if($prop_type->name == 'Citation') {
-        $uniquename = $node->new_value;
-      }
-      $pub[$prop_type->name] = $node->new_value;
-    }
-  }
-  // if the citation is missing then try to generate one
-  if (!$uniquename) {
-    $pub['Title'] = $title;
-    $pub['Publication Type'][0] = $cvterm[0]->name;
-    $pub['Year'] = $pyear;
-    $uniquename = tripal_pub_create_citation($pub);
-    if (!$uniquename) {
-      form_set_error('uniquename', "Cannot automatically generate a citation for this publication type. Please add one manually.");
-    }
-  }
-
-  $skip_duplicate_check = 0;
-
-  // if this publication is a Patent then skip the validation below.  Patents can have the title
-  // name and year but be different
-  if (strcmp($cvterm[0]->name,'Patent') == 0) {
-    $skip_duplicate_check = 1;
-  }
-
-  // Validating for an update
-  if (!is_null($node->nid)) { 
-    
-    $pub_id = $node->pub_id;
-    
-    // first get the original title, type and year before it was changed
-    $values = array('pub_id' => $pub_id);
-    $columns = array('title', 'pyear', 'type_id', 'series_name');
-    $options = array('statement_name' => 'sel_pub_id');
-    $pub = tripal_core_chado_select('pub', $columns, $values, $options);
-
-    // if the title, type,  year or series_name have changed then check the pub
-    // to see if it is a duplicate of another
-    if((strcmp(strtolower($pub[0]->title), strtolower($title)) == 0) and
-       (strcmp(strtolower($pub[0]->series_name), strtolower($series_name)) == 0) and
-       ($pub[0]->type_id == $type_id) and
-       ($pub[0]->pyear == $pyear)) {
-      $skip_duplicate_check = 1;
-    }
-
-    // check to see if a duplicate publication already exists
-    if (!$skip_duplicate_check) {
-      chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm, $pub_id); 
-    }
-    chado_pub_validate_check_uniquename($uniquename, $pub_id);
-  }
-  // Validating for an insert
-  else {
-    chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm);
-    chado_pub_validate_check_uniquename($uniquename);
-  }
-}
-/**
- * 
- * @param unknown $uniquename
- */
-function chado_pub_validate_check_uniquename($uniquename, $pub_id = NULL) {
-  
-  $results = tripal_pub_get_pub_by_uniquename($uniquename);
-  // make sure we don't capture our pub_id in the list (remove it)
-  foreach ($results as $index => $found_pub_id) {
-    if($found_pub_id == $pub_id){
-      unset($results[$index]);
-    }
-  }
-  if (count($results) > 0) {
-    $message = t('A publication with this unique citation already exists.');
-    form_set_error('uniquename', $message);
-  }
-}
-/**
- * 
- */
-function chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm, $pub_id = NULL) {
-  
-  // make sure the publication is unique using the prefereed import duplication check
-  $import_dups_check = variable_get('tripal_pub_import_duplicate_check', 'title_year_media');
-  switch ($import_dups_check) {
-    case 'title_year':
-      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, NULL, $pyear, NULL);
-      // make sure we don't capture our pub_id in the list (remove it)
-      foreach ($results as $index => $found_pub_id) {
-        if($found_pub_id == $pub_id){
-          unset($results[$index]);
-        }
-      }
-      if (count($results) > 0) {
-        $message = t('A publication with this title and publication year, already exists.');
-        form_set_error('pyear', $message);
-      }
-      break;
-    case 'title_year_type':
-      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, $cvterm[0]->name, $pyear, NULL);
-  
-      // make sure we don't capture our pub_id in the list (remove it)
-      foreach ($results as $index => $found_pub_id) {
-        if($found_pub_id == $pub_id){
-          unset($results[$index]);
-        }
-      }
-      if (count($results) > 0) {
-        $message = t('A publication with this title, type and publication year, already exists.');
-        form_set_error('pyear', $message);
-      }
-      break;
-    case 'title_year_media':
-      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, NULL, $pyear, $series_name);
-  
-      // make sure we don't capture our pub_id in the list (remove it)
-      foreach ($results as $index => $found_pub_id) {
-        if($found_pub_id == $pub_id){
-          unset($results[$index]);
-        }
-      }
-      if (count($results) > 0) {
-        $message = t('A publication with this title, media name (e.g. Journal Name) and publication year, already exists.');
-        form_set_error('pyear', $message);
-      }
-      break;
-  }
-}
-

+ 0 - 522
tripal_pub/includes/pub_search.inc

@@ -1,522 +0,0 @@
-<?php
-/*
- *
- */
-function tripal_pub_search_page() {
-  global $pager_total, $pager_total_items;
-
-  $pager_id = 0;
-  $limit = 25;
-
-  // generate the search form
-  $form = drupal_get_form('tripal_pub_search_form');
-  $output .= $form;
-
-  // retrieve any results
-  if ($_SESSION['tripal_pub_search_form']['perform_search']) {
-    $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'];
-    $from_year    = $_SESSION['tripal_pub_search_form']['from_year'];
-    $to_year      = $_SESSION['tripal_pub_search_form']['to_year'];
-     
-    $search_array = array();
-    $search_array['num_criteria'] = $num_criteria;
-    $search_array['from_year'] = $from_year;
-    $search_array['to_year'] = $to_year;
-    for ($i = 0; $i <= $num_criteria; $i++) {
-      $search_array['criteria'][$i]['search_terms'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'];
-      $search_array['criteria'][$i]['scope']        = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope'];
-      $search_array['criteria'][$i]['mode']         = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode'];
-      $search_array['criteria'][$i]['operation']    = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation'];
-    }
-
-    // get the list of publications from the remote database using the search criteria.
-    $pubs = tripal_pub_get_search_results($search_array, $limit, $pager_id);
-
-    // generate the pager
-    $total_pages = $pager_total[$pager_id];
-    $total_items = $pager_total_items[$pager_id];
-    $page = isset($_GET['page']) ? $_GET['page'] : '0';
-    $pager = theme('pager');
-
-    // iterate through the results and construct the table displaying the publications
-    $rows = array();
-    $i = $page * $limit + 1;
-    while($pub = $pubs->fetchObject()) {
-      // get the citation for this publication
-      $values = array(
-        'pub_id' => $pub->pub_id, 
-        'type_id' => array(
-          'name' => 'Citation',
-      ),
-      );
-      $citation_rec = tripal_core_generate_chado_var('pubprop', $values);
-      $citation_rec = tripal_core_expand_chado_vars($citation_rec, 'field', 'pubprop.value');
-
-      // if we have the citation then use it, otherwise, just use the title
-      $title = htmlspecialchars($pub->title);
-      $result = $title;
-      if ($pub->nid) {
-        $result = l($title ,'node/' . $pub->nid, array('attributes' => array('target' => '_blank')));
-      }
-      if ($citation_rec->value) {
-        $citation = htmlspecialchars($citation_rec->value);
-        $result .= '<br>' . $citation;
-      }
-      $rows[] = array(
-      number_format($i) . ".",
-      $pub->pyear,
-      $result
-      );
-      $i++;
-    }
-
-    $headers = array('', 'Year', 'Publication');
-    $table = theme('table', $headers, $rows);
-
-    // join all to form the results
-    $output .= "<br><p><b>Found " . number_format($total_items) .
-      ". Page " . ($page + 1) . " of $total_pages. " .
-      " Results</b></br>" . $table . '</p>' . $pager;    
-  }
-  return $output;
-}
-/**
- * Purpose: Provides the form to search pubmed
- *
- * @ingroup tripal_pub
- */
-function tripal_pub_search_form(&$form_state = NULL) {
-  tripal_core_ahah_init_form();
-
-  // Set the default values. If the pub_import_id isn't already defined by the form values
-  // and one is provided then look it up in the database
-  $criteria = NULL;
-
-  // if the session has variables then use those.  This should only happen when
-  // the 'Test Criteria' button is clicked.
-  $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'] ? $_SESSION['tripal_pub_search_form']['num_criteria'] : $num_criteria;
-  $from_year = $_SESSION['tripal_pub_search_form']['from_year'] ? $_SESSION['tripal_pub_search_form']['from_year'] : '';
-  $to_year = $_SESSION['tripal_pub_search_form']['to_year'] ? $_SESSION['tripal_pub_search_form']['to_year'] : '';
-
-
-  // If the form_state has variables then use those.  This happens when an error occurs on the form or the
-  // form is resbumitted using AJAX
-  $num_criteria = $form_state['values']['num_criteria'] ? $form_state['values']['num_criteria'] : $num_criteria;
-
-   
-  // change the number of criteria based on form_state post data.
-  if (!$num_criteria) {
-    $num_criteria = 2;
-  }
-  if($form_state['post']["add-$num_criteria"]) {
-    $num_criteria++;
-  }
-  if($form_state['post']["remove-$num_criteria"]) {
-    $num_criteria--;
-  }
-
-  $form['num_criteria']= array(
-    '#type'          => 'hidden',
-    '#default_value' => $num_criteria,
-  );
-  $form['instructions'] = array(
-    '#type'  => 'item',
-    '#value' => t('To search for publications enter keywords in the text boxes below.  You can limit your search by selecting the field in the dropdown box. Click the plus and minus symbols to add additional fields for searching. '),
-  );
-
-  // get publication properties list
-  $properties = array();
-  $properties[] = 'Any Field';
-  $sql = "
-    SELECT DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
-    FROM {cvtermpath} CVTP
-      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
-      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
-      INNER JOIN {cv} ON CVTO.cv_id = CV.cv_id
-    WHERE CV.name = 'tripal_pub' and 
-      (CVTO.name = 'Publication Details' or CVTS.name = 'Publication Type') and 
-      NOT CVTS.is_obsolete = 1
-    ORDER BY CVTS.name ASC 
-  ";
-  $allowed_fields = variable_get('tripal_pub_allowed_search_fields', array());
-  $prop_types = chado_query($sql);
-  while ($prop = $prop_types->fetchObject()) {
-    if($allowed_fields[$prop->cvterm_id] > 0) {
-      $properties[$prop->cvterm_id] = $prop->name;
-    }
-  }
-
-  for($i = 1; $i <= $num_criteria; $i++) {
-    $search_terms = '';
-    $scope = '';
-    $operation = '';
-    $mode = '';
-
-    // if we have criteria supplied from the database then use that, othrewise look from the form_state or the session
-    if ($criteria) {
-      $search_terms = $criteria['criteria'][$i]['search_terms'];
-      $scope = $criteria['criteria'][$i]['scope'];
-      $mode = $criteria['criteria'][$i]['mode'];
-      $operation = $criteria['criteria'][$i]['operation'];
-    }
-    // first populate defaults using any values in the SESSION variable
-    $search_terms = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] : $search_terms;
-    $scope        = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope']        ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope']        : $scope;
-    $mode         = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode']         ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode']         : $mode;
-    $operation    = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation']    ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation']    : $operation;
-
-    // next populate defaults using any form values
-    $search_terms = $form_state['values']["search_terms-$i"] ? $form_state['values']["search_terms-$i"] : $search_terms;
-    $scope        = $form_state['values']["scope-$i"]        ? $form_state['values']["scope-$i"]        : $scope;
-    $mode         = $form_state['values']["mode-$i"]         ? $form_state['values']["mode-$i"]         : $mode;
-    $operation    = $form_state['values']["operation-$i"]    ? $form_state['values']["operation-$i"]    : $operation;
-
-    // default to searching the title and abstract
-    if (!$scope) {
-      $scope = 'abstract';
-    }
-
-    $form['criteria'][$i]["search_terms-$i"] = array(
-      '#type'          => 'textfield',
-      '#default_value' => $search_terms,
-      '#required'      => FALSE,
-    );
-    $form['criteria'][$i]["scope-$i"] = array(
-      '#type'          => 'select',
-      '#options'       => $properties,
-      '#default_value' => $scope,
-      '#attributes' => array('class' => 'tripal-pub-search-form-scope-select'),
-    );
-    /*
-     $form['criteria'][$i]["mode-$i"] = array(
-     '#type'          => 'select',
-     '#options'       => array(
-     'Contains'    => 'Contains',
-     'Starts With' => 'Starts With',
-     'Ends With'   => 'Ends With',
-     'Exactly'     => 'Exactly'),
-     '#default_value' => $mode,
-     );*/
-
-    if ($i > 1) {
-      $form['criteria'][$i]["operation-$i"] = array(
-        '#type'          => 'select',
-        '#options'       => array(
-          'AND' => 'AND',
-          'OR'  => 'OR',
-          'NOT' => 'NOT'),
-        '#default_value' => $operation,
-      );
-    }
-    if ($i == $num_criteria) {
-      if($i > 1) {
-        $form['criteria'][$i]["remove-$i"] = array(
-          '#type'         => 'image_button',
-          '#value'        => t('Remove'),
-          '#src'          => drupal_get_path('theme', 'tripal') . '/images/minus.png',
-          '#ahah' => array(
-            'path'    => "find/publications/criteria/minus/$i",
-            'wrapper' => 'tripal-pub-search-form',
-            'event'   => 'click',
-            'method'  => 'replace',
-        ),
-          '#attributes' => array('onClick' => 'return false;'),
-        );
-      }
-      $form['criteria'][$i]["add-$i"] = array(
-        '#type'         => 'image_button',      
-        '#value'        => t('Add'),
-        '#src'          => drupal_get_path('theme', 'tripal') . '/images/add.png',
-        '#ahah' => array(
-          'path'    => "find/publications/criteria/add/$i",
-          'wrapper' => 'tripal-pub-search-form',
-          'event'   => 'click',
-          'method'  => 'replace',          
-      ),
-        '#attributes' => array('onClick' => 'return false;'),
-      );
-    }
-  }
-  $form['criteria']["date"] = array(
-      '#type'          => 'select',
-      '#options'       => array('Years' => 'Years'),
-      '#attributes' => array('class' => 'tripal-pub-search-form-scope-select'),
-  );
-  $form['criteria']["from_year"] = array(
-    '#type'          => 'textfield',
-    '#default_value' => $from_year,
-    '#required'      => FALSE,
-    '#title'         => 'from',
-    '#size'          => 4,
-    '#maxlength'     => 4,
-  );
-  $form['criteria']["to_year"] = array(
-    '#type'          => 'textfield',
-    '#default_value' => $to_year,
-    '#required'      => FALSE,
-    '#title'         => 'to',
-    '#size'          => 4,
-    '#maxlength'     => 4,
-  );
-
-  $form['search'] = array(
-    '#type'         => 'submit',
-    '#value'        => t('Search'),
-  );
-  $form['reset'] = array(
-    '#type'         => 'submit',
-    '#value'        => t('Reset'),
-  );
-
-  return $form;
-}
-/*
- *
- */
-function theme_tripal_pub_search_form($form) {
-  $rows = array();
-  foreach ($form['criteria'] as $i => $element) {
-    if(is_numeric($i)) {
-      $rows[] = array(
-      drupal_render($element["operation-$i"]),
-      drupal_render($element["scope-$i"]),
-      //drupal_render($element["mode-$i"]) .
-      drupal_render($element["search_terms-$i"]),
-      drupal_render($element["add-$i"]) . drupal_render($element["remove-$i"]),
-      );
-    }
-  }
-
-  $rows[] = array(
-    '&nbsp;',
-  drupal_render($form['criteria']['date']),
-  array(
-      'data' =>
-        "<div id=\"pub-search-form-dates-row\"> 
-           <div id=\"pub-search-form-dates\"> ".
-  drupal_render($form['criteria']['from_year']) .
-  drupal_render($form['criteria']['to_year']) . "
-          </div>
-         </div>",
-  ),
-    ''
-    );
-    $table = theme('table', $headers, $rows, array('id' => 'tripal-pub-search-form-table', 'border' => '0'));
-    $headers = array();
-    $markup  = drupal_render($form['instructions']) . "
-     <div id=\"pub-search-form-row1\">$table</div>
-     <div style=\"clear: both;\"></div>
-  "; 
-
-    $form['criteria'] = array(
-    '#type' => 'markup',
-    '#value' =>  $markup,
-    '#weight' => -10,
-    );
-    return drupal_render($form);
-}
-/**
- *
- */
-function tripal_pub_search_form_validate($form, &$form_state) {
-  $num_criteria = $form_state['values']['num_criteria'];
-  $from_year = $form_state['values']['from_year'];
-  $to_year   = $form_state['values']['to_year'];
-  $op        = $form_state['values']['op'];
-
-  // no need to vlaidate on a reset
-  if ($op == 'Reset') {
-    return;
-  }
-
-  if($from_year and !$to_year) {
-    form_set_error('to_year', 'Please provide a 4-digit year.');
-  }
-  if(!$from_year and $to_year) {
-    form_set_error('from_year', 'Please provide a 4-digit year.');
-  }
-  if($from_year and !preg_match('/\d\d\d\d/' , $from_year)) {
-    form_set_error('from_year', 'Please provide a 4-digit year.');
-  }
-  if($to_year and !preg_match('/\d\d\d\d/' , $to_year)) {
-    form_set_error('to_year', 'Please provide a 4-digit year.');
-  }
-}
-/**
- *
- */
-function tripal_pub_search_form_submit($form, &$form_state) {
-  $num_criteria = $form_state['values']['num_criteria'];
-  $from_year    = $form_state['values']['from_year'];
-  $to_year      = $form_state['values']['to_year'];
-  $op           = $form_state['values']['op'];
-
-  // set the session variables
-  if($op == 'Search') {
-    $_SESSION['tripal_pub_search_form']['num_criteria'] = $num_criteria;
-    unset($_SESSION['tripal_pub_search_form']['criteria']);
-    for ($i = 0; $i <= $num_criteria; $i++) {
-      $search_terms =  trim($form_state['values']["search_terms-$i"]);
-      $scope =  $form_state['values']["scope-$i"];
-      //$mode =  $form_state['values']["mode-$i"];
-      $mode = 'Contains';
-      $operation =  $form_state['values']["operation-$i"];
-
-      $_SESSION['tripal_pub_search_form']['criteria'][$i] = array(
-        'search_terms' => $search_terms,
-        'scope' => $scope,
-        'mode' => $mode,
-        'operation' => $operation
-      );
-    }
-    $_SESSION['tripal_pub_search_form']['from_year'] = $from_year;
-    $_SESSION['tripal_pub_search_form']['to_year'] = $to_year;
-    $_SESSION['tripal_pub_search_form']['perform_search'] = 1;
-  }
-  if($op == 'Reset') {
-    unset($_SESSION['tripal_pub_search_form']);
-  }
-}
-
-/*
- * AHAH callback
- */
-function tripal_pub_search_page_update_criteria($action, $i) {
-  $status = TRUE;
-
-  // prepare and render the form
-  $form = tripal_core_ahah_prepare_form();
-  $data = theme('tripal_pub_search_form', $form);
-
-  // bind javascript events to the new objects that will be returned
-  // so that AHAH enabled elements will work.
-  $settings = tripal_core_ahah_bind_events();
-
-  // return the updated JSON
-  drupal_json(
-  array(
-      'status'   => $status, 
-      'data'     => $data,
-      'settings' => $settings,
-  )
-  );
-}
-/*
- *
- */
-function tripal_pub_get_search_results($search_array, $limit, $pager_id) {
-
-  // build the SQL based on the criteria provided by the user
-  $select = "SELECT DISTINCT P.*, CP.nid ";
-  $from   = "FROM {pub} P
-               LEFT JOIN public.chado_pub CP on P.pub_id = CP.pub_id 
-               INNER JOIN cvterm CVT on CVT.cvterm_id = P.type_id
-            ";
-  $where  = "WHERE (NOT P.title = 'null') "; // always exclude the dummy pub
-  $order  = "ORDER BY P.pyear DESC, P.title ASC";
-  $args = array();  // arguments for where clause
-  $join = 0;
-
-  $num_criteria = $search_array['num_criteria'];
-  $from_year    = $search_array['from_year'];
-  $to_year      = $search_array['to_year'];
-
-  for ($i = 1; $i <= $num_criteria; $i++) {
-    $value = $search_array['criteria'][$i]['search_terms'];
-    $type_id = $search_array['criteria'][$i]['scope'];
-    $mode = $search_array['criteria'][$i]['mode'];
-    $op = $search_array['criteria'][$i]['operation'];
-
-    // skip criteria with no values
-    if(!$value) {
-      continue;
-    }
-
-    // to prevent SQL injection make sure our operator is
-    // what we expect
-    if ($op and $op != "AND" and $op != "OR" and $op != 'NOT') {
-      $op = 'AND';
-    }
-    if ($op == 'NOT') {
-      $op = 'AND NOT';
-    }
-    if (!$op) {
-      $op = 'AND';
-    }
-
-    $action = "= lower('%s')";
-    if($mode == 'Contains') {
-      $action = 'LIKE lower(\'%%' . ":crit$i" . '%%\')';
-    }
-    if($mode == 'Starts With') {
-      $action = '= lower(\'%%' . ":crit$i" . '\')';
-    }
-    if($mode == 'Ends With') {
-      $action = '= lower(\'' . ":crit$i" . '%%\')';
-    }
-     
-    // get the scope type
-    $values = array('cvterm_id' => $type_id);
-    $cvterm = tripal_core_chado_select('cvterm', array('name'), $values);
-    $type_name = $cvterm[0]->name;
-    if ($type_name == 'Title') {
-      $where .= " $op (lower(P.title)  $action) ";
-      $args[":crit$i"] = $value;
-    }
-    elseif ($type_name == 'Year') {
-      $where .= " $op (lower(P.pyear)  $action) ";
-      $args[":crit$i"] = $value;
-    }
-    elseif ($type_name == 'Volume') {
-      $where .= " $op (lower(P.volume)  $action) ";
-      $args[":crit$i"] = $value;
-    }
-    elseif ($type_name == 'Issue') {
-      $where .= " $op (lower(P.issue)  $action)";
-      $args[":crit$i"] = $value;
-    }
-    elseif ($type_name == 'Journal Name') {
-      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
-      $where .= " $op ((lower(P.series_name) $action and CVT.name = 'Journal Article') OR
-                       (lower(PP$i.value) $action)) ";
-      $args[":crit$i"] = $type_id;
-    }
-    elseif ($type_name == 'Conference Name') {
-      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
-      $where .= " $op ((lower(P.series_name) $action and CVT.name = 'Conference Proceedings') OR
-                       (lower(PP$i.value) $action)) ";
-      $args[":crit$i"] = $type_id;
-    }
-    elseif ($type_name == 'Publication Type') {
-      $where .= " $op (lower(CVT.name) $action)";
-      $args[":crit$i"] = $value;
-    }
-    elseif ($type_id == 0) { //'Any Field'
-      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id ";
-      $where .= " $op (lower(PP$i.value)  $action OR
-                       lower(P.title) $action OR 
-                       lower(P.volumetitle) $action OR
-                       lower(P.publisher) $action OR
-                       lower(P.uniquename) $action OR
-                       lower(P.pubplace) $action OR
-                       lower(P.miniref) $action OR
-                       lower(P.series_name) $action) ";
-      $args[":crit$i"] = $value;
-    }
-    // for all other properties
-    else {
-      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
-      $where .= " $op (lower(PP$i.value) $action) ";
-      $args[":crit$i"] = $type_id;
-    }
-
-  }
-  if($from_year and $to_year) {
-    $where .= " AND (P.pyear ~ '....' AND to_number(P.pyear,'9999') >= :from$i AND to_number(P.pyear,'9999') <= :to$i) ";
-    $args[":from$i"] = $from_year;
-    $args[":to$i"] = $to_year;
-  }
-  $sql = "$select $from $where $order";
-  $count = "SELECT count(*) FROM ($select $from $where $order) as t1";
-  return chado_pager_query($sql, $limit, $pager_id, $count, $args);
-}

+ 890 - 0
tripal_pub/includes/tripal_pub.chado_node.inc

@@ -0,0 +1,890 @@
+<?php
+
+/**
+ * This is the chado_pub node form callback. The arguments
+ * are out of order from a typical form because it's a defined callback
+ */
+
+function chado_pub_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 pub
+  // 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
+  $pub_id      = null;
+  $title       = '';
+  $pyear       = '';
+  $uniquename  = '';
+  $type_id     = '';
+  $is_obsolete = '';
+  
+  // some of the fields in the pub table should show up in the properties 
+  // form elements to make the form more seemless.  We will add them
+  // to this array.
+  $more_props = array();
+
+  // if we are editing an existing node then the pub is already part of the node
+  if (property_exists($node, 'pub')) {
+    $pub = $node->pub;
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.volumetitle');
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.uniquename');
+    $pub_id = $pub->pub_id;
+    
+    $title       = $pub->title;
+    $pyear       = $pub->pyear;
+    $uniquename  = $pub->uniquename;
+    $type_id     = $pub->type_id->cvterm_id;
+    $is_obsolete = $pub->is_obsolete;
+    
+    // if the obsolete value is set by the database then it is in the form of
+    // 't' or 'f', we need to convert to 1 or 0
+    $is_obsolete = $is_obsolete == 't' ? 1 : $is_obsolete;
+    $is_obsolete = $is_obsolete == 'f' ? 0 : $is_obsolete;
+    
+    // set the organism_id in the form
+    $form['pub_id'] = array(
+      '#type' => 'value',
+      '#value' => $pub->pub_id,
+    );
+    
+    // get fields from the pub table and convert them to properties. We will add these to the $more_props
+    // array which gets passed in to the tripal_core_properties_form() API call further down
+    if ($pub->volumetitle) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Volume Title', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->volumetitle);
+    }
+    if ($pub->volume) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Volume', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->volume);
+    }
+    if ($pub->series_name) {
+      switch ($pub->type_id->name) {
+        case 'Journal Article':
+          $cvterm = tripal_cv_get_cvterm_by_name('Journal Name', NULL, 'tripal_pub');
+          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
+          break;
+        case 'Conference Proceedings':
+          $cvterm = tripal_cv_get_cvterm_by_name('Conference Name', NULL, 'tripal_pub');
+          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
+          break;
+        default:
+          $cvterm = tripal_cv_get_cvterm_by_name('Series Name', NULL, 'tripal_pub');
+          $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->series_name);
+      }
+    }
+    if ($pub->issue) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Issue', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->issue);
+    }
+    if ($pub->pages) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Pages', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->pages);
+    }
+    if ($pub->miniref) {
+      // not sure what to do with this one
+    }
+    if ($pub->publisher) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Publisher', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->publisher);
+    }
+    if ($pub->pubplace) {
+      $cvterm = tripal_cv_get_cvterm_by_name('Published Location', NULL, 'tripal_pub');
+      $more_props[] = array('cvterm' => $cvterm, 'value' => $pub->pages);
+    }
+  }
+  // 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)) {
+    $title        = $form_state['values']['pubtitle'];
+    $pyear        = $form_state['values']['pyear'];
+    $uniquename   = $form_state['values']['uniquename'];
+    $type_id      = $form_state['values']['type_id'];
+    $is_obsolete  = $form_state['values']['is_obsolete'];
+  }
+  // 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'])) {
+    $title        = $form_state['input']['pubtitle'];
+    $uniquename   = $form_state['input']['uniquename'];
+    $type_id      = $form_state['input']['type_id'];
+    $is_obsolete  = $form_state['input']['is_obsolete'];
+  }
+ 
+  // a drupal title can only be 255 characters, but the Chado title can be much longer.
+  // we use the publication title as the drupal title, but we'll need to truncate it.
+  $form['title'] = array(
+    '#type' => 'hidden',
+    '#value' => substr($title, 0, 255),
+  );
+  $form['pubtitle'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Publication Title'),
+    '#default_value' => $title,
+    '#required' => TRUE,
+  );
+  // get the list of publication types.  In the Tripal publication
+  // ontologies these are all grouped under the term 'Publication Type'
+  // we want the default to be 'Journal Article'
+  $sql = "
+    SELECT
+      CVTS.cvterm_id, CVTS.name
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id  = CVTO.cvterm_id
+      INNER JOIN {cv}          ON CVTO.cv_id      = CV.cv_id
+    WHERE
+      CV.name = 'tripal_pub' AND CVTO.name = 'Publication Type' AND
+      NOT CVTS.is_obsolete = 1
+    ORDER BY CVTS.name ASC
+  ";
+  $results = chado_query($sql);
+  $pub_types = array();
+  while ($pub_type = $results->fetchObject()) {
+    $pub_types[$pub_type->cvterm_id] = $pub_type->name;
+    // if we don't have a default type then set the default to be 'Journal Article'
+    if (strcmp($pub_type->name,"Journal Article") == 0 and !$type_id) {
+      $type_id = $pub_type->cvterm_id;
+    }
+  }
+  
+  $form['type_id'] = array(
+    '#type' => 'select',
+    '#title' => t('Publication Type'),
+    '#options' => $pub_types,
+    '#required' => TRUE,
+    '#default_value' => $type_id,
+  );
+  $form['pyear'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Publication Year'),
+    '#default_value' => $pyear,
+    '#required' => TRUE,
+    '#size' => 5,
+    '#description' => t('Enter the year of publication. Also, if available, please add a <b>Publication Date</b> property to specify the full date of publication.'),
+  );
+  $form['uniquename'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Citation'),
+    '#default_value' => $uniquename,
+    '#description' => t('All publications must have a unique citation. 
+      <b>Please enter the full citation for this publication or leave blank and one will be generated 
+      automatically if possible</b>.  For PubMed style citations list 
+      the last name of the author followed by initials. Each author should be separated by a comma. Next comes 
+      the title, followed by the series title (e.g. journal name), publication date (4 digit year, 3 character Month, day), volume, issue and page numbers. You may also use HTML to provide a link in the citation.  
+      Below is an example: <pre>Medeiros PM, Ladio AH, Santos AM, Albuquerque UP. <a href="http://www.ncbi.nlm.nih.gov/pubmed/23462414" target="_blank">Does the selection of medicinal plants by Brazilian local populations 
+        suffer taxonomic influence?</a> J Ethnopharmacol. 2013 Apr 19; 146(3):842-52.</pre>'),
+  );
+  $form['is_obsolete'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Is Obsolete? (Check for Yes)'),
+    '#default_value' => $is_obsolete,
+  );
+ 
+  // get publication properties list
+  $properties_select = array();
+  $properties_select[] = 'Select a Property';
+  $sql = "
+    SELECT
+      DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id  = CVTO.cvterm_id
+      INNER JOIN {cv}          ON CVTO.cv_id      = CV.cv_id
+    WHERE CV.name = 'tripal_pub' and
+      (CVTO.name = 'Publication Details' OR CVTS.name = 'Publication Type') AND
+      NOT CVTS.is_obsolete = 1
+    ORDER BY CVTS.name ASC
+  ";
+  $prop_types = chado_query($sql);
+  while ($prop = $prop_types->fetchObject()) {
+    // add all properties except the Citation. That property is set via the uniquename field
+    if ($prop->name != 'Citation') {
+      $properties[$prop->cvterm_id] = $prop->name;
+    }
+  }
+  
+  // add in the properties fields. The 'Citation' term is special because it serves
+  // both as a property and as the uniquename for the publiation table so we exclude it
+  // as it shouldn't be selected as a property
+  $exclude = array("Citation"); 
+  $instructions = '';
+  tripal_core_properties_form($form, $form_state, 'pubprop', 'pub_id', 'tripal_pub',
+    $properties, $pub_id, $exclude, $more_props, $instructions, 'Properties');
+
+  return $form;
+
+}
+/*
+ *
+ */
+function chado_pub_validate($node, $form, &$form_state) {
+
+  // get the submitted values
+  $title        = trim($node->pubtitle);
+  $pyear        = trim($node->pyear);
+  $uniquename   = trim($node->uniquename);
+  $is_obsolete  = $node->is_obsolete;
+  $type_id      = $node->type_id;  
+
+  // if this is a delete then don't validate
+  if($node->op == 'Delete') {
+    return;
+  }
+
+  // we are syncing if we do not have a node ID but we do have a pub_id. We don't
+  // need to validate during syncing so just skip it.
+  if (is_null($node->nid) and property_exists($node, 'pub_id') and $node->pub_id != 0) {
+    return;
+  }
+  
+  $pub = array();
+  
+  // make sure the year is four digits
+  if(!preg_match('/^\d{4}$/', $pyear)){
+    form_set_error('pyear', t('The publication year should be a 4 digit year.'));
+    return;
+  }
+
+  // get the type of publication
+  $values = array('cvterm_id' => $type_id);
+  $options = array('statement_name' => 'sel_pub_ty');
+  $cvterm = tripal_core_chado_select('cvterm', array('name'), $values, $options);
+  if (count($cvterm) == 0) {
+    $message = t('Invalid publication type.');
+    form_set_error('type_id', $message);
+    return;
+  }  
+
+  // get the media name looking at the properties
+  $series_name = '';
+  foreach ($node as $element => $value) {
+    // if this is an existing property (either previously in the database or
+    // added via AHAH/AJAX callback)
+    if (preg_match('/^prop_value-(\d+)-(\d+)$/', $element, $matches)) {
+      $prop_type_id = $matches[1];
+      $prop_type = tripal_cv_get_cvterm_by_id($prop_type_id);
+      if($prop_type->name == 'Conference Name' or $prop_type->name == 'Journal Name') {
+        $series_name = $value;
+      }
+      if($prop_type->name == 'Citation') {
+        $uniquename = $value;
+      }
+      $pub[$prop_type->name] = $value;
+    }
+    // if this is a new property (added by this submit of the form)
+    elseif ($element == 'new_id') {       
+      $prop_type = tripal_cv_get_cvterm_by_id($value);
+      if($prop_type->name == 'Conference Name' or $prop_type->name == 'Journal Name') {
+        $series_name = $node->new_value;
+      }
+      if($prop_type->name == 'Citation') {
+        $uniquename = $node->new_value;
+      }
+      $pub[$prop_type->name] = $node->new_value;
+    }
+  }
+  // if the citation is missing then try to generate one
+  if (!$uniquename) {
+    $pub['Title'] = $title;
+    $pub['Publication Type'][0] = $cvterm[0]->name;
+    $pub['Year'] = $pyear;
+    $uniquename = tripal_pub_create_citation($pub);
+    if (!$uniquename) {
+      form_set_error('uniquename', "Cannot automatically generate a citation for this publication type. Please add one manually.");
+    }
+  }
+
+  $skip_duplicate_check = 0;
+
+  // if this publication is a Patent then skip the validation below.  Patents can have the title
+  // name and year but be different
+  if (strcmp($cvterm[0]->name,'Patent') == 0) {
+    $skip_duplicate_check = 1;
+  }
+
+  // Validating for an update
+  if (!is_null($node->nid)) { 
+    
+    $pub_id = $node->pub_id;
+    
+    // first get the original title, type and year before it was changed
+    $values = array('pub_id' => $pub_id);
+    $columns = array('title', 'pyear', 'type_id', 'series_name');
+    $options = array('statement_name' => 'sel_pub_id');
+    $pub = tripal_core_chado_select('pub', $columns, $values, $options);
+
+    // if the title, type,  year or series_name have changed then check the pub
+    // to see if it is a duplicate of another
+    if((strcmp(strtolower($pub[0]->title), strtolower($title)) == 0) and
+       (strcmp(strtolower($pub[0]->series_name), strtolower($series_name)) == 0) and
+       ($pub[0]->type_id == $type_id) and
+       ($pub[0]->pyear == $pyear)) {
+      $skip_duplicate_check = 1;
+    }
+
+    // check to see if a duplicate publication already exists
+    if (!$skip_duplicate_check) {
+      chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm, $pub_id); 
+    }
+    chado_pub_validate_check_uniquename($uniquename, $pub_id);
+  }
+  // Validating for an insert
+  else {
+    chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm);
+    chado_pub_validate_check_uniquename($uniquename);
+  }
+}
+/**
+ * 
+ * @param unknown $uniquename
+ */
+function chado_pub_validate_check_uniquename($uniquename, $pub_id = NULL) {
+  
+  $results = tripal_pub_get_pub_by_uniquename($uniquename);
+  // make sure we don't capture our pub_id in the list (remove it)
+  foreach ($results as $index => $found_pub_id) {
+    if($found_pub_id == $pub_id){
+      unset($results[$index]);
+    }
+  }
+  if (count($results) > 0) {
+    $message = t('A publication with this unique citation already exists.');
+    form_set_error('uniquename', $message);
+  }
+}
+/**
+ * 
+ */
+function chado_pub_validate_check_duplicate($title, $pyear, $series_name, $cvterm, $pub_id = NULL) {
+  
+  // make sure the publication is unique using the prefereed import duplication check
+  $import_dups_check = variable_get('tripal_pub_import_duplicate_check', 'title_year_media');
+  switch ($import_dups_check) {
+    case 'title_year':
+      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, NULL, $pyear, NULL);
+      // make sure we don't capture our pub_id in the list (remove it)
+      foreach ($results as $index => $found_pub_id) {
+        if($found_pub_id == $pub_id){
+          unset($results[$index]);
+        }
+      }
+      if (count($results) > 0) {
+        $message = t('A publication with this title and publication year, already exists.');
+        form_set_error('pyear', $message);
+      }
+      break;
+    case 'title_year_type':
+      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, $cvterm[0]->name, $pyear, NULL);
+  
+      // make sure we don't capture our pub_id in the list (remove it)
+      foreach ($results as $index => $found_pub_id) {
+        if($found_pub_id == $pub_id){
+          unset($results[$index]);
+        }
+      }
+      if (count($results) > 0) {
+        $message = t('A publication with this title, type and publication year, already exists.');
+        form_set_error('pyear', $message);
+      }
+      break;
+    case 'title_year_media':
+      $results = tripal_pub_get_pubs_by_title_type_pyear_series($title, NULL, $pyear, $series_name);
+  
+      // make sure we don't capture our pub_id in the list (remove it)
+      foreach ($results as $index => $found_pub_id) {
+        if($found_pub_id == $pub_id){
+          unset($results[$index]);
+        }
+      }
+      if (count($results) > 0) {
+        $message = t('A publication with this title, media name (e.g. Journal Name) and publication year, already exists.');
+        form_set_error('pyear', $message);
+      }
+      break;
+  }
+}
+
+
+/**
+ * Implement hook_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.
+ *
+ */
+function chado_pub_node_access($node, $op, $account ) {
+  if ($op == 'create') {
+    if (!user_access('create chado_pub content', $account)) {
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  if ($op == 'update') {
+    if (!user_access('edit chado_pub content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'delete') {
+    if (!user_access('delete chado_pub content', $account)) {
+      return FALSE;
+    }
+  }
+  if ($op == 'view') {
+    if (!user_access('access chado_pub content', $account)) {
+      return FALSE;
+    }
+  }
+  return NULL;
+}
+
+
+
+
+
+/**
+ * Implementation of tripal_pub_insert().
+ *
+ * This function inserts user entered information pertaining to the Publication instance into the
+ * 'pubauthor', 'pubprop', 'chado_pub', 'pub' talble of the database.
+ *
+ *  @parm $node
+ *    Then node which contains the information stored within the node-ID
+ *
+ *
+ */
+function chado_pub_insert($node) {
+
+  $title        = trim($node->pubtitle);
+  $pyear        = trim($node->pyear);
+  $uniquename   = trim($node->uniquename);
+  $is_obsolete  = $node->is_obsolete;
+  $type_id      = $node->type_id;
+
+  // we need an array suitable for the tripal_pub_create_citation() function
+  // to automatically generate a citation if a uniquename doesn't already exist
+  $pub_arr = array();
+
+  // if there is an pub_id in the $node object then this must be a sync so
+  // we can skip adding the pub as it is already there, although
+  // we do need to proceed with the rest of the insert
+  if (!property_exists($node, 'pub_id')) {
+
+    $properties = array(); // stores all of the properties we need to add
+    $cross_refs = array(); // stores any cross references for this publication
+
+    // get the properties from the form
+    $properties = tripal_core_properties_form_retreive($node, 'tripal_pub');
+
+    // get the list of properties for easy lookup (without doing lots of database queries
+    $properties_list = array();
+    $sql = "
+      SELECT CVTS.cvterm_id, CVTS.name, CVTS.definition
+      FROM {cvtermpath} CVTP
+        INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+        INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+        INNER JOIN {cv} ON CVTO.cv_id = CV.cv_id
+      WHERE CV.name = 'tripal_pub' and CVTO.name = 'Publication Details' and
+        NOT CVTS.is_obsolete = 1
+      ORDER BY CVTS.name ASC
+    ";
+    $prop_types = chado_query($sql);
+    while ($prop = $prop_types->fetchObject()) {
+      $properties_list[$prop->cvterm_id] = $prop->name;
+      // The 'Citation' term is special because it serves
+      // both as a property and as the uniquename for the
+      // pub and we want it stored in both the pub table and the pubprop table
+      if ($prop->name == 'Citation') {
+        $properties[$prop->name][0] = $node->uniquename;
+      }
+    }
+
+    // iterate through all of the properties and remove those that really are
+    // part of the pub table fields
+    $volume = '';
+    $volumetitle = '';
+    $issue = '';
+    $pages = '';
+    $publisher = '';
+    $series_name = '';
+    $pubplace = '';
+    $miniref = '';
+    $cross_refs = array();
+    foreach ($properties as $name => $element) {
+      $value = trim($element[0]);
+
+      // populate our $pub_array for building a citation
+      $pub_arr[$name] = $value;
+
+      // remove properties that are stored in the pub table
+      if ($name == "Volume") {
+        $volume = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Volume Title") {
+        $volumetitle = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Issue") {
+        $issue = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Pages") {
+        $pages = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Publisher") {
+        $publisher = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Series Name" or $name == "Journal Name" or $name == "Conference Name") {
+        $series_name = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Journal Country" or $name == "Published Location") {
+        $pubplace = $value;
+        // allow this property to go into the pubprop table so we don't loose info
+        // so don't unset it. But it will also go into the pub.pubplace field
+      }
+      elseif ($name == "Publication Dbxref") {
+        // we will add the cross-references to the pub_dbxref table
+        // but we also want to keep the property in the pubprop table so don't unset it
+        $cross_refs[] = $value;
+      }
+    }
+    // generate a citation for this pub if one doesn't already exist
+    if (!$node->uniquename and array_key_exists('Citation', $properties)) {
+      $pub_type = tripal_cv_get_cvterm_by_id($node->type_id);
+      $pub_arr['Title'] = $node->pubtitle;
+      $pub_arr['Publication Type'][0] = $pub_type->name;
+      $pub_arr['Year'] = $node->pyear;
+      $node->uniquename = tripal_pub_create_citation($pub_arr);
+      $properties['Citation'][0] = $node->uniquename;
+    }
+
+    // insert the pub record
+    $values = array(
+      'title'       => $node->pubtitle,
+      'series_name' => substr($series_name, 0, 255),
+      'type_id'     => $node->type_id,
+      'pyear'       => $node->pyear,
+      'is_obsolete' => $node->is_obsolete ? 'true' : 'false',
+      'uniquename'  => $node->uniquename,
+      'volumetitle' => $volumetitle,
+      'volume'      => $volume,
+      'issue'       => $issue,
+      'pages'       => $pages,
+      'miniref'     => substr($miniref, 0, 255),
+      'publisher'   => substr($publisher, 0, 255),
+      'pubplace'    => substr($pubplace, 0, 255),
+    );
+    $pub = tripal_core_chado_insert('pub', $values);
+    if (!$pub) {
+      drupal_set_message("Error inserting publication", "error");
+      watchdog('tripal_pub', "Error inserting publication", array(), WATCHDOG_ERROR);
+      return;
+    }
+    $pub_id = $pub['pub_id'];
+
+    // now add in the properties
+    foreach ($properties as $property => $elements) {
+      foreach ($elements as $rank => $value) {
+
+        $status = tripal_pub_insert_property($pub['pub_id'], $property, $value, FALSE);
+        if (!$status) {
+          drupal_set_message("Error cannot add property: $property", "error");
+          watchdog('tripal_pub', "Error cannot add property: %prop",
+          array('%property' => $property), WATCHDOG_ERROR);
+        }
+      }
+    }
+
+    // add in any database cross-references
+    foreach ($cross_refs as $index => $ref) {
+      $pub_dbxref = tripal_pub_add_pub_dbxref($pub['pub_id'], trim($ref));
+      if (!$pub_dbxref) {
+        drupal_set_message("Error cannot add publication cross reference: $ref", "error");
+        watchdog('tripal_pub', "Error cannot add publication cross reference: %ref",
+        array('%ref' => $ref), WATCHDOG_ERROR);
+      }
+    }
+  }
+  else {
+    $pub_id = $node->pub_id;
+  }
+
+  // Make sure the entry for this pub doesn't already exist in the
+  // chado_pub table if it doesn't exist then we want to add it.
+  $check_org_id = chado_get_id_for_node('pub', $node->nid);
+  if (!$check_org_id) {
+    $record = new stdClass();
+    $record->nid = $node->nid;
+    $record->vid = $node->vid;
+    $record->pub_id = $pub_id;
+    drupal_write_record('chado_pub', $record);
+  }
+
+}
+
+/*
+ *
+* Implements hook_update
+*
+* The purpose of the function is to allow the module to take action when an edited node is being
+* updated. It updates any name changes to the database tables that werec reated upon registering a Publication.
+* As well, the database will be changed, so the user changed information will be saved to the database.
+*
+* @param $node
+*   The node being updated
+*
+* @ingroup tripal_pub
+*/
+function chado_pub_update($node) {
+  $title        = trim($node->pubtitle);
+  $pyear        = trim($node->pyear);
+  $uniquename   = trim($node->uniquename);
+  $is_obsolete  = $node->is_obsolete;
+  $type_id      = $node->type_id;
+
+  // we need an array suitable for the tripal_pub_create_citation() function
+  // to automatically generate a citation if a uniquename doesn't already exist
+  $pub_arr = array();
+
+  // get the publication ID for this publication
+  $pub_id = chado_get_id_for_node('pub', $node->nid) ;
+
+  $properties = array(); // stores all of the properties we need to add
+  $cross_refs = array(); // stores any cross references for this publication
+
+  // get the properties from the form
+  $properties = tripal_core_properties_form_retreive($node, 'tripal_pub');
+
+  // get the list of properties for easy lookup (without doing lots of database queries
+  $properties_list = array();
+  $sql = "
+    SELECT DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+      INNER JOIN {cv} ON CVTO.cv_id = CV.cv_id
+    WHERE CV.name = 'tripal_pub' and
+      (CVTO.name = 'Publication Details' or CVTS.name = 'Publication Type') and
+      NOT CVTS.is_obsolete = 1
+    ORDER BY CVTS.name ASC
+  ";
+  $prop_types = chado_query($sql);
+  while ($prop = $prop_types->fetchObject()) {
+    $properties_list[$prop->cvterm_id] = $prop->name;
+    // The 'Citation' term is special because it serves
+    // both as a property and as the uniquename for the
+    // pub and we want it stored in both the pub table and the pubprop table
+    if ($prop->name == 'Citation') {
+      $properties[$prop->name][0] = $node->uniquename;
+    }
+  }
+
+  // iterate through all of the properties and remove those that really are
+  // part of the pub table fields
+  $volume = '';
+  $volumetitle = '';
+  $issue = '';
+  $pages = '';
+  $publisher = '';
+  $series_name = '';
+  $pubplace = '';
+  $miniref = '';
+  $cross_refs = array();
+  foreach ($properties as $name => $element) {
+    foreach ($element as $index => $value) {
+      // populate our $pub_array for building a citation
+      $pub_arr[$name] = $value;
+
+      // remove properties that are stored in the pub table
+      if ($name == "Volume") {
+        $volume = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Volume Title") {
+        $volumetitle = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Issue") {
+        $issue = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Pages") {
+        $pages = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Publisher") {
+        $publisher = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Journal Name" or $name == "Conference Name") {
+        $series_name = $value;
+        unset($properties[$name]);
+      }
+      elseif ($name == "Journal Country" or $name == "Published Location") {
+        $pubplace = $value;
+        // allow this property to go into the pubprop table so we don't loose info
+        // so don't unset it. But it will also go into the pub.pubplace field
+      }
+      elseif ($name == "Publication Dbxref") {
+        // we will add the cross-references to the pub_dbxref table
+        // but we also want to keep the property in the pubprop table so don't unset it
+        $cross_refs[] = $value;
+      }
+    }
+  }
+  // generate a citation for this pub if one doesn't already exist
+  if (!$node->uniquename) {
+    $pub_type = tripal_cv_get_cvterm_by_id($node->type_id);
+    $pub_arr['Title'] = $node->pubtitle;
+    $pub_arr['Publication Type'][0] = $pub_type->name;
+    $pub_arr['Year'] = $node->pyear;
+    $node->uniquename = tripal_pub_create_citation($pub_arr);
+    $properties['Citation'][0] = $node->uniquename;
+  }
+
+  // update the pub record
+  $match = array(
+    'pub_id' => $pub_id,
+  );
+  $values = array(
+    'title'       => $node->pubtitle,
+    'type_id'     => $node->type_id,
+    'pyear'       => $node->pyear,
+    'is_obsolete' => $node->is_obsolete ? 'true' : 'false',
+    'uniquename'  => $node->uniquename,
+    'series_name' => substr($series_name, 0, 255),
+    'volumetitle' => $volumetitle,
+    'volume'      => $volume,
+    'issue'       => $issue,
+    'pages'       => $pages,
+    'miniref'     => substr($miniref, 0, 255),
+    'publisher'   => substr($publisher, 0, 255),
+    'pubplace'    => substr($pubplace, 0, 255),
+  );
+  $status = tripal_core_chado_update('pub', $match, $values);
+  if (!$status) {
+    drupal_set_message("Error updating publication", "error");
+    watchdog('tripal_pub', "Error updating publication", array(), WATCHDOG_ERROR);
+    return;
+  }
+
+  // now add in the properties by first removing any the publication
+  // already has and adding the ones we have
+  tripal_core_chado_delete('pubprop', array('pub_id' => $pub_id));
+  foreach ($properties as $property => $elements) {
+    foreach ($elements as $rank => $value) {
+      $status = tripal_pub_insert_property($pub_id, $property, $value, FALSE);
+      if (!$status) {
+        drupal_set_message("Error cannot add property: '$property'", "error");
+        watchdog('tripal_pub', "Error cannot add property: '%prop'",
+        array('%prop' => $property), WATCHDOG_ERROR);
+      }
+    }
+  }
+
+  // add in any database cross-references after first removing
+  tripal_core_chado_delete('pub_dbxref', array('pub_id' => $pub_id));
+  foreach ($cross_refs as $index => $ref) {
+    $pub_dbxref = tripal_pub_add_pub_dbxref($pub_id, trim($ref));
+    if (!$pub_dbxref) {
+      drupal_set_message("Error cannot add publication cross reference: $ref", "error");
+      watchdog('tripal_pub', "Error cannot add publication cross reference: %ref",
+      array('%ref' => $ref), WATCHDOG_ERROR);
+    }
+  }
+}
+
+
+/**
+ * Implementation of tripal_pub_load().
+ *
+ *
+ * @param $node
+ *   The node that is to be accessed from the database
+ *
+ * @return $node
+ *   The node with the information to be loaded into the database
+ *
+ */
+function chado_pub_load($nodes) {
+
+  foreach ($nodes as $nid => $node) {
+    // find the pub and add in the details
+    $pub_id = chado_get_id_for_node('pub', $nid);
+
+    // get the pub
+    $values = array('pub_id' => $pub_id);
+    $pub = tripal_core_generate_chado_var('pub', $values);
+
+    // expand the 'text' fields as those aren't included by default
+    // and they really shouldn't be so large to cause problems
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.title');
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.volumetitle');
+    $pub = tripal_core_expand_chado_vars($pub, 'field', 'pub.uniquename');
+
+    // set the URL path
+    $nodes[$nid]->path = "pub/$pub_id";
+    $nodes[$nid]->pub = $pub;
+  }
+}
+
+/**
+ * Implementation of tripal_pub_delete().
+ *
+ * This function takes a node and if the delete button has been chosen by the user, the publication
+ * and it's details will be removed.Following,given the node-ID, the instance will be deleted from
+ * the 'chado_pub' table.
+ *
+ *  @parm $node
+ *    Then node which contains the information stored within the node-ID
+ *
+ */
+function chado_pub_delete(&$node) {
+
+  $pub_id = chado_get_id_for_node('pub', $node->nid);
+
+  // if we don't have a pub id for this node then this isn't a node of
+  // type chado_pub or the entry in the chado_pub table was lost.
+  if (!$pub_id) {
+    return;
+  }
+
+  // Remove data from {chado_pub}, {node} and {node_revision} tables of
+  // drupal database
+  $sql_del = "DELETE FROM {chado_pub} 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 pub and pubprop tables of chado database as well
+  chado_query("DELETE FROM {pubprop} WHERE pub_id = :pub_id", array(':pub_id' => $pub_id));
+  chado_query("DELETE FROM {pub} WHERE pub_id = :pub_id", array(':pub_id' => $pub_id));
+}

+ 0 - 0
tripal_pub/includes/pub_citation.inc → tripal_pub/includes/tripal_pub.pub_citation.inc


+ 41 - 8
tripal_pub/includes/pub_importers.inc → tripal_pub/includes/tripal_pub.pub_importers.inc

@@ -25,7 +25,11 @@ function tripal_pub_importers_list() {
     }
 
     $rows[] = array(
-      l(t('Edit/Test'), "admin/tripal/chado/tripal_pub/import/edit/$importer->pub_import_id"),
+      array(
+        'data' => l(t('Edit/Test'), "admin/tripal/chado/tripal_pub/import/edit/$importer->pub_import_id") . '<br>' .
+                  l(t('Import Pubs'), "admin/tripal/chado/tripal_pub/import/submit/$importer->pub_import_id"),
+        'nowrap' => 'nowrap'
+      ),
       $importer->name,
       $criteria['remote_db'],
       $criteria_str,
@@ -45,9 +49,15 @@ function tripal_pub_importers_list() {
      to query a remote database, find publications that match the specified criteria 
      and then import those publications into the Chado database. An example use case would
      be to peridocially add new publications to this Tripal site that have appeared in PubMed
-     in the last 30 days.  See the " . 
+     in the last 30 days.  You can import publications in one of two ways:
+     <ol>
+      <li>Create a new importer by clicking the 'New Importer' link above, and after saving it should appear in the list below.  Click the
+          link labeled 'Import Pubs' to schedule a job to import the publications</li>
+      <li>The first method only performs the import once.  However, you can schedule the 
+          importer to run peridically by adding a cron job. See the " . 
      l("Pub Module help instructions", "admin/tripal/chado/tripal_pub/help") . " to learn how to 
-     set the importers to run automatically.") . '</p>';
+     set the importers to run automatically.") . '</li>
+     </ol><br>';
 
   $page .= theme('table', array('header' => $header, 'rows' => $rows));
   
@@ -232,6 +242,12 @@ function tripal_pub_importer_setup_form($form, &$form_state = NULL, $pub_import_
     $do_contact   = $_SESSION['tripal_pub_import']['do_contact'];
     $num_criteria = $_SESSION['tripal_pub_import']['num_criteria'];
     $loader_name  = $_SESSION['tripal_pub_import']['loader_name'];
+    
+    // check if the pub_import_id in the session variable is not the same as the one we've been provided
+    // if so, then clear the session variable
+    if ($pub_import_id and $pub_import_id != $_SESSION['tripal_pub_import']['pub_import_id']) {
+      unset($_SESSION['tripal_pub_import']);
+    }
   }
   
   // if we are re constructing the form from a failed validation or ajax callback
@@ -267,11 +283,7 @@ function tripal_pub_importer_setup_form($form, &$form_state = NULL, $pub_import_
     $num_criteria--;
   }
   
-  // check if the pub_import_id in the session variable is not the same as the one we've been provided
-  // if so, then clear the session variable
-  if ($pub_import_id and $pub_import_id != $_SESSION['tripal_pub_import']['pub_import_id']) {
-    unset($_SESSION['tripal_pub_import']);
-  }
+
   
   // set the values we need for later but that should not be shown on the form
   $form['num_criteria']= array(
@@ -732,3 +744,24 @@ function theme_tripal_pub_importer_setup_form_elements($variables) {
   
   return drupal_render($form);
 }
+
+/**
+ * Add a job to import publications
+ * 
+ * @param $pub_importer_id
+ */
+function tripal_pub_importer_submit_job($import_id) {
+  global $user;
+  
+  // get all of the loaders
+  $args = array(':import_id' => $import_id);
+  $sql = "SELECT * FROM {tripal_pub_import} WHERE pub_import_id = :import_id ";
+  $import = db_query($sql, $args)->fetchObject();
+  
+  $args = array($import_id);
+  tripal_add_job("Import publications $import->name", 'tripal_pub',
+    'tripal_pub_import_publications_by_import_id', $args, $user->uid);
+  
+  drupal_goto('admin/tripal/chado/tripal_pub/import_list');
+}
+

+ 634 - 0
tripal_pub/includes/tripal_pub.pub_search.inc

@@ -0,0 +1,634 @@
+<?php
+/*
+ *
+ */
+function tripal_pub_search_page() {
+
+  $limit = 25;
+
+  // generate the search form
+  $form = drupal_get_form('tripal_pub_search_form');
+  $output = drupal_render($form);
+
+  // retrieve any results
+  if (array_key_exists('tripal_pub_search_form', $_SESSION) and 
+      $_SESSION['tripal_pub_search_form']['perform_search']) {
+    $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'];
+    $from_year    = $_SESSION['tripal_pub_search_form']['from_year'];
+    $to_year      = $_SESSION['tripal_pub_search_form']['to_year'];
+     
+    $search_array = array();
+    $search_array['num_criteria'] = $num_criteria;
+    $search_array['from_year']    = $from_year;
+    $search_array['to_year']      = $to_year;
+    for ($i = 0; $i <= $num_criteria; $i++) {
+      $search_array['criteria'][$i]['search_terms'] = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'];
+      $search_array['criteria'][$i]['scope']        = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope'];
+      $search_array['criteria'][$i]['mode']         = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode'];
+      $search_array['criteria'][$i]['operation']    = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation'];
+    }
+
+    // get the list of publications from the remote database using the search criteria.
+    $pubs = tripal_pub_get_search_results($search_array, $limit);
+    $page = isset($_GET['page']) ? $_GET['page'] : '0';
+    $total_records = $_SESSION['chado_pager'][0]['total_records'];
+    $total_pages = (int) ($total_records / $limit) + 1;
+
+    // iterate through the results and construct the table displaying the publications
+    $rows = array();
+    $i = $page * $limit + 1;
+    foreach ($pubs as $pub) {
+      // get the citation for this publication
+      $values = array(
+        'pub_id' => $pub->pub_id, 
+        'type_id' => array(
+          'name' => 'Citation',
+        ),
+      );
+      $citation_rec = tripal_core_generate_chado_var('pubprop', $values);
+      $citation_rec = tripal_core_expand_chado_vars($citation_rec, 'field', 'pubprop.value');
+
+      // if we have the citation then use it, otherwise, just use the title
+      $title = htmlspecialchars($pub->title);
+      $result = $title;
+      if ($pub->nid) {
+        $result = l($title ,'node/' . $pub->nid, array('attributes' => array('target' => '_blank')));
+      }
+      if ($citation_rec->value) {
+        $citation = htmlspecialchars($citation_rec->value);
+        $result .= '<br>' . $citation;
+      }
+      $rows[] = array(
+      number_format($i) . ".",
+      $pub->pyear,
+      $result
+      );
+      $i++;
+    }
+    
+    if (count($rows) == 0) {
+      $rows[] = array(
+        array(
+          'data' => 'No results found',
+          'colspan' => 3
+        )
+      );
+    }
+
+    $headers = array('', 'Year', 'Publication');
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array('id' => 'tripal-pub-search-results-table', 'border' => '0'),
+      'sticky' => TRUE,
+      'caption' => '',
+      'colgroups' => array(),
+      'empty' => '',
+    );
+    $results = theme_table($table);
+    
+    // generate the pager
+    pager_default_initialize($total_records, $limit);
+    $pager = array(
+      'tags' => array(),
+      'element' => 0,
+      'parameters' => array(),
+      'quantity' => $limit,
+    );
+    $pager = theme_pager($pager);
+    
+    // join all to form the results
+    $output .= "<br><p><b>Found " . number_format($total_records) .
+      ". Page " . ($page + 1) . " of $total_pages. " .
+      " Results</b></br>" . $results . $pager;    
+  }
+  return $output;
+}
+/**
+ * Purpose: Provides the form to search pubmed
+ *
+ * @ingroup tripal_pub
+ */
+function tripal_pub_search_form($form, &$form_state) {
+  // Default values can come in the following ways:
+  //
+  // 1) as elements of the $pub_importer object.  This occurs when editing an existing importer
+  // 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 the default values. If the pub_import_id isn't already defined by the form values
+  // and one is provided then look it up in the database
+  $criteria = NULL;
+  $num_criteria = 2;
+  $from_year = '';
+  $to_year = '';
+
+  // if the session has variables then use those.  This should only happen when
+  // the 'Test Criteria' button is clicked.
+  if (array_key_exists('tripal_pub_search_form', $_SESSION)) {
+    $num_criteria = $_SESSION['tripal_pub_search_form']['num_criteria'] ? $_SESSION['tripal_pub_search_form']['num_criteria'] : $num_criteria;
+    $from_year    = $_SESSION['tripal_pub_search_form']['from_year']    ? $_SESSION['tripal_pub_search_form']['from_year']    : '';
+    $to_year      = $_SESSION['tripal_pub_search_form']['to_year']      ? $_SESSION['tripal_pub_search_form']['to_year']      : '';
+  }
+  if (array_key_exists('values', $form_state)) {
+    $num_criteria = $form_state['values']['num_criteria'] ? $form_state['values']['num_criteria'] : $num_criteria;
+    $from_year    = $form_state['values']['from_year']    ? $form_state['values']['from_year']    : $from_year;
+    $to_year      = $form_state['values']['to_year']      ? $form_state['values']['to_year']      : $to_year;
+  }
+  if (array_key_exists('input', $form_state) and !empty($form_state['input'])) {
+    $num_criteria = $form_state['input']['num_criteria'] ? $form_state['input']['num_criteria'] : $num_criteria;
+    $from_year    = $form_state['input']['from_year']    ? $form_state['input']['from_year']    : $from_year;
+    $to_year      = $form_state['input']['to_year']      ? $form_state['input']['to_year']      : $to_year;
+    
+  }
+
+  if (array_key_exists('triggering_element', $form_state) and
+  $form_state['triggering_element']['#name'] == 'add') {
+    $num_criteria++;
+  }
+  if (array_key_exists('triggering_element', $form_state) and
+  $form_state['triggering_element']['#name'] == 'remove') {
+    $num_criteria--;
+  }
+  
+  $form['num_criteria']= array(
+    '#type'          => 'hidden',
+    '#default_value' => $num_criteria,
+  );
+  
+  if (user_access('access administration pages')) {
+    $form['admin-instructions'] = array(
+      '#prefix' => '<div class="tripal-no-results">',
+      '#markup'  =>  t('Administrators, you can select the fields with which a user can use to search,
+          by checking the desired fields on the ' .
+          l('Publication Module Settings Page', 'admin/tripal/chado/tripal_pub/configuration'). ' in
+         the section titled "Search Options".  The selected fields will appear in the dropdowns below.'),
+      '#suffix' => '</div>'
+    );
+  }
+  $form['instructions'] = array(
+    '#markup'  =>  t('To search for publications enter keywords in the text boxes below.  
+        You can limit your search by selecting the field in the dropdown box. Click the 
+        add and remove buttons to add additional fields for searching. '),
+  );
+
+  // get publication properties list
+  $properties = array();
+  $properties[] = 'Any Field';
+  $sql = "
+    SELECT DISTINCT CVTS.cvterm_id, CVTS.name, CVTS.definition
+    FROM {cvtermpath} CVTP
+      INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+      INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+      INNER JOIN {cv} ON CVTO.cv_id = CV.cv_id
+    WHERE CV.name = 'tripal_pub' and 
+      (CVTO.name = 'Publication Details' or CVTS.name = 'Publication Type') and 
+      NOT CVTS.is_obsolete = 1
+    ORDER BY CVTS.name ASC 
+  ";
+  $allowed_fields = variable_get('tripal_pub_allowed_search_fields', array());
+  $prop_types = chado_query($sql);
+  foreach ($prop_types as $prop) {
+    if(array_key_exists($prop->cvterm_id, $allowed_fields) and $allowed_fields[$prop->cvterm_id] > 0) {
+      $properties[$prop->cvterm_id] = $prop->name;
+    }
+  }
+
+  for($i = 1; $i <= $num_criteria; $i++) {
+    $search_terms = '';
+    $scope = '';
+    $operation = '';
+    $mode = '';
+
+    // first populate defaults using any values in the SESSION variable
+    if (array_key_exists('tripal_pub_search_form', $_SESSION)) {
+      $search_terms = $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['search_terms'] : $search_terms;
+      $scope        = $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope']        ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['scope']        : $scope;
+      $mode         = $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode']         ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['mode']         : $mode;
+      $operation    = $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation']    ? $_SESSION['tripal_pub_search_form']['criteria'][$i]['operation']    : $operation;
+    }
+    if (array_key_exists('values', $form_state)) {      
+      $search_terms = array_key_exists("search_terms-$i", $form_state['values']) ? $form_state['values']["search_terms-$i"] : $search_terms;
+      $scope        = array_key_exists("scope-$i", $form_state['values'])        ? $form_state['values']["scope-$i"]        : $scope;
+      $mode         = array_key_exists("mode-$i", $form_state['values'])         ? $form_state['values']["mode-$i"]         : $mode;
+      $operation    = array_key_exists("operation-$i", $form_state['values'])    ? $form_state['values']["operation-$i"]    : $operation;
+    }
+    if (array_key_exists('input', $form_state)) {
+      $search_terms = array_key_exists("search_terms-$i", $form_state['input']) ? $form_state['input']["search_terms-$i"] : $search_terms;
+      $scope        = array_key_exists("scope-$i", $form_state['input'])        ? $form_state['input']["scope-$i"]        : $scope;
+      $mode         = array_key_exists("mode-$i", $form_state['input'])         ? $form_state['input']["mode-$i"]         : $mode;
+      $operation    = array_key_exists("operation-$i", $form_state['input'])    ? $form_state['input']["operation-$i"]    : $operation;
+    }
+
+    // default to searching the title and abstract
+    if (!$scope) {
+      $scope = 'abstract';
+    }
+
+    $form['criteria'][$i]["search_terms-$i"] = array(
+      '#type'          => 'textfield',
+      '#default_value' => $search_terms,
+      '#required'      => FALSE,
+    );
+    $form['criteria'][$i]["scope-$i"] = array(
+      '#type'          => 'select',
+      '#options'       => $properties,
+      '#default_value' => $scope,
+      '#attributes' => array('class' => array('tripal-pub-search-form-scope-select')),
+    );
+    /*
+     $form['criteria'][$i]["mode-$i"] = array(
+     '#type'          => 'select',
+     '#options'       => array(
+     'Contains'    => 'Contains',
+     'Starts With' => 'Starts With',
+     'Ends With'   => 'Ends With',
+     'Exactly'     => 'Exactly'),
+     '#default_value' => $mode,
+     );*/
+
+    if ($i > 1) {
+      $form['criteria'][$i]["operation-$i"] = array(
+        '#type'          => 'select',
+        '#options'       => array(
+          'AND' => 'AND',
+          'OR'  => 'OR',
+          'NOT' => 'NOT'),
+        '#default_value' => $operation,
+      );
+    }
+    if ($i == $num_criteria) {
+      if($i > 1) {
+        $form['criteria'][$i]["remove-$i"] = array(
+          '#type'  => 'button',
+          '#name'  => 'remove',
+          '#value' => t('Remove'),
+          '#ajax' => array(
+            'callback' => "tripal_pubs_search_form_ajax_update",
+            'wrapper'  => 'tripal-pub-search-form-criteria',
+            'effect'   => 'fade',
+            'method'   => 'replace',
+            'prevent'  => 'click'
+          ),
+          // When this button is clicked, the form will be validated and submitted.
+          // Therefore, we set custom submit and validate functions to override the
+          // default form submit.  In the validate function we set the form_state
+          // to rebuild the form so the submit function never actually gets called,
+          // but we need it or Drupal will run the default validate anyway.
+          // we also set #limit_validation_errors to empty so fields that
+          // are required that don't have values won't generate warnings.
+          '#submit'   => array('tripal_pub_search_form_ajax_button_submit'),
+          '#validate' => array('tripal_pub_search_form_ajax_button_validate'),
+          '#limit_validation_errors' => array(),
+        );
+      }
+      $form['criteria'][$i]["add-$i"] = array(
+        '#type'  => 'button',      
+        '#name'  => 'add',
+        '#value' => t('Add'),
+        '#ajax' => array(
+          'callback' => "tripal_pubs_search_form_ajax_update",
+          'wrapper'  => 'tripal-pub-search-form-criteria',
+          'effect'   => 'fade',
+          'method'   => 'replace',
+          'prevent'  => 'click'
+        ),
+        // When this button is clicked, the form will be validated and submitted.
+        // Therefore, we set custom submit and validate functions to override the
+        // default form submit.  In the validate function we set the form_state
+        // to rebuild the form so the submit function never actually gets called,
+        // but we need it or Drupal will run the default validate anyway.
+        // we also set #limit_validation_errors to empty so fields that
+        // are required that don't have values won't generate warnings.
+        '#submit'   => array('tripal_pub_search_form_ajax_button_submit'),
+        '#validate' => array('tripal_pub_search_form_ajax_button_validate'),
+        '#limit_validation_errors' => array(),
+      );
+    }
+  }
+  $form['criteria']["date"] = array(
+      '#type'          => 'select',
+      '#options'       => array('Years' => 'Years'),
+      '#attributes'    => array('class' => array('tripal-pub-search-form-scope-select')),
+  );
+  $form['criteria']["from_year"] = array(
+    '#type'          => 'textfield',
+    '#default_value' => $from_year,
+    '#required'      => FALSE,
+    '#title'         => 'from',
+    '#size'          => 4,
+    '#maxlength'     => 4,
+  );
+  $form['criteria']["to_year"] = array(
+    '#type'          => 'textfield',
+    '#default_value' => $to_year,
+    '#required'      => FALSE,
+    '#title'         => 'to',
+    '#size'          => 4,
+    '#maxlength'     => 4,
+  );
+
+  $form['search'] = array(
+    '#type'         => 'submit',
+    '#value'        => t('Search'),
+  );
+  $form['reset'] = array(
+    '#type'         => 'submit',
+    '#value'        => t('Reset'),
+  );
+  
+  $form['criteria']['#theme'] = 'tripal_pub_search_setup_form_elements';
+
+  return $form;
+}
+/**
+ * This function is used to rebuild the form if an ajax call is made vai a button.
+ * The button causes the form to be submitted. We don't want this so we override
+ * the validate and submit routines on the form button. Therefore, this function
+ * only needs to tell Drupal to rebuild the form
+ */
+function tripal_pub_search_form_ajax_button_submit() {
+  $form_state['rebuild'] = TRUE;
+  
+}
+/**
+ * This function is just a dummy to override the default form submit on ajax calls for buttons
+ */
+function tripal_pub_search_form_ajax_button_validate() {
+  // do nothing
+}
+
+/**
+ *
+ */
+function tripal_pub_search_form_validate($form, &$form_state) {
+  $num_criteria = $form_state['values']['num_criteria'];
+  $from_year    = $form_state['values']['from_year'];
+  $to_year      = $form_state['values']['to_year'];
+  $op           = $form_state['values']['op'];
+
+  // no need to vlaidate on a reset
+  if ($op == 'Reset') {
+    return;
+  }
+
+  if($from_year and !$to_year) {
+    form_set_error('to_year', 'Please provide a 4-digit year.');
+  }
+  if(!$from_year and $to_year) {
+    form_set_error('from_year', 'Please provide a 4-digit year.');
+  }
+  if($from_year and !preg_match('/\d\d\d\d/' , $from_year)) {
+    form_set_error('from_year', 'Please provide a 4-digit year.');
+  }
+  if($to_year and !preg_match('/\d\d\d\d/' , $to_year)) {
+    form_set_error('to_year', 'Please provide a 4-digit year.');
+  }
+}
+/**
+ *
+ */
+function tripal_pub_search_form_submit($form, &$form_state) {
+  $num_criteria = $form_state['values']['num_criteria'];
+  $from_year    = $form_state['values']['from_year'];
+  $to_year      = $form_state['values']['to_year'];
+  $op           = $form_state['values']['op'];
+
+  // set the session variables
+  if($op == 'Search') {
+    $_SESSION['tripal_pub_search_form']['num_criteria'] = $num_criteria;
+    unset($_SESSION['tripal_pub_search_form']['criteria']);
+    for ($i = 0; $i <= $num_criteria; $i++) {
+      $search_terms = '';
+      $scope = '';
+      $mode = 'Contains';
+      $operation = '';
+      if (array_key_exists("search_terms-$i", $form_state['values'])) {
+        $search_terms =  trim($form_state['values']["search_terms-$i"]);
+      }
+      if (array_key_exists("scope-$i", $form_state['values'])) {
+        $scope =  $form_state['values']["scope-$i"];
+      }
+      if (array_key_exists("operation-$i", $form_state['values'])) {
+        $operation =  $form_state['values']["operation-$i"];
+      }
+      //$mode =  $form_state['values']["mode-$i"];
+      
+      $_SESSION['tripal_pub_search_form']['criteria'][$i] = array(
+        'search_terms' => $search_terms,
+        'scope' => $scope,
+        'mode' => $mode,
+        'operation' => $operation
+      );
+      
+    }
+    $_SESSION['tripal_pub_search_form']['from_year'] = $from_year;
+    $_SESSION['tripal_pub_search_form']['to_year'] = $to_year;
+    $_SESSION['tripal_pub_search_form']['perform_search'] = 1;
+  }
+  if($op == 'Reset') {
+    unset($_SESSION['tripal_pub_search_form']);
+  }
+}
+
+/*
+ * AHAH callback
+ */
+function tripal_pub_search_page_update_criteria($action, $i) {
+  $status = TRUE;
+
+  // prepare and render the form
+  $form = tripal_core_ahah_prepare_form();
+  $data = theme('tripal_pub_search_form', $form);
+
+  // bind javascript events to the new objects that will be returned
+  // so that AHAH enabled elements will work.
+  $settings = tripal_core_ahah_bind_events();
+
+  // return the updated JSON
+  drupal_json(
+  array(
+      'status'   => $status, 
+      'data'     => $data,
+      'settings' => $settings,
+  )
+  );
+}
+/**
+ *
+ */
+function tripal_pub_get_search_results($search_array, $limit) {
+
+  // build the SQL based on the criteria provided by the user
+  $select = "SELECT DISTINCT P.*, CP.nid ";
+  $from   = "FROM {pub} P
+               LEFT JOIN public.chado_pub CP on P.pub_id = CP.pub_id 
+               INNER JOIN {cvterm} CVT on CVT.cvterm_id = P.type_id
+            ";
+  $where  = "WHERE (NOT P.title = 'null') "; // always exclude the dummy pub
+  $order  = "ORDER BY P.pyear DESC, P.title ASC";
+  $args = array();  // arguments for where clause
+  $join = 0;
+
+  $num_criteria = $search_array['num_criteria'];
+  $from_year    = $search_array['from_year'];
+  $to_year      = $search_array['to_year'];
+
+  for ($i = 1; $i <= $num_criteria; $i++) {
+    $value = $search_array['criteria'][$i]['search_terms'];
+    $type_id = $search_array['criteria'][$i]['scope'];
+    $mode = $search_array['criteria'][$i]['mode'];
+    $op = $search_array['criteria'][$i]['operation'];
+
+    // skip criteria with no values
+    if(!$value) {
+      continue;
+    }
+
+    // to prevent SQL injection make sure our operator is
+    // what we expect
+    if ($op and $op != "AND" and $op != "OR" and $op != 'NOT') {
+      $op = 'AND';
+    }
+    if ($op == 'NOT') {
+      $op = 'AND NOT';
+    }
+    if (!$op) {
+      $op = 'AND';
+    }
+
+    // get the scope type
+    $values = array('cvterm_id' => $type_id);
+    $cvterm = tripal_core_chado_select('cvterm', array('name'), $values);
+    $type_name = '';
+    if (count($cvterm) > 0) {
+      $type_name = $cvterm[0]->name;
+    }
+    if ($type_name == 'Title') {
+      $where .= " $op (lower(P.title) LIKE lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+    }
+    elseif ($type_name == 'Year') {
+      $where .= " $op (lower(P.pyear) = lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+    }
+    elseif ($type_name == 'Volume') {
+      $where .= " $op (lower(P.volume) = lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+    }
+    elseif ($type_name == 'Issue') {
+      $where .= " $op (lower(P.issue) = lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+    }
+    elseif ($type_name == 'Journal Name') {
+      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
+      $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Journal Article') OR
+                       (lower(PP$i.value) = lower(:crit$i))) ";
+      $args[":crit$i"] = $type_id;
+    }
+    elseif ($type_name == 'Conference Name') {
+      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :crit$i ";
+      $where .= " $op ((lower(P.series_name) = lower(:crit$i) and CVT.name = 'Conference Proceedings') OR
+                       (lower(PP$i.value) = lower(:crit$i))) ";
+      $args[":crit$i"] = $type_id;
+    }
+    elseif ($type_name == 'Publication Type') {
+      $where .= " $op (lower(CVT.name) = lower(:crit$i))";
+      $args[":crit$i"] = $value;
+    }
+    elseif ($type_id == 0) { //'Any Field'
+      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id ";
+      $where .= " $op (lower(PP$i.value)  LIKE lower(:crit$i) OR
+                       lower(P.title) LIKE lower(:crit$i) OR 
+                       lower(P.volumetitle) LIKE lower(:crit$i) OR
+                       lower(P.publisher) LIKE lower(:crit$i) OR
+                       lower(P.uniquename) LIKE lower(:crit$i) OR
+                       lower(P.pubplace) LIKE lower(:crit$i) OR
+                       lower(P.miniref) LIKE lower(:crit$i) OR
+                       lower(P.series_name) LIKE lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+    }
+    // for all other properties
+    else {
+      $from .= " LEFT JOIN {pubprop} PP$i ON PP$i.pub_id = P.pub_id AND PP$i.type_id = :type_id$i ";
+      $where .= " $op (lower(PP$i.value) LIKE lower(:crit$i)) ";
+      $args[":crit$i"] = '%' . $value . '%';
+      $args[":type_id$i"] = $type_id;
+    }
+  }
+  if($from_year and $to_year) {
+    $where .= " AND (P.pyear ~ '....' AND to_number(P.pyear,'9999') >= :from$i AND to_number(P.pyear,'9999') <= :to$i) ";
+    $args[":from$i"] = $from_year;
+    $args[":to$i"] = $to_year;
+  }
+  $sql = "$select $from $where $order";
+  $count = "SELECT count(*) FROM ($select $from $where $order) as t1";
+  return chado_pager_query($sql, $args, $limit, 0, $count);
+}
+
+/**
+ * 
+ */
+function tripal_pubs_search_form_ajax_update($form, $form_state) {
+  return $form['criteria'];
+}
+
+/**
+*
+* @param unknown $form
+*/
+function theme_tripal_pub_search_setup_form_elements($variables) {
+  $form = $variables['form'];
+
+  $rows = array();
+  // put each criteria element in a single table row
+  foreach ($form as $i => $element) {
+    if(is_numeric($i)) {
+      $rows[] = array(
+        drupal_render($element["operation-$i"]),
+        drupal_render($element["scope-$i"]),
+        //drupal_render($element["mode-$i"]) .
+        drupal_render($element["search_terms-$i"]),
+        array(
+          'data' => drupal_render($element["add-$i"]) . drupal_render($element["remove-$i"]),
+          'nowrap' => 'nowrap', 
+        ),
+      );
+    }
+  }
+
+  // add in the from_year and to_year elements as the final row of the table
+  $rows[] = array(
+    '&nbsp;',
+    drupal_render($form['date']),
+    array(
+      'data' =>
+        "<div id=\"pub-search-form-dates-row\">
+           <div id=\"pub-search-form-dates\"> ".
+             drupal_render($form['from_year']) .
+             drupal_render($form['to_year']) . "
+           </div>
+         </div>
+        ",
+    ),
+    ''
+  );
+  
+  $headers = array();  
+  $table = array(
+    'header' => $headers,
+    'rows' => $rows,
+    'attributes' => array('id' => 'tripal-pub-search-form-table', 'border' => '0'),
+    'sticky' => TRUE,
+    'caption' => '',
+    'colgroups' => array(),
+    'empty' => '',
+  );
+  $results  = '<div id="tripal-pub-search-form-criteria">';
+  $results .= theme_table($table);
+  $results .= '</div>';
+  return $results;
+}

Some files were not shown because too many files changed in this diff