chado_linker__prop_adder.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. class chado_linker__prop_adder extends TripalField {
  3. // The default lable for this field.
  4. public static $default_label = 'Add a Property Type';
  5. // The default description for this field.
  6. public static $default_description = 'This record may have any number of properties. Use
  7. this field to first add the type.';
  8. // Add any default settings elements. If you override the globalSettingsForm()
  9. // or the instanceSettingsForm() functions then you need to be sure that
  10. // any settings you want those functions to manage are listed in this
  11. // array.
  12. public static $default_settings = array(
  13. 'chado_table' => '',
  14. 'chado_column' => '',
  15. 'base_table' => '',
  16. 'semantic_web' => '',
  17. );
  18. // Set this to the name of the storage backend that by default will support
  19. // this field.
  20. public static $default_storage = 'field_chado_storage';
  21. /**
  22. * @see TripalField::formatterView()
  23. */
  24. public function formatterView(&$element, $entity_type, $entity, $langcode, $items, $display) {
  25. // This field should never be viewed. It's to help add new properties
  26. // when editing an entity. So return nothing.
  27. return '';
  28. }
  29. /**
  30. * @see TripalField::widgetForm()
  31. */
  32. public function widgetForm(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
  33. parent::widgetForm($widget, $form, $form_state, $langcode, $items, $delta, $element);
  34. $field_name = $widget['#field_name'];
  35. $widget['#type'] = 'fieldset';
  36. $widget['#title'] = $element['#title'];
  37. $widget['#description'] = $element['#description'];
  38. $widget['#group'] = 'entity_form_vtabs';
  39. $widget['kvproperty_instructions'] = array(
  40. '#type' => 'item',
  41. '#markup' => t('You may add additional properties to this form by
  42. providing a property name (from a vocabulary) in the field below
  43. and clicking the "Lookup Term" button. Terms that match the value
  44. entered will be displayed for selection. After selecting the
  45. appropriate term click the "Use this term" button and a
  46. new field will be added to the form above for the property you selected.
  47. In the future, this field will be present for all records
  48. of this type.'),
  49. );
  50. $term_name = array_key_exists('values', $form_state) ? $form_state['values'][$field_name]['und'][0]['wrapper']['term_name'] : '';
  51. // Drupal's vertical feild set is a bit quirky in that we can't just
  52. // add a prefix and suffix to the weidget. If we do, then the
  53. // field doesn't show up on the page after an AJAX call. We have to add
  54. // an internal wrapper (below) for AJAX calls.
  55. $widget['wrapper'] = array(
  56. '#prefix' => "<span id='$field_name-lookup-form'>",
  57. '#suffix' => '</span>',
  58. );
  59. // If no term has been selected yet then provide the auto complete field.
  60. $widget['wrapper']['term_name'] = array(
  61. '#title' => t('Term'),
  62. '#type' => 'textfield',
  63. '#description' => t("The content type must be the name of a term in
  64. a controlled vocabulary and the controlled vocabulary should
  65. already be loaded into Tripal. For example, to create a content
  66. type for storing 'genes', use the 'gene' term from the
  67. Sequence Ontology (SO)."),
  68. '#default_value' => $term_name,
  69. '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/cvterm/",
  70. );
  71. $widget['wrapper']['select_button'] = array(
  72. '#type' => 'button',
  73. '#value' => t('Lookup Term'),
  74. '#name' => 'select_cvterm',
  75. '#ajax' => array(
  76. 'callback' => "tripal_chado_prop_adder_form_ajax_callback",
  77. 'wrapper' => "$field_name-lookup-form",
  78. 'effect' => 'fade',
  79. 'method' => 'replace'
  80. ),
  81. );
  82. if ($term_name) {
  83. $widget['wrapper']['terms_list'] = array(
  84. '#type' => 'fieldset',
  85. '#title' => t('Matching Terms'),
  86. '#description' => t('Please select the term the best matches the
  87. content type you want to create. If the same term exists in
  88. multiple vocabularies you will see more than one option below.')
  89. );
  90. $match = array(
  91. 'name' => $term_name,
  92. );
  93. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  94. $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
  95. $num_terms = 0;
  96. foreach ($terms as $term) {
  97. // Save the user a click by setting the default value as 1 if there's
  98. // only one matching term.
  99. $default = FALSE;
  100. $attrs = array();
  101. if ($num_terms == 0 and count($terms) == 1) {
  102. $default = TRUE;
  103. $attrs = array('checked' => 'checked');
  104. }
  105. $widget['wrapper']['terms_list']['term-' . $term->cvterm_id] = array(
  106. '#type' => 'checkbox',
  107. '#title' => $term->name,
  108. '#default_value' => $default,
  109. '#attributes' => $attrs,
  110. '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name . ' (' . $term->dbxref_id->db_id->name . ') ' . $term->cv_id->definition .
  111. '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '. ' .
  112. '<br><b>Definition:</b> ' . $term->definition,
  113. );
  114. $num_terms++;
  115. }
  116. if ($num_terms == 0) {
  117. $widget['wrapper']['terms_list']['none'] = array(
  118. '#type' => 'item',
  119. '#markup' => '<i>' . t('There is no term that matches the entered text.') . '</i>'
  120. );
  121. }
  122. else {
  123. $widget['wrapper']['cardinality'] = array(
  124. '#title' => t('Number of Values'),
  125. '#type' => 'textfield',
  126. '#description' => t("The number of values allowed for this property. 0 for unlimited values"),
  127. '#size' => 10,
  128. '#default_value' => 1,
  129. );
  130. // Add in the button for the cases of no terms or too many.
  131. $widget['wrapper']['submit_button'] = array(
  132. '#type' => 'submit',
  133. '#value' => t('Use this term'),
  134. '#name' => 'use_term_button',
  135. );
  136. }
  137. }
  138. }
  139. /**
  140. * @see TripalField::widgetFormValidate()
  141. */
  142. public function widgetFormValidate($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
  143. $field = $this->field;
  144. $field_name = $field['field_name'];
  145. // If the user has clicked the 'user_term_button' then we need to makes
  146. // sure that the cardinality textbox contains a positive integer.
  147. if ($form_state['triggering_element']['#name'] == 'use_term_button') {
  148. $cardinality = $form_state['values'][$field_name][$langcode][$delta]['wrapper']['cardinality'];
  149. if (!preg_match('/^\d+$/', $cardinality) or $cardinality < 0) {
  150. form_set_error("$field_name][$langcode][$delta][wrapper][cardinality", "Please provide positive number for the number of values.");
  151. }
  152. }
  153. }
  154. /**
  155. * @see TripalField::widgetFormValidate
  156. */
  157. public function validate($entity_type, $entity, $field, $items, &$errors) {
  158. // Nothing to validate.
  159. }
  160. /**
  161. * @see TripalField::widgetFormSubmit()
  162. */
  163. public function widgetFormSubmit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
  164. return;
  165. // We will never have more than one item for this field at a time, so
  166. // delta is always zero.
  167. $delta = 0;
  168. // Add the new field to the entity but only if the property adder button
  169. // was clicked
  170. if (!array_key_exists('triggering_element', $form_state) or
  171. $form_state['triggering_element']['#name'] != 'kvproperty_adder_button') {
  172. return;
  173. }
  174. // Because we're going to add a new property we want to rebuild the form
  175. // rather than have it fully submit.
  176. $form_state['rebuild'] = TRUE;
  177. // Get the table and base table.
  178. $base_table = $this->field['settings']['base_table'];
  179. // Get the term for the property
  180. $kvproperty = tripal_get_field_item_keyval($items, $delta, 'value', '');
  181. $cvterm = chado_generate_var('cvterm', array('name' => $kvproperty));
  182. // Generate the name for the property table and the field name that we'll
  183. // be creating.
  184. $prop_table = $base_table . 'prop';
  185. $field_name = $prop_table . '__' . $cvterm->cvterm_id;
  186. // The field name is the table name in this case. We want to get the
  187. // primary key as this should be the field that maps th the value.
  188. $schema = chado_get_schema($prop_table);
  189. $pkey = $schema['primary key'][0];
  190. // Add the field if it doesn't already exists.
  191. $field = field_info_field($field_name);
  192. if (!$field) {
  193. $field = field_create_field(array(
  194. 'field_name' => $field_name,
  195. 'type' => 'chado_linker__prop',
  196. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  197. 'locked' => FALSE,
  198. 'storage' => array(
  199. 'type' => 'field_chado_storage',
  200. ),
  201. 'settings' => array(
  202. 'chado_table' => $prop_table,
  203. 'chado_column' => $pkey,
  204. 'base_table' => $base_table,
  205. 'semantic_web' => $cvterm->dbxref_id->db_id->name . ':' . $cvterm->dbxref_id->accession,
  206. ),
  207. ));
  208. }
  209. // Create an instance of the field.
  210. $instance = field_info_instance($entity_type, $field_name, $entity->bundle);
  211. if (!$instance) {
  212. $instance = field_create_instance(array(
  213. 'field_name' => $field_name,
  214. 'entity_type' => 'TripalEntity',
  215. 'bundle' => $entity->bundle,
  216. 'label' => ucfirst(preg_replace('/_/', ' ', $cvterm->name)),
  217. 'description' => $cvterm->definition ? $cvterm->definition : '',
  218. 'required' => FALSE,
  219. 'settings' => array(),
  220. 'widget' => array(
  221. 'type' => $field_name . '_widget',
  222. 'settings' => array(
  223. 'display_label' => 1,
  224. ),
  225. ),
  226. 'display' => array(
  227. 'default' => array(
  228. 'label' => 'inline',
  229. 'type' => $field_name . '_formatter',
  230. 'settings' => array(),
  231. ),
  232. ),
  233. ));
  234. }
  235. }
  236. }
  237. /**
  238. *
  239. */
  240. function tripal_chado_prop_adder_form_ajax_callback($form, $form_state) {
  241. $field_name = $form_state['triggering_element']['#parents'][0];
  242. // Because this field is inside a vertical fieldset we can't just
  243. // return $form[$field_name]. We have set the AJAX call to replace
  244. // everything inside of the 'wrapper' element, so we must return that.
  245. return $form[$field_name]['und'][0]['wrapper'];
  246. }