remote__data_formatter.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. <?php
  2. class remote__data_formatter extends WebServicesFieldFormatter {
  3. // The default label for this field.
  4. public static $default_label = 'Remote Data';
  5. // The list of field types for which this formatter is appropriate.
  6. public static $field_types = array('remote__data');
  7. // The list of default settings for this formatter.
  8. public static $default_settings = array(
  9. 'setting1' => 'default_value',
  10. );
  11. /**
  12. * Provides the field's setting form.
  13. *
  14. * This function corresponds to the hook_field_formatter_settings_form()
  15. * function of the Drupal Field API.
  16. *
  17. * The settings form appears on the 'Manage Display' page of the content
  18. * type administration page. This function provides the form that will
  19. * appear on that page.
  20. *
  21. * To add a validate function, please create a static function in the
  22. * implementing class, and indicate that this function should be used
  23. * in the form array that is returned by this function.
  24. *
  25. * This form will not be displayed if the formatter_settings_summary()
  26. * function does not return anything.
  27. *
  28. * param $field
  29. * The field structure being configured.
  30. * param $instance
  31. * The instance structure being configured.
  32. * param $view_mode
  33. * The view mode being configured.
  34. * param $form
  35. * The (entire) configuration form array, which will usually have no use
  36. * here. Typically for reference only.
  37. * param $form_state
  38. * The form state of the (entire) configuration form.
  39. *
  40. * @return
  41. * A Drupal Form array containing the settings form for this field.
  42. */
  43. public function settingsForm($view_mode, $form, &$form_state) {
  44. }
  45. /**
  46. * Provides the display for a field
  47. *
  48. * This function corresponds to the hook_field_formatter_view()
  49. * function of the Drupal Field API.
  50. *
  51. * This function provides the display for a field when it is viewed on
  52. * the web page. The content returned by the formatter should only include
  53. * what is present in the $items[$delta]['values] array. This way, the
  54. * contents that are displayed on the page, via webservices and downloaded
  55. * into a CSV file will always be identical. The view need not show all
  56. * of the data in the 'values' array.
  57. *
  58. * @param $element
  59. * @param $entity_type
  60. * @param $entity
  61. * @param $langcode
  62. * @param $items
  63. * @param $display
  64. *
  65. * @return
  66. * An element array compatible with that returned by the
  67. * hook_field_formatter_view() function.
  68. */
  69. public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
  70. $content = '';
  71. dpm($items);
  72. // Get the settings
  73. $settings = $display['settings'];
  74. $field_name = $this->field['field_name'];
  75. // Get any subfields and the header label. Shift the array because the
  76. // results should already be the value of the fisrt entry.
  77. $rd_field_name = $this->instance['settings']['data_info']['rd_field_name'];
  78. $subfields = explode(',', $rd_field_name);
  79. $header_label = $this->getHeaderLabel($subfields);
  80. $flabel = array_shift($subfields);
  81. // Get the site logo if one is provided
  82. $site_logo = $this->instance['settings']['data_info']['site_logo'];
  83. if ($site_logo) {
  84. $site_logo = file_load($site_logo);
  85. }
  86. // Get the site name where the data came from.
  87. $site_id_ws = $this->instance['settings']['data_info']['remote_site'];
  88. $site = db_select('tripal_sites', 'ts')
  89. ->fields('ts', array('name', 'url'))
  90. ->condition('ts.id', $site_id_ws)
  91. ->execute()
  92. ->fetchObject();
  93. // Iterate through the results and create a generic table.
  94. $rows = array();
  95. $headers = array('');
  96. foreach ($items as $index => $item) {
  97. if (!$item['value'] or empty($item['value'])) {
  98. continue;
  99. }
  100. $value = $item['value'];
  101. $error = $item['error'];
  102. $warning = $item['warning'];
  103. if ($error) {
  104. $rows[] = [$value];
  105. continue;
  106. }
  107. if ($warning) {
  108. $rows[] = [$value];
  109. continue;
  110. }
  111. $remote_entity_label = array_key_exists('label', $item) ? $item['remote_entity']['label'] : '';
  112. $remote_entity_page = $item['remote_entity']['ItemPage'];
  113. $link = t('View !data on %site',
  114. array('!data' => l('this content', $remote_entity_page, array('attributes' => array('target' => '_blank'))),
  115. '%site' => $site->name));
  116. // If this is a collection then handle it as a list of members.
  117. if (is_array($value)) {
  118. if (array_key_exists('members', $value)) {
  119. foreach ($value['members'] as $subvalue) {
  120. $subvalue = $this->refineSubValue($subvalue, $subfields, $header_label);
  121. $rows[] = array($subvalue);
  122. }
  123. }
  124. else {
  125. if (count($subfields) > 0) {
  126. $subvalue = $this->refineSubValue($value, $subfields, $header_label);
  127. $rows[] = array($subvalue);
  128. }
  129. else {
  130. if (array_key_exists($flabel, $value)) {
  131. $rows[] = array($value[$flabel]);
  132. }
  133. else {
  134. $value['Link'] = l('View content on ' . $site->name, $remote_entity_page, array('attributes' => array('target' => '_blank')));
  135. $rows[] = array($value);
  136. }
  137. }
  138. }
  139. }
  140. }
  141. $has_sub_tables = FALSE;
  142. for ($i = 0; $i < count($rows); $i++) {
  143. if (is_array($rows[$i][0])) {
  144. $rows[$i][0] = $this->createTable($rows[$i]);
  145. $has_sub_tables = TRUE;
  146. }
  147. else {
  148. $rows[$i] = [
  149. 'colspan' => 2,
  150. 'data' => $rows[$i],
  151. ];
  152. }
  153. }
  154. // If we don't have tables for each row then we'll put everything into
  155. // a table.
  156. if (!$has_sub_tables) {
  157. $headers = array($header_label . '(s)');
  158. $content .= theme_table(array(
  159. 'header' => $headers,
  160. 'rows' => $rows,
  161. 'attributes' => array(
  162. 'class' => 'tripal-remote--data-field-table',
  163. ),
  164. 'sticky' => FALSE,
  165. 'caption' => "",
  166. 'colgroups' => array(),
  167. 'empty' => 'There are no results.',
  168. ));
  169. }
  170. else {
  171. for ($i = 0; $i < count($rows); $i++) {
  172. if (count($rows) > 1) {
  173. $content .= '<span class="tripal-remote--data-field-table-label">' . $header_label . ' ' . ($i + 1) . '</span>';
  174. }
  175. $content .= $rows[$i][0];
  176. }
  177. }
  178. $content .= '<p>';
  179. if (is_object($site_logo)) {
  180. $content .= '<img class="tripal-remote--data-field-logo" src="' . file_create_url($site_logo->uri) . '"><br/>';
  181. }
  182. $content .= t('This content provided by !site.',
  183. array('!site' => l($site->name, $site->url, array('attributes' => array("target" => '_blank')))));
  184. $content .= '</p>';
  185. // Return the content for this field.
  186. $element[0] = array(
  187. '#type' => 'markup',
  188. '#markup' => '<div class="tripal-remote--data-field">' . $content . '</div>',
  189. );
  190. }
  191. /**
  192. * Retrieves the header label given the subfields criteria.
  193. *
  194. * @param $subfields
  195. * An array of the sequence of subfields.
  196. */
  197. private function getHeaderLabel($subfields) {
  198. $subfield = array_shift($subfields);
  199. $header_label = ucwords(preg_replace('/_/', ' ', $subfield));
  200. if (count($subfields) > 0) {
  201. $header_label .= ' ' . $this->getHeaderLabel($subfields);
  202. }
  203. return $header_label;
  204. }
  205. /**
  206. * Adjusts the items array to contain only the section/subsection desired.
  207. *
  208. * The field settings can indicate a field with sub fields that should
  209. * be displayed (e.g. organism,genus or relationship,clause). We want
  210. * to adjust the item to only include what the user requested.
  211. *
  212. * @param $values
  213. * @param $subfields
  214. */
  215. private function refineSubValue($values, $subfields) {
  216. // Remove unwanted elements.
  217. unset($values['@id']);
  218. unset($values['@context']);
  219. unset($values['@type']);
  220. unset($values['remote_entity']);
  221. $subfield = array_shift($subfields);
  222. if (array_key_exists($subfield, $values)) {
  223. if (is_array($values[$subfield]) and count($subfields) > 0) {
  224. return $this->refineSubvalue($values[$subfield], $subfields);
  225. }
  226. else {
  227. return $values[$subfield];
  228. }
  229. }
  230. else {
  231. return $values;
  232. }
  233. }
  234. /**
  235. * A recursive function for displaying an item in a table.
  236. *
  237. * @param $item
  238. * An item from the $items array passed to the view() function.
  239. * @return
  240. * An HTML formatted Table.
  241. */
  242. private function createTable($item, &$pkey = '', &$rows = array(), $depth = 0) {
  243. foreach ($item as $key => $value) {
  244. // Skip JSON-LD keys.
  245. if (preg_match('/^\@/', $key)) {
  246. continue;
  247. }
  248. $key = preg_replace('/_/', ' ', $key);
  249. $key = ucwords($key);
  250. if ($pkey) {
  251. $key = $pkey . ' ' . $key;
  252. }
  253. if (is_array($value)) {
  254. $this->createTable($value, $key, $rows, $depth + 1);
  255. }
  256. else {
  257. $rows[] = array(
  258. 'data'=> array(
  259. $key,
  260. $value
  261. ),
  262. 'no_striping' => TRUE,
  263. );
  264. }
  265. }
  266. if ($depth == 0) {
  267. $headers = array('Data Type', 'Value');
  268. return theme_table(array(
  269. 'header' => $headers,
  270. 'rows' => $rows,
  271. 'attributes' => array(
  272. 'class' => 'tripal-remote--data-field-table',
  273. ),
  274. 'sticky' => FALSE,
  275. 'caption' => "",
  276. 'colgroups' => array(),
  277. 'empty' => 'There are no results.',
  278. ));
  279. }
  280. }
  281. /**
  282. * A recursive function for creating an HTML dictionary list from
  283. * the results for the item provided.
  284. *
  285. * @param $item
  286. * An item from the $items array passed to the view() function.
  287. * @return
  288. * An HTML formatted DL.
  289. */
  290. private function createDL($item, &$pkey = '', &$content= '', $depth = 0) {
  291. if ($depth == 0) {
  292. $content = '<dl class="tripal-remote--data-field-dl">';
  293. }
  294. foreach ($item as $key => $value) {
  295. // Skip JSON-LD keys.
  296. if (preg_match('/^\@/', $key)) {
  297. continue;
  298. }
  299. $key = preg_replace('/_/', ' ', $key);
  300. $key = ucwords($key);
  301. if ($pkey) {
  302. $key = $pkey . ' ' . $key;
  303. }
  304. if (is_array($value)) {
  305. $this->createDL($value, $key, $content, $depth + 1);
  306. }
  307. else {
  308. $content .= '<dt>' . $key . '&nbsp;:&nbsp;</dt><dd>' . $value . '</dd>';
  309. }
  310. }
  311. if ($depth == 0) {
  312. $content .= '</dl>';
  313. return $content;
  314. }
  315. }
  316. /**
  317. * A recursive function for creating an HTML dictionary list from
  318. * the results for the item provided.
  319. *
  320. * @param $item
  321. * An item from the $items array passed to the view() function.
  322. * @return
  323. * An HTML formatted DL.
  324. */
  325. private function createNestedDL($item) {
  326. $content = '<dl>';
  327. foreach ($item as $key => $value) {
  328. // Skip JSON-LD keys.
  329. if (preg_match('/^\@/', $key)) {
  330. continue;
  331. }
  332. $key = preg_replace('/_/', ' ', $key);
  333. $key = ucwords($key);
  334. if (is_array($value)) {
  335. $value = $this->createDL($value);
  336. }
  337. $content .= '<dt>' . $key . '</dt><dd>' . $value . '</dd>';
  338. }
  339. $content .= '</dl>';
  340. return $content;
  341. }
  342. /**
  343. * Provides a summary of the formatter settings.
  344. *
  345. * This function corresponds to the hook_field_formatter_settings_summary()
  346. * function of the Drupal Field API.
  347. *
  348. * On the 'Manage Display' page of the content type administration page,
  349. * fields are allowed to provide a settings form. This settings form can
  350. * be used to allow the site admin to define how the field should be
  351. * formatted. The settings are then available for the formatter()
  352. * function of this class. This function provides a text-based description
  353. * of the settings for the site developer to see. It appears on the manage
  354. * display page inline with the field. A field must always return a
  355. * value in this function if the settings form gear button is to appear.
  356. *
  357. * See the hook_field_formatter_settings_summary() function for more
  358. * information.
  359. *
  360. * @param $field
  361. * @param $instance
  362. * @param $view_mode
  363. *
  364. * @return string
  365. * A string that provides a very brief summary of the field settings
  366. * to the user.
  367. *
  368. */
  369. public function settingsSummary($view_mode) {
  370. }
  371. }