tripal_entities.field_storage.inc 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. /**
  3. * Implements hook_field_storage_info().
  4. */
  5. function tripal_entities_field_storage_info() {
  6. return array(
  7. 'field_chado_storage' => array(
  8. 'label' => t('Chado storage'),
  9. 'description' => t('Stores fields in the local Chado database.'),
  10. 'settings' => array(),
  11. ),
  12. );
  13. }
  14. /**
  15. * Implements hook_field_storage_write().
  16. */
  17. function tripal_entities_field_storage_write($entity_type, $entity, $op, $fields) {
  18. switch ($op) {
  19. case FIELD_STORAGE_INSERT:
  20. // Use the cvterm_id to look up tables where this term is used
  21. $sel_values = array(
  22. 'term_id' => array(
  23. 'cvterm_id' => $entity->cvterm_id,
  24. ),
  25. );
  26. $term_usage = chado_generate_var('tripal_term_usage', $sel_values, array('return_array' => 1));
  27. // For each table that uses this term, insert the field recursively
  28. foreach ($term_usage as $usage) {
  29. $data_table = $usage->data_table;
  30. //$type_table = $usage->type_table;
  31. $type_field = $usage->field;
  32. tripal_entities_field_storage_write_recursive($entity_type, $entity,
  33. $op, $fields, $data_table, $type_field);
  34. }
  35. break;
  36. case FIELD_STORAGE_UPDATE :
  37. // Get the base table and record id for the fields of this entity.
  38. $details = db_select('chado_entity', 'ce')
  39. ->fields('ce')
  40. ->condition('entity_id', $entity->id)
  41. ->execute()
  42. ->fetchObject();
  43. $tablename = $details->data_table;
  44. $type_field = $details->field;
  45. $record_id = $details->record_id;
  46. tripal_entities_field_storage_write_recursive($entity_type, $entity,
  47. $op, $fields, $tablename, $type_field, $record_id);
  48. if (!$details) {
  49. // TODO: what to do if record is missing!
  50. }
  51. break;
  52. }
  53. }
  54. /**
  55. * Implements hook_field_storage_write_recursive().
  56. */
  57. function tripal_entities_field_storage_write_recursive($entity_type, $entity,
  58. $op, $fields, $tablename, $type_field = NULL, $record_id = NULL, $depth = 0) {
  59. // Intialize the values array and $record_id;
  60. $values = array();
  61. // Get the schema for this table so that we can identify the primary key
  62. // and foreign keys.
  63. $schema = chado_get_schema($tablename);
  64. $pkey_field = $schema['primary key'][0];
  65. $fkey_fields = $schema['foreign keys'];
  66. $fkey_fields_list = array();
  67. // STEP 1: Recurse on the FK fields.
  68. // Loop through the foreign keys os that we can recurse on those first.
  69. foreach ($fkey_fields as $fk_table => $details) {
  70. foreach ($details['columns'] as $local_id => $remote_id) {
  71. // If this is the base table then do not recurse on the type_id. The
  72. // type_id is set in the entity. We are at the base table when
  73. // the depth is 0.
  74. if ($depth == 0 && $local_id == $type_field) {
  75. $values[$local_id] = $entity->cvterm_id;
  76. continue;
  77. }
  78. // Keep track of the FK fields so that in STEP 2 we don't have to
  79. // loop through the $fk_fields again.
  80. $fkey_fields_list[] = $local_id;
  81. // Recurse differently if this is an insert or an update.
  82. $fk_val = NULL;
  83. switch ($op) {
  84. case FIELD_STORAGE_INSERT:
  85. // On an insert we do not pass in a $record_id because
  86. // we don't have any.
  87. $fk_val = tripal_entities_field_storage_write_recursive($entity_type,
  88. $entity, $op, $fields, $fk_table, NULL, NULL, $depth + 1);
  89. break;
  90. case FIELD_STORAGE_UPDATE:
  91. // On an update we must get the value of the FK field. This should
  92. // be present as a field, so get it's value and pass it in as the
  93. // $record_id field.
  94. $fk_val = tripal_entities_get_field_value($tablename . '__' . $local_id, $entity, $entity_type);
  95. $fk_val = tripal_entities_field_storage_write_recursive($entity_type,
  96. $entity, $op, $fields, $fk_table, NULL, $fk_val, $depth + 1);
  97. break;
  98. }
  99. if ($fk_val) {
  100. $values[$local_id] = $fk_val;
  101. }
  102. }
  103. }
  104. // STEP 2: Loop through the incoming fields.
  105. // Loop through the fields passed to the function and find any that
  106. // are for this table. Then add their values to the $values array.
  107. foreach ($fields as $field_id) {
  108. $field = field_info_field_by_id($field_id);
  109. $field_name = $field['field_name'];
  110. if (preg_match('/^' . $tablename . '__(.*)/', $field_name, $matches)) {
  111. $chado_field = $matches[1];
  112. // Skip FK fields as those should already have been dealt with the
  113. // recursive code above.
  114. if (in_array($field_id, $fkey_fields_list)) {
  115. continue;
  116. }
  117. // Add the value of the field to the $values arr for later insert/update.
  118. $values[$chado_field] = tripal_entities_get_field_value($tablename . '__' . $chado_field, $entity, $entity_type);
  119. }
  120. }
  121. // STEP 3: Insert/Update the record.
  122. // If there are no values then return.
  123. $entity->storage = array();
  124. switch ($op) {
  125. case FIELD_STORAGE_INSERT:
  126. if (count($values) == 0) {
  127. return NULL;
  128. }
  129. // Inser the values array as a new record in the table.
  130. $record = chado_insert_record($tablename, $values);
  131. if ($record === FALSE) {
  132. drupal_set_message('Could not insert Chado record.', 'error');
  133. }
  134. $record_id = $record[$pkey_field];
  135. // Add a record to the chado_entity table so that the data for the
  136. // fields can be pulled from Chado when loaded the next time. Only do
  137. // this for the base table record.
  138. if ($depth == 0) {
  139. $record = array(
  140. 'entity_id' => $entity->id,
  141. 'record_id' => $record_id,
  142. 'data_table' => $tablename,
  143. 'type_table' => $tablename, // TODO: this must be fixed.
  144. 'field' => $type_field,
  145. );
  146. $success = drupal_write_record('chado_entity', $record);
  147. if (!$success) {
  148. drupal_set_message('Unable to insert new data.', 'error');
  149. }
  150. }
  151. break;
  152. case FIELD_STORAGE_UPDATE:
  153. // If we don't have any values we are not going to update the
  154. // record because there is nothing to udpate, do just return the
  155. // record_id.
  156. if (count($values) == 0) {
  157. return $record_id;
  158. }
  159. $match[$pkey_field] = $record_id;
  160. chado_update_record($tablename, $match, $values);
  161. break;
  162. }
  163. return $record_id;
  164. }
  165. /**
  166. *
  167. */
  168. function tripal_entities_get_field_value($field_name, $entity, $entity_type) {
  169. $value = NULL;
  170. $field = field_info_field($field_name);
  171. if (!$field) {
  172. return $value;
  173. }
  174. // Currently, we only support one language, but for for the sake of
  175. // thoroughness we'll iterate through all possible languages.
  176. $all_languages = field_available_languages($entity_type, $field);
  177. $field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
  178. foreach ($field_languages as $langcode) {
  179. $items = (array) $entity->{$field_name}[$langcode];
  180. // The number of items is related to the cardinatily of the field.
  181. // We should always only have one item because this is a field in a
  182. // table. But we loop anyway.
  183. foreach ($items as $delta => $item) {
  184. $value = $item['value'];
  185. }
  186. }
  187. return $value;
  188. }
  189. /**
  190. * Implements hook_field_storage_load().
  191. *
  192. * Responsible for loading the fields from the Chado database and adding
  193. * their values to the entity.
  194. */
  195. function tripal_entities_field_storage_load($entity_type, $entities, $age, $fields, $options) {
  196. $load_current = $age == FIELD_LOAD_CURRENT;
  197. global $language;
  198. $langcode = $language->language;
  199. foreach ($entities as $id => $entity) {
  200. // Get the base table and record id for the fields of this entity.
  201. $details = db_select('chado_entity', 'ce')
  202. ->fields('ce')
  203. ->condition('entity_id', $entity->id)
  204. ->execute()
  205. ->fetchObject();
  206. if (!$details) {
  207. // TODO: what to do if record is missing!
  208. }
  209. // Find out which table should receive the insert.
  210. $tablename = $details->data_table;
  211. $type_field = $details->field;
  212. $schema = chado_get_schema($tablename);
  213. $pkey_field = $schema['primary key'][0];
  214. $record_id = $details->record_id;
  215. // Iterate through the field names to get the list of tables and fields
  216. // that should be queried.
  217. $columns = array();
  218. foreach ($fields as $field_id => $ids) {
  219. // By the time this hook runs, the relevant field definitions have been
  220. // populated and cached in FieldInfo, so calling field_info_field_by_id()
  221. // on each field individually is more efficient than loading all fields in
  222. // memory upfront with field_info_field_by_ids().
  223. $field = field_info_field_by_id($field_id);
  224. $field_name = $field['field_name'];
  225. $matches = array();
  226. if (preg_match('/^(.*?)__(.*?)$/', $field_name, $matches)) {
  227. $table = $matches[1];
  228. $field = $matches[2];
  229. $columns[$table][] = $field;
  230. }
  231. }
  232. // Get the record
  233. $values = array($pkey_field => $record_id);
  234. $record = chado_select_record($tablename, $columns[$tablename], $values);
  235. // Now set the field values
  236. foreach ($fields as $field_id => $ids) {
  237. $field = field_info_field_by_id($field_id);
  238. $field_name = $field['field_name'];
  239. $matches = array();
  240. if (preg_match('/^(.*?)__(.*?)$/', $field_name, $matches)) {
  241. $table = $matches[1];
  242. $field = $matches[2];
  243. $entity->{$field_name}['und'][] = array('value' => $record[0]->$field);
  244. }
  245. }
  246. }
  247. }