tripal.fields.api.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) for working with
  5. * fields attached to TripalEntity content types (bundles).
  6. */
  7. /**
  8. * @defgroup tripal_fields_api Tripal Fields
  9. * @ingroup tripal_api
  10. * @{
  11. * Provides an application programming interface (API) for working with
  12. * fields attached to TripalEntity content types (bundles).
  13. * @}
  14. *
  15. */
  16. /**
  17. * Executes a TripalFieldQuery using the provided conditions.
  18. *
  19. * This hook is called to find the entities having certain field
  20. * conditions and sort them in the given field order.
  21. *
  22. * @param $conditions
  23. * An array of filter representing the conditions to be applied to the query.
  24. * Each filter is an associative array whose keys include the following:
  25. * - field: an array representing the field identical to the output of the
  26. * field_info_field() function.
  27. * - filter: the name of the field on which the filter should be applied.
  28. * - value: the value of the filter.
  29. * - operator: the operation to apply: '=', '<>', '>', '>=', '<', '<=',
  30. * 'STARTS_WITH', 'CONTAINS': These operators expect $value to be a
  31. * literal of the same type as the column. 'IN', 'NOT IN': These operators
  32. * expect $value to be an array of literals of the same type as the column.
  33. * @param $orderBy
  34. * An array of sorting instructions. Each sort is an associative array with
  35. * the following keys:
  36. * - field: an array representing the field identical to the output of the
  37. * field_info_field() function.
  38. * - orderBy: the name of the field on which the filter should be applied.
  39. * - direction: either the string 'ASC' (for ascending sort) or 'DESC' (for
  40. * descending).
  41. *
  42. * @ingroup tripal_fields_api
  43. */
  44. function hook_field_storage_tquery($conditions, $orderBy) {
  45. // See the tripal_chado_field_storage_tquery() function for an example.
  46. }
  47. /**
  48. *
  49. * @param unknown $entity_type
  50. * @param unknown $bundle
  51. *
  52. * @ingroup tripal_fields_api
  53. */
  54. function hook_bundle_fields_info($entity_type, $bundle) {
  55. }
  56. /**
  57. *
  58. * @param unknown $entity_type
  59. * @param unknown $bundle
  60. *
  61. * @ingroup tripal_fields_api
  62. */
  63. function hook_bundle_instances_info($entity_type, $bundle) {
  64. }
  65. /**
  66. *
  67. * @param unknown $info
  68. * @param unknown $bundle
  69. * @param unknown $term
  70. *
  71. * @ingroup tripal_fields_api
  72. */
  73. function hook_bundle_fields_info_alter(&$info, $bundle, $term) {
  74. }
  75. /**
  76. *
  77. * @param unknown $info
  78. * @param unknown $bundle
  79. * @param unknown $term
  80. *
  81. * @ingroup tripal_fields_api
  82. */
  83. function hook_bundle_instances_info_alter(&$info, $bundle, $term) {
  84. }
  85. /**
  86. * Retrieves a list of TripalField types.
  87. *
  88. * The TripalField classes can be added by a site developer and should be
  89. * placed in the [module]/includes/TripalFields directory. Tripal will support
  90. * any field as long as it is in this directory and extends the TripalField
  91. * class. To support dynamic inclusion of new fields this function
  92. * will look for TripalField class files and return a type for
  93. * each one.
  94. *
  95. * @return
  96. * A list of TripalField names.
  97. *
  98. * @ingroup tripal_fields_api
  99. */
  100. function tripal_get_field_types() {
  101. $types = array();
  102. $modules = module_list(TRUE);
  103. foreach ($modules as $module) {
  104. // Only run this for modules that are enabled.
  105. if (!module_exists($module)) {
  106. continue;
  107. }
  108. // Find all of the files in the tripal_chado/includes/TripalFields/ directory.
  109. $fields_path = drupal_get_path('module', $module) . '/includes/TripalFields';
  110. $field_files = file_scan_directory($fields_path, '/.*\.inc$/');
  111. // Iterate through the fields, include the file and run the info function.
  112. foreach ($field_files as $file) {
  113. // Ignore the formatter and widget classes for now.
  114. if (preg_match('/_formatter|_widget/', $file->name)) {
  115. continue;
  116. }
  117. $field_type = $file->name;
  118. module_load_include('inc', $module, 'includes/TripalFields/' . $field_type . '/' . $field_type);
  119. if (class_exists($field_type) and is_subclass_of($field_type, 'TripalField')) {
  120. $types[] = $field_type;
  121. }
  122. }
  123. }
  124. // If the libraries module is enabled then we want to look for a TripalFields
  125. // library folder and see if our field exist there.
  126. if (module_exists('libraries')) {
  127. $library_path = libraries_get_path('TripalFields');
  128. $fields_path = realpath(".") . '/' . $library_path;
  129. $field_files = file_scan_directory($fields_path, '/.*\.inc$/');
  130. foreach ($field_files as $file) {
  131. // Ignore the formatter and widget classes for now.
  132. if (preg_match('/_formatter|_widget/', $file->name)) {
  133. continue;
  134. }
  135. $field_type = $file->name;
  136. $file_path = realpath(".") . '/' . $library_path .'/' . $field_type . '/' . $field_type . '.inc';
  137. if (file_exists($file_path)) {
  138. require_once($file_path);
  139. if (class_exists($field_type) and is_subclass_of($field_type, 'TripalField')) {
  140. $types[] = $field_type;
  141. }
  142. }
  143. }
  144. }
  145. return $types;
  146. }
  147. /**
  148. * Retrieves a list of TripalFieldWidgets.
  149. *
  150. * The TripalFieldWidget classes can be added by a site developer and should be
  151. * placed in the [module]/includes/TripalFields directory. Tripal will support
  152. * any widget as long as it is in this directory and extends the
  153. * TripalFieldWidget class.
  154. *
  155. * @return
  156. * A list of TripalFieldWidget names.
  157. *
  158. * @ingroup tripal_fields_api
  159. */
  160. function tripal_get_field_widgets() {
  161. $widgets = array();
  162. $modules = module_list(TRUE);
  163. foreach ($modules as $module) {
  164. // Only run this for modules that are enabled.
  165. if (!module_exists($module)) {
  166. continue;
  167. }
  168. // Find all of the files in the tripal_chado/includes/fields directory.
  169. $fields_path = drupal_get_path('module', $module) . '/includes/TripalFields';
  170. $field_files = file_scan_directory($fields_path, '/.*_widget\.inc$/');
  171. // Iterate through the fields, include the file and run the info function.
  172. foreach ($field_files as $file) {
  173. $widget_type = $file->name;
  174. $field_type = preg_replace('/(^.*)_widget/', '$1', $widget_type);
  175. module_load_include('inc', $module, 'includes/TripalFields/' . $field_type . '/' . $widget_type);
  176. if (class_exists($widget_type) and is_subclass_of($widget_type, 'TripalFieldWidget')) {
  177. $widgets[] = $widget_type;
  178. }
  179. }
  180. }
  181. // If the libraries module is enabled then we want to look for a TripalFields
  182. // library folder and see if our field exist there.
  183. if (module_exists('libraries')) {
  184. $library_path = libraries_get_path('TripalFields');
  185. $fields_path = realpath(".") . '/' . $library_path;
  186. $field_files = file_scan_directory($fields_path, '/.*_widget\.inc$/');
  187. foreach ($field_files as $file) {
  188. $widget_type = $file->name;
  189. $field_type = preg_replace('/(^.*)_widget/', '$1', $widget_type);
  190. $file_path = realpath(".") . '/' . $library_path .'/' . $field_type . '/' . $widget_type . '.inc';
  191. if (file_exists($file_path)) {
  192. require_once($file_path);
  193. if (class_exists($widget_type) and is_subclass_of($widget_type, 'TripalFieldWidget')) {
  194. $widgets[] = $widget_type;
  195. }
  196. }
  197. }
  198. }
  199. return $widgets;
  200. }
  201. /**
  202. * Retrieves a list of field formatters compatible with a given field.
  203. *
  204. * @param $field
  205. * A field array as returned by the field_info_field() function.
  206. * @return
  207. * A list of file formatter class names.
  208. */
  209. function tripal_get_field_field_formatters($field) {
  210. $field_name = $field['field_name'];
  211. $field_type = $field['type'];
  212. $downloaders = array();
  213. // All fields should support the Tab and CSV downloaders.
  214. tripal_load_include_downloader_class('TripalTabDownloader');
  215. $downloaders['TripalTabDownloader'] = TripalTabDownloader::$label;
  216. tripal_load_include_downloader_class('TripalCSVDownloader');
  217. $downloaders['TripalCSVDownloader'] = TripalCSVDownloader::$label;
  218. if (tripal_load_include_field_class($field_type)) {
  219. $settings = $field_type::$default_instance_settings;
  220. if (array_key_exists('download_formatters', $settings)) {
  221. foreach ($settings['download_formatters'] as $class_name) {
  222. if (!array_key_exists($class_name, $downloaders)) {
  223. tripal_load_include_downloader_class($class_name);
  224. $downloaders[$class_name] = $class_name::$label;
  225. }
  226. }
  227. }
  228. }
  229. return $downloaders;
  230. }
  231. /**
  232. * Retrieves a list of TripalFieldFormatters.
  233. *
  234. * The TripalFieldFormatter classes can be added by a site developer and should
  235. * be placed in the [module]/includes/TripalFields directory. Tripal will
  236. * support any widget as long as it is in this directory and extends the
  237. * TripalFieldFormatter class.
  238. *
  239. * @return
  240. * A list of TripalFieldFormatter names.
  241. *
  242. * @ingroup tripal_fields_api
  243. */
  244. function tripal_get_field_formatters() {
  245. $formatters = array();
  246. $modules = module_list(TRUE);
  247. foreach ($modules as $module) {
  248. // Only run this for modules that are enabled.
  249. if (!module_exists($module)) {
  250. continue;
  251. }
  252. // Find all of the files in the tripal_chado/includes/fields directory.
  253. $fields_path = drupal_get_path('module', $module) . '/includes/TripalFields';
  254. $field_files = file_scan_directory($fields_path, '/.*_formatter\.inc$/');
  255. // Iterate through the fields, include the file and run the info function.
  256. foreach ($field_files as $file) {
  257. $formatter_type = $file->name;
  258. $field_type = preg_replace('/(^.*)_formatter/', '$1', $formatter_type);
  259. module_load_include('inc', $module, 'includes/TripalFields/' . $field_type . '/' . $formatter_type);
  260. if (class_exists($formatter_type) and is_subclass_of($formatter_type, 'TripalFieldFormatter')) {
  261. $formatters[] = $formatter_type;
  262. }
  263. }
  264. }
  265. // If the libraries module is enabled then we want to look for a TripalFields
  266. // library folder and see if our field exist there.
  267. if (module_exists('libraries')) {
  268. $library_path = libraries_get_path('TripalFields');
  269. $fields_path = realpath(".") . '/' . $library_path;
  270. $field_files = file_scan_directory($fields_path, '/.*_formatter\.inc$/');
  271. foreach ($field_files as $file) {
  272. $formatter_type = $file->name;
  273. $field_type = preg_replace('/(^.*)_formatter/', '$1', $formatter_type);
  274. $file_path = realpath(".") . '/' . $library_path .'/' . $field_type . '/' . $formatter_type . '.inc';
  275. if (file_exists($file_path)) {
  276. require_once($file_path);
  277. if (class_exists($formatter_type) and is_subclass_of($formatter_type, 'TripalFieldFormatter')) {
  278. $formatters[] = $formatter_type;
  279. }
  280. }
  281. }
  282. }
  283. return $formatters;
  284. }
  285. /**
  286. * Loads the TripalField class file into scope.
  287. *
  288. * @param $class
  289. * The class to include. This can be a TripalField, TripalFieldWidget or
  290. * TripalFieldFormatter class name.
  291. *
  292. * @return
  293. * TRUE if the field type class file was found, FALSE otherwise.
  294. *
  295. * @ingroup tripal_fields_api
  296. */
  297. function tripal_load_include_field_class($class) {
  298. $modules = module_list(TRUE);
  299. foreach ($modules as $module) {
  300. $field_type = preg_replace('/(^.*)_(formatter|widget)/', '$1', $class);
  301. $file_path = realpath(".") . '/' . drupal_get_path('module', $module) . '/includes/TripalFields/' . $field_type . '/' . $class . '.inc';
  302. if (file_exists($file_path)) {
  303. module_load_include('inc', $module, 'includes/TripalFields/' . $field_type . '/' . $class);
  304. if (class_exists($class)) {
  305. return TRUE;
  306. }
  307. }
  308. }
  309. // If the libraries module is enabled then we want to look for a TripalFields
  310. // library folder and see if our field exist there.
  311. if (module_exists('libraries')) {
  312. $library_path = libraries_get_path('TripalFields');
  313. $field_type = preg_replace('/(^.*)_(formatter|widget)/', '$1', $class);
  314. $file_path = realpath(".") . '/' . $library_path .'/' . $field_type . '/' . $class . '.inc';
  315. if (file_exists($file_path)) {
  316. require_once($file_path);
  317. if (class_exists($class)) {
  318. return TRUE;
  319. }
  320. }
  321. }
  322. return FALSE;
  323. }
  324. /**
  325. * Loads the TripalEntityDownloader file into scope.
  326. *
  327. * @param $class
  328. * The name of the class to include.
  329. *
  330. * @return
  331. * TRUE if the downloader class file was found, FALSE otherwise.
  332. *
  333. * @ingroup tripal_fields_api
  334. */
  335. function tripal_load_include_downloader_class($class) {
  336. $modules = module_list(TRUE);
  337. foreach ($modules as $module) {
  338. $file_path = realpath(".") . '/' . drupal_get_path('module', $module) . '/includes/TripalFieldDownloaders/' . $class . '.inc';
  339. if (file_exists($file_path)) {
  340. module_load_include('inc', $module, 'includes/TripalFieldDownloaders/' . $class);
  341. if (class_exists($class)) {
  342. return TRUE;
  343. }
  344. }
  345. }
  346. // If the libraries module is enabled then we want to look for a
  347. // TripalFieldDownloader library folder and see if our field exist there.
  348. if (module_exists('libraries')) {
  349. $library_path = libraries_get_path('TripalFieldDownloaders');
  350. $file_path = realpath(".") . '/' . $library_path .'/' . $class . '.inc';
  351. if (file_exists($file_path)) {
  352. require_once($file_path);
  353. if (class_exists($class)) {
  354. return TRUE;
  355. }
  356. }
  357. }
  358. return FALSE;
  359. }
  360. /**
  361. * More easily get the value of a single item from a field's items array.
  362. *
  363. * A Drupal field attached to an entity may have multiple items (i.e. it has
  364. * a cardinality > 1). Each of these items will always have a 'value' key that
  365. * contains the data for that field. However, fields can also have other keys
  366. * with their own values. You can easily retreive the value of these keys
  367. * using this function. What makes this function useful is that you can
  368. * provide a default value to use if the key has no value. This is useful
  369. * when developing a TripalField::widgetForm function and you need to
  370. * retreive default values and you don't want to have to always check if the
  371. * value is set.
  372. *
  373. * @param $items
  374. * The fields $items array. Compatbile with that returned by field_get_items.
  375. * @param $delta
  376. * The index of the item.
  377. * @parm $key
  378. * The name of the key within the item.
  379. * @param $default
  380. * A default value to return if the key is not set. By default the empty
  381. * string is returned.
  382. *
  383. * @return
  384. * The value assigned to the item's key; FALSE if the key doesn't exist or
  385. * the $default argument if no value is associated with the key.
  386. *
  387. * @ingroup tripal_fields_api
  388. */
  389. function tripal_get_field_item_keyval($items, $delta, $key, $default='') {
  390. if (!array_key_exists($delta, $items)) {
  391. return FALSE;
  392. }
  393. if (!array_key_exists($key, $items[$delta])) {
  394. return FALSE;
  395. }
  396. if (!$items[$delta][$key]) {
  397. return $default;
  398. }
  399. return $items[$delta][$key];
  400. }
  401. /**
  402. * Formats an element of a TripalField for use by Drupal Views.
  403. *
  404. * Sometimes the value of TripalField can be more than just a single scalar. In
  405. * this case the value is an array of key value pairs where each key is a
  406. * controlled vocabulary term. In order to support fields, filtering and
  407. * sorting by these sub elements using Drupal Views, the TripalField
  408. * implementation must provide some help to Views by describing these elements,
  409. * and then implementing a query() function to support them. However, the
  410. * naming of sub elements must follow a set convention. This function
  411. * guarantees proper naming for sub elements.
  412. *
  413. * @param $field_name
  414. * The name of the field to which the element belongs.
  415. * @param $term
  416. * The term object as returned by tripal_get_term_details();
  417. *
  418. * @ingroup tripal_fields_api
  419. */
  420. function tripal_format_views_field_element($field_name, $term) {
  421. $element_name = $term['vocabulary']['short_name'] . '__' . $term['accession'];
  422. return $field_name . '.' . $element_name;
  423. }