TripalBundleUIController.inc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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. * Renders the Bundle overview table
  50. */
  51. public function overviewTable($conditions = array()) {
  52. $entities = entity_load($this->entityType, FALSE, $conditions);
  53. // Sort the entities by label.
  54. $sorted = [];
  55. foreach ($entities as $entity) {
  56. $sorted[$entity->label] = $entity;
  57. }
  58. ksort($sorted, SORT_STRING|SORT_FLAG_CASE);
  59. $rows = array();
  60. foreach ($sorted as $entity) {
  61. // Get the term for this content type
  62. $additional_cols = [$entity->term->name . ' (' . l($entity->accession, 'cv/lookup/' . $entity->term->vocab->vocabulary . '/' . $entity->term->accession) . ')'];
  63. $rows[] = $this->overviewTableRow($conditions,
  64. entity_id($this->entityType, $entity), $entity,
  65. $additional_cols);
  66. }
  67. // Assemble the right table header.
  68. $header = array(t('Label'));
  69. if (!empty($this->entityInfo['exportable'])) {
  70. $header[] = t('Status');
  71. }
  72. $header[] = array(
  73. 'data' => t('Term'),
  74. );
  75. // Add operations with the right colspan.
  76. $field_ui = !empty($this->entityInfo['bundle of']) && module_exists('field_ui');
  77. $exportable = !empty($this->entityInfo['exportable']);
  78. $colspan = 3;
  79. $colspan = $field_ui ? $colspan + 2 : $colspan;
  80. $colspan = $exportable ? $colspan + 1 : $colspan;
  81. $header[] = array(
  82. 'data' => t('Operations'),
  83. 'colspan' => $colspan,
  84. );
  85. $render = array(
  86. '#theme' => 'table',
  87. '#header' => $header,
  88. '#rows' => $rows,
  89. '#empty' => t('None.'),
  90. );
  91. return $render;
  92. }
  93. }
  94. /**
  95. * Tripal content type edit form.
  96. *
  97. * @param $form
  98. * The default form array. Usually empty.
  99. * @param $form_state
  100. * Build information for the form including the entity type and submitted values.
  101. * @param $entityDataType
  102. * A string indicating the entity type. This will always be TripalBundle.
  103. */
  104. function tripal_tripal_bundle_form($form, &$form_state, $entityDataType) {
  105. $bundle = $form_state['build_info']['args'][0];
  106. $term = NULL;
  107. $vocab = NULL;
  108. if (preg_match('/bio_data_(\d+)/', $bundle->name, $matches)) {
  109. $term = entity_load('TripalTerm', array('id' => $matches[1]));
  110. $term = reset($term);
  111. $vocab = entity_load('TripalVocab', array('id' => $term->vocab_id));
  112. $vocab = reset($vocab);
  113. }
  114. // Add a validate and submit handler to save the data in this form.
  115. $form['#validate'] = array('tripal_tripal_bundle_form_validate');
  116. $form['#submit'] = array('tripal_tripal_bundle_form_submit');
  117. $form['#bundle'] = $bundle;
  118. // @TODO: Move this into a css file.
  119. $form['#attached']['css'] = array(
  120. array(
  121. 'data' => '
  122. th.side-header { width: 220px; }',
  123. 'type' => 'inline',
  124. ),
  125. );
  126. if ($term) {
  127. $rows = array(
  128. array(
  129. array(
  130. 'header' => TRUE,
  131. 'data' => 'Vocabulary',
  132. 'class' => array('side-header')
  133. ),
  134. $vocab->vocabulary
  135. ),
  136. array(
  137. array(
  138. 'header' => TRUE,
  139. 'data' => 'Term Name',
  140. 'class' => array('side-header')
  141. ),
  142. $term->name
  143. ),
  144. array(
  145. array(
  146. 'header' => TRUE,
  147. 'data' => 'Accession',
  148. 'class' => array('side-header')
  149. ),
  150. $term->accession
  151. ),
  152. array(
  153. array(
  154. 'header' => TRUE,
  155. 'data' => 'Definition',
  156. 'class' => array('side-header')
  157. ),
  158. $term->definition
  159. )
  160. );
  161. $table_vars = array(
  162. 'header' => array(),
  163. 'rows' => $rows,
  164. 'attributes' => array(),
  165. 'caption' => '',
  166. 'sticky' => FALSE,
  167. 'colgroups' => array(),
  168. 'empty' => '',
  169. );
  170. $form['term'] = array(
  171. '#type' => 'item',
  172. '#title' => t('Vocabulary Term'),
  173. '#markup' => theme_table($table_vars)
  174. );
  175. }
  176. $form['label'] = array(
  177. '#type' => 'textfield',
  178. '#title' => t('Name'),
  179. '#required' => TRUE,
  180. '#description' => t('The human-readable name of this content type. This text will be
  181. displayed as part of the list on the <em>Add new content page</em>. It is recommended that
  182. this name begin with a capital letter and contain only letters, numbers, and spaces.
  183. This name must be unique.'),
  184. '#default_value' => $bundle->label,
  185. );
  186. $form['description'] = array(
  187. '#type' => 'textarea',
  188. '#title' => t('Description'),
  189. '#required' => TRUE,
  190. '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content page</em>.'),
  191. );
  192. if ($term) {
  193. $form['description']['#default_value'] = tripal_get_bundle_variable('description', $bundle->id, $term->definition);
  194. }
  195. else {
  196. $form['description']['#default_value'] = tripal_get_bundle_variable('description', $bundle->id, '');
  197. }
  198. $hide_empty_field_var = tripal_get_bundle_variable('hide_empty_field', $bundle->id);
  199. if ($hide_empty_field_var != 0) {
  200. $hide_empty_field_var = TRUE;
  201. }
  202. $ajax_field_var = tripal_get_bundle_variable('ajax_field', $bundle->id);
  203. if ($ajax_field_var != 0) {
  204. $ajax_field_var = TRUE;
  205. }
  206. $form['hide_empty_field'] = array(
  207. '#type' => 'checkbox',
  208. '#title' => t('Hide empty fields'),
  209. '#description' => t('Uncheck this box if you would like to show all empty fields.'),
  210. '#default_value' => $hide_empty_field_var,
  211. '#weight' => 9,
  212. );
  213. $form['ajax_field'] = array(
  214. '#type' => 'checkbox',
  215. '#title' => t('Load field using AJAX'),
  216. '#description' => t('Uncheck this box if you do not want field data to load by ajax, this may signifiantly increase page load times.'),
  217. '#default_value' => $ajax_field_var,
  218. '#weight' => 9,
  219. );
  220. $form['ajax_field disclaimer'] = array(
  221. '#type' => 'item',
  222. '#markup' => t(
  223. '<p>Please note, if both "Hide empty fields" and "Load field using AJAX"
  224. are checked empty fields will be hidden using javascript which may result
  225. in some jumpiness of content as the page finishes loading.</p>'
  226. ),
  227. '#weight' => 10,
  228. );
  229. $form['additional_settings'] = array(
  230. '#type' => 'vertical_tabs',
  231. '#weight' => 99,
  232. );
  233. // Set Title Format.
  234. //-------------------------
  235. $title_format = tripal_get_title_format($bundle);
  236. $form['set_titles'] = array(
  237. '#type' => 'fieldset',
  238. '#title' => t('Page Title options'),
  239. '#collapsible' => TRUE,
  240. '#collapsed' => FALSE,
  241. '#tree' => TRUE,
  242. '#group' => 'additional_settings',
  243. );
  244. $form['set_titles']['explanation'] = array(
  245. '#type' => 'item',
  246. '#markup' => t('<p>The format below is used to determine the title displayed on %type content
  247. pages. This ensures all content of this type is consistent while still allowing you
  248. to indicate which data you want represented in the title (ie: which data would most
  249. identify your content).</p>
  250. <p>Keep in mind that it might be confusing to users if more than
  251. one page has the same title. We recommend you <strong>choose a combination of tokens that
  252. will uniquely identify your content</strong>.</p>',
  253. array('%type' => $bundle->label)),
  254. );
  255. $form['set_titles']['title_format'] = array(
  256. '#type' => 'textarea',
  257. '#title' => t('Page Title Format'),
  258. '#description' => t('You may rearrange elements in this text box to customize the page
  259. titles. The available tokens are listed below. You can separate or include any text
  260. between the tokens.'),
  261. '#required' => TRUE,
  262. '#default_value' => $title_format,
  263. '#rows' => 1
  264. );
  265. $form['set_titles']['token_display'] = array(
  266. '#type' => 'fieldset',
  267. '#title' => t('Available Tokens'),
  268. '#description' => t('Copy the token and paste it into the "Custom Page Title" text field above.'),
  269. '#collapsible' => TRUE,
  270. '#collapsed' => TRUE
  271. );
  272. $tokens = tripal_get_entity_tokens($bundle);
  273. $form['set_titles']['tokens'] = array(
  274. '#type' => 'hidden',
  275. '#value' => serialize($tokens)
  276. );
  277. $form['set_titles']['token_display']['content'] = array(
  278. '#type' => 'item',
  279. '#markup' => theme_token_list($tokens),
  280. );
  281. $form['set_titles']['bp_explanation'] = array(
  282. '#type' => 'item',
  283. '#markup' => t('Retroactively apply the new title pattern to
  284. existing content by clicking the button below.',
  285. array('%type' => $bundle->label)),
  286. );
  287. $form['set_titles']['bulk_update'] = array(
  288. '#type' => 'submit',
  289. '#value' => t('Bulk update all titles'),
  290. //'#submit' => array('tripal_bulk_update_submit'),
  291. );
  292. // Set URL Alias Pattern.
  293. //-------------------------
  294. $url_pattern = tripal_get_bundle_variable('url_format', $bundle->id, '');
  295. if (!$url_pattern) $url_pattern = str_replace(' ', '', $term->name) . '/[TripalEntity__entity_id]';
  296. $form['url'] = array(
  297. '#type' => 'fieldset',
  298. '#title' => t('URL Path options'),
  299. '#collapsible' => TRUE,
  300. '#collapsed' => FALSE,
  301. '#tree' => TRUE,
  302. '#group' => 'additional_settings',
  303. );
  304. $form['url']['explanation'] = array(
  305. '#type' => 'item',
  306. '#markup' => t('<p>The pattern below is used to specify the URL of %type content pages.
  307. This allows you to present more friendly, informative URLs to your user.</p>
  308. <p><strong>You must choose a combination of tokens that results in a unique path for
  309. each page!</strong></p>',
  310. array('%type' => $bundle->label)),
  311. );
  312. $form['url']['url_pattern'] = array(
  313. '#type' => 'textarea',
  314. '#title' => t('URL Alias Pattern'),
  315. '#description' => t('You may rearrange elements in this text box to customize the url
  316. alias. The available tokens are listed below. <strong>Make sure the pattern forms a
  317. valid, unique URL</strong>. Leave this field blank to use the original path.'),
  318. '#default_value' => $url_pattern,
  319. '#required' => TRUE,
  320. '#rows' => 1
  321. );
  322. $tokens = tripal_get_entity_tokens($bundle);
  323. $form['url']['tokens'] = array(
  324. '#type' => 'hidden',
  325. '#value' => serialize($tokens)
  326. );
  327. $form['url']['token_display'] = array(
  328. '#type' => 'fieldset',
  329. '#title' => t('Available Tokens'),
  330. '#description' => t('Copy the token and paste it into the "URL Alias Pattern" ' .
  331. 'text field above. Please choose tokens that will guarantee a unique URL.'),
  332. '#collapsible' => TRUE,
  333. '#collapsed' => TRUE
  334. );
  335. $form['url']['token_display']['content'] = array(
  336. '#type' => 'item',
  337. '#markup' => theme_token_list($tokens),
  338. );
  339. $form['url']['bp_explanation'] = array(
  340. '#type' => 'item',
  341. '#markup' => t('Retroactively apply the new url alias pattern to
  342. existing content by clicking the button below.',
  343. array('%type' => $bundle->label)),
  344. );
  345. $form['url']['bulk_update'] = array(
  346. '#type' => 'submit',
  347. '#value' => t('Bulk update all aliases'),
  348. //'#submit' => array('tripal_bulk_update_submit'),
  349. );
  350. // Submit Buttons
  351. //-------------------------
  352. $form['save'] = array(
  353. '#type' => 'submit',
  354. '#value' => t('Save Content Type'),
  355. '#weight' => 100
  356. );
  357. $form['delete'] = array(
  358. '#type' => 'submit',
  359. '#value' => t('Delete Content Type'),
  360. '#weight' => 101
  361. );
  362. return $form;
  363. }
  364. /**
  365. * Validate: Tripal content type edit form.
  366. */
  367. function tripal_tripal_bundle_form_validate($form, $form_state) {
  368. // VALIDATE: That there is a value passed for the hide_empty_field option. If
  369. // no value passed default to hide field.
  370. if(empty($form_state['values']['hide_empty_field'])){
  371. $form_state['values']['hide_empty_field'] = TRUE;
  372. }
  373. if (empty($form_state['values']['ajax_field'])) {
  374. $form_state['values']['ajax_field'] = TRUE;
  375. }
  376. // VALIDATE: The only tokens used should be those we mentioned under "Available Tokens".
  377. // PART 1: Set Titles.
  378. $tokens_available = unserialize($form_state['values']['set_titles']['tokens']);
  379. if (preg_match_all('/(\[\w+\])/', $form_state['values']['set_titles']['title_format'], $matches)) {
  380. // The matches of the first and only pattern will be our tokens.
  381. $tokens_used = $matches[1];
  382. // Determine if any of the tokens used were not in the original list of available tokens.
  383. $tokens_missing = array_diff($tokens_used, array_keys($tokens_available));
  384. if ($tokens_missing) {
  385. $msg = t('You must only use tokens listed under available tokens. You used the following incorrect tokens: %tokens',
  386. array('%tokens' => implode(', ', $tokens_missing)));
  387. form_set_error('set_titles][title_format', $msg);
  388. }
  389. }
  390. else {
  391. $msg = t('You should use at least one token in your title format or the title for all %type pages will be the same.',
  392. array('%type' => $form_state['build_info']['args'][0]->label));
  393. form_set_error('set_titles][title_format', $msg);
  394. }
  395. // PART 2: URL Alias'
  396. if ($form_state['values']['url']['url_pattern']) {
  397. $tokens_available = unserialize($form_state['values']['url']['tokens']);
  398. if (preg_match_all('/(\[\w+\])/', $form_state['values']['url']['url_pattern'], $matches)) {
  399. // The matches of the first and only pattern will be our tokens.
  400. $tokens_used = $matches[1];
  401. // Determine if any of the tokens used were not in the original list of available tokens.
  402. $tokens_missing = array_diff($tokens_used, array_keys($tokens_available));
  403. if ($tokens_missing) {
  404. $msg = t('You must only use tokens listed under available tokens. You used the following incorrect tokens: %tokens',
  405. array('%tokens' => implode(', ', $tokens_missing)));
  406. form_set_error('url][url_pattern', $msg);
  407. }
  408. }
  409. else {
  410. $msg = t('You should use at least one token in your URL pattern or the URL for all %type pages will be the same.',
  411. array('%type' => $form_state['build_info']['args'][0]->label));
  412. form_set_error('url][url_pattern', $msg);
  413. }
  414. }
  415. }
  416. /**
  417. * Submit: Tripal content type edit form.
  418. */
  419. function tripal_tripal_bundle_form_submit($form, &$form_state) {
  420. global $user;
  421. $trigger = $form_state['triggering_element']['#value'];
  422. $bundle = $form_state['build_info']['args'][0];
  423. if ($trigger == 'Save Content Type' or $trigger == 'Bulk update all aliases' or
  424. $trigger == 'Bulk update all titles') {
  425. // Save the label.
  426. $bundle->label = $form_state['values']['label'];
  427. $bundle->save();
  428. // Save the description.
  429. tripal_set_bundle_variable('description', $bundle->id, $form_state['values']['description']);
  430. // Save the hide_empty_field setting.
  431. tripal_set_bundle_variable('hide_empty_field', $bundle->id, $form_state['values']['hide_empty_field']);
  432. tripal_set_bundle_variable('ajax_field', $bundle->id, $form_state['values']['ajax_field']);
  433. // Save the page title format.
  434. tripal_save_title_format(
  435. $bundle,
  436. $form_state['values']['set_titles']['title_format']
  437. );
  438. // Save the URL alias pattern if it's set.
  439. if ($form_state['values']['url']['url_pattern']) {
  440. tripal_set_bundle_variable('url_format', $bundle->id, $form_state['values']['url']['url_pattern']);
  441. }
  442. // There are two submit buttons for this either updating the paths or the
  443. // titles.
  444. if ($trigger == 'Bulk update all titles') {
  445. $update = $form_state['input']['set_titles']['title_format'];
  446. $type = 'title';
  447. $args = array(
  448. 'bundle_id' => $bundle->name,
  449. 'update' => $update,
  450. 'type' => $type
  451. );
  452. $includes = array(
  453. module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
  454. );
  455. tripal_add_job('Update all aliases for content type: ' . $bundle->label, 'tripal',
  456. 'tripal_update_all_urls_and_titles', $args, $user->uid, 10, $includes);
  457. }
  458. elseif ($trigger == 'Bulk update all aliases'){
  459. $update = $form_state['input']['url']['url_pattern'];
  460. $type = 'alias';
  461. $args = array(
  462. 'bundle_id' => $bundle->name,
  463. 'update' => $update,
  464. 'type' => $type
  465. );
  466. $includes = array(
  467. module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
  468. );
  469. tripal_add_job('Update all aliases for content type: ' . $bundle->label, 'tripal',
  470. 'tripal_update_all_urls_and_titles', $args, $user->uid, 10, $includes);
  471. }
  472. $form_state['redirect'] = 'admin/structure/bio_data';
  473. drupal_set_message(t('Successfully saved %type content type.', array('%type' => $form_state['build_info']['args'][0]->label)));
  474. }
  475. else {
  476. $form_state['redirect'] = array(
  477. 'admin/structure/bio_data/manage/' . $bundle->name . '/delete',
  478. array('query' => array('destination' => 'admin/structure/bio_data'))
  479. );
  480. }
  481. }
  482. /**
  483. * Access callback for the entity API.
  484. */
  485. function tripal_bundle_access($op, $type = NULL, $account = NULL) {
  486. return user_access('manage tripal content types', $account);
  487. }
  488. /**
  489. * Form for creating tripal data types.
  490. *
  491. * This form is available on the menu at Admin >> Structure >> Biological Data
  492. * Types. It requires that a module implmennt the vocabulary storage. Tripal
  493. * knows which vocabulary storage methods are available when a module
  494. * implements the hook_vocab_storage_info() hook.
  495. *
  496. */
  497. function tripal_admin_add_type_form($form, &$form_state) {
  498. // Make sure we have a storage backend for managing content types.
  499. $stores = module_invoke_all('vocab_storage_info');
  500. if (!is_array($stores) or count($stores) == 0) {
  501. tripal_set_message('A storage backend is not enabled for managing
  502. the vocabulary terms used to create content. Please enable
  503. a module that supports storage of vocabualary terms (e.g. tripal_chado)
  504. and return to create new Tripal content types.', TRIPAL_NOTICE);
  505. return;
  506. }
  507. // Set the stage to step1 if it isn't already set.
  508. if (!isset($form_state['stage'])) $form_state['stage'] = 'step1';
  509. $stage = $form_state['stage'];
  510. // Get the selected term.
  511. if (array_key_exists('values', $form_state) and
  512. array_key_exists('term', $form_state['values'])) {
  513. $selected_term = $form_state['values']['term'];
  514. }
  515. else {
  516. $selected = tripal_get_term_lookup_form_result($form, $form_state);
  517. if ($selected) {
  518. $selected_term = $selected[0];
  519. }
  520. }
  521. // Get the selected storage element.
  522. $default_store = 'term_chado_storage';
  523. if (array_key_exists('values', $form_state) and
  524. array_key_exists('store_select', $form_state['values'])) {
  525. $default_store = $form_state['values']['store_select'];
  526. }
  527. // Handle the different stages:
  528. if ($stage == 'step1') {
  529. tripal_admin_add_type_form_step1($form, $form_state);
  530. }
  531. if ($form_state['stage'] == 'step2') {
  532. tripal_admin_add_type_form_step1_summary($form, $form_state, $selected_term);
  533. tripal_admin_add_type_form_step2($form, $form_state, $stores, $selected_term, $default_store);
  534. }
  535. if ($form_state['stage'] == 'step3') {
  536. tripal_admin_add_type_form_step1_summary($form, $form_state, $selected_term);
  537. tripal_admin_add_type_form_step2_summary($form, $form_state, $stores, $selected_term, $default_store);
  538. tripal_admin_add_type_form_step3($form, $form_state, $stores, $selected_term, $default_store);
  539. }
  540. $form['#prefix'] = '<div id = "tripal-add-type-form">';
  541. $form['#suffix'] = '</div>';
  542. return $form;
  543. }
  544. /**
  545. * Builds step1 of the tripal_admin_add_type_form()
  546. */
  547. function tripal_admin_add_type_form_step1(&$form, &$form_state) {
  548. // Get the term name from the form_state.
  549. $term_name = '';
  550. if (array_key_exists('values', $form_state) and array_key_exists('term_name0', $form_state['values'])) {
  551. $term_name = $form_state['values']['term_name0'];
  552. }
  553. if (array_key_exists('input', $form_state) and array_key_exists('term_name0', $form_state['input'])) {
  554. $term_name = $form_state['input']['term_name0'];
  555. }
  556. // Get the term lookup form.
  557. $description = t("The content type must be the name of a term in
  558. a controlled vocabulary and the controlled vocabulary should
  559. already be loaded into Tripal. For example, to create a content
  560. type for storing 'genes', use the 'gene' term from the
  561. Sequence Ontology (SO).");
  562. tripal_get_term_lookup_form($form, $form_state, $term_name,
  563. 'Step 1: Content Type', $description, TRUE, '', 0,
  564. 'tripal_admin_add_type_form_ajax_callback');
  565. if ($term_name) {
  566. $form['term_match']['step1-continue'] = array(
  567. '#type' => 'submit',
  568. '#value' => t('Continue'),
  569. '#name' => 'step1-continue',
  570. );
  571. }
  572. }
  573. /**
  574. * Provides a summary of values selected in Step 1.
  575. */
  576. function tripal_admin_add_type_form_step1_summary(&$form, &$form_state, $selected_term) {
  577. $form['term'] = [
  578. '#type' => 'value',
  579. '#value' => $selected_term,
  580. ];
  581. $form['term_summary'] = [
  582. '#type' => 'fieldset',
  583. '#title' => t('Step 1: Content Type'),
  584. '#description' => '',
  585. '#collapsible' => TRUE,
  586. '#collapsed' => TRUE,
  587. ];
  588. $definition = property_exists($selected_term, 'definition') ? $selected_term->definition : '';
  589. $form['term_summary']['details'] = [
  590. '#type' => 'item',
  591. '#title' => t('Term'),
  592. '#markup' => 'Name: ' . $selected_term->name .
  593. '<br>Vocabulary: ' . $selected_term->cv_id->name . ' (' . $selected_term->dbxref_id->db_id->name . ') ' .
  594. '<br>Term ID: ' . $selected_term->dbxref_id->db_id->name . ':' . $selected_term->dbxref_id->accession . '. ' .
  595. '<br>Definition: ' . $definition
  596. ];
  597. $form['term_summary']['step1-return'] = array(
  598. '#type' => 'submit',
  599. '#value' => t('Pick a different term'),
  600. '#name' => 'step1-return',
  601. );
  602. }
  603. /**
  604. * Builds step1 of the tripal_admin_add_type_form()
  605. */
  606. function tripal_admin_add_type_form_step2(&$form, &$form_state, $stores, $selected_term, $default_store) {
  607. // Now let the user select where the data type will be stored.
  608. $form['storage'] = array(
  609. '#type' => 'fieldset',
  610. '#title' => t('Step 2: Storage'),
  611. '#description' => t('The primary record for each content of this type
  612. must be stored in a single storage backend. Please select the
  613. storage method and settings for this content type.')
  614. );
  615. $store_options = array(0 => '-- Select --');
  616. foreach ($stores as $store_type => $store) {
  617. $store_options[$store_type] = $store['label'];
  618. }
  619. $form['storage']['store_select'] = array(
  620. '#type' => 'select',
  621. '#title' => 'Storage backend',
  622. '#options' => $store_options,
  623. '#default_value' => $default_store,
  624. '#description' => 'Select a storage background for this content type.'
  625. );
  626. if ($default_store) {
  627. $form['term_match']['step2-continue'] = array(
  628. '#type' => 'submit',
  629. '#value' => t('Continue'),
  630. '#name' => 'step2-continue',
  631. );
  632. }
  633. }
  634. /**
  635. * Provides a summary of values selected in Step 1.
  636. */
  637. function tripal_admin_add_type_form_step2_summary(&$form, &$form_state, $stores, $selected_term, $default_store) {
  638. $default_store = $form_state['values']['store_select'];
  639. $selected_store_module = $stores[$default_store]['module'];
  640. $form['store_select'] = [
  641. '#type' => 'value',
  642. '#value' => $default_store,
  643. ];
  644. $form['store_summary'] = [
  645. '#type' => 'fieldset',
  646. '#title' => t('Step 2: Storage'),
  647. '#description' => '',
  648. '#collapsible' => TRUE,
  649. '#collapsed' => TRUE,
  650. ];
  651. $form['store_summary']['details'] = [
  652. '#type' => 'item',
  653. '#title' => t('Storage backend'),
  654. '#markup' => $stores[$default_store]['label']
  655. ];
  656. $form['term_summary']['step1-return'] = array(
  657. '#type' => 'submit',
  658. '#value' => t('Pick a different term'),
  659. '#name' => 'step1-return',
  660. );
  661. }
  662. /**
  663. * Builds step1 of the tripal_admin_add_type_form()
  664. */
  665. function tripal_admin_add_type_form_step3(&$form, &$form_state, $stores, $selected_term, $default_store) {
  666. $default_store = $form_state['values']['store_select'];
  667. $selected_store_module = $stores[$default_store]['module'];
  668. $form['store_settings'] = [
  669. '#type' => 'fieldset',
  670. '#title' => t('Step 3: Storage Settings'),
  671. '#description' => '',
  672. ];
  673. $function = $selected_store_module . '_field_storage_bundle_mapping_form';
  674. if (function_exists($function)) {
  675. $store_form = $function($form, $form_state, $selected_term, $submit_disabled);
  676. $form['store_settings'][$default_store] = $store_form;
  677. }
  678. // Add in the button for the cases of no terms or too many.
  679. $form['submit_button'] = array(
  680. '#type' => 'submit',
  681. '#value' => t('Create content type'),
  682. '#name' => 'create-content',
  683. '#disabled' => $submit_disabled,
  684. );
  685. }
  686. /**
  687. * Implements an AJAX callback for the tripal_chado_vocab_select_term_form.
  688. */
  689. function tripal_admin_add_type_form_ajax_callback($form, $form_state) {
  690. return $form;
  691. }
  692. /**
  693. * Implements hook_validate() for the tripal_admin_add_type_form.
  694. *
  695. */
  696. function tripal_admin_add_type_form_validate($form, &$form_state) {
  697. $stores = module_invoke_all('vocab_storage_info');
  698. $store_select = (isset($form_state['values']['store_select'])) ? $form_state['values']['store_select'] : NULL;
  699. $clicked_button = $form_state['clicked_button']['#name'];
  700. // Don't do validation on an ajax callback.
  701. if (array_key_exists('#ajax', $form_state['triggering_element'])) {
  702. return;
  703. }
  704. if ($clicked_button =='step1-continue') {
  705. $form_state['rebuild'] = TRUE;
  706. $form_state['stage'] = 'step2';
  707. $selected = tripal_get_term_lookup_form_result($form, $form_state);
  708. if (count($selected) == 0) {
  709. form_set_error('term_match][term_name', 'Please select a vocabulary term.');
  710. }
  711. if (count($selected) > 1) {
  712. form_set_error('term_match][term_name', 'Please select only one vocabulary term.');
  713. }
  714. }
  715. if ($clicked_button =='step1-return') {
  716. $form_state['rebuild'] = TRUE;
  717. $form_state['stage'] = 'step1';
  718. }
  719. if ($clicked_button =='step2-continue') {
  720. if (!$store_select) {
  721. form_set_error('store_select', 'Please select only one vocabulary term.');
  722. }
  723. $form_state['rebuild'] = TRUE;
  724. $form_state['stage'] = 'step3';
  725. }
  726. if ($clicked_button == 'create-content') {
  727. // Call the submit hook for this form for the storage method that
  728. // will be responsible for this cotent type.
  729. $stores = module_invoke_all('vocab_storage_info');
  730. $selected_store_module = $stores[$store_select]['module'];
  731. $selected_term = $form_state['values']['term'];
  732. $function = $selected_store_module . '_field_storage_bundle_mapping_form_validate';
  733. if (function_exists($function)) {
  734. $function($form, $form_state, $selected_term);
  735. }
  736. }
  737. else {
  738. $form_state['rebuild'] = TRUE;
  739. }
  740. }
  741. /**
  742. * Implements hook_submit() for the tripal_admin_add_type_form.
  743. */
  744. function tripal_admin_add_type_form_submit($form, &$form_state) {
  745. $vocabulary = '';
  746. $accession = '';
  747. if (array_key_exists('term', $form_state['values'])) {
  748. $selected_term = $form_state['values']['term'];
  749. $store_select = $form_state['values']['store_select'];
  750. $vocabulary = $selected_term->dbxref_id->db_id->name;
  751. $accession = $selected_term->dbxref_id->accession;
  752. $term_name = $selected_term->name;
  753. // Before we try to add this type, check to see if it already exists
  754. // as a bundle.
  755. $term = tripal_load_term_entity(['vocabulary' => $vocabulary, 'accession' => $accession]);
  756. if (!$term) {
  757. // Call the submit hook for this form for the storage method that
  758. // will be responsible for this cotent type.
  759. $stores = module_invoke_all('vocab_storage_info');
  760. $selected_store_module = $stores[$store_select]['module'];
  761. $storage_args = array();
  762. $function = $selected_store_module . '_field_storage_bundle_mapping_form_submit';
  763. if (function_exists($function)) {
  764. $function($form, $form_state, $term, $storage_args);
  765. }
  766. $args = array(
  767. 'vocabulary' => $vocabulary,
  768. 'accession' => $accession,
  769. 'term_name' => $term_name,
  770. 'storage_args' => $storage_args,
  771. );
  772. global $user;
  773. $job_id = tripal_add_job("Create content type: " . $term_name . ' ('. $vocabulary . ':' . $accession . ')',
  774. 'tripal', 'tripal_create_bundle', [$args], $user->uid);
  775. if (!$job_id) {
  776. drupal_set_message($error, 'error');
  777. $form_state['redirect'] = "admin/structure/bio_data";
  778. }
  779. else {
  780. drupal_set_message('After the content type is created, please ' . l("set the user permissions", "admin/people/permissions") . ' for this new content type.');
  781. $form_state['redirect'] = "admin/structure/bio_data";
  782. }
  783. }
  784. else {
  785. drupal_set_message("The term ". $term->name . " (" . $vocabulary . ':' . $accession. ") already exists as a content type.", 'warning');
  786. }
  787. }
  788. }
  789. /**
  790. * Checks access permissions for a given entity.
  791. */
  792. function tripal_admin_access($entity) {
  793. if ($entity) {
  794. $bundle_name = $entity->name;
  795. }
  796. else {
  797. return FALSE;
  798. }
  799. // Get the bundle object.
  800. $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
  801. if (!$bundle) {
  802. tripal_report_error('tripal', TRIPAL_WARNING,
  803. 'Unable to load bundle :name when creating permissions.', array(':name' => $bundle_name));
  804. return FALSE;
  805. }
  806. // Get the administrative user roles.
  807. $admin_role = NULL;
  808. $admin_rid = variable_get('user_admin_role');
  809. if (!$admin_rid) {
  810. // If we couldn't identify a single role from the 'user_admin_role' variable
  811. // then let's get the role that is currently set to administer tripal. If
  812. // there is more than one then we don't really know which to choose unless
  813. // the default rid of '3' is present.
  814. $admin_roles = user_roles(FALSE, 'administer tripal');
  815. if (count(array_keys($admin_roles)) == 1) {
  816. $admin_rid = key($admin_roles);
  817. }
  818. // The rid 3 is Drupal's default for the admin user.
  819. else if (in_array(3, array_keys($admin_roles))) {
  820. $admin_rid = 3;
  821. }
  822. }
  823. // If we can't find a unique admin role then just don't add one and
  824. // the user will be forced to manually set permissions for the admin.
  825. if (!$admin_rid) {
  826. return FALSE;
  827. }
  828. // Define the permissions.
  829. $permission_for_role = array(
  830. 'create ' . $bundle->name => TRUE,
  831. 'view ' . $bundle->name => TRUE,
  832. 'edit ' . $bundle->name => TRUE,
  833. 'delete ' . $bundle->name => TRUE,
  834. );
  835. // Assign the permissions
  836. user_role_change_permissions($admin_rid, $permission_for_role);
  837. return TRUE;
  838. }