TripalEntityUIController.inc 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. <?php
  2. /**
  3. * UI controller.
  4. */
  5. class TripalEntityUIController extends EntityDefaultUIController {
  6. /**
  7. * Overrides hook_menu() defaults. Main reason for doing this is that
  8. * parent class hook_menu() is optimized for entity type administration.
  9. */
  10. public function hook_menu() {
  11. $items = [];
  12. // Set this on the object so classes that extend hook_menu() can use it.
  13. $this->id_count = count(explode('/', $this->path));
  14. $wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
  15. $id_count = count(explode('/', $this->path));
  16. // The content menu.
  17. $items[$this->path] = [
  18. 'title' => 'Tripal Content',
  19. 'page callback' => 'tripal_content_view',
  20. 'file' => 'includes/tripal.admin.inc',
  21. 'file path' => drupal_get_path('module', 'tripal'),
  22. 'access arguments' => ['access tripal content overview'],
  23. 'type' => MENU_LOCAL_TASK,
  24. 'weight' => -9,
  25. ];
  26. $items['bio_data/add'] = [
  27. 'title' => 'Add Tripal Content',
  28. 'page callback' => 'tripal_add_page',
  29. 'access callback' => '_tripal_entity_add_access',
  30. ];
  31. // Add a menu item for creating each bundle
  32. $bundles = array_keys($this->entityInfo['bundles']);
  33. foreach ($bundles as $bundle_name) {
  34. $matches = [];
  35. if (preg_match('/^bio_data_(.*?)$/', $bundle_name, $matches)) {
  36. $bundle = tripal_load_bundle_entity(['name' => $bundle_name]);
  37. if (!$bundle) {
  38. throw new Exception(t("Cannot find bundle that matches: %bundle_name",
  39. ['%bundle_name' => $bundle_name]));
  40. }
  41. $term_id = $matches[1];
  42. // Get the term for this bundle
  43. $term = entity_load('TripalTerm', ['id' => $term_id]);
  44. $term = reset($term);
  45. $default_description = $term->definition ? $term->definition : '';
  46. // Set a custom page for adding new tripal data entities.
  47. $items['bio_data/add/' . $term->id] = [
  48. 'title' => ucfirst($bundle->label),
  49. 'description' => tripal_get_bundle_variable('description', $bundle->id, $default_description),
  50. 'page callback' => 'drupal_get_form',
  51. 'page arguments' => ['tripal_entity_form', 2],
  52. 'access arguments' => ['create bio_data_' . $term->id],
  53. ];
  54. }
  55. }
  56. // Link for viewing a tripal data type.
  57. $items['bio_data/%'] = [
  58. 'title callback' => 'tripal_entity_title',
  59. 'title arguments' => [1],
  60. 'page callback' => 'tripal_view_entity',
  61. 'page arguments' => [1],
  62. 'access callback' => 'tripal_entity_access',
  63. 'access arguments' => ['view', 1],
  64. 'type' => MENU_CALLBACK,
  65. ];
  66. // 'View' tab for an individual entity page.
  67. $items['bio_data/%/view'] = [
  68. 'title' => 'View',
  69. 'page callback' => 'tripal_view_entity',
  70. 'page arguments' => [1],
  71. 'access callback' => 'tripal_entity_access',
  72. 'access arguments' => ['view', 1],
  73. 'type' => MENU_DEFAULT_LOCAL_TASK,
  74. 'weight' => -10,
  75. ];
  76. // 'Edit' tab for an individual entity page.
  77. $items['bio_data/' . $wildcard . '/edit'] = [
  78. 'title' => 'Edit',
  79. 'page callback' => 'drupal_get_form',
  80. 'page arguments' => ['tripal_entity_form', NULL, 1],
  81. 'access callback' => 'tripal_entity_access',
  82. 'access arguments' => ['edit', 1],
  83. 'type' => MENU_LOCAL_TASK,
  84. 'weight' => -8,
  85. ];
  86. $items['bio_data/' . $wildcard . '/reload'] = [
  87. 'title' => 'Reload',
  88. 'page callback' => 'tripal_entity_reload',
  89. 'page arguments' => [1],
  90. 'access arguments' => ['administer tripal'],
  91. 'type' => MENU_LOCAL_TASK,
  92. 'weight' => 10,
  93. ];
  94. $items['bio_data/' . $wildcard . '/unpublish'] = [
  95. 'title' => 'Unpublish',
  96. 'page callback' => 'drupal_get_form',
  97. 'page arguments' => ['tripal_entity_unpublish_form', 1],
  98. 'access callback' => 'tripal_entity_access',
  99. 'access arguments' => ['unpublish', 1],
  100. 'type' => MENU_CALLBACK,
  101. 'weight' => 11,
  102. ];
  103. $items['bio_data/' . $wildcard . '/delete'] = [
  104. 'title' => 'Delete',
  105. 'page callback' => 'drupal_get_form',
  106. 'page arguments' => ['tripal_entity_delete_form', 1],
  107. 'access callback' => 'tripal_entity_access',
  108. 'access arguments' => ['delete', 1],
  109. 'type' => MENU_CALLBACK,
  110. 'weight' => 12,
  111. ];
  112. return $items;
  113. }
  114. }
  115. /**
  116. * Menu callback to display an entity.
  117. *
  118. * As we load the entity for display, we're responsible for invoking a number
  119. * of hooks in their proper order.
  120. *
  121. * @see hook_entity_prepare_view()
  122. * @see hook_entity_view()
  123. * @see hook_entity_view_alter()
  124. */
  125. function tripal_view_entity($entity, $view_mode = 'full') {
  126. if (!is_object($entity)) {
  127. $id = intval($entity);
  128. if ($id === 0) {
  129. return drupal_not_found();
  130. }
  131. $entities = tripal_load_entity('TripalEntity', [$id]);
  132. if (empty($entities)) {
  133. return drupal_not_found();
  134. }
  135. $entity = reset($entities);
  136. }
  137. $controller = entity_get_controller($entity->type);
  138. $content = $controller->view([$entity->id => $entity]);
  139. drupal_set_title($entity->title);
  140. if ($entity->status == 0) {
  141. drupal_set_message('This page is currently unpublished', 'warning');
  142. }
  143. return $content;
  144. }
  145. /**
  146. * Provide a data listing for tripal entites (ie: biological data).
  147. *
  148. * This function is a callback in a menu item which is set in the
  149. * TripalEntityUIController class.
  150. */
  151. function tripal_content_view() {
  152. // Retrieve our data listing form and render it.
  153. $form = drupal_get_form('tripal_content_overview_form');
  154. $output = drupal_render($form);
  155. // Set the breadcrumb.
  156. $breadcrumb = [];
  157. $breadcrumb[] = l('Home', '<front>');
  158. $breadcrumb[] = l('Administration', 'admin');
  159. drupal_set_breadcrumb($breadcrumb);
  160. return $output;
  161. }
  162. /**
  163. * Display a listing of Tripal entities.
  164. *
  165. * @TODO Filters and bulk operations needed to be added to this form.
  166. *
  167. * @param array $form
  168. * @param array $form_state
  169. *
  170. * @return
  171. * A form array describing this listing to the Form API.
  172. */
  173. function tripal_content_overview_form($form, &$form_state) {
  174. global $user;
  175. // Set form defaults. The $_SESSION contains the last known selection
  176. // by this user. That should be overridden if the $_GET variable contains
  177. // values.
  178. $etype = '';
  179. $status = '';
  180. if (array_key_exists('tripal_content_overview', $_SESSION)) {
  181. $etype = $_SESSION['tripal_content_overview']['type'];
  182. $status = $_SESSION['tripal_content_overview']['status'];
  183. }
  184. $etype = array_key_exists('type', $_GET) ? $_GET['type'] : $etype;
  185. $status = array_key_exists('status', $_GET) ? $_GET['status'] : $status;
  186. $headers = [
  187. 'title' => [
  188. 'data' => t('Title'),
  189. 'type' => 'property',
  190. 'specifier' => 'title',
  191. ],
  192. 'Type',
  193. 'Term',
  194. 'Author',
  195. 'status' => [
  196. 'data' => t('Status'),
  197. 'type' => 'property',
  198. 'specifier' => 'status',
  199. ],
  200. 'changed' => [
  201. 'data' => t('Updated'),
  202. 'type' => 'property',
  203. 'specifier' => 'changed',
  204. 'sort' => 'desc',
  205. ],
  206. 'Operations',
  207. ];
  208. $rows = [];
  209. // Get the Options arrays used by the fields below. We need to build them
  210. // here because we will use them both for creating the item list below
  211. // and for the fields.
  212. $etypes = db_select('tripal_bundle', 'tb')
  213. ->fields('tb', ['name', 'label'])
  214. ->execute()
  215. ->fetchAllKeyed();
  216. $etypes = ['0' => 'any'] + $etypes;
  217. $statuses = [
  218. '0' => 'any',
  219. 'status-1' => 'published',
  220. 'status-0' => 'not published',
  221. ];
  222. // Build the list of existing filters.
  223. $items = [];
  224. if ($etype) {
  225. $items[] = 'where <strong>type</strong> is <strong>' . $etypes[$etype] . '</strong>';
  226. }
  227. if ($status) {
  228. $items[] = 'where <strong>status</strong> is <strong>' . $statuses[$status] . '</strong>';
  229. }
  230. // Add 'and' to the beginning of every filter after the first
  231. if (count($items) > 1) {
  232. for ($i = 1; $i < count($items); $i++) {
  233. $items[$i] = 'and ' . $items[$i];
  234. }
  235. }
  236. $list = theme_item_list([
  237. 'items' => $items,
  238. 'title' => '',
  239. 'type' => 'ul',
  240. 'attributes' => [],
  241. ]);
  242. // Set the title to be informative (defaults to content for some reason).
  243. drupal_set_title('Tripal Content');
  244. $form['filter'] = [
  245. '#type' => 'fieldset',
  246. '#title' => 'Show only items where',
  247. '#collapsible' => FALSE,
  248. '#collapsed' => FALSE,
  249. '#prefix' => '<div class="exposed-filters">',
  250. '#suffix' => '</div>',
  251. ];
  252. if (count($items) > 0) {
  253. $form['filter']['filters'] = [
  254. '#type' => 'item',
  255. '#markup' => $list,
  256. ];
  257. }
  258. if (!$status) {
  259. $form['filter']['status'] = [
  260. '#type' => 'select',
  261. '#title' => 'Status',
  262. '#options' => $statuses,
  263. ];
  264. }
  265. else {
  266. $form['filter']['status'] = [
  267. '#type' => 'value',
  268. '#value' => $status,
  269. ];
  270. }
  271. if (!$etype) {
  272. $form['filter']['type'] = [
  273. '#type' => 'select',
  274. '#title' => 'Content Type',
  275. '#options' => $etypes,
  276. ];
  277. }
  278. else {
  279. $form['filter']['type'] = [
  280. '#type' => 'value',
  281. '#value' => $etype,
  282. ];
  283. }
  284. $form['filter']['buttons'] = [
  285. '#type' => 'value',
  286. '#prefix' => '<div id="edit-actions" class="container-inline form-actions form-wrapper">',
  287. '#suffix' => '</div>',
  288. ];
  289. if (count($items) > 0) {
  290. if (count($items) < 2) {
  291. $form['filter']['buttons']['refinebtn'] = [
  292. '#type' => 'submit',
  293. '#value' => 'Refine',
  294. '#name' => 'refine',
  295. ];
  296. }
  297. $form['filter']['buttons']['filterbtn'] = [
  298. '#type' => 'submit',
  299. '#value' => 'Reset',
  300. '#name' => 'reset',
  301. ];
  302. }
  303. else {
  304. $form['filter']['buttons']['filterbtn'] = [
  305. '#type' => 'submit',
  306. '#value' => 'Filter',
  307. '#name' => 'filter',
  308. ];
  309. }
  310. $query = new EntityFieldQuery();
  311. $query->entityCondition('entity_type', 'TripalEntity');
  312. if ($etype) {
  313. $query->entityCondition('bundle', $etype);
  314. }
  315. if ($status) {
  316. if ($status == 'status-1') {
  317. $query->propertyCondition('status', 1);
  318. }
  319. if ($status == 'status-0') {
  320. $query->propertyCondition('status', 0);
  321. }
  322. }
  323. // Find out the total number of records and determine what page we're on, and
  324. // initialize the pager.
  325. $cquery = clone $query;
  326. $cquery->count();
  327. $num_records = $cquery->execute();
  328. // Calculate the range and create a pager.
  329. $query->pager(25);
  330. $query->tableSort($headers);
  331. $results = $query->execute();
  332. $pager = theme('pager');
  333. // For each entity retrieved add a row to the data listing.
  334. if (!isset($results['TripalEntity'])) {
  335. $results['TripalEntity'] = [];
  336. }
  337. foreach ($results['TripalEntity'] as $entity_id => $stub) {
  338. $vocabulary = '';
  339. $term_name = '';
  340. // We don't need all of the attached fields for an entity so, we'll
  341. // not use the entity_load() function. Instead just pull it from the
  342. // database table.
  343. $equery = db_select('tripal_entity', 'TE');
  344. $equery->join('tripal_bundle', 'TB', 'TE.bundle = TB.name');
  345. $equery->fields('TB', ['label']);
  346. $equery->fields('TE');
  347. $equery->condition('TE.id', $entity_id);
  348. $entity = $equery->execute()->fetchObject();
  349. if (!$entity) {
  350. continue;
  351. }
  352. // Get the term
  353. $term = entity_load('TripalTerm', ['id' => $entity->term_id]);
  354. $term = reset($term);
  355. if ($term) {
  356. $term_name = $term->name;
  357. $vocab = entity_load('TripalVocab', ['id' => $term->vocab_id]);
  358. $vocab = reset($vocab);
  359. $vocabulary = $vocab->vocabulary;
  360. }
  361. // Retrieve details about the user who created this data.
  362. $author = user_load($entity->uid);
  363. // Build the action links
  364. $links = '';
  365. if (entity_access('edit', 'TripalEntity', $entity, $user)) {
  366. $links .= '&nbsp;&nbsp;' . l('edit', 'bio_data/' . $entity->id . '/edit');
  367. }
  368. if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
  369. $links .= '&nbsp;&nbsp;' . l('unpublish', 'bio_data/' . $entity->id . '/unpublish');
  370. }
  371. // Add information to the table.
  372. $rows[] = [
  373. l($entity->title, 'bio_data/' . $entity->id),
  374. $entity->label,
  375. $vocabulary . ':' . $term_name,
  376. l($author->name, 'user/' . $entity->uid),
  377. $entity->status == 1 ? 'published' : 'unpublished',
  378. format_date($entity->changed, 'short'),
  379. $links,
  380. ];
  381. }
  382. // If there are no entites created yet then add a message to the table to
  383. // provide guidance to administrators.
  384. if (empty($rows)) {
  385. $rows[] = [
  386. [
  387. 'data' => t('No content can be found.'),
  388. 'colspan' => 7,
  389. ],
  390. ];
  391. }
  392. // Render the data listing.
  393. $table_vars = [
  394. 'header' => $headers,
  395. 'rows' => $rows,
  396. 'attributes' => [],
  397. 'sticky' => TRUE,
  398. 'caption' => '',
  399. 'colgroups' => [],
  400. 'empty' => '',
  401. ];
  402. $output = "<div><strong>Found $num_records records</strong></div>" . $pager . theme('table', $table_vars) . $pager;
  403. $form['results'] = [
  404. '#type' => 'markup',
  405. '#markup' => $output,
  406. ];
  407. return $form;
  408. }
  409. /**
  410. *
  411. */
  412. function tripal_content_overview_form_validate($form, &$form_state) {
  413. }
  414. /**
  415. *
  416. */
  417. function tripal_content_overview_form_submit($form, &$form_state) {
  418. // Always just rebuild the form on submit. that will update the
  419. // result table using the filters provided.
  420. $form_state['rebuild'] = TRUE;
  421. // Save the current user filter settings.
  422. if ($form_state['clicked_button']['#name'] == 'filter' or
  423. $form_state['clicked_button']['#name'] == 'refine') {
  424. $_SESSION['tripal_content_overview']['type'] = array_key_exists('type', $form_state['values']) ? $form_state['values']['type'] : '';
  425. $_SESSION['tripal_content_overview']['status'] = array_key_exists('status', $form_state['values']) ? $form_state['values']['status'] : '';
  426. }
  427. if ($form_state['clicked_button']['#name'] == 'reset') {
  428. unset($_SESSION['tripal_content_overview']);
  429. }
  430. }
  431. /**
  432. * Clears the cache of a given entity to force a reload.
  433. *
  434. * @param $entity_id
  435. * The entity_id of the entity to reload.
  436. */
  437. function tripal_entity_reload($entity) {
  438. $entity_id = $entity->id;
  439. $cid = 'field:TripalEntity:' . $entity_id . ':';
  440. cache_clear_all($cid, 'cache_field', TRUE);
  441. $sql = "SELECT count(*) FROM cache_field WHERE cid like :cid";
  442. $count = db_query($sql, [':cid' => $cid . '%'])->fetchField();
  443. if (!isset($count) or $count > 0) {
  444. drupal_set_message('Failed to clear the cache for this entity.');
  445. }
  446. else {
  447. // We must reload the entity. If we don't then other processes that
  448. // depended on a fully loaded entity object will mess up.
  449. $entity = tripal_load_entity('TripalEntity', [$entity->id]);
  450. drupal_set_message('Cache cleared, entity reloaded');
  451. }
  452. drupal_goto('bio_data/' . $entity_id);
  453. }
  454. /**
  455. *
  456. */
  457. function tripal_entity_form($form, &$form_state, $term_id = '', $entity = NULL) {
  458. global $user;
  459. $bundle_name = 'bio_data_' . $term_id;
  460. // Add a vertical tabs element
  461. $form['entity_form_vtabs'] = [
  462. '#type' => 'vertical_tabs',
  463. '#weight' => 999,
  464. ];
  465. // If the entity doesn't exist then create one.
  466. if (!$entity) {
  467. $entity = entity_get_controller('TripalEntity')->create([
  468. 'bundle' => $bundle_name,
  469. 'term_id' => $term_id,
  470. ]);
  471. field_attach_form('TripalEntity', $entity, $form, $form_state);
  472. $form['add_button'] = [
  473. '#type' => 'submit',
  474. '#value' => t('Save'),
  475. '#name' => 'add_data',
  476. '#weight' => 1000,
  477. ];
  478. }
  479. else {
  480. field_attach_form('TripalEntity', $entity, $form, $form_state);
  481. $form['update_button'] = [
  482. '#type' => 'submit',
  483. '#value' => t('Update'),
  484. '#name' => 'update_data',
  485. '#weight' => 1000,
  486. ];
  487. if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
  488. $form['unpublish_button'] = [
  489. '#type' => 'submit',
  490. '#value' => t('Unpublish'),
  491. '#name' => 'unpublish_data',
  492. '#weight' => 1002,
  493. ];
  494. }
  495. // Put the delete button on the far-right so that it's harder
  496. // to accidentally click it.
  497. if (entity_access('delete', 'TripalEntity', $entity, $user)) {
  498. $form['delete_button'] = [
  499. '#type' => 'submit',
  500. '#value' => t('Delete'),
  501. '#name' => 'delete_data',
  502. '#weight' => 1003,
  503. '#attributes' => ['style' => 'float: right'],
  504. ];
  505. }
  506. }
  507. $form['additional_settings'] = [
  508. '#type' => 'vertical_tabs',
  509. '#weight' => 99,
  510. ];
  511. // Node author information for administrators
  512. $form['author'] = [
  513. '#type' => 'fieldset',
  514. '#access' => user_access('administer nodes'),
  515. '#title' => t('Authoring information'),
  516. '#collapsible' => TRUE,
  517. '#collapsed' => TRUE,
  518. '#group' => 'additional_settings',
  519. '#attributes' => [
  520. 'class' => ['TripalEntity-form-author'],
  521. ],
  522. '#attached' => [
  523. 'js' => [
  524. drupal_get_path('module', 'node') . '/node.js',
  525. [
  526. 'type' => 'setting',
  527. 'data' => ['anonymous' => variable_get('anonymous', t('Anonymous'))],
  528. ],
  529. ],
  530. ],
  531. '#weight' => 90,
  532. ];
  533. $account = user_load($entity->uid);
  534. $form['author']['author_name'] = [
  535. '#type' => 'textfield',
  536. '#title' => t('Authored by'),
  537. '#maxlength' => 60,
  538. '#autocomplete_path' => 'user/autocomplete',
  539. '#default_value' => !empty($account->name) ? $account->name : '',
  540. '#weight' => -1,
  541. '#description' => t('Leave blank for %anonymous.', ['%anonymous' => variable_get('anonymous', t('Anonymous'))]),
  542. ];
  543. $form['author']['author_date'] = [
  544. '#type' => 'textfield',
  545. '#title' => t('Authored on'),
  546. '#maxlength' => 25,
  547. '#description' => t('Format: %time. The date format is YYYY-MM-DD and ' .
  548. '%timezone is the time zone offset from UTC. Leave blank to use the ' .
  549. 'time of form submission.',
  550. [
  551. '%time' => !empty($entity->created) ? date('Y-m-d H:i:s O', $entity->created) : format_date($entity->created, 'custom', 'Y-m-d H:i:s O'),
  552. '%timezone' => !empty($entity->created) ? date('O', $entity->created) : format_date($entity->created, 'custom', 'O'),
  553. ]
  554. ),
  555. '#default_value' => !empty($entity->created) ? date('Y-m-d H:i:s O', $entity->created) : '',
  556. ];
  557. // Node options for administrators
  558. $form['options'] = [
  559. '#type' => 'fieldset',
  560. '#access' => user_access('administer nodes'),
  561. '#title' => t('Publishing options'),
  562. '#collapsible' => TRUE,
  563. '#collapsed' => TRUE,
  564. '#group' => 'additional_settings',
  565. '#attributes' => [
  566. 'class' => ['node-form-options'],
  567. ],
  568. '#attached' => [
  569. 'js' => [drupal_get_path('module', 'node') . '/node.js'],
  570. ],
  571. '#weight' => 95,
  572. ];
  573. $form['options']['status'] = [
  574. '#type' => 'checkbox',
  575. '#title' => t('Published'),
  576. '#default_value' => $entity->status,
  577. ];
  578. $form['cancel_button'] = [
  579. '#type' => 'submit',
  580. '#value' => t('Cancel'),
  581. '#name' => 'cancel_data',
  582. '#weight' => 1001,
  583. '#limit_validation_errors' => [['']],
  584. ];
  585. // The entity object must be added to the $form_state in order for
  586. // the Entity API to work. It must have a key of the entity name.
  587. $form_state['TripalEntity'] = $entity;
  588. $form['#prefix'] = "<div id='$bundle_name-entity-form'>";
  589. $form['#suffix'] = "</div>";
  590. $form['#submit'][] = 'tripal_entity_form_submit';
  591. return $form;
  592. }
  593. /**
  594. * An Ajax callback for the tripal_entity_form.
  595. */
  596. function tripal_entity_form_ajax_callback($form, $form_state) {
  597. // return the form so Drupal can update the content on the page
  598. return $form;
  599. }
  600. /**
  601. * Implements hook_validate() for the tripal_entity_form.
  602. */
  603. function tripal_entity_form_validate($form, &$form_state) {
  604. // If the user is cancelling or deleting the entity then don't validate.
  605. if (array_key_exists('clicked_button', $form_state) and
  606. ($form_state['clicked_button']['#name'] == 'cancel_data' or
  607. $form_state['clicked_button']['#name'] == 'delete_data')) {
  608. return;
  609. }
  610. // For adds and updates, perform validation.
  611. $entity = $form_state['TripalEntity'];
  612. field_attach_form_validate('TripalEntity', $entity, $form, $form_state);
  613. $username = $form_state['values']['author_name'];
  614. $user = user_load_by_name($username);
  615. if (!$user) {
  616. form_set_error('author_name', 'Please provide a valid author name.');
  617. }
  618. try {
  619. $create_date = new DateTime($form_state['values']['author_date']);
  620. } catch (Exception $e) {
  621. form_set_error('author_date', 'Please provide a valid authored on date.');
  622. }
  623. }
  624. /**
  625. * Implements hook_submit() for the tripal_entity_form.
  626. */
  627. function tripal_entity_form_submit($form, &$form_state) {
  628. $entity = $form_state['TripalEntity'];
  629. global $user;
  630. if ($form_state['clicked_button']['#name'] == 'cancel_data') {
  631. if (property_exists($entity, 'id')) {
  632. $form_state['redirect'] = "bio_data/" . $entity->id;
  633. }
  634. else {
  635. $form_state['redirect'] = 'bio_data/add';
  636. }
  637. return;
  638. }
  639. if ($form_state['clicked_button']['#name'] == 'delete_data') {
  640. if (entity_access('delete', 'TripalEntity', $entity, $user)) {
  641. $form_state['redirect'] = 'bio_data/' . $entity->id . '/delete';
  642. }
  643. return;
  644. }
  645. if ($form_state['clicked_button']['#name'] == 'unpublish_data') {
  646. if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
  647. $form_state['redirect'] = 'bio_data/' . $entity->id . '/unpublish';
  648. }
  649. return;
  650. }
  651. $username = $form_state['values']['author_name'];
  652. $user = user_load_by_name($username);
  653. $entity->uid = $user->uid;
  654. $create_date = $form_state['values']['author_date'];
  655. $entity->created = $create_date;
  656. $published = $form_state['values']['status'];
  657. $entity->status = $published;
  658. // Allow the fields to perform actions prior to submit.
  659. $instances = field_info_instances('TripalEntity', $entity->bundle);
  660. $langcode = 'und';
  661. foreach ($instances as $field_name => $instance) {
  662. $entity_type = $instance['entity_type'];
  663. if ($entity_type == 'TripalEntity' and array_key_exists($field_name, $form)) {
  664. foreach ($form[$field_name][$langcode] as $delta => $field_form) {
  665. if (!preg_match('/^\d+$/', $delta)) {
  666. continue;
  667. }
  668. $widget_type = $instance['widget']['type'];
  669. if (tripal_load_include_field_class($widget_type)) {
  670. $field = $field_form['#field'];
  671. $widget = new $widget_type($field, $instance);
  672. $widget->submit($form, $form_state, $entity_type, $entity, $langcode, $delta);
  673. }
  674. }
  675. }
  676. }
  677. $entityform = entity_ui_controller('TripalEntity')->entityFormSubmitBuildEntity($form, $form_state);
  678. if ($entityform->save()) {
  679. $form_state['redirect'] = "bio_data/" . $entity->id;
  680. }
  681. else {
  682. drupal_set_message('Cannot save entity', 'error');
  683. }
  684. }
  685. /**
  686. * Provides a list of TripalEntity types (bundles) for the user to add.
  687. *
  688. * This function is a callback in a menu item which is set in the
  689. * TripalEntityUIController class.
  690. */
  691. function tripal_add_page() {
  692. // The content array to be returned.
  693. $content = [];
  694. $content['instructions'] = [
  695. '#type' => 'markup',
  696. '#markup' => 'This page provides links for creating pages for Tripal ' .
  697. 'supported content types. These content types are organized by categories. ' .
  698. 'Please note, however, that the categorization is the most common use ' .
  699. 'for a given type. Some types may be useful in other "categories" as well.',
  700. '#weight' => -15,
  701. ];
  702. // Get the list of categories.
  703. $select = "
  704. SELECT TBV.value as category
  705. FROM tripal_bundle_variables TBV
  706. INNER JOIN tripal_variables TV on TV.variable_id = TBV.variable_id
  707. WHERE TV.name = 'bundle_category'
  708. ";
  709. $categories = db_query($select);
  710. // Build the fieldsets for the categories.
  711. $fieldsets = [];
  712. $category_weight = 1;
  713. while ($category = $categories->fetchField()) {
  714. $machine_name = preg_replace('/[^\w]/', '_', $category);
  715. $fieldsets[$machine_name . '_fieldset'] = [
  716. '#type' => 'fieldset',
  717. '#title' => $category,
  718. '#collapsed' => TRUE,
  719. '#collapsible' => TRUE,
  720. '#attributes' => [
  721. 'class' => ['collapsible', 'tripal-content-list'],
  722. ],
  723. '#attached' => [
  724. 'js' => ['misc/collapse.js', 'misc/form.js'],
  725. ],
  726. '#weight' => $category == 'General' ? -10 : $category_weight++,
  727. ];
  728. }
  729. // Create the "other" fieldset, and set it's weight to 100 so it goes to
  730. // the bottom.
  731. $fieldsets['Other_fieldset'] = [
  732. '#type' => 'fieldset',
  733. '#title' => 'Other',
  734. '#weight' => 100,
  735. '#collapsed' => TRUE,
  736. '#collapsible' => TRUE,
  737. '#attributes' => [
  738. 'class' => ['collapsible'],
  739. ],
  740. '#attached' => [
  741. 'js' => ['misc/collapse.js', 'misc/form.js'],
  742. ],
  743. ];
  744. // Get the list of bundles and iterate through them.
  745. $select = "SELECT id, name, label FROM tripal_bundle ORDER BY label";
  746. $bundles = db_query($select);
  747. while ($bundle = $bundles->fetchObject()) {
  748. // Lookup the bundle category.
  749. $sql = "
  750. SELECT TBV.value as category
  751. FROM tripal_bundle TB
  752. INNER JOIN tripal_bundle_variables TBV on TB.id = TBV.bundle_id
  753. INNER JOIN tripal_variables TV on TV.variable_id = TBV.variable_id
  754. WHERE TV.name = 'bundle_category' and TB.id = :id;
  755. ";
  756. $category = db_query($sql, [':id' => $bundle->id])->fetchField();
  757. if (!$category) {
  758. $category = 'Other';
  759. }
  760. $machine_name = preg_replace('/[^\w]/', '_', $category);
  761. $bundle = tripal_load_bundle_entity(['id' => $bundle->id]);
  762. if (!$bundle) {
  763. continue;
  764. }
  765. if (user_access('create ' . $bundle->name)) {
  766. if (!array_key_exists($machine_name . '_fieldset', $content)) {
  767. $content[$machine_name . '_fieldset'] = $fieldsets[$machine_name . '_fieldset'];
  768. }
  769. $content[$machine_name . '_fieldset'][$bundle->name] = [
  770. '#type' => 'item',
  771. '#markup' => l($bundle->label, 'bio_data/add/' . $bundle->id),
  772. '#description' => $bundle->term->definition,
  773. ];
  774. }
  775. }
  776. // Now iterate through the fieldsets and set their weight
  777. return $content;
  778. }
  779. /**
  780. * Returns HTML for a list of available node types for node creation.
  781. *
  782. * @param $variables
  783. * An associative array containing:
  784. * - content: An array of content types.
  785. *
  786. * @ingroup themeable
  787. */
  788. function theme_tripal_add_list($variables) {
  789. $content = $variables['content'];
  790. $output = '';
  791. if ($content) {
  792. $output = '<dl class="node-type-list">';
  793. foreach ($content as $item) {
  794. $output .= '<dt>' . l($item['title'], $item['href'], $item['localized_options']) . '</dt>';
  795. $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>';
  796. }
  797. $output .= '</dl>';
  798. }
  799. else {
  800. $output = tripal_set_message(
  801. t('This page is for adding Tripal content to your site. However, before you can add data you have to specify what types of data your site will support. For example, if you want to add genes to be displayed to users, you must first create a data type "gene".'),
  802. TRIPAL_INFO,
  803. ['return_html' => TRUE]
  804. );
  805. $output .= '<p>' . t('You have not created any biological data types yet. ' .
  806. 'Go to the <a href="@create-content">data type creation page</a> to ' .
  807. 'add a new data type.',
  808. ['@create-content' => url('admin/structure/bio_data/add')]) . '</p>';
  809. }
  810. return $output;
  811. }
  812. /**
  813. * Form callback: confirmation form for unpublishing a tripal_entity.
  814. *
  815. * @param $tripal_entity
  816. * The tripal_entity to delete
  817. *
  818. * @see confirm_form()
  819. */
  820. function tripal_entity_unpublish_form($form, &$form_state, $entity) {
  821. $form_state['entity'] = $entity;
  822. $form['#submit'][] = 'tripal_entity_unpublish_form_submit';
  823. $form = confirm_form($form,
  824. t('Unpublish the record "%title"? This will delete the Drupal record, but not the underlying (eg Chado) record.',
  825. ['%title' => $entity->title]), 'admin/content/bio_data',
  826. '<p>' . t('This action cannot be undone.') . '</p>',
  827. t('Yes, Unpublish'), t('No, Cancel'), 'confirm');
  828. return $form;
  829. }
  830. /**
  831. * Submit callback for tripal_entity_unpublish_form
  832. */
  833. function tripal_entity_unpublish_form_submit($form, &$form_state) {
  834. global $user;
  835. $entity = $form_state['entity'];
  836. if (!entity_access('unpublish', 'TripalEntity', $entity, $user)) {
  837. drupal_set_message(t('You do not have permission to unpublish this content.'), "error");
  838. $form_state['redirect'] = 'admin/content/bio_data';
  839. return;
  840. }
  841. $entity_controller = new TripalEntityController($entity->type);
  842. if ($entity_controller->unpublish([$entity->id])) {
  843. drupal_set_message(t('The record "%name" has been unpublished. The record, however, remains in the database and you can republish it later.', ['%name' => $entity->title]));
  844. $form_state['redirect'] = 'admin/content/bio_data';
  845. }
  846. else {
  847. drupal_set_message(t('The record "%name" was not unpublished.', ['%name' => $entity->title]), "error");
  848. }
  849. }
  850. /**
  851. * Form callback: confirmation form for deleting a tripal_entity.
  852. *
  853. * @param $tripal_entity
  854. * The tripal_entity to delete
  855. *
  856. * @see confirm_form()
  857. */
  858. function tripal_entity_delete_form($form, &$form_state, $entity) {
  859. $form_state['entity'] = $entity;
  860. $form['#submit'][] = 'tripal_entity_delete_form_submit';
  861. $form = confirm_form($form,
  862. t('Delete the record "%title"?',
  863. ['%title' => $entity->title]), 'admin/content/bio_data',
  864. '<p>' . t('This action cannot be undone. It will result in this record being unpublished and completely removed from the database. Any downstream records that depend on this entry will also be unpublished and completely removed as well. Please delete with caution!') . '</p>', t('Yes, Delete'), t('No, Cancel'), 'confirm');
  865. return $form;
  866. }
  867. /**
  868. * Submit callback for tripal_entity_unpublish_form
  869. */
  870. function tripal_entity_delete_form_submit($form, &$form_state) {
  871. global $user;
  872. $entity = $form_state['entity'];
  873. if (!entity_access('delete', 'TripalEntity', $entity, $user)) {
  874. drupal_set_message(t('You do not have permission to delete this content.'), "error");
  875. $form_state['redirect'] = 'admin/content/bio_data';
  876. return;
  877. }
  878. $entity_controller = new TripalEntityController($entity->type);
  879. if ($entity_controller->delete([$entity->id])) {
  880. drupal_set_message(t('The record "%name" was deleted along with any dependent, downstream records. Deleted records are no longer in the database. However, the site may still have published records. Therefore, a job has been added to remove any published but orphaned records.', ['%name' => $entity->title]));
  881. $form_state['redirect'] = 'admin/content/bio_data';
  882. }
  883. else {
  884. drupal_set_message(t('The record "%name" was not deleted.', ['%name' => $entity->title]), "error");
  885. $form_state['redirect'] = 'admin/content/bio_data';
  886. }
  887. }
  888. /**
  889. * A helper function for checking if a user can add Tripal Content.
  890. *
  891. * This function is a callback for the bio_data/add menu path.
  892. */
  893. function _tripal_entity_add_access() {
  894. global $user;
  895. $types = tripal_get_content_types();
  896. foreach ($types as $type) {
  897. if (user_access('create ' . $type->name, $user)) {
  898. return TRUE;
  899. }
  900. }
  901. return FALSE;
  902. }