tripal.terms.api.inc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) for working with
  5. * controlled vocaublary terms.
  6. */
  7. /**
  8. * @defgroup tripal_terms_api CV Terms
  9. * @ingroup tripal_api
  10. * @{
  11. * Tripal provides an application programming interface (API) for working with
  12. * controlled vocaublary terms. Tripal v3 is highly dependent on controlled
  13. * vocabularies for identifying all content types and fields attached to those
  14. * content types. However, Tripal v3 is also database agnostic. Therefore,
  15. * controlled vocabularies can be stored in any database back-end. By default
  16. * the tripal_chado module is used for storing controlled vocabularies. However,
  17. * if someone wanted to store controlled vocabularies in a database other than
  18. * Chado they can do so. These API functions provide a convenient wrapper for
  19. * accession controlled vocabularies no matter where they are stored.
  20. *
  21. * @}
  22. */
  23. /**
  24. * @section
  25. * Vocabulary Hooks.
  26. */
  27. /**
  28. * A hook for specifying information about the data store for vocabularies.
  29. *
  30. * The storage backend for controlled vocabularies has traditionally been
  31. * the Chado CV term tables. However, Tripal v3.0 introduces APIs for supporting
  32. * other backends. Therefore, this function indicates to Tripal which
  33. * data stores are capable of providing support for terms.
  34. *
  35. * @return
  36. * An array describing the storage backends implemented by the module. The
  37. * keys are storage backend names. To avoid name clashes, storage
  38. * backend names should be prefixed with the name of the module that
  39. * exposes them. The values are arrays describing the storage backend,
  40. * with the following key/value pairs:
  41. *
  42. * label: The human-readable name of the storage backend.
  43. * module: The name of the module providing the support for this backend.
  44. * description: A short description for the storage backend.
  45. * settings: An array whose keys are the names of the settings available for
  46. * the storage backend, and whose values are the default values for
  47. * those settings.
  48. *
  49. * @ingroup tripal_terms_api
  50. */
  51. function hook_vocab_storage_info() {
  52. return array(
  53. 'term_chado_storage' => array(
  54. 'label' => t('Chado'),
  55. 'description' => t('Integrates terms stored in the local Chado database with Tripal entities.'),
  56. 'settings' => array(),
  57. ),
  58. );
  59. }
  60. /**
  61. * Creates a form for specifying a term for TripalEntity creation.
  62. *
  63. * This hook allows the module that implements a vocabulary storage backend
  64. * to provide the form necessary to select a term that will then be used for
  65. * creating a new TripalEntity type. Tripal will expect that a 'vocabulary' and
  66. * 'accession' are in the $form_state['storage'] array. The 'vocabulary' and
  67. * must be the abbreviated uppercase vocabulary for the vocabulary (e.g. 'RO',
  68. * 'SO', 'PATO', etc.). The 'accession' must be the unique term ID (or
  69. * accession) for the term in the vocabulary.
  70. *
  71. * @param $form
  72. * @param $form_state
  73. *
  74. * @return
  75. * A form object.
  76. *
  77. * @ingroup tripal_terms_api
  78. */
  79. function hook_vocab_select_term_form(&$form, &$form_state) {
  80. return $form;
  81. }
  82. /**
  83. * Validates the hook_vocab_select_term_form().
  84. *
  85. * @param $form
  86. * @param $form_state
  87. *
  88. * @ingroup tripal_terms_api
  89. */
  90. function hook_vocab_select_term_form_validate($form, &$form_state) {
  91. }
  92. /**
  93. * Provides a form for importing vocabularies and their terms.
  94. *
  95. * Tripal allows for vocabularies to be stored separately from the biological
  96. * data. This hook allows the default term storage backend to provide an
  97. * approprite form for importing ontologies (either in OBO or OWL format).
  98. *
  99. * @param $form
  100. * @param $form_state
  101. *
  102. * @ingroup tripal_terms_api
  103. *
  104. */
  105. function hook_vocab_import_form($form, &$form_state) {
  106. return $form;
  107. }
  108. /**
  109. * Validates the hook_vocab_import_form().
  110. *
  111. * @param $form
  112. * @param $form_state
  113. *
  114. * @ingroup tripal_terms_api
  115. */
  116. function hook_vocab_import_form_validate($form, &$form_state) {
  117. }
  118. /**
  119. * Submits the hook_vocab_import_form().
  120. *
  121. * @param $form
  122. * @param $form_state
  123. *
  124. * @ingroup tripal_terms_api
  125. */
  126. function hook_vocab_import_form_submit($form, &$form_state) {
  127. }
  128. /**
  129. * Hook used by the default term storage backend to provide details for a term.
  130. *
  131. * This hook is called by the tripal_entity module to retrieve information
  132. * about the term from the storage backend. It must return an array with
  133. * a set of keys.
  134. *
  135. * @param $vocabulary
  136. * The vocabulary of the vocabulary in which the term is found.
  137. * @param $accession
  138. * The unique identifier (accession) for this term.
  139. *
  140. * @return
  141. * An array with at least the following keys:
  142. * -vocabulary : An associative array with the following keys:
  143. * -name: The short name for the vocabulary (e.g. SO, PATO, etc).
  144. * -description: The description of this vocabulary.
  145. * -url: The URL for the vocabulary.
  146. * -urlprefix : (optional) A URL to which the short_name and term
  147. * accession can be appended to form a complete URL for a term. If the
  148. * prefix does not support appending then the exact location for the
  149. * position of the short_name and the term accession will be
  150. * specified with the {db} and {accession} tags respectively.
  151. * -accession : The name unique ID of the term.
  152. * -url : The URL for the term.
  153. * -name : The name of the term.
  154. * -definition : The term's description.
  155. * any other keys may be added as desired. Returns NULL if the term
  156. * cannot be found.
  157. *
  158. * @ingroup tripal_terms_api
  159. */
  160. function hook_vocab_get_term($vocabulary, $accession) {
  161. // See the tripal_chado_vocab_get_term() function for an example.
  162. }
  163. /**
  164. * Retrieves a paged list of terms from a vocabulary.
  165. *
  166. * @param $vocabulary
  167. * The short name of the vocabulary.
  168. * @param $limit
  169. * The number of results to return.
  170. * @param $element
  171. * The pager element. This is equivalent to the element from the
  172. * pager_default_initialize() function of Drupal.
  173. *
  174. * @ingroup tripal_terms_api
  175. */
  176. function hook_vocab_get_terms($vocabulary, $limit = 25, $element = 0) {
  177. // See the tripal_chado_vocab_get_terms() function for an example.
  178. }
  179. /**
  180. * Hook used by the default term storage backend to provide children for a term.
  181. *
  182. * This hook is called by the tripal_entity module to retrieve a list of
  183. * children for a term from the storage backend. It must return an array
  184. * of terms where each term contains the same structure as that of the
  185. * hook_vocab_get_term().
  186. *
  187. * @param $vocabulary
  188. * The vocabulary of the vocabulary in which the term is found.
  189. * @param $accession
  190. * The unique identifier (accession) for this term.
  191. *
  192. * @return
  193. * An array of terms where each term contains the same structure as that of
  194. * the hook_vocab_get_term(), or an empty array if no children are present.
  195. *
  196. * @ingroup tripal_terms_api
  197. */
  198. function hook_vocab_get_term_children($vocabulary, $accession) {
  199. // See the tripal_chado_vocab_get_term_children() function for an example.
  200. }
  201. /**
  202. * Hook used by the default term storage backend to provide root terms.
  203. *
  204. * This hook is called by the tripal_entity module to retrieve a list of
  205. * root terms for a given vocabulary from the storage backend. It must return
  206. * an array of terms where each term contains the same structure as that of the
  207. * hook_vocab_get_term().
  208. *
  209. * @param $vocabulary
  210. * The vocabulary of the vocabulary in which the term is found.
  211. *
  212. * @return
  213. * An array of root terms where each term contains the same structure as that
  214. * of the hook_vocab_get_term(), or an empty array if no children are present.
  215. *
  216. * @ingroup tripal_terms_api
  217. */
  218. function hook_vocab_get_root_terms($vocabulary) {
  219. // See the tripal_chado_vocab_get_root_terms() function for an example.
  220. }
  221. /**
  222. * Hook used by the default term storage backend to provide details for a vocab.
  223. *
  224. * This hook is called by the tripal_entity module to retrieve information
  225. * about the vocabulary from the storage backend. It must return an array with
  226. * a set of keys.
  227. *
  228. * @param $vocabulary
  229. * The vocabulary of the vocabulary in which the term is found.
  230. *
  231. * @return
  232. * An array with at least the following keys:
  233. * - name : The full name of the vocabulary.
  234. * - short_name : The short name abbreviation for the vocabulary.
  235. * - description : A brief description of the vocabulary.
  236. * - url : (optional) A URL for the online resources for the vocabulary.
  237. * - urlprefix : (optional) A URL to which the short_name and term
  238. * accession can be appended to form a complete URL for a term. If the
  239. * prefix does not support appending then the exact location for the
  240. * position of the short_name and the term accession will be
  241. * specified with the {db} and {accession} tags respectively.
  242. *
  243. * @ingroup tripal_terms_api
  244. */
  245. function hook_vocab_get_vocabulary($vocabulary) {
  246. // See the tripal_chado_vocab_get_vocabulary() function for an example.
  247. }
  248. /**
  249. * Retrieves the list of vocabularies that are available on the site.
  250. *
  251. * @return
  252. * An array of vocabularies where each entry in the array is compatible
  253. * with the array returned by the tripal_get_vocabulary_details()
  254. * function.
  255. *
  256. * @ingroup tripal_terms_api
  257. */
  258. function hook_vocab_get_vocabularies() {
  259. // See the tripal_chado_vocab_get_vocabularies() function for an example.
  260. }
  261. /**
  262. * Hook used by the default term storage backend to add new terms.
  263. *
  264. * @param $details
  265. * An array with at least the following keys:
  266. * -vocabulary : An associative array with the following keys:
  267. * -name: The short name for the vocabulary (e.g. SO, PATO, etc).
  268. * -description: The description of this vocabulary.
  269. * -url: The URL for the vocabulary.
  270. * -urlprefix: (optional) A URL to which the short_name and term
  271. * accession can be appended to form a complete URL for a term. If the
  272. * prefix does not support appending then the exact location for the
  273. * position of the short_name and the term accession will be
  274. * specified with the {db} and {accession} tags respectively.
  275. * -accession : The name unique ID of the term.
  276. * -url : The URL for the term.
  277. * -name : The name of the term.
  278. * -definition : The term's description.
  279. * @return
  280. * TRUE if the term was added, FALSE otherwise. If the term already exists
  281. * it will be updated and the return value will be TRUE.
  282. *
  283. * @ingroup tripal_terms_api
  284. */
  285. function hook_vocab_add_term($details) {
  286. // See the tripal_chado_vocab_set_term() function for an example.
  287. }
  288. /**
  289. * Adds a term to the vocabulary storage backend.
  290. *
  291. * Use this function to add new terms dynamically to the vocabulary storage
  292. * backend. If the term already exists no new term is added.
  293. *
  294. * @param $details
  295. * An array with at least the following keys:
  296. * -vocabulary : An associative array with the following keys
  297. * -name: The short name for the vocabulary (e.g. SO, PATO, etc).
  298. * -description: The description of this vocabulary.
  299. * -url: The URL for the vocabulary.
  300. * -accession : The name unique ID of the term.
  301. * -url : The URL for the term.
  302. * -name : The name of the term.
  303. * -definition : The term's description.
  304. * @return
  305. * TRUE if the term was added, FALSE otherwise. If the term already exists
  306. * it will be updated and the return value will be TRUE.
  307. *
  308. * @ingroup tripal_terms_api
  309. */
  310. function tripal_add_term($details) {
  311. // TODO: we need some sort of administrative interface that lets the user
  312. // switch to the desired vocabulary type. For now, we'll just use the
  313. // first one in the list.
  314. $stores = module_invoke_all('vocab_storage_info');
  315. if (is_array($stores) and count($stores) > 0) {
  316. $keys = array_keys($stores);
  317. $module = $stores[$keys[0]]['module'];
  318. $function = $module . '_vocab_add_term';
  319. if (function_exists($function)) {
  320. return $function($details);
  321. }
  322. }
  323. }
  324. /**
  325. * Retrieves full information about a vocabulary term.
  326. *
  327. * @param $vocabulary
  328. * The vocabulary of the vocabulary in which the term is found.
  329. * @param $accession
  330. * The unique identifier (accession) for this term.
  331. *
  332. * @return
  333. * An array with at least the following keys:
  334. * - vocabulary : An array containing the following keys:
  335. * - name : The full name of the vocabulary.
  336. * - short_name : The short name abbreviation for the vocabulary.
  337. * - description : A brief description of the vocabulary.
  338. * - url : (optional) A URL for the online resources for the vocabulary.
  339. * - urlprefix : (optional) A URL to which the short_name and term
  340. * accession can be appended to form a complete URL for a term. If the
  341. * prefix does not support appending then the exact location for the
  342. * position of the short_name and the term accession will be
  343. * specified with the {db} and {accession} tags respectively.
  344. * - accession : The name unique ID of the term.
  345. * - url : The URL for the term.
  346. * - name : The name of the term.
  347. * - definition : The term's description.
  348. * any other keys may be added as desired. Returns NULL if the term
  349. * cannot be found.
  350. *
  351. * @ingroup tripal_terms_api
  352. */
  353. function tripal_get_term_details($vocabulary, $accession) {
  354. if (empty($vocabulary) OR empty($accession)) {
  355. tripal_report_error('tripal_term', TRIPAL_ERROR, "Unable to retrieve details for term due to missing vocabulary and/or accession");
  356. }
  357. // TODO: we need some sort of administrative interface that lets the user
  358. // switch to the desired vocabulary type. For now, we'll just use the
  359. // first one in the list.
  360. $stores = module_invoke_all('vocab_storage_info');
  361. if (is_array($stores) and count($stores) > 0) {
  362. $keys = array_keys($stores);
  363. $module = $stores[$keys[0]]['module'];
  364. $function = $module . '_vocab_get_term';
  365. if (function_exists($function)) {
  366. $term = $function($vocabulary, $accession);
  367. // Make sure the term has a URL. If it does not, then use the Tripal
  368. // interface as the URL for the term.
  369. $url_missing = FALSE;
  370. if (!$term['url']) {
  371. $url_missing = TRUE;
  372. $term['url'] = url('cv/lookup/' . $term['vocabulary']['short_name'] . '/' . $term['accession'], ['absolute' => TRUE]);
  373. }
  374. if (!$term['vocabulary']['sw_url']) {
  375. $url_missing = TRUE;
  376. $term['vocabulary']['sw_url'] = url('cv/lookup/' . $term['vocabulary']['short_name'] . '/' . $term['accession'], ['absolute' => TRUE]);
  377. }
  378. // Let the user know that the vocabulary is missing.
  379. if ($url_missing) {
  380. tripal_add_notification(
  381. "Missing CV term URL",
  382. t("The controlled vocabulary, %vocab, is missing a URL. Tripal will handle " .
  383. "this by linking to the cv/lookup page of this site. However, the correct " .
  384. "should be updated for this site",
  385. ['%vocab' => $term['vocabulary']['short_name']]),
  386. 'Controlled Vocabularies',
  387. NULL,
  388. 'mising-vocab-' . $term['vocabulary']['short_name']
  389. );
  390. }
  391. return $term;
  392. }
  393. }
  394. }
  395. /**
  396. * Retrieves the immediate children of the given term.
  397. *
  398. * @param $vocabulary
  399. * The vocabulary of the vocabulary in which the term is found.
  400. * @param $accession
  401. * The unique identifier (accession) for this term.
  402. *
  403. * @return
  404. * Returns an array of terms where each term is compatible with the
  405. * array returned by the tripal_get_term_details() function.
  406. *
  407. * @ingroup tripal_terms_api
  408. */
  409. function tripal_get_vocabulary_root_terms($vocabulary) {
  410. if (empty($vocabulary)) {
  411. tripal_report_error('tripal_term', TRIPAL_ERROR, 'Unable to retrieve details for term due to missing vocabulary.');
  412. }
  413. // TODO: we need some sort of administrative interface that lets the user
  414. // switch to the desired vocabulary type. For now, we'll just use the
  415. // first one in the list.
  416. $stores = module_invoke_all('vocab_storage_info');
  417. if (is_array($stores) and count($stores) > 0) {
  418. $keys = array_keys($stores);
  419. $module = $stores[$keys[0]]['module'];
  420. $function = $module . '_vocab_get_root_terms';
  421. if (function_exists($function)) {
  422. return $function($vocabulary);
  423. }
  424. }
  425. }
  426. /**
  427. * Retrieves the immediate children of the given term.
  428. *
  429. * @param $vocabulary
  430. * The vocabulary of the vocabulary in which the term is found.
  431. * @param $accession
  432. * The unique identifier (accession) for this term.
  433. *
  434. * @return
  435. * Returns an array of terms where each term is compatible with the
  436. * array returned by the tripal_get_term_details() function.
  437. *
  438. * @ingroup tripal_terms_api
  439. */
  440. function tripal_get_term_children($vocabulary, $accession) {
  441. if (empty($vocabulary) OR empty($accession)) {
  442. tripal_report_error('tripal_term', TRIPAL_ERROR, 'Unable to retrieve details for term due to missing vocabulary and/or accession.');
  443. }
  444. $stores = module_invoke_all('vocab_storage_info');
  445. if (is_array($stores) and count($stores) > 0) {
  446. $keys = array_keys($stores);
  447. $module = $stores[$keys[0]]['module'];
  448. $function = $module . '_vocab_get_term_children';
  449. if (function_exists($function)) {
  450. return $function($vocabulary, $accession);
  451. }
  452. }
  453. }
  454. /**
  455. * Retrieves full information about a vocabulary.
  456. *
  457. * Vocabularies are stored in a database backend. Tripal has no requirements
  458. * for how terms are stored. By default, the tripal_chado modules provides
  459. * storage for vocabularies and terms. This function will call the
  460. * hook_vocab_get_term() function for the database backend that is housing the
  461. * vocabularies and allow it to return the details about the term.
  462. *
  463. * @param $vocabulary
  464. * The vocabulary of the vocabulary in which the term is found.
  465. *
  466. * @return
  467. * An array with at least the following keys:
  468. * - name: The full name of the vocabulary.
  469. * - short_name: The short name abbreviation for the vocabulary.
  470. * - description: A brief description of the vocabulary.
  471. * - url: A URL for the online resources for the vocabulary.
  472. * - urlprefix: A URL to which the short_name and term
  473. * accession can be appended to form a complete URL for a term. If the
  474. * prefix does not support appending then the exact location for the
  475. * position of the short_name and the term accession will be
  476. * specified with the {db} and {accession} tags respectively.
  477. * - sw_url: The URL for mapping terms via the semantic web.
  478. * - num_terms: The number of terms loaded in the vocabulary.
  479. *
  480. * @ingroup tripal_terms_api
  481. */
  482. function tripal_get_vocabulary_details($vocabulary) {
  483. // TODO: we need some sort of administrative interface that lets the user
  484. // switch to the desired vocabulary type. For now, we'll just use the
  485. // first one in the list.
  486. $stores = module_invoke_all('vocab_storage_info');
  487. if (is_array($stores) and count($stores) > 0) {
  488. $keys = array_keys($stores);
  489. $module = $stores[$keys[0]]['module'];
  490. $function = $module . '_vocab_get_vocabulary';
  491. if (function_exists($function)) {
  492. return $function($vocabulary);
  493. }
  494. }
  495. }
  496. /**
  497. * Retrieves a paged list of terms from a vocabulary.
  498. *
  499. * @param $vocabulary
  500. * The short name of the vocabulary.
  501. * @param $limit
  502. * The number of results to return.
  503. * @param $element
  504. * The pager element. This is equivalent to the element from the
  505. * pager_default_initialize() function of Drupal.
  506. *
  507. * @ingroup tripal_terms_api
  508. */
  509. function tripal_get_vocabulary_terms($vocabulary, $limit = 25, $element = 0) {
  510. $stores = module_invoke_all('vocab_storage_info');
  511. if (is_array($stores) and count($stores) > 0) {
  512. $keys = array_keys($stores);
  513. $module = $stores[$keys[0]]['module'];
  514. $function = $module . '_vocab_get_terms';
  515. if (function_exists($function)) {
  516. return $function($vocabulary, $limit, $element);
  517. }
  518. }
  519. }
  520. /**
  521. * Retrieves the list of vocabularies that are available on the site.
  522. *
  523. * @return
  524. * An array of vocabularies where each entry in the array is compatible
  525. * with the array returned by the tripal_get_vocabulary_details()
  526. * function.
  527. *
  528. * @ingroup tripal_terms_api
  529. */
  530. function tripal_get_vocabularies() {
  531. $stores = module_invoke_all('vocab_storage_info');
  532. if (is_array($stores) and count($stores) > 0) {
  533. $keys = array_keys($stores);
  534. $module = $stores[$keys[0]]['module'];
  535. $function = $module . '_vocab_get_vocabularies';
  536. if (function_exists($function)) {
  537. return $function();
  538. }
  539. }
  540. }
  541. /**
  542. * Provides a term lookup form.
  543. *
  544. * It may be necessary at times for a form to provide to the user the ability
  545. * to lookup and use a controlled vocabulary term. However, a simple text box
  546. * or auto-lookup is not sufficient because a term name may be identical in
  547. * multiple vocabularies and the user would need to select the proper term.
  548. *
  549. * This function will add the form elements necessary to provide a lookup form.
  550. * The form elements should work with a flat form (no #tree set for the form)
  551. * or with a form in a TripalField.
  552. *
  553. * Use the tripal_get_term_lookup_form_result() function to retreive the
  554. * result in a form submit or validate.
  555. *
  556. * @param $form
  557. * The form (or $widget form).
  558. * @param $form_state
  559. * The form state.
  560. * @param $title
  561. * The title to give to the field set.
  562. * @param $description
  563. * A description for the lookup field element.
  564. * @param $is_required
  565. * Indicates if this form element is required.
  566. * @param $field_name
  567. * The name of the field, if this form is being added to a field widget.
  568. * @param $delta
  569. * The delta value for the field if this form is being added to a field
  570. * widget.
  571. *
  572. * @ingroup tripal_terms_api
  573. */
  574. function tripal_get_term_lookup_form(&$form, &$form_state, $default_name = '',
  575. $title = 'Vocabulary Term', $description = '', $is_required,
  576. $field_name = '', $delta = 0 ) {
  577. $ajax_wrapper_id = 'tripal-vocab-select-form-' . $delta;
  578. if ($field_name) {
  579. $ajax_wrapper_id = $field_name . '-' . $delta;
  580. }
  581. $term_name = $default_name;
  582. if (array_key_exists('values', $form_state)) {
  583. $term_name = $form_state['values']['term_name'];
  584. }
  585. if ($field_name and array_key_exists('input', $form_state) and array_key_exists($field_name, $form_state['input'])) {
  586. $term_name = $form_state['input'][$field_name]['und'][$delta]['term_match']['term_name'];
  587. }
  588. if (!$description) {
  589. $description = t('Enter the name of the term that specifies the type. ' .
  590. 'The type must be the name of a term in a controlled vocabulary and ' .
  591. 'the controlled vocabulary should already be loaded into this site.');
  592. }
  593. $form_state['storage'][$ajax_wrapper_id]['term_match_field'] = $field_name;
  594. $form_state['storage'][$ajax_wrapper_id]['term_match_delta'] = $delta;
  595. $form['term_match'] = array(
  596. '#type' => 'fieldset',
  597. '#collapsible' => FALSE,
  598. '#collapsed' => FALSE,
  599. '#title' => t($title),
  600. '#prefix' => '<div id = "' . $ajax_wrapper_id . '">',
  601. '#suffix' => '</div>',
  602. );
  603. $form['term_match']['term_name'] = array(
  604. '#title' => t('Type'),
  605. '#type' => 'textfield',
  606. '#description' => $description,
  607. '#required' => $is_required,
  608. '#default_value' => $term_name,
  609. '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/cvterm/",
  610. );
  611. $form['term_match']['select_button'] = array(
  612. '#type' => 'button',
  613. '#value' => t('Lookup Term'),
  614. '#name' => 'select_cvterm_' . $ajax_wrapper_id,
  615. '#validate' => array(),
  616. '#limit_validation_errors' => array(),
  617. '#ajax' => array(
  618. 'callback' => "tripal_get_term_lookup_form_ajax_callback",
  619. 'wrapper' => $ajax_wrapper_id,
  620. 'effect' => 'fade',
  621. 'method' => 'replace'
  622. ),
  623. );
  624. // If the term has been provided by the user then we want to search for
  625. // matching terms in the database and let them select among any matches.
  626. if ($term_name) {
  627. $submit_disabled = TRUE;
  628. $form['term_match']['terms_list'] = array(
  629. '#type' => 'fieldset',
  630. '#title' => t('Matching Terms'),
  631. '#description' => t('Please select the term the best matches the
  632. content type you want to create. If the same term exists in
  633. multiple vocabularies you will see more than one option below.')
  634. );
  635. $match = array(
  636. 'name' => $term_name,
  637. );
  638. // TODO: this should not call the chado functions because we're in the
  639. // tripal module.
  640. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  641. $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
  642. $num_terms = 0;
  643. $selected_term = '';
  644. // Let the user select from any matching terms. Sometimes there may be
  645. // more than one that match.
  646. foreach ($terms as $term) {
  647. // Save the user a click by setting the default value as 1 if there's
  648. // only one matching term.
  649. $default = FALSE;
  650. $attrs = array();
  651. if ($num_terms == 0 and count($terms) == 1) {
  652. $default = TRUE;
  653. $attrs = array('checked' => 'checked');
  654. }
  655. $term_element_name = 'term-' . $term->cvterm_id;
  656. $form['term_match']['terms_list'][$term_element_name] = array(
  657. '#type' => 'checkbox',
  658. '#title' => $term->name,
  659. '#default_value' => $default,
  660. '#attributes' => $attrs,
  661. '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name . ' (' . $term->dbxref_id->db_id->name . ') ' . $term->cv_id->definition .
  662. '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '. ' .
  663. '<br><b>Definition:</b> ' . $term->definition,
  664. '#ajax' => array(
  665. 'callback' => "tripal_get_term_lookup_form_ajax_callback",
  666. 'wrapper' => $ajax_wrapper_id,
  667. 'effect' => 'fade',
  668. 'method' => 'replace'
  669. ),
  670. );
  671. if (array_key_exists('values', $form_state) and array_key_exists($term_element_name, $form_state['values']) and
  672. $form_state['values'][$term_element_name] == 1) {
  673. $selected_term = $term;
  674. }
  675. $num_terms++;
  676. }
  677. // Next find terms that are synonyms
  678. $match = array(
  679. 'synonym' => $term_name,
  680. );
  681. $termsyn = chado_generate_var('cvtermsynonym', $match, array('return_array' => TRUE));
  682. // Let the user select from any matching terms. Sometimes there may be
  683. // more than one that match.
  684. foreach ($termsyn as $synonym) {
  685. $term = $synonym->cvterm_id;
  686. // Save the user a click by setting the default value as 1 if there's
  687. // only one matching term.
  688. $default = FALSE;
  689. $attrs = array();
  690. if ($num_terms == 0 and count($terms) == 1) {
  691. $default = TRUE;
  692. $attrs = array('checked' => 'checked');
  693. }
  694. $term_element_name = 'term-' . $term->cvterm_id;
  695. $form['term_match']['terms_list'][$term_element_name] = array(
  696. '#type' => 'checkbox',
  697. '#title' => $term->name,
  698. '#default_value' => $default,
  699. '#attributes' => $attrs,
  700. '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name . ' (' . $term->dbxref_id->db_id->name . ') ' . $term->cv_id->definition .
  701. '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '. ' .
  702. '<br><b>Definition:</b> ' . $term->definition .
  703. '<br><b>Synonym:</b> ' . $synonym->synonym,
  704. '#ajax' => array(
  705. 'callback' => "tripal_get_term_lookup_form_ajax_callback",
  706. 'wrapper' => $ajax_wrapper_id,
  707. 'effect' => 'fade',
  708. 'method' => 'replace'
  709. ),
  710. );
  711. if (array_key_exists('values', $form_state) and array_key_exists($term_element_name, $form_state['values']) and
  712. $form_state['values'][$term_element_name] == 1) {
  713. $selected_term = $term;
  714. }
  715. $num_terms++;
  716. }
  717. if ($num_terms == 0) {
  718. $form['term_match']['terms_list']['none'] = array(
  719. '#type' => 'item',
  720. '#markup' => '<i>' . t('There is no term that matches the entered text.') . '</i>'
  721. );
  722. }
  723. }
  724. }
  725. /**
  726. * Returns the terms selected from the tripal_get_term_lookup_form.
  727. *
  728. * @param $form
  729. * The form (or $widget form).
  730. * @param $form_state
  731. * The form state.
  732. * @param $field_name
  733. * The name of the field, if this form is being added to a field widget.
  734. * @param $delta
  735. * The delta value for the field if this form is being added to a field
  736. * widget.
  737. *
  738. * @return
  739. * An array of term objects for each of the user selected terms.
  740. *
  741. * @ingroup tripal_terms_api
  742. */
  743. function tripal_get_term_lookup_form_result($form, $form_state, $field_name = '', $delta = 0) {
  744. $values = array();
  745. $selected = array();
  746. if ($field_name) {
  747. if (array_key_exists('term_match', $form_state['values'][$field_name]['und'][$delta])) {
  748. $values = $form_state['values'][$field_name]['und'][$delta]['term_match']['terms_list'];
  749. }
  750. }
  751. else {
  752. $values = $form_state['values'];
  753. }
  754. if (is_array($values)) {
  755. foreach ($values as $key => $value) {
  756. $matches = array();
  757. if (preg_match("/^term-(\d+)$/", $key, $matches) and $values['term-' . $matches[1]]) {
  758. $cvterm_id = $matches[1];
  759. $selected[] = chado_generate_var('cvterm', array('cvterm_id' => $cvterm_id));
  760. }
  761. }
  762. }
  763. return $selected;
  764. }
  765. /**
  766. * Implements an AJAX callback for the tripal_chado_vocab_select_term_form.
  767. *
  768. * @ingroup tripal_terms_api
  769. */
  770. function tripal_get_term_lookup_form_ajax_callback($form, $form_state) {
  771. $ajax_wrapper_id = $form_state['triggering_element']['#ajax']['wrapper'];
  772. $field_name = $form_state['storage'][$ajax_wrapper_id]['term_match_field'];
  773. $delta = $form_state['storage'][$ajax_wrapper_id]['term_match_delta'];
  774. // If this form is in a field then we need to dig a bit deeper to return
  775. // the form elements.
  776. if ($field_name) {
  777. return $form[$field_name]['und'][$delta]['term_match'];
  778. }
  779. else {
  780. return $form['term_match'];
  781. }
  782. }