TripalBundleUIController.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. <?php
  2. /**
  3. * @file
  4. */
  5. /**
  6. * UI controller.
  7. */
  8. class TripalBundleUIController extends EntityDefaultUIController {
  9. public function __construct($entity_type, $entity_info) {
  10. parent::__construct($entity_type, $entity_info);
  11. }
  12. /**
  13. * Overrides hook_menu() defaults.
  14. */
  15. public function hook_menu() {
  16. $items = parent::hook_menu();
  17. // Alter the Admin > Structure > Tripal Content Types menu item.
  18. $items[$this->path]['description'] = 'Manage biological content types that are
  19. added using Tripal.';
  20. // We don't want to let the user import new Tripal data types.
  21. unset($items[$this->path . '/import']);
  22. // Add an action link to Admin > Structure > Tripal Content Types for adding types.
  23. $items[$this->path . '/add'] = array(
  24. 'title' => 'Add Tripal Content Type',
  25. 'description' => 'Add data type content',
  26. 'page callback' => 'drupal_get_form',
  27. 'page arguments' => array('tripal_admin_add_type_form'),
  28. 'access arguments' => array('manage tripal content types'),
  29. 'type' => MENU_LOCAL_ACTION,
  30. 'weight' => 2
  31. );
  32. return $items;
  33. }
  34. /**
  35. * Allows us to change the forms created by the parent class.
  36. */
  37. function hook_forms() {
  38. $forms = parent::hook_forms();
  39. // The edit form for the entity type by default expects a function,
  40. // named after the entity type but we can't dynamically create these
  41. // functions. We'll use a single form for all entity types.
  42. $forms[$this->entityType . '_form'] = array(
  43. 'callback' => 'tripal_tripal_bundle_form',
  44. 'callback arguments' => array($this->entityType)
  45. );
  46. return $forms;
  47. }
  48. }
  49. /**
  50. * Tripal content type edit form.
  51. *
  52. * @param $form
  53. * The default form array. Usually empty.
  54. * @param $form_state
  55. * Build information for the form including the entity type and submitted values.
  56. * @param $entityDataType
  57. * A string indicating the entity type. This will always be TripalBundle.
  58. */
  59. function tripal_tripal_bundle_form($form, &$form_state, $entityDataType) {
  60. $bundle = $form_state['build_info']['args'][0];
  61. $term = NULL;
  62. $vocab = NULL;
  63. if (preg_match('/bio_data_(\d+)/', $bundle->name, $matches)) {
  64. $term = entity_load('TripalTerm', array('id' => $matches[1]));
  65. $term = reset($term);
  66. $vocab = entity_load('TripalVocab', array('id' => $term->vocab_id));
  67. $vocab = reset($vocab);
  68. }
  69. // Add a validate and submit handler to save the data in this form.
  70. $form['#validate'] = array('tripal_tripal_bundle_form_validate');
  71. $form['#submit'] = array('tripal_tripal_bundle_form_submit');
  72. $form['#bundle'] = $bundle;
  73. // @TODO: Move this into a css file.
  74. $form['#attached']['css'] = array(
  75. array(
  76. 'data' => '
  77. th.side-header { width: 220px; }',
  78. 'type' => 'inline',
  79. ),
  80. );
  81. if ($term) {
  82. $rows = array(
  83. array(
  84. array(
  85. 'header' => TRUE,
  86. 'data' => 'Vocabulary',
  87. 'class' => array('side-header')
  88. ),
  89. $vocab->vocabulary
  90. ),
  91. array(
  92. array(
  93. 'header' => TRUE,
  94. 'data' => 'Term Name',
  95. 'class' => array('side-header')
  96. ),
  97. $term->name
  98. ),
  99. array(
  100. array(
  101. 'header' => TRUE,
  102. 'data' => 'Accession',
  103. 'class' => array('side-header')
  104. ),
  105. $term->accession
  106. ),
  107. array(
  108. array(
  109. 'header' => TRUE,
  110. 'data' => 'Definition',
  111. 'class' => array('side-header')
  112. ),
  113. $term->definition
  114. )
  115. );
  116. $table_vars = array(
  117. 'header' => array(),
  118. 'rows' => $rows,
  119. 'attributes' => array(),
  120. 'caption' => '',
  121. 'sticky' => FALSE,
  122. 'colgroups' => array(),
  123. 'empty' => '',
  124. );
  125. $form['term'] = array(
  126. '#type' => 'item',
  127. '#title' => t('Vocabulary Term'),
  128. '#markup' => theme_table($table_vars)
  129. );
  130. }
  131. $form['label'] = array(
  132. '#type' => 'textfield',
  133. '#title' => t('Name'),
  134. '#required' => TRUE,
  135. '#description' => t('The human-readable name of this content type. This text will be
  136. displayed as part of the list on the <em>Add new content page</em>. It is recommended that
  137. this name begin with a capital letter and contain only letters, numbers, and spaces.
  138. This name must be unique.'),
  139. '#default_value' => $bundle->label,
  140. );
  141. $form['description'] = array(
  142. '#type' => 'textarea',
  143. '#title' => t('Description'),
  144. '#required' => TRUE,
  145. '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content page</em>.'),
  146. );
  147. if ($term) {
  148. $form['description']['#default_value'] = tripal_get_bundle_variable('description', $bundle->id, $term->definition);
  149. }
  150. else {
  151. $form['description']['#default_value'] = tripal_get_bundle_variable('description', $bundle->id, '');
  152. }
  153. $empty_fields = tripal_get_bundle_variable('hide_empty_field', $bundle->id, '');
  154. $form['hide_empty_field'] = array(
  155. '#type' => 'select',
  156. '#title' => t('Field Display'),
  157. '#options' => array(
  158. 'hide' => t('Hide empty fields'),
  159. 'show' => t('Show empty fields'),
  160. ),
  161. '#description' => t('Choose either to show or hide all empty fields. If "Show empty fields" is selected then fields will be loaded via AJAX to help speed page loads.'),
  162. '#default_value' => !empty($empty_fields) ? array($empty_fields,) : array('hide',),
  163. );
  164. $form['additional_settings'] = array(
  165. '#type' => 'vertical_tabs',
  166. '#weight' => 99,
  167. );
  168. // Set Title Format.
  169. //-------------------------
  170. $title_format = tripal_get_title_format($bundle);
  171. $form['set_titles'] = array(
  172. '#type' => 'fieldset',
  173. '#title' => t('Page Title options'),
  174. '#collapsible' => TRUE,
  175. '#collapsed' => FALSE,
  176. '#tree' => TRUE,
  177. '#group' => 'additional_settings',
  178. );
  179. $form['set_titles']['explanation'] = array(
  180. '#type' => 'item',
  181. '#markup' => t('<p>The format below is used to determine the title displayed on %type content
  182. pages. This ensures all content of this type is consistent while still allowing you
  183. to indicate which data you want represented in the title (ie: which data would most
  184. identify your content).</p>
  185. <p>Keep in mind that it might be confusing to users if more than
  186. one page has the same title. We recommend you <strong>choose a combination of tokens that
  187. will uniquely identify your content</strong>.</p>',
  188. array('%type' => $bundle->label)),
  189. );
  190. $form['set_titles']['title_format'] = array(
  191. '#type' => 'textarea',
  192. '#title' => t('Page Title Format'),
  193. '#description' => t('You may rearrange elements in this text box to customize the page
  194. titles. The available tokens are listed below. You can separate or include any text
  195. between the tokens.'),
  196. '#required' => TRUE,
  197. '#default_value' => $title_format,
  198. '#rows' => 1
  199. );
  200. $form['set_titles']['token_display'] = array(
  201. '#type' => 'fieldset',
  202. '#title' => t('Available Tokens'),
  203. '#description' => t('Copy the token and paste it into the "Custom Page Title" text field above.'),
  204. '#collapsible' => TRUE,
  205. '#collapsed' => TRUE
  206. );
  207. $tokens = tripal_get_entity_tokens($bundle);
  208. $form['set_titles']['tokens'] = array(
  209. '#type' => 'hidden',
  210. '#value' => serialize($tokens)
  211. );
  212. $form['set_titles']['token_display']['content'] = array(
  213. '#type' => 'item',
  214. '#markup' => theme_token_list($tokens),
  215. );
  216. $form['set_titles']['bp_explanation'] = array(
  217. '#type' => 'item',
  218. '#markup' => t('Retroactively apply the new title pattern to
  219. existing content by clicking the button below.',
  220. array('%type' => $bundle->label)),
  221. );
  222. $form['set_titles']['bulk_update'] = array(
  223. '#type' => 'submit',
  224. '#value' => t('Bulk update all titles'),
  225. //'#submit' => array('tripal_bulk_update_submit'),
  226. );
  227. // Set URL Alias Pattern.
  228. //-------------------------
  229. $url_pattern = tripal_get_bundle_variable('url_format', $bundle->id, '');
  230. if (!$url_pattern) $url_pattern = str_replace(' ', '', $term->name) . '/[TripalEntity__entity_id]';
  231. $form['url'] = array(
  232. '#type' => 'fieldset',
  233. '#title' => t('URL Path options'),
  234. '#collapsible' => TRUE,
  235. '#collapsed' => FALSE,
  236. '#tree' => TRUE,
  237. '#group' => 'additional_settings',
  238. );
  239. $form['url']['explanation'] = array(
  240. '#type' => 'item',
  241. '#markup' => t('<p>The pattern below is used to specify the URL of %type content pages.
  242. This allows you to present more friendly, informative URLs to your user.</p>
  243. <p><strong>You must choose a combination of tokens that results in a unique path for
  244. each page!</strong></p>',
  245. array('%type' => $bundle->label)),
  246. );
  247. $form['url']['url_pattern'] = array(
  248. '#type' => 'textarea',
  249. '#title' => t('URL Alias Pattern'),
  250. '#description' => t('You may rearrange elements in this text box to customize the url
  251. alias. The available tokens are listed below. <strong>Make sure the pattern forms a
  252. valid, unique URL</strong>. Leave this field blank to use the original path.'),
  253. '#default_value' => $url_pattern,
  254. '#required' => TRUE,
  255. '#rows' => 1
  256. );
  257. $tokens = tripal_get_entity_tokens($bundle, array('required only' => TRUE));
  258. $form['url']['tokens'] = array(
  259. '#type' => 'hidden',
  260. '#value' => serialize($tokens)
  261. );
  262. $form['url']['token_display'] = array(
  263. '#type' => 'fieldset',
  264. '#title' => t('Available Tokens'),
  265. '#description' => t('Copy the token and paste it into the "URL Alias Pattern" text field above.'),
  266. '#collapsible' => TRUE,
  267. '#collapsed' => TRUE
  268. );
  269. $form['url']['token_display']['content'] = array(
  270. '#type' => 'item',
  271. '#markup' => theme_token_list($tokens),
  272. );
  273. $form['url']['bp_explanation'] = array(
  274. '#type' => 'item',
  275. '#markup' => t('Retroactively apply the new url alias pattern to
  276. existing content by clicking the button below.',
  277. array('%type' => $bundle->label)),
  278. );
  279. $form['url']['bulk_update'] = array(
  280. '#type' => 'submit',
  281. '#value' => t('Bulk update all aliases'),
  282. //'#submit' => array('tripal_bulk_update_submit'),
  283. );
  284. // Submit Buttons
  285. //-------------------------
  286. $form['save'] = array(
  287. '#type' => 'submit',
  288. '#value' => t('Save Content Type'),
  289. '#weight' => 100
  290. );
  291. $form['delete'] = array(
  292. '#type' => 'submit',
  293. '#value' => t('Delete Content Type'),
  294. '#weight' => 101
  295. );
  296. return $form;
  297. }
  298. /**
  299. * Validate: Tripal content type edit form.
  300. */
  301. function tripal_tripal_bundle_form_validate($form, $form_state) {
  302. // VALIDATE: That there is a value passed for the hide_empty_field option. If
  303. // no value passed default to hide field.
  304. if(empty($form_state['values']['hide_empty_field'])){
  305. $form_state['values']['hide_empty_field'] = 'hide';
  306. }
  307. // VALIDATE: The only tokens used should be those we mentioned under "Available Tokens".
  308. // PART 1: Set Titles.
  309. $tokens_available = unserialize($form_state['values']['set_titles']['tokens']);
  310. if (preg_match_all('/(\[\w+\])/', $form_state['values']['set_titles']['title_format'], $matches)) {
  311. // The matches of the first and only pattern will be our tokens.
  312. $tokens_used = $matches[1];
  313. // Determine if any of the tokens used were not in the original list of available tokens.
  314. $tokens_missing = array_diff($tokens_used, array_keys($tokens_available));
  315. if ($tokens_missing) {
  316. $msg = t('You must only use tokens listed under available tokens. You used the following incorrect tokens: %tokens',
  317. array('%tokens' => implode(', ', $tokens_missing)));
  318. form_set_error('set_titles][title_format', $msg);
  319. }
  320. }
  321. else {
  322. $msg = t('You should use at least one token in your title format or the title for all %type pages will be the same.',
  323. array('%type' => $form_state['build_info']['args'][0]->label));
  324. form_set_error('set_titles][title_format', $msg);
  325. }
  326. // PART 2: URL Alias'
  327. if ($form_state['values']['url']['url_pattern']) {
  328. $tokens_available = unserialize($form_state['values']['url']['tokens']);
  329. if (preg_match_all('/(\[\w+\])/', $form_state['values']['url']['url_pattern'], $matches)) {
  330. // The matches of the first and only pattern will be our tokens.
  331. $tokens_used = $matches[1];
  332. // Determine if any of the tokens used were not in the original list of available tokens.
  333. $tokens_missing = array_diff($tokens_used, array_keys($tokens_available));
  334. if ($tokens_missing) {
  335. $msg = t('You must only use tokens listed under available tokens. You used the following incorrect tokens: %tokens',
  336. array('%tokens' => implode(', ', $tokens_missing)));
  337. form_set_error('url][url_pattern', $msg);
  338. }
  339. }
  340. else {
  341. $msg = t('You should use at least one token in your URL pattern or the URL for all %type pages will be the same.',
  342. array('%type' => $form_state['build_info']['args'][0]->label));
  343. form_set_error('url][url_pattern', $msg);
  344. }
  345. }
  346. }
  347. /**
  348. * Submit: Tripal content type edit form.
  349. */
  350. function tripal_tripal_bundle_form_submit($form, &$form_state) {
  351. global $user;
  352. $trigger = $form_state['triggering_element']['#value'];
  353. $bundle = $form_state['build_info']['args'][0];
  354. if ($trigger == 'Save Content Type' or $trigger == 'Bulk update all aliases' or
  355. $trigger == 'Bulk update all titles') {
  356. // Save the label.
  357. $bundle->label = $form_state['values']['label'];
  358. $bundle->save();
  359. // Save the description.
  360. tripal_set_bundle_variable('description', $bundle->id, $form_state['values']['description']);
  361. // Save the hide_empty_field setting.
  362. tripal_set_bundle_variable('hide_empty_field', $bundle->id, $form_state['values']['hide_empty_field']);
  363. // Save the page title format.
  364. tripal_save_title_format(
  365. $bundle,
  366. $form_state['values']['set_titles']['title_format']
  367. );
  368. // Save the URL alias pattern if it's set.
  369. if ($form_state['values']['url']['url_pattern']) {
  370. tripal_set_bundle_variable('url_format', $bundle->id, $form_state['values']['url']['url_pattern']);
  371. }
  372. // There are two submit buttons for this either updating the paths or the
  373. // titles.
  374. if ($trigger == 'Bulk update all titles') {
  375. $update = $form_state['input']['set_titles']['title_format'];
  376. $type = 'title';
  377. $args = array(
  378. 'bundle_id' => $bundle->name,
  379. 'update' => $update,
  380. 'type' => $type
  381. );
  382. $includes = array(
  383. module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
  384. );
  385. tripal_add_job('Update all aliases', 'tripal', 'tripal_update_all_urls_and_titles', $args,
  386. $user->uid, 10, $includes);
  387. }
  388. elseif ($trigger == 'Bulk update all aliases'){
  389. $update = $form_state['input']['url']['url_pattern'];
  390. $type = 'alias';
  391. $args = array(
  392. 'bundle_id' => $bundle->name,
  393. 'update' => $update,
  394. 'type' => $type
  395. );
  396. $includes = array(
  397. module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
  398. );
  399. tripal_add_job('Update all aliases', 'tripal', 'tripal_update_all_urls_and_titles', $args,
  400. $user->uid, 10, $includes);
  401. }
  402. $form_state['redirect'] = 'admin/structure/bio_data';
  403. drupal_set_message(t('Successfully saved %type content type.', array('%type' => $form_state['build_info']['args'][0]->label)));
  404. }
  405. else {
  406. $form_state['redirect'] = array(
  407. 'admin/structure/bio_data/manage/' . $bundle->name . '/delete',
  408. array('query' => array('destination' => 'admin/structure/bio_data'))
  409. );
  410. }
  411. }
  412. /**
  413. * Access callback for the entity API.
  414. */
  415. function tripal_bundle_access($op, $type = NULL, $account = NULL) {
  416. return user_access('manage tripal content types', $account);
  417. }
  418. /**
  419. * Form for creating tripal data types.
  420. *
  421. * This form is available on the menu at Admin >> Structure >> Biological Data
  422. * Types. It requires that a module implmennt the vocabulary storage. Tripal
  423. * knows which vocabulary storage methods are available when a module
  424. * implements the hook_vocab_storage_info() hook.
  425. *
  426. */
  427. function tripal_admin_add_type_form($form, &$form_state) {
  428. $stores = module_invoke_all('vocab_storage_info');
  429. if (!is_array($stores) or count($stores) == 0) {
  430. tripal_set_message('A storage backend is not enabled for managing
  431. the vocabulary terms used to create content. Please enable
  432. a module that supports storage of vocabualary terms (e.g. tripal_chado)
  433. and return to create new Tripal content types.', TRIPAL_NOTICE);
  434. return;
  435. }
  436. $keys = array_keys($stores);
  437. $module = $stores[$keys[0]]['module'];
  438. $function = $module . '_vocab_select_term_form';
  439. if (function_exists($function)) {
  440. $form = $function($form, $form_state);
  441. }
  442. $term_name = array_key_exists('values', $form_state) ? $form_state['values']['term_name'] : '';
  443. // If no term has been selected yet then provide the auto complete field.
  444. $form['term_name'] = array(
  445. '#title' => t('Content Type'),
  446. '#type' => 'textfield',
  447. '#description' => t("The content type must be the name of a term in
  448. a controlled vocabulary and the controlled vocabulary should
  449. already be loaded into Tripal. For example, to create a content
  450. type for storing 'genes', use the 'gene' term from the
  451. Sequence Ontology (SO)."),
  452. '#required' => TRUE,
  453. '#default_value' => $term_name,
  454. '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/cvterm/",
  455. );
  456. $form['select_button'] = array(
  457. '#type' => 'submit',
  458. '#value' => t('Lookup Term'),
  459. '#name' => 'select_cvterm',
  460. '#ajax' => array(
  461. 'callback' => "tripal_admin_add_type_form_ajax_callback",
  462. 'wrapper' => "tripal-vocab-select-form",
  463. 'effect' => 'fade',
  464. 'method' => 'replace'
  465. ),
  466. );
  467. $form['#prefix'] = '<div id = "tripal-vocab-select-form">';
  468. $form['#suffix'] = '</div>';
  469. // If the term has been provided by the user then we want to search for
  470. // matching terms in the database and let them select among any matches.
  471. if ($term_name) {
  472. $submit_disabled = TRUE;
  473. $form['terms_list'] = array(
  474. '#type' => 'fieldset',
  475. '#title' => t('Matching Terms'),
  476. '#description' => t('Please select the term the best matches the
  477. content type you want to create. If the same term exists in
  478. multiple vocabularies you will see more than one option below.')
  479. );
  480. $match = array(
  481. 'name' => $term_name,
  482. );
  483. $terms = chado_generate_var('cvterm', $match, array('return_array' => TRUE));
  484. $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
  485. $num_terms = 0;
  486. $selected_term = '';
  487. // Let the user select from any matching terms. Sometimes there may be
  488. // more than one that match.
  489. foreach ($terms as $term) {
  490. // Save the user a click by setting the default value as 1 if there's
  491. // only one matching term.
  492. $default = FALSE;
  493. $attrs = array();
  494. if ($num_terms == 0 and count($terms) == 1) {
  495. $default = TRUE;
  496. $attrs = array('checked' => 'checked');
  497. }
  498. $term_element_name = 'term-' . $term->cvterm_id;
  499. $form['terms_list'][$term_element_name] = array(
  500. '#type' => 'checkbox',
  501. '#title' => $term->name,
  502. '#default_value' => $default,
  503. '#attributes' => $attrs,
  504. '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name . ' (' . $term->dbxref_id->db_id->name . ') ' . $term->cv_id->definition .
  505. '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '. ' .
  506. '<br><b>Definition:</b> ' . $term->definition,
  507. '#ajax' => array(
  508. 'callback' => "tripal_admin_add_type_form_ajax_callback",
  509. 'wrapper' => "tripal-vocab-select-form",
  510. 'effect' => 'fade',
  511. 'method' => 'replace'
  512. ),
  513. );
  514. if (array_key_exists('values', $form_state) and array_key_exists($term_element_name, $form_state['values']) and
  515. $form_state['values'][$term_element_name] == 1) {
  516. $selected_term = $term;
  517. }
  518. $num_terms++;
  519. }
  520. if ($num_terms == 0) {
  521. $form['terms_list']['none'] = array(
  522. '#type' => 'item',
  523. '#markup' => '<i>' . t('There is no term that matches the entered text.') . '</i>'
  524. );
  525. return $form;
  526. }
  527. // Now let the user select where the data type will be stored.
  528. $form['storage'] = array(
  529. '#type' => 'fieldset',
  530. '#title' => t('Storage Settings'),
  531. '#description' => t('The primary record for each content of this type
  532. must be stored in a single storage backend. Please select the
  533. storage method and settings for this content type.')
  534. );
  535. // TODO: there should be a way for each storage backend to determine if
  536. // it can handle the content type. Maybe certain content types aren't
  537. // yet supported by every storage backend.
  538. $default_store = 'term_chado_storage';
  539. $store_options = array(0 => '-- Select --');
  540. foreach ($stores as $store_type => $store) {
  541. $store_options[$store_type] = $store['label'];
  542. }
  543. if (array_key_exists('values', $form_state) and
  544. array_key_exists('store_select', $form_state['values'])) {
  545. $default_store = $form_state['values']['store_select'];
  546. }
  547. $form['storage']['store_select'] = array(
  548. '#type' => 'select',
  549. '#title' => 'Storage backend',
  550. '#options' => $store_options,
  551. '#default_value' => $default_store,
  552. '#ajax' => array(
  553. 'callback' => "tripal_admin_add_type_form_ajax_callback",
  554. 'wrapper' => "tripal-vocab-select-form",
  555. 'effect' => 'fade',
  556. 'method' => 'replace'
  557. ),
  558. '#description' => 'Select a storage background for this content type.'
  559. );
  560. if ($default_store) {
  561. $selected_store_module = $stores[$store_type]['module'];
  562. $function = $selected_store_module . '_field_storage_bundle_mapping_form';
  563. if (function_exists($function)) {
  564. $store_form = $function($form, $form_state, $selected_term, $submit_disabled);
  565. $form['storage'][$store_type] = $store_form;
  566. }
  567. // Add in the button for the cases of no terms or too many.
  568. $form['submit_button'] = array(
  569. '#type' => 'submit',
  570. '#value' => t('Create content type'),
  571. '#name' => 'use_cvterm',
  572. '#disabled' => $submit_disabled,
  573. );
  574. }
  575. }
  576. return $form;
  577. }
  578. /**
  579. * Implements an AJAX callback for the tripal_chado_vocab_select_term_form.
  580. */
  581. function tripal_admin_add_type_form_ajax_callback($form, $form_state) {
  582. return $form;
  583. }
  584. /**
  585. * Implements hook_validate() for the tripal_admin_add_type_form.
  586. *
  587. */
  588. function tripal_admin_add_type_form_validate($form, &$form_state) {
  589. $stores = module_invoke_all('vocab_storage_info');
  590. $store_select = (isset($form_state['values']['store_select'])) ? $form_state['values']['store_select'] : NULL;
  591. if (array_key_exists('clicked_button', $form_state) and
  592. $form_state['clicked_button']['#name'] =='use_cvterm') {
  593. $cvterm_id = NULL;
  594. // Make sure we have a cvterm selected
  595. $num_selected = 0;
  596. foreach ($form_state['values'] as $key => $value) {
  597. $matches = array();
  598. if (preg_match("/^term-(\d+)$/", $key, $matches) and
  599. $form_state['values']['term-' . $matches[1]]) {
  600. $cvterm_id = $matches[1];
  601. $term = chado_generate_var('cvterm', array('cvterm_id' => $cvterm_id));
  602. $num_selected++;
  603. }
  604. }
  605. if ($num_selected == 0) {
  606. form_set_error('', 'Please select at least one term.');
  607. }
  608. else if ($num_selected > 1) {
  609. form_set_error('term-' . $cvterm_id, 'Please select only one term from the list below.');
  610. }
  611. else {
  612. // Add the term to the form state so we can access it later.
  613. $form_state['term']['vocabulary'] = $term->dbxref_id->db_id->name;
  614. $form_state['term']['accession'] = $term->dbxref_id->accession;
  615. $form_state['term']['term_name'] = $term->name;
  616. // Call the submit hook for this form for the storage method that
  617. // will be responsible for this cotent type.
  618. $stores = module_invoke_all('vocab_storage_info');
  619. $selected_store_module = $stores[$store_select]['module'];
  620. $selected_term = $form_state['term'];
  621. $function = $selected_store_module . '_field_storage_bundle_mapping_form_validate';
  622. if (function_exists($function)) {
  623. $function($form, $form_state, $selected_term);
  624. }
  625. }
  626. }
  627. // For any other button click it's an AJAX call and we just want to reubild
  628. // the form.
  629. else {
  630. $form_state['rebuild'] = TRUE;
  631. }
  632. }
  633. /**
  634. * Implements hook_submit() for the tripal_admin_add_type_form.
  635. */
  636. function tripal_admin_add_type_form_submit($form, &$form_state) {
  637. $vocabulary = '';
  638. $accession = '';
  639. if (array_key_exists('term', $form_state)) {
  640. $selected_term = $form_state['term'];
  641. $store_select = $form_state['values']['store_select'];
  642. $vocabulary = array_key_exists('vocabulary', $selected_term) ? $selected_term['vocabulary'] : '';
  643. $accession = array_key_exists('accession', $selected_term) ? $selected_term['accession'] : '';
  644. $term_name = array_key_exists('term_name', $selected_term) ? $selected_term['term_name'] : '';
  645. // Before we try to add this type, check to see if it already exists
  646. // as a bundle.
  647. $term = tripal_load_term_entity(array('vocabulary' => $vocabulary, 'accession' => $accession));
  648. if (!$term) {
  649. // Call the submit hook for this form for the storage method that
  650. // will be responsible for this cotent type.
  651. $stores = module_invoke_all('vocab_storage_info');
  652. $selected_store_module = $stores[$store_select]['module'];
  653. $storage_args = array();
  654. $function = $selected_store_module . '_field_storage_bundle_mapping_form_submit';
  655. if (function_exists($function)) {
  656. $function($form, $form_state, $term, $storage_args);
  657. }
  658. $args = array(
  659. 'vocabulary' => $vocabulary,
  660. 'accession' => $accession,
  661. 'term_name' => $term_name,
  662. 'storage_args' => $storage_args,
  663. );
  664. $bundle = tripal_create_bundle($args, $error);
  665. if (!$bundle) {
  666. drupal_set_message($error, 'error');
  667. $form_state['redirect'] = "admin/structure/bio_data";
  668. }
  669. else {
  670. drupal_set_message('New content type created!');
  671. drupal_set_message('Please ' . l("set the user permissions", "admin/people/permissions") . ' for this new content type.');
  672. tripal_admin_access($bundle);
  673. $form_state['redirect'] = "admin/structure/bio_data";
  674. }
  675. }
  676. else {
  677. drupal_set_message("The term '$accession' already exists as a content type.", 'warning');
  678. }
  679. }
  680. }
  681. /**
  682. * Checks access permissions for a given entity.
  683. */
  684. function tripal_admin_access($entity) {
  685. if ($entity) {
  686. $bundle_name = $entity->name;
  687. }
  688. else {
  689. return FALSE;
  690. }
  691. // Get the bundle object.
  692. $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
  693. // Identify the administrative user roles.
  694. $admin_role = user_role_load_by_name('administrator');
  695. $roles = array($admin_role->rid => $admin_role->name);
  696. // Define the permissions.
  697. $permission_for_role = array(
  698. 'create ' . $bundle->name => TRUE,
  699. 'view ' . $bundle->name => TRUE,
  700. 'edit ' . $bundle->name => TRUE,
  701. 'delete ' . $bundle->name => TRUE,
  702. );
  703. // Assign the permissions
  704. foreach($roles as $role => $value){
  705. user_role_change_permissions($role, $permission_for_role);
  706. }
  707. return TRUE;
  708. }