tripal_entities.module 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. <?php
  2. // http://www.bluespark.com/blog/drupal-entities-part-3-programming-hello-drupal-entity
  3. // http://dikini.net/31.08.2010/entities_bundles_fields_and_field_instances
  4. /**
  5. * Implement hook_entity_info().
  6. */
  7. function tripal_entities_entity_info() {
  8. $entities = array();
  9. $entities['chado_data'] = array(
  10. // A human readable label to identify our entity.
  11. 'label' => t('Chado Data'),
  12. 'plural label' => t('Vocabulary Terms'),
  13. // The controller for our Entity, extending the Drupal core controller.
  14. 'controller class' => 'ChadoDataController',
  15. // The table for this entity defined in hook_schema()
  16. 'base table' => 'chado_data',
  17. // Returns the uri elements of an entity.
  18. 'uri callback' => 'tripal_entities_vocbulary_term_uri',
  19. // IF fieldable == FALSE, we can't attach fields.
  20. 'fieldable' => TRUE,
  21. // entity_keys tells the controller what database fields are used for key
  22. // functions. It is not required if we don't have bundles or revisions.
  23. // Here we do not support a revision, so that entity key is omitted.
  24. 'entity keys' => array(
  25. 'id' => 'entity_id',
  26. 'bundle' => 'type',
  27. ),
  28. 'bundle keys' => array(
  29. 'bundle' => 'type',
  30. ),
  31. // FALSE disables caching. Caching functionality is handled by Drupal core.
  32. 'static cache' => FALSE,
  33. // Bundles are defined by the model types below
  34. 'bundles' => array(),
  35. );
  36. // Bundles are alternative groups of fields or configuration
  37. // associated with a base entity type.
  38. // We want to dynamically add the bundles (or term types) to the entity.
  39. $values = array(
  40. 'cv_id' => array(
  41. 'name' => 'sequence'
  42. ),
  43. 'name' => 'gene',
  44. );
  45. $cvterm = chado_generate_var('cvterm', $values);
  46. $label = preg_replace('/_/', ' ', ucwords($cvterm->name));
  47. $bundle_id = $cvterm->dbxref_id->db_id->name . '_' . $cvterm->dbxref_id->accession;
  48. $entities['trp_vocabulary_term']['bundles'][$bundle_id] = array(
  49. 'label' => $label,
  50. 'admin' => array(
  51. 'path' => 'admin/structure/chado_data/manage',
  52. 'access arguments' => array('administer chado_data entities'),
  53. ),
  54. 'entity keys' => array(
  55. 'id' => 'entity_id',
  56. 'bundle' => 'bundle',
  57. ),
  58. );
  59. return $entities;
  60. }
  61. /**
  62. * Fetch a basic object.
  63. *
  64. * This function ends up being a shim between the menu system and
  65. * chado_data_load_multiple().
  66. *
  67. * @param int $entity_id
  68. * Integer specifying the basic entity id.
  69. * @param bool $reset
  70. * A boolean indicating that the internal cache should be reset.
  71. *
  72. * @return object
  73. * A fully-loaded $chado_data object or FALSE if it cannot be loaded.
  74. *
  75. */
  76. function chado_data_load($entity_id = NULL, $reset = FALSE) {
  77. $entity_ids = (isset($entity_id) ? array($entity_id) : array());
  78. $basic = chado_data_load_multiple($entity_ids, array(), $reset);
  79. return $basic ? reset($basic) : FALSE;
  80. }
  81. /**
  82. * Loads multiple basic entities.
  83. *
  84. * We only need to pass this request along to entity_load(), which
  85. * will in turn call the load() method of our entity controller class.
  86. */
  87. function chado_data_load_multiple($entity_ids = array(), $conditions = array(), $reset = FALSE){
  88. return entity_load('chado_data', $entity_ids, $conditions, $reset);
  89. }
  90. /**
  91. * Implements hook_menu().
  92. */
  93. function tripal_entities_menu() {
  94. // This provides a place for Field API to hang its own
  95. // interface and has to be the same as what was defined
  96. // in basic_entity_info() above.
  97. $items['admin/structure/chado_data/manage'] = array(
  98. 'title' => 'Chado Data',
  99. 'description' => t('Manage chado records, including default status, fields, settings, etc.'),
  100. 'page callback' => 'tripal_entities_list_entities',
  101. 'access arguments' => array('administer chado_data'),
  102. );
  103. // Add entities.
  104. $items['admin/structure/chado_data/manage/add'] = array(
  105. 'title' => 'Add Chado Data',
  106. 'page callback' => 'drupal_get_form',
  107. 'page arguments' => array('chado_data_form'),
  108. 'access arguments' => array('create chado_data entities'),
  109. 'type' => MENU_LOCAL_ACTION,
  110. );
  111. // List of all chado_data entities.
  112. $items['admin/structure/chado_data/manage/list'] = array(
  113. 'title' => 'List',
  114. 'type' => MENU_DEFAULT_LOCAL_TASK,
  115. );
  116. // The page to view our entities - needs to follow what
  117. // is defined in basic_uri and will use load_basic to retrieve
  118. // the necessary entity info.
  119. $items['chado_data/%chado_data'] = array(
  120. 'title callback' => 'chado_data_title',
  121. 'title arguments' => array(1),
  122. 'page callback' => 'chado_data_view',
  123. 'page arguments' => array(1),
  124. 'access arguments' => array('view chado_data'),
  125. 'type' => MENU_CALLBACK,
  126. );
  127. // 'View' tab for an individual entity page.
  128. $items['chado_data/%chado_data/view'] = array(
  129. 'title' => 'View',
  130. 'type' => MENU_DEFAULT_LOCAL_TASK,
  131. 'weight' => -10,
  132. );
  133. // 'Edit' tab for an individual entity page.
  134. $items['chado_data/%chado_data/edit'] = array(
  135. 'title' => 'Edit',
  136. 'page callback' => 'drupal_get_form',
  137. 'page arguments' => array('chado_data_form', 1),
  138. 'access arguments' => array('edit any chado_data entity'),
  139. 'type' => MENU_LOCAL_TASK,
  140. );
  141. // Add example entities.
  142. $items['examples/entity_example/basic/add'] = array(
  143. 'title' => 'Add Chado Data',
  144. 'page callback' => 'drupal_get_form',
  145. 'page arguments' => array('chado_data_form'),
  146. 'access arguments' => array('create chado_data entities'),
  147. );
  148. return $items;
  149. }
  150. /**
  151. * We save the entity by calling the controller.
  152. */
  153. function chado_data_save(&$entity) {
  154. return entity_get_controller('chado_data')->save($entity);
  155. }
  156. /**
  157. * Use the controller to delete the entity.
  158. */
  159. function chado_data_delete($entity) {
  160. entity_get_controller('chado_data')->delete($entity);
  161. }
  162. /**
  163. * Implements hook_permission().
  164. */
  165. function tripal_entities_permission() {
  166. $permissions = array(
  167. 'administer chado_data entities' => array(
  168. 'title' => t('Administer Chado data entity'),
  169. ),
  170. 'view any chado_data entity' => array(
  171. 'title' => t('View any Chado data entity'),
  172. ),
  173. 'edit any chado_data entity' => array(
  174. 'title' => t('Edit any Chado data entity'),
  175. ),
  176. 'create chado_data entities' => array(
  177. 'title' => t('Create Chado data entities'),
  178. ),
  179. );
  180. return $permissions;
  181. }
  182. /**
  183. * Returns a render array with all chado_data entities.
  184. *
  185. * @see pager_example.module
  186. */
  187. function tripal_entities_list_entities() {
  188. $content = array();
  189. // Load all of our entities.
  190. $entities = chado_data_load_multiple();
  191. if (!empty($entities)) {
  192. foreach ($entities as $entity) {
  193. // Create tabular rows for our entities.
  194. $rows[] = array(
  195. 'data' => array(
  196. 'id' => $entity->entity_id,
  197. 'title' => l($entity->title, 'chado_data/' . $entity->entity_id),
  198. 'type' => $entity->type,
  199. ),
  200. );
  201. }
  202. // Put our entities into a themed table. See theme_table() for details.
  203. $content['entity_table'] = array(
  204. '#theme' => 'table',
  205. '#rows' => $rows,
  206. '#header' => array(t('ID'), t('Item Description'), t('Bundle')),
  207. );
  208. }
  209. else {
  210. // There were no entities. Tell the user.
  211. $content[] = array(
  212. '#type' => 'item',
  213. '#markup' => t('No chado data entities currently exist.'),
  214. );
  215. }
  216. return $content;
  217. }
  218. /**
  219. *
  220. */
  221. function chado_data_title($entity){
  222. return $entity->title;
  223. }
  224. /**
  225. * Implements the uri callback.
  226. */
  227. function chado_data_uri($entity) {
  228. return array(
  229. 'path' => 'chado_data/' . $entity->entity_id,
  230. );
  231. }
  232. /**
  233. * Menu callback to display an entity.
  234. *
  235. * As we load the entity for display, we're responsible for invoking a number
  236. * of hooks in their proper order.
  237. *
  238. * @see hook_entity_prepare_view()
  239. * @see hook_entity_view()
  240. * @see hook_entity_view_alter()
  241. */
  242. function chado_data_view($entity, $view_mode = 'full') {
  243. // Our entity type, for convenience.
  244. $entity_type = 'chado_data';
  245. // Start setting up the content.
  246. $entity->content = array(
  247. '#view_mode' => $view_mode,
  248. );
  249. // Build fields content - this is where the Field API really comes in to play.
  250. // The task has very little code here because it all gets taken care of by
  251. // field module. field_attach_prepare_view() lets the fields load any
  252. // data they need before viewing.
  253. field_attach_prepare_view($entity_type, array($entity->entity_id => $entity),
  254. $view_mode);
  255. // We call entity_prepare_view() so it can invoke hook_entity_prepare_view()
  256. // for us.
  257. entity_prepare_view($entity_type, array($entity->entity_id => $entity));
  258. // Now field_attach_view() generates the content for the fields.
  259. $entity->content += field_attach_view($entity_type, $entity, $view_mode);
  260. // OK, Field API done, now we can set up some of our own data.
  261. // $entity->content['created'] = array(
  262. // '#type' => 'item',
  263. // '#title' => t('Created date'),
  264. // '#markup' => format_date($entity->created),
  265. // );
  266. // Now to invoke some hooks. We need the language code for
  267. // hook_entity_view(), so let's get that.
  268. global $language;
  269. $langcode = $language->language;
  270. // And now invoke hook_entity_view().
  271. module_invoke_all('entity_view', $entity, $entity_type, $view_mode, $langcode);
  272. // Now invoke hook_entity_view_alter().
  273. drupal_alter(array('chado_data', 'entity_view'), $entity->content, $entity_type);
  274. // And finally return the content.
  275. return $entity->content;
  276. }
  277. /**
  278. *
  279. */
  280. function chado_data_page_view($entity, $view_mode = 'full'){
  281. $entity->content = array();
  282. // Build fields content.
  283. field_attach_prepare_view('chado_data', array($entity->entity_id => $entity), $view_mode);
  284. entity_prepare_view('chado_data', array($entity->entity_id => $entity));
  285. $entity->content += field_attach_view('chado_data', $entity, $view_mode);
  286. return $entity->content;
  287. }
  288. /**
  289. *
  290. */
  291. function tripal_entities_vocbulary_term_uri($entity) {
  292. return array(
  293. 'path' => 'chado_data/' . $entity->entity_id,
  294. );
  295. }
  296. /**
  297. *
  298. */
  299. function chado_data_form($form, &$form_state, $entity = NULL) {
  300. // Set the defaults.
  301. $cv_id = NULL;
  302. $term_name = NULL;
  303. $entity_id = NULL;
  304. $cvterm = NULL;
  305. // Set defaults if an entity was provided.
  306. if ($entity) {
  307. $entity_id = $entity->entity_id;
  308. $values = array('cvterm_id' => $entity->cvterm_id);
  309. $cvterm = chado_generate_var('cvterm', $values);
  310. $cv_id = $cvterm->cv_id->cv_id;
  311. $term_name = $cvterm->name;
  312. }
  313. // Set defaults using the form state.
  314. if (array_key_exists('values', $form_state)) {
  315. $cv_id = array_key_exists('cv_id', $form_state['values']) ? $form_state['values']['cv_id'] : NULL;
  316. $term_name = array_key_exists('term_name', $form_state['values']) ? $form_state['values']['term_name'] : NULL;
  317. // Get the cvterm that matches
  318. $values = array(
  319. 'cv_id' => $cv_id,
  320. 'name' => $term_name
  321. );
  322. $cvterm = chado_generate_var('cvterm', $values);
  323. }
  324. // Add in the IDs for the entity.
  325. if ($entity) {
  326. $form['entity_id'] = array(
  327. '#type' => 'hidden',
  328. '#value' => $entity_id,
  329. );
  330. $form['entity'] = array(
  331. '#type' => 'value',
  332. '#value' => $entity,
  333. );
  334. $form['record_id'] = array(
  335. '#type' => 'hidden',
  336. '#value' => $entity->record_id,
  337. );
  338. }
  339. // Let the user select the vocabulary and chado_data but only if they haven't
  340. // already selected a chado_data.
  341. $cvs = tripal_get_cv_select_options();
  342. if (!$term_name) {
  343. $form['cv_id'] = array(
  344. '#type' => 'select',
  345. '#title' => t('Vocabulary'),
  346. '#options' => $cvs,
  347. '#required' => TRUE,
  348. '#description' => t('Select a vocabulary that contains the term for the type of data you want to add.'),
  349. '#default_value' => $cv_id,
  350. '#ajax' => array(
  351. 'callback' => "chado_data_form_ajax_callback",
  352. 'wrapper' => 'chado_data_form',
  353. 'effect' => 'fade',
  354. 'method' => 'replace'
  355. )
  356. );
  357. }
  358. // If we have a CV ID then we want to provide an autocomplete field
  359. if ($cv_id and !$term_name) {
  360. $form['cvterm_select']['term_name'] = array(
  361. '#title' => t('Record Type'),
  362. '#type' => 'textfield',
  363. '#description' => t("Enter the name of a term within the selected vocabulary for the record type you want to enter."),
  364. '#required' => TRUE,
  365. '#default_value' => $term_name,
  366. '#autocomplete_path' => "admin/tripal/chado/tripal_cv/cvterm/auto_name/$cv_id",
  367. );
  368. $form['cvterm_select']['select_button'] = array(
  369. '#type' => 'submit',
  370. '#value' => t('Use this term'),
  371. '#name' => 'select_cvterm',
  372. );
  373. }
  374. // Once the CV term is selected then provide the other fields.
  375. if ($cvterm) {
  376. $bundle_id = $cvterm->dbxref_id->db_id->name . '_' . $cvterm->dbxref_id->accession;
  377. $form['cv_id'] = array(
  378. '#type' => 'hidden',
  379. '#value' => $cv_id,
  380. );
  381. $form['term_name'] = array(
  382. '#type' => 'hidden',
  383. '#value' => $term_name,
  384. );
  385. $form['cvterm_id'] = array(
  386. '#type' => 'hidden',
  387. '#value' => $cvterm->cvterm_id,
  388. );
  389. $form['type'] = array(
  390. '#type' => 'hidden',
  391. '#value' => $bundle_id,
  392. );
  393. $form['details'] = array(
  394. '#type' => 'fieldset',
  395. '#title' => 'Record Type',
  396. '#collapsable' => FALSE,
  397. '#weight' => -100,
  398. );
  399. $form['details']['cv_name_shown'] = array(
  400. '#type' => 'item',
  401. '#title' => 'Vocabulary',
  402. '#markup' => $cvterm->cv_id->name,
  403. );
  404. $form['details']['term_name_shown'] = array(
  405. '#type' => 'item',
  406. '#title' => 'Term',
  407. '#markup' => $cvterm->name,
  408. );
  409. /*
  410. // Drupal field types and settings:
  411. // https://www.drupal.org/node/1879542
  412. $field = array(
  413. 'field_name' => 'feature__name',
  414. 'type' => 'text',
  415. 'cardinality' => 1,
  416. 'storage' => array(
  417. 'type' => 'tripal_entities_storage'
  418. ),
  419. );
  420. field_create_field($field);
  421. $field_instance = array(
  422. 'field_name' => 'feature__name',
  423. 'label' => 'Name',
  424. 'widget' => array(
  425. 'type' => 'text_textfield'
  426. ),
  427. 'entity_type' => 'chado_data',
  428. 'required' => 'true',
  429. 'settings' => array(
  430. 'max_length' => 255
  431. ),
  432. 'bundle' => $bundle_id,
  433. );
  434. field_create_instance($field_instance);
  435. $field = array(
  436. 'field_name' => 'feature__uniquename',
  437. 'type' => 'text',
  438. 'cardinality' => 1,
  439. 'storage' => array(
  440. 'type' => 'tripal_entities_storage'
  441. ),
  442. );
  443. field_create_field($field);
  444. $field_instance = array(
  445. 'field_name' => 'feature__uniquename',
  446. 'label' => 'Unique Name',
  447. 'widget' => array(
  448. 'type' => 'text_textfield'
  449. ),
  450. 'entity_type' => 'chado_data',
  451. 'required' => 'true',
  452. 'settings' => array(
  453. 'max_length' => 255
  454. ),
  455. 'bundle' => $bundle_id,
  456. );
  457. field_create_instance($field_instance);
  458. $field = array(
  459. 'field_name' => 'feature__organism_id',
  460. 'type' => 'organism_id',
  461. 'cardinality' => 1,
  462. 'storage' => array(
  463. 'type' => 'tripal_entities_storage'
  464. ),
  465. );
  466. field_create_field($field);
  467. $field_instance = array(
  468. 'field_name' => 'feature__organism_id',
  469. 'label' => 'Organism',
  470. 'entity_type' => 'chado_data',
  471. 'required' => 'true',
  472. 'settings' => array(),
  473. 'bundle' => $bundle_id,
  474. );
  475. field_create_instance($field_instance);
  476. */
  477. // Create the object for this entity instance. The entity instance type
  478. // is always the name of the term.
  479. if (!$entity) {
  480. $entity = new stdClass();
  481. $entity->entity_id = NULL;
  482. $entity->type = $bundle_id;
  483. }
  484. $form['#parents'] = array('attached');
  485. field_attach_form('chado_data', $entity, $form, $form_state);
  486. if (!$entity_id) {
  487. $form['submit'] = array(
  488. '#type' => 'submit',
  489. '#value' => t('Add a new ' . $cvterm->name),
  490. '#name' => 'add_data',
  491. '#weight' => 1000
  492. );
  493. }
  494. else {
  495. $form['submit'] = array(
  496. '#type' => 'submit',
  497. '#value' => t('Update'),
  498. '#name' => 'update_data',
  499. '#weight' => 1000
  500. );
  501. }
  502. }
  503. $form['cancel'] = array(
  504. '#type' => 'submit',
  505. '#value' => t('Cancel'),
  506. '#name' => 'cancel',
  507. '#weight' => 1000
  508. );
  509. $form['#prefix'] = '<div id="chado_data_form">';
  510. $form['#suffix'] = '</div>';
  511. return $form;
  512. }
  513. /**
  514. * Implements hook_field_info().
  515. */
  516. function tripal_entities_field_info() {
  517. $fields = array(
  518. 'organism_id' => array(
  519. 'label' => t('Organism'),
  520. 'description' => t('A field for specifying an organism.'),
  521. 'default_widget' => 'tripal_entities_organism_select_widget',
  522. 'default_formatter' => 'tripal_entities_organism_formatter',
  523. 'settings' => array(),
  524. 'storage' => array(
  525. 'type' => 'tripal_entities_storage',
  526. 'module' => 'tripal_entities',
  527. 'active' => TRUE
  528. ),
  529. ),
  530. );
  531. return $fields;
  532. }
  533. /**
  534. * Implements hook_field_widget_info().
  535. */
  536. function tripal_entities_field_widget_info() {
  537. return array(
  538. 'tripal_entities_organism_select_widget' => array(
  539. 'label' => t('Organism Select'),
  540. 'field types' => array('organism_id')
  541. ),
  542. );
  543. }
  544. /**
  545. * Implements hook_field_formatter_info().
  546. */
  547. function tripal_entities_field_formatter_info() {
  548. return array(
  549. 'tripal_entities_organism_formatter' => array(
  550. 'label' => t('Organism'),
  551. 'field types' => array('organism_id')
  552. ),
  553. );
  554. }
  555. /**
  556. * Implements hook_field_formatter_view().
  557. *
  558. * Two formatters are implemented.
  559. * - field_example_simple_text just outputs markup indicating the color that
  560. * was entered and uses an inline style to set the text color to that value.
  561. * - field_example_color_background does the same but also changes the
  562. * background color of div.region-content.
  563. *
  564. * @see field_example_field_formatter_info()
  565. */
  566. function tripal_entities_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  567. $element = array();
  568. switch ($display['type']) {
  569. // This formatter simply outputs the field as text and with a color.
  570. case 'tripal_entities_organism_formatter':
  571. foreach ($items as $delta => $item) {
  572. $organism = chado_select_record('organism', array('genus', 'species'), array('organism_id' => $item['value']));
  573. $element[$delta] = array(
  574. // We create a render array to produce the desired markup,
  575. // "<p>Genus Species</p>".
  576. // See theme_html_tag().
  577. '#type' => 'html_tag',
  578. '#tag' => 'p',
  579. '#value' => '<i>' . $organism[0]->genus .' ' . $organism[0]->species . '</i>',
  580. );
  581. }
  582. break;
  583. }
  584. return $element;
  585. }
  586. /**
  587. * Implements hook_field_widget_form().
  588. */
  589. function tripal_entities_field_widget_form(&$form, &$form_state, $field,
  590. $instance, $langcode, $items, $delta, $element) {
  591. $widget = $element;
  592. $widget['#delta'] = $delta;
  593. switch ($instance['widget']['type']) {
  594. case 'tripal_entities_organism_select_widget':
  595. $options = tripal_get_organism_select_options();
  596. $widget += array(
  597. '#type' => 'select',
  598. '#title' => $element['#title'],
  599. '#description' => $element['#description'],
  600. '#options' => $options,
  601. '#default_value' => $items[0]['value'],
  602. '#required' => $element['#required'],
  603. '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
  604. '#delta' => $delta,
  605. '#element_validate' => array('tripal_entities_organism_select_widget_validate'),
  606. );
  607. $element['value'] = $widget;
  608. break;
  609. }
  610. return $element;
  611. }
  612. /**
  613. * Callback function for validating the tripal_entities_organism_select_widget.
  614. */
  615. function tripal_entities_organism_select_widget_validate($element, &$form_state) {
  616. $field_name = $element['#field_name'];
  617. // Make sure we have a valid organism
  618. foreach ($form_state['values'][$field_name] as $langcode => $items) {
  619. foreach ($items as $delta => $value) {
  620. $organism_id = chado_select_record('organism', array('organism_id'),
  621. array('organism_id' => $value['value']), array('has_record' => TRUE));
  622. if (!$organism_id) {
  623. form_error($element, t("Please specify an organism that already exists in the database."));
  624. }
  625. }
  626. }
  627. }
  628. /**
  629. * Implements hook_field_is_empty().
  630. */
  631. function tripal_entities_field_is_empty($item, $field) {
  632. if (empty($item['tripal_entities_organism_select_widget'])) {
  633. return TRUE;
  634. }
  635. }
  636. /**
  637. * Implements hook_field_storage_info().
  638. */
  639. function tripal_entities_field_storage_info() {
  640. return array(
  641. 'tripal_entities_storage' => array(
  642. 'label' => t('Chado storage'),
  643. 'description' => t('Stores fields in the local Chado database.'),
  644. 'settings' => array(),
  645. ),
  646. );
  647. }
  648. /**
  649. * Implements hook_field_storage_write().
  650. */
  651. function tripal_entities_field_storage_write($entity_type, $entity, $op, $fields) {
  652. // Get the IDs for this entity.
  653. list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
  654. // Find out which table should receive the insert.
  655. $tablename = 'feature';
  656. $type_field = 'type_id';
  657. $schema = chado_get_schema($tablename);
  658. $pkey_field = $schema['primary key'][0];
  659. // Construct the values array that will be used to insert into the table.
  660. $values = array();
  661. foreach ($fields as $field_id) {
  662. $field = field_info_field_by_id($field_id);
  663. $field_name = $field['field_name'];
  664. $matches = array();
  665. if (preg_match('/^' . $tablename . '__(.*)/', $field_name, $matches)) {
  666. $chado_field = $matches[1];
  667. // Currently, we only support one language, but for for the sake of
  668. // thoroughness we'll iterate through all possible languages.
  669. $all_languages = field_available_languages($entity_type, $field);
  670. $field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
  671. foreach ($field_languages as $langcode) {
  672. $items = (array) $entity->{$field_name}[$langcode];
  673. // The number of items is related to the cardinatily of the field.
  674. foreach ($items as $delta => $item) {
  675. $values[$chado_field] = $item['value'];
  676. }
  677. }
  678. }
  679. }
  680. // Add in the type_id field.
  681. $values[$type_field] = $entity->cvterm_id;
  682. switch ($op) {
  683. case FIELD_STORAGE_INSERT:
  684. $record = chado_insert_record($tablename, $values);
  685. if ($record === FALSE) {
  686. drupal_set_message('Could not insert Chado record.', 'error');
  687. }
  688. $entity->record_id = $record[$pkey_field];
  689. break;
  690. case FIELD_STORAGE_UPDATE:
  691. $match[$pkey_field] = $entity->record_id;
  692. chado_update_record($tablename, $match, $values);
  693. break;
  694. }
  695. }
  696. /**
  697. * Implements hook_field_storage_load().
  698. *
  699. * Responsible for loading the fields from the Chado database and adding
  700. * their values to the entity.
  701. */
  702. function tripal_entities_field_storage_load($entity_type, $entities, $age, $fields, $options) {
  703. $load_current = $age == FIELD_LOAD_CURRENT;
  704. global $language;
  705. $langcode = $language->language;
  706. foreach ($entities as $entity_id => $entity) {
  707. // Find out which table should receive the insert.
  708. $tablename = 'feature';
  709. $type_field = 'type_id';
  710. $schema = chado_get_schema($tablename);
  711. $pkey_field = $schema['primary key'][0];
  712. $record_id = $entity->record_id;
  713. // Iterate through the field names to get the list of tables and fields
  714. // that should be queried.
  715. $columns = array();
  716. foreach ($fields as $field_id => $ids) {
  717. // By the time this hook runs, the relevant field definitions have been
  718. // populated and cached in FieldInfo, so calling field_info_field_by_id()
  719. // on each field individually is more efficient than loading all fields in
  720. // memory upfront with field_info_field_by_ids().
  721. $field = field_info_field_by_id($field_id);
  722. $field_name = $field['field_name'];
  723. $matches = array();
  724. if (preg_match('/^(.*?)__(.*?)$/', $field_name, $matches)) {
  725. $table = $matches[1];
  726. $field = $matches[2];
  727. $columns[$table][] = $field;
  728. }
  729. }
  730. // Get the record
  731. $record = chado_select_record($tablename, $columns[$tablename], array($pkey_field => $entity->record_id));
  732. // Now set the field values
  733. foreach ($fields as $field_id => $ids) {
  734. $field = field_info_field_by_id($field_id);
  735. $field_name = $field['field_name'];
  736. $matches = array();
  737. if (preg_match('/^(.*?)__(.*?)$/', $field_name, $matches)) {
  738. $table = $matches[1];
  739. $field = $matches[2];
  740. $entity->{$field_name}['und'][] = array('value' => $record[0]->$field);
  741. }
  742. }
  743. }
  744. }
  745. /**
  746. * An Ajax callback for the chado_data_form.
  747. */
  748. function chado_data_form_ajax_callback($form, $form_state) {
  749. // return the form so Drupal can update the content on the page
  750. return $form;
  751. }
  752. /**
  753. * Implements hook_validate() for the chado_data_form.
  754. */
  755. function chado_data_form_validate($form, &$form_state) {
  756. if ($form_state['clicked_button']['#name'] == 'add_data') {
  757. $chado_data = (object) $form_state['values'];
  758. field_attach_form_validate('chado_data', $chado_data, $form, $form_state);
  759. }
  760. }
  761. /**
  762. * Implements hook_submit() for the chado_data_form.
  763. *
  764. */
  765. function chado_data_form_submit($form, &$form_state) {
  766. if ($form_state['clicked_button']['#name'] == 'cancel') {
  767. if (array_key_exists('entity_id', $form_state['values'])){
  768. $entity = $form_state['values']['entity'];
  769. $form_state['redirect'] = "chado_data/$entity->entity_id";
  770. }
  771. else {
  772. $form_state['redirect'] = "admin/structure/chado_data/manage";
  773. }
  774. return;
  775. }
  776. if ($form_state['clicked_button']['#name'] == 'select_cvterm') {
  777. // don't do anything, we just need to know what the term name is.
  778. $form_state['rebuild'] = TRUE;
  779. }
  780. else {
  781. // Build and entity instance object.
  782. $entity = (object) $form_state['values'];
  783. // This is an update if the entity_id is in the form_state.
  784. if (array_key_exists('entity_id', $form_state['values'])) {
  785. $entity->entity_id = $form_state['values']['entity_id'];
  786. field_attach_update('chado_data', $entity);
  787. }
  788. else {
  789. field_attach_insert('chado_data', $entity);
  790. }
  791. // Now save the entity
  792. $entity = chado_data_save($entity);
  793. $form_state['redirect'] = "chado_data/$entity->entity_id";
  794. }
  795. }
  796. /**
  797. * Implements hook_theme().
  798. */
  799. function tripal_entities_theme($existing, $type, $theme, $path) {
  800. return array(
  801. );
  802. }
  803. /**
  804. * https://api.drupal.org/api/drupal/modules!rdf!rdf.module/group/rdf/7
  805. */
  806. function tripal_entities_rdf_mapping() {
  807. return array();
  808. /* return array(
  809. 'type' => 'chado_data',
  810. 'bundle' => 'gene',
  811. 'mapping' => array(
  812. 'rdftype' => array('sioc:Item', 'foaf:Document'),
  813. 'title' => array(
  814. 'predicates' => array('dc:title'),
  815. ),
  816. 'uid' => array(
  817. 'predicates' => array('sioc:has_creator'),
  818. 'type' => 'rel',
  819. ),
  820. 'name' => array(
  821. 'predicates' => array('foaf:name'),
  822. ),
  823. 'uniquename' => array(
  824. 'predicates' => array('foaf:name'),
  825. ),
  826. 'organism_id' => array(
  827. 'predicates' => array('sioc:has_parent'),
  828. 'type' => 'rel'
  829. )
  830. ),
  831. ); */
  832. }
  833. /**
  834. * ChadoDataControllerInterface definition.
  835. *
  836. * We create an interface here because anyone could come along and
  837. * use hook_entity_info_alter() to change our controller class.
  838. * We want to let them know what methods our class needs in order
  839. * to function with the rest of the module, so here's a handy list.
  840. *
  841. * @see hook_entity_info_alter()
  842. */
  843. interface ChadoDataControllerInterface
  844. extends DrupalEntityControllerInterface {
  845. /**
  846. * Create an entity.
  847. */
  848. public function create();
  849. /**
  850. * Save an entity.
  851. *
  852. * @param object $entity
  853. * The entity to save.
  854. */
  855. public function save($entity);
  856. /**
  857. * Delete an entity.
  858. *
  859. * @param object $entity
  860. * The entity to delete.
  861. */
  862. public function delete($entity);
  863. }
  864. /**
  865. * ChadoDataController extends DrupalDefaultEntityController.
  866. *
  867. * Our subclass of DrupalDefaultEntityController lets us add a few
  868. * important create, update, and delete methods.
  869. */
  870. class ChadoDataController
  871. extends DrupalDefaultEntityController
  872. implements ChadoDataControllerInterface {
  873. /**
  874. * Create and return a new tripal_entities entity.
  875. */
  876. public function create() {
  877. $entity = new stdClass();
  878. $entity->type = 'chado_data';
  879. $entity->entity_id = 0;
  880. return $entity;
  881. }
  882. /**
  883. * Delete a single entity.
  884. *
  885. * Really a convenience function for deleteMultiple().
  886. */
  887. public function delete($entity) {
  888. $this->deleteMultiple(array($entity));
  889. }
  890. /**
  891. * Delete one or more tripal_entities entities.
  892. *
  893. * Deletion is unfortunately not supported in the base
  894. * DrupalDefaultEntityController class.
  895. *
  896. * @param array $entities
  897. * An array of entity IDs or a single numeric ID.
  898. */
  899. public function deleteMultiple($entities) {
  900. $entity_ids = array();
  901. if (!empty($entities)) {
  902. $transaction = db_transaction();
  903. try {
  904. foreach ($entities as $entity) {
  905. // Invoke hook_entity_delete().
  906. module_invoke_all('entity_delete', $entity, 'chado_data');
  907. field_attach_delete('chado_data', $entity);
  908. $entity_ids[] = $entity->entity_id;
  909. }
  910. db_delete('chado_data')
  911. ->condition('entity_id', $entity_ids, 'IN')
  912. ->execute();
  913. }
  914. catch (Exception $e) {
  915. $transaction->rollback();
  916. watchdog_exception('entity_example', $e);
  917. throw $e;
  918. }
  919. }
  920. }
  921. /**
  922. * Saves the custom fields using drupal_write_record().
  923. */
  924. public function save($entity) {
  925. global $user;
  926. // If our entity has no entity_id, then we need to give it a
  927. // time of creation.
  928. if (empty($entity->entity_id)) {
  929. $entity->created = time();
  930. $invocation = 'entity_insert';
  931. }
  932. else {
  933. $invocation = 'entity_update';
  934. }
  935. // Invoke hook_entity_presave().
  936. module_invoke_all('entity_presave', $entity, 'chado_data');
  937. // Write out the entity record.
  938. $tablename = 'feature';
  939. $type_field = 'type_id';
  940. $schema = chado_get_schema($tablename);
  941. $pkey_field = $schema['primary key'][0];
  942. $record = array(
  943. 'cvterm_id' => $entity->cvterm_id,
  944. 'type' => $entity->type,
  945. 'tablename' => $tablename,
  946. 'record_id' => $entity->record_id,
  947. 'title' => 'title',
  948. 'uid' => $user->uid,
  949. 'created' => $entity->created,
  950. 'changed' => time(),
  951. );
  952. $success = drupal_write_record('chado_data', $record);
  953. if ($success == SAVED_NEW) {
  954. $entity->entity_id = $record['entity_id'];
  955. }
  956. // Now we need to either insert or update the fields which are
  957. // attached to this entity. We use the same primary_keys logic
  958. // to determine whether to update or insert, and which hook we
  959. // need to invoke.
  960. if ($invocation == 'entity_insert') {
  961. field_attach_insert('chado_data', $entity);
  962. }
  963. else {
  964. field_attach_update('chado_data', $entity);
  965. }
  966. // Invoke either hook_entity_update() or hook_entity_insert().
  967. module_invoke_all($invocation, $entity, 'chado_data');
  968. return $entity;
  969. }
  970. }