tripal_views.api.inc 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. <?php
  2. /**
  3. * @file
  4. * API functions for Tripal Views Integration
  5. */
  6. /**
  7. * @defgroup tripal_views_api Tripal Views Module API
  8. * @ingroup tripal_api
  9. * @{
  10. * Provides functions to help extension modules add their own tripal views integrations
  11. * as well as functions for managing default views.
  12. *
  13. * Managing Default Views:
  14. *
  15. * When you create administrative default views (or really any default view) you really
  16. * have no way to ensure that the site administrator keeps these views enabled. In some
  17. * cases this is a good thing and provides the site administrator the ability to disable
  18. * views that don't apply to their particular installation or to replace your default view
  19. * with a custom view of their own. But in other cases, particularily for administration
  20. * views, you want to gaurd against accidental disabling of your views.
  21. *
  22. * One way to do this is to add a landing page using a heook_menu() definition to a custom
  23. * callback returning HTML. You can use this page to render the view if it is enabled but
  24. * provide logic to display a message if the view is disabled. Furthermore, it's often
  25. * helpful to provide a link allowing site administrators to enable the view from your
  26. * page rather than expecting them to go to the views administration UI. This is done for
  27. * all the administration views provided by Tripal. The following is an example of how to
  28. * achomplish this functionality for your own module:
  29. * @code
  30. function mymodule_menu() {
  31. $items = array();
  32. // Create the landing page
  33. $items['admin/tripal/<PATH-TO-YOUR-LANDING-PAGE>'] = array(
  34. 'title' => 'MyModule Administration',
  35. 'description' => 'Administration of my module.',
  36. 'page callback' => 'mymodule_admin_landing_page',
  37. 'access arguments' => array('<YOUR-PERMISSION-KEY>'),
  38. 'type' => MENU_NORMAL_ITEM,
  39. );
  40. // Create one of these for each of your default views
  41. $items['admin/tripal/<PATH-TO-YOUR-ADMIN-SECTION>/views/<VIEW-MACHINE-NAME>/enable'] = array(
  42. 'title' => 'Enable <VIEW-HUMAN-READABLE-NAME>',
  43. 'page callback' => 'tripal_views_admin_enable_view',
  44. 'page arguments' => array('<VIEW-MACHINE-NAME>', '<PATH-TO-REDIRECT-TO-AFTERWARDS>'),
  45. 'access arguments' => array('<YOUR-PERMISSION-KEY>'),
  46. 'type' => MENU_CALLBACK,
  47. );
  48. return $items;
  49. }
  50. function mymodule_admin_landing_page() {
  51. // Get the View Embed Code
  52. // This function will return FALSE if your view is not enabled
  53. $view_code = views_embed_view('<VIEW-MACHINE-NAME>', '<DISPLAY-MACHINE-NAME');
  54. // If your view is enabled then embed it in this page by returning the embed code
  55. if (isset($view_code)) {
  56. $output .= $view_code;
  57. }
  58. else {
  59. // Provide the landing page with links to the menu item created in hook_menu to
  60. // to enable your view
  61. $output .= '<p>The My Module module uses primarily views to provide an '
  62. . 'administrative interface. Currently one or more views needed for this '
  63. . 'administrative interface are disabled. <strong>Click each of the following links to '
  64. . 'enable the pertinent views</strong>:</p>';
  65. $output .= '<ul>';
  66. // NOTE: <URL-FROM-MENU-TO-ENABLE-VIEW> is
  67. // admin/tripal/<PATH-TO-YOUR-ADMIN-SECTION>/views/<VIEW-MACHINE-NAME>/enable
  68. // from above hook_menu().
  69. $output .= '<li>' . l('<VIEW-HUMAN-RADABLE-NAME>', '<URL-FROM-MENU-TO-ENABLE-VIEW>') . '</li>';
  70. $output .= '</ul>';
  71. }
  72. return $output;
  73. }
  74. * @endcode
  75. *
  76. * Adding your own Tripal Views Integrations:
  77. *
  78. * One of the main ways the Tripal View API is likely to be used is if your module needs
  79. * to create it's own tripal views integration. You might need to do this for any number of
  80. * reasons but the following examples are thought to be the most common:
  81. *
  82. * 1) Your module wants to add handlers with better functionality to fields it has more
  83. * knowledge of than the general integration for all tables
  84. * @code
  85. mymodule_views_data() {
  86. // First check that your integration has not already been added
  87. // When selecting a priority, do not choose -10 or -9 and make sure it is below 0
  88. // so that individual sites still have the ability to override it, if needed
  89. $table_name = 'my_chado_table';
  90. $priority = -5;
  91. if (!tripal_views_is_integrated($table_name, $priority)) {
  92. // If you really only need to tweak an existing integration you can clone it
  93. // If you want to clone the integration that is currently taking priority
  94. // then use tripal_views_get_table_lightest_priority() as below
  95. $lightest_priority = tripal_views_get_table_lightest_priority($table_name);
  96. $setup_id = tripal_views_clone_integration($table_name, $priority, $lightest_priority);
  97. // And then make a few changes
  98. // First get the definition array created via the clone above
  99. $defn_array = tripal_views_integration_export_entry($setup_id);
  100. // Then make some changes to the array here
  101. // And finally save the changes to the integration
  102. tripal_views_integration_update_entry($setup_id, $defn_array);
  103. }
  104. }
  105. * @endcode
  106. * 2) Your module creates a chado table that is not already integrated.
  107. * @code
  108. mymodule_views_data() {
  109. // First check that your integration has not already been added
  110. // When selecting a priority, do not choose 10 or 9 and make sure it is below 0
  111. // so that individual sites still have the ability to override it, if needed
  112. $table_name = 'my_chado_table';
  113. $priority = 5;
  114. if (!tripal_views_is_integrated($table_name, $priority)) {
  115. // Describe your table using a large array as specified by tripal_views_integration_add_entry().
  116. $defn_array = array(
  117. 'table' => $table_name, //tablename or materialized view name
  118. 'name' => 'My Chado Table', // Human readable name
  119. 'type' => 'chado', //either chado or mview depending on tablename
  120. 'description' => 'Create a listing from my chado table.', //description seen when creating a view of this type
  121. 'priority' => $priority, //For Base tripal modules: 10; custom modules: 9 to 0;
  122. 'base_table' => TRUE //either TRUE or FALSE depending on whether the current table should show up in the add view list
  123. 'fields' => array(
  124. 'feature_id' => array(
  125. 'name' => 'feature_id', //field name in database
  126. 'title' => 'Feature ID', //human-readable name -seen in Views UI
  127. 'description' => 'This is the unique identifier for features', //help/description seen in Views UI
  128. 'type' => 'int', // the type of field
  129. 'handlers' => array( //possible keys are field, filter, sort, argument, relationship
  130. 'field' => array(
  131. 'name' => 'chado_views_handler_numeric' //name of handler
  132. ),
  133. 'filter' => array( ... ),
  134. ...
  135. ),
  136. 'join' => array( //describe a table that joins to this one via this field
  137. 'table' => 'featureprop', //table to join to
  138. 'field' => 'feature_id', //field in above table (featureprop)
  139. 'handler' => 'views_handler_join_chado_aggregator', //handler to use
  140. ),
  141. )
  142. ),
  143. );
  144. // Actually create the entry
  145. tripal_views_integration_add_entry($defn_array);
  146. }
  147. }
  148. * @endcode
  149. * @}
  150. */
  151. /**
  152. * Programatically enable view
  153. *
  154. * This should be used in a hook_menu definition as the callback to provide a link
  155. * to enable the view (first example). It can also be called directly if needed (second example).
  156. * @code
  157. // Create a URL that when the user navigates there, a given view will be enabled.
  158. // You will still need to provide a link to this menu item somewhere appropriate (ie: an admin landing page).
  159. function mymodule_menu() {
  160. $items = array();
  161. // Create one of these for each of your default views
  162. $items['admin/tripal/<PATH-TO-YOUR-ADMIN-SECTION>/views/<VIEW-MACHINE-NAME>/enable'] = array(
  163. 'title' => 'Enable <VIEW-HUMAN-READABLE-NAME>',
  164. 'page callback' => 'tripal_views_admin_enable_view',
  165. 'page arguments' => array('<VIEW-MACHINE-NAME>', '<PATH-TO-REDIRECT-TO-AFTERWARDS>'),
  166. 'access arguments' => array('<YOUR-PERMISSION-KEY>'),
  167. 'type' => MENU_CALLBACK,
  168. );
  169. return $items;
  170. }
  171. // Call this function directly to disable a view
  172. // The example shows enabling your own default view when your module is enabled.
  173. // This might be useful if you disable your view when your module is disabled.
  174. function mymodule_enable() {
  175. $view_name = '<VIEW-MACHINE-NAME>';
  176. tripal_views_admin_enable_view($view_name);
  177. }
  178. * @endcode
  179. *
  180. * @param $view_name
  181. * The machine-name of the view to be enabled
  182. * @param $redirect_link
  183. * The path to redirect to. FALSE if no redirect needed
  184. *
  185. * @ingroup tripal_views_api
  186. */
  187. function tripal_views_admin_enable_view($view_name, $redirect_link = FALSE) {
  188. $status = variable_get('views_defaults', array());
  189. if (isset($status[$view_name])) {
  190. $status[$view_name] = FALSE;
  191. variable_set('views_defaults', $status);
  192. drupal_set_message("Successfully Enabled $view_name");
  193. }
  194. else {
  195. drupal_set_message("Unable to find a view by the name of '$view_name'. Unable to enable this view.",'error');
  196. }
  197. if ($redirect_link) {
  198. drupal_goto($redirect_link);
  199. }
  200. }
  201. /**
  202. * Programatically disable view.
  203. *
  204. * This should be used in a hook_menu definition as the callback to provide a link
  205. * to disable the view (first example). It can also be called directly if needed (second example).
  206. * @code
  207. // Create a URL that when the user navigates there, a given view will be disabled.
  208. // You will still need to provide a link to this menu item somewhere appropriate.
  209. function mymodule_menu() {
  210. $items = array();
  211. // Create one of these for each of your default views
  212. $items['admin/tripal/<PATH-TO-YOUR-ADMIN-SECTION>/views/<VIEW-MACHINE-NAME>/disable'] = array(
  213. 'title' => 'Disable <VIEW-HUMAN-READABLE-NAME>',
  214. 'page callback' => 'tripal_views_admin_disable_view',
  215. 'page arguments' => array('<VIEW-MACHINE-NAME>', '<PATH-TO-REDIRECT-TO-AFTERWARDS>'),
  216. 'access arguments' => array('<YOUR-PERMISSION-KEY>'),
  217. 'type' => MENU_CALLBACK,
  218. );
  219. return $items;
  220. }
  221. // Call this function directly to disable a view
  222. // The example shows disabling your own default view when your module is uninstalled
  223. function mymodule_uninstall() {
  224. $view_name = '<VIEW-MACHINE-NAME>';
  225. tripal_views_admin_disable_view($view_name);
  226. }
  227. * @endcode
  228. *
  229. * @param $view_name
  230. * The machine-name of the view to be enabled
  231. * @param $redirect_link
  232. * The path to redirect to. FALSE if no redirect needed
  233. *
  234. * @ingroup tripal_views_api
  235. */
  236. function tripal_views_admin_disable_view($view_name, $redirect_link = FALSE) {
  237. $status = variable_get('views_defaults', array());
  238. if (isset($status[$view_name])) {
  239. $status[$view_name] = TRUE;
  240. variable_set('views_defaults', $status);
  241. drupal_set_message("Disabled $view_name");
  242. }
  243. else {
  244. drupal_set_message("Unable to find a view by the name of '$view_name'. Unable to disable this view.",'error');
  245. }
  246. if ($redirect_link) {
  247. drupal_goto($redirect_link);
  248. }
  249. }
  250. /**
  251. * Retrieve the priority of the lightest priority for a given table.
  252. *
  253. * NOTE: Uses lightest priority (drupal-style) where the range is from -10 to 10
  254. * and -10 is of highest priority.
  255. *
  256. * @param $table_name
  257. * The name of the table to retrieve the setup ID for. This can be either a materialized
  258. * view or a chado table
  259. *
  260. * @return
  261. * returns the lowest priority. If the table has not been integrated, a priority of 10
  262. * is returned.
  263. *
  264. * @ingroup tripal_views_api
  265. */
  266. function tripal_views_get_table_lightest_priority($table_name) {
  267. // D7 TODO: Check DBTNG changes work
  268. $sql = "SELECT priority FROM {tripal_views} WHERE table_name=:table ORDER BY priority ASC";
  269. $setup = db_query($sql, array(':table' => $table_name));
  270. $setup = $setup->fetchObject();
  271. if ($setup) {
  272. return $setup->priority;
  273. }
  274. else {
  275. // default priority is 10
  276. return 10;
  277. }
  278. }
  279. /**
  280. * Retrieve the views integration setup_id with the lightest priority for a given table
  281. *
  282. * NOTE: Uses lightest priority (drupal-style) where the range is from -10 to 10
  283. * and -10 is of highest priority.
  284. *
  285. * @param $table_name
  286. * The name of the table to retrieve the setup ID for. This can be either a materialized
  287. * view or a chado table
  288. *
  289. * @return
  290. * On success, the setup_id to use for integration of this table; otherwise FALSE
  291. *
  292. * @ingroup tripal_views_api
  293. */
  294. function tripal_views_get_lightest_priority_setup($table_name) {
  295. // D7 TODO: Check DBTNG changes work
  296. $sql = "SELECT setup_id FROM {tripal_views} WHERE table_name=:table ORDER BY priority ASC";
  297. $setup = db_query($sql, array(':table' => $table_name));
  298. $setup = $setup->fetchObject();
  299. if ($setup) {
  300. return $setup->setup_id;
  301. }
  302. else {
  303. return FALSE;
  304. }
  305. }
  306. /**
  307. * Retrieve the views integration setup_id with the given priority/table combination.
  308. *
  309. * @param $table_name
  310. * The name of the table to retrieve the setup ID for. This can be either a materialized
  311. * view or a chado table
  312. * @param $priority
  313. * The priority of the integration to retrieve the setup_id for
  314. *
  315. * @return
  316. * On success, the setup_id to use for integration of this table; otherwise FALSE
  317. *
  318. * @ingroup tripal_views_api
  319. */
  320. function tripal_views_get_setup_id($table_name, $priority) {
  321. // D7 TODO: Check DBTNG changes work
  322. $sql = "SELECT setup_id FROM {tripal_views} WHERE table_name=:table AND priority=:priority ORDER BY priority ASC";
  323. $setup = db_query($sql, array(':table' => $table_name, ':priority' => $priority));
  324. $setup = $setup->fetchObject();
  325. if ($setup) {
  326. return $setup->setup_id;
  327. }
  328. else {
  329. return FALSE;
  330. }
  331. }
  332. /**
  333. * Check to see if this table already has an integration record with the given priority.
  334. *
  335. * @param $table_name
  336. * The name of the table to check for integration
  337. * @param $priority (optional)
  338. * The priority of record to check for
  339. *
  340. * @return
  341. * If the table is already integrated, the setup_id of the existing integration
  342. * record is returned (If priority is not specified this will be the lightest record);
  343. * Otherwise the table is not already integrated and FALSE is returned.
  344. *
  345. * @ingroup tripal_views_api
  346. */
  347. function tripal_views_is_integrated($table_name, $priority = NULL) {
  348. if ($priority) {
  349. // D7 TODO: Check DBTNG changes work
  350. $sql = "SELECT setup_id FROM {tripal_views} WHERE table_name=:table AND priority=:priority";
  351. $setup = db_query($sql, array(':table' => $table_name, ':priority' => $priority));
  352. $setup = $setup->fetchObject();
  353. }
  354. else {
  355. // D7 TODO: Check DBTNG changes work
  356. $sql = "SELECT setup_id FROM {tripal_views} WHERE table_name=:table ORDER BY priority ASC";
  357. $setup = db_query($sql, array(':table' => $table_name));
  358. $setup = $setup->fetchObject();
  359. }
  360. if ($setup) {
  361. return $setup->setup_id;
  362. }
  363. else {
  364. return FALSE;
  365. }
  366. }
  367. /**
  368. * Checks if you are dealing with the lightest priority setup for a given table. This is a
  369. * good way to determine whether your modules integration is being used by views.
  370. *
  371. * @param $setup_id
  372. * The ID of the setup to check (is this setup the lightest one?)
  373. * @param $table_name
  374. * The name of the table associated with this setup
  375. *
  376. * @return TRUE is this is the lightest priority; FALSE otherwise
  377. *
  378. * @ingroup tripal_views_api
  379. */
  380. function tripal_views_is_lightest_priority_setup($setup_id, $table_name) {
  381. $lightest_priority_setup_id = tripal_views_get_lightest_priority_setup($table_name);
  382. if ($lightest_priority_setup_id == $setup_id) {
  383. return TRUE;
  384. }
  385. else {
  386. return FALSE;
  387. }
  388. }
  389. /**
  390. * Rebuilds all the default integrations.
  391. *
  392. * This essentially clears the cache in case you mess up the integrations in your site.
  393. * This should not be used during module development since it really only rebuilds the
  394. * integrations described by all enabled modules in the site and if $delete_first is
  395. * TRUE it can delete custom integrations created by site administrators which will not
  396. * make your module popular.
  397. *
  398. * @param $delete_first
  399. * If TRUE then all integrations are first deleted.
  400. *
  401. * @ingroup tripal_views_api
  402. */
  403. function tripal_views_rebuild_views_integrations($delete_first = FALSE) {
  404. if ($delete_first) {
  405. tripal_views_delete_all_integrations();
  406. }
  407. tripal_views_integrate_all_chado_tables();
  408. drupal_set_message('Successfully rebuilt default Tripal Views Integrations');
  409. }
  410. /**
  411. * Add views integration records into the tripal_views* tables.
  412. *
  413. * This is the programatic way to add your own integrations to the tripal views integrations
  414. * list. Keep in mind that the priority set in your $defn_array needs to be lighter than
  415. * any existing integrations to be used by views and that it should still be below 0
  416. * in order to allow site administrators to override it should they need to.
  417. *
  418. * @param $defn_array
  419. * An array describing the structure and fields of the table
  420. *
  421. * @return
  422. * True/False if completed successfully/not
  423. *
  424. * Example usage (in hook_install()):
  425. * @code
  426. $defn_array = array(
  427. 'table' => 'feature', //tablename or materialized view name
  428. 'name' => 'Sequence Features', // Human readable name
  429. 'type' => 'chado', //either chado or mview depending on tablename
  430. 'description' => 'Create a listing of features.', //description seen when creating a view of this type
  431. 'priority' => 10, //For Base tripal modules: 10; custom modules: 9 to 0;
  432. 'base_table' => TRUE //either TRUE or FALSE depending on whether the current table should show up in the add view list
  433. 'fields' => array(
  434. 'feature_id' => array(
  435. 'name' => 'feature_id', //field name in database
  436. 'title' => 'Feature ID', //human-readable name -seen in Views UI
  437. 'description' => 'This is the unique identifier for features', //help/description seen in Views UI
  438. 'type' => 'int', // the type of field
  439. 'handlers' => array( //possible keys are field, filter, sort, argument, relationship
  440. 'field' => array(
  441. 'name' => 'chado_views_handler_numeric' //name of handler
  442. ),
  443. 'filter' => array( ... ),
  444. ...
  445. ),
  446. 'join' => array( //describe a table that joins to this one via this field
  447. 'table' => 'featureprop', //table to join to
  448. 'field' => 'feature_id', //field in above table (featureprop)
  449. 'handler' => 'views_handler_join_chado_aggregator', //handler to use
  450. ),
  451. )
  452. ),
  453. );
  454. tripal_views_integration_add_entry($defn_array);
  455. * @endcode
  456. *
  457. * @ingroup tripal_views_api
  458. */
  459. function tripal_views_integration_add_entry($defn_array) {
  460. $no_errors = TRUE;
  461. if (empty($defn_array['table'])) {
  462. tripal_report_error('tripal_views', TRIPAL_WARNING, 'Recieved integration with no tablename: %defn', array('%defn' => print_r($defn_array,TRUE)));
  463. $no_errors = FALSE;
  464. return $no_errors;
  465. }
  466. // First insert into tripal_views
  467. $view_record = array(
  468. 'table_name' => $defn_array['table'],
  469. 'name' => $defn_array['name'],
  470. 'comment' => $defn_array['description'],
  471. 'priority' => $defn_array['priority'],
  472. 'base_table' => $defn_array['base_table'],
  473. );
  474. if ($defn_array['type'] == 'mview') {
  475. // D7 TODO: Check DBTNG changes work
  476. $mview = db_query("SELECT mview_id FROM {tripal_mviews} WHERE mv_table=:table", array(':table' => $defn_array['table']));
  477. $mview = $mview->fetchObject();
  478. $view_record['mview_id'] = $mview->mview_id;
  479. if (!$mview->mview_id) {
  480. return FALSE;
  481. }
  482. }
  483. if ($view_record['name']) { // && $view_record['comment']) { # SPF: commented out 9/24/2012 .. It's not required on the form
  484. if (isset($defn_array['additional_content'])) {
  485. // D7 TODO: Check DBTNG changes work
  486. $setup = db_query(
  487. "SELECT * FROM {tripal_views} WHERE table_name=:table AND priority=:priority",
  488. array(':table' => $view_record['table_name'], ':priority' => $view_record['priority'])
  489. );
  490. $setup = $setup->fetchObject();
  491. if (empty($setup->setup_id)) {
  492. $status = drupal_write_record('tripal_views', $view_record);
  493. }
  494. else {
  495. $view_record['setup_id'] = $setup->setup_id;
  496. $status = drupal_write_record('tripal_views', $view_record, 'setup_id');
  497. }
  498. }
  499. else {
  500. $status = drupal_write_record('tripal_views', $view_record);
  501. }
  502. }
  503. else {
  504. $status = FALSE;
  505. drupal_set_message(t('Unable to integrate "%table" table due to a missing name field.', array('%table' => $defn_array['table'])), 'error');
  506. }
  507. if ($status) {
  508. // Need to update the tripal_views record so base_table can be false
  509. // this is a fix because drupal_write_record() puts in defaults if !isset()
  510. // and a variable is considered not set if it's null!
  511. // D7 TODO: Check DBTNG changes work
  512. db_query(
  513. "UPDATE {tripal_views} SET base_table=:base WHERE table_name=:table AND priority=:priority",
  514. array(
  515. ':base' => $defn_array['base_table'],
  516. ':table' => $defn_array['table'],
  517. ':priority' => $defn_array['priority']
  518. )
  519. );
  520. // Insert Field Definitions
  521. foreach ($defn_array['fields'] as $field) {
  522. $field_record = array(
  523. 'setup_id' => $view_record['setup_id'],
  524. 'column_name' => $field['name'],
  525. 'name' => $field['title'],
  526. 'description' => $field['description'],
  527. 'type' => $field['type'],
  528. );
  529. if ($view_record['setup_id'] && $field['name'] && $field['title'] && $field['description'] && $field['type']) {
  530. if (isset($defn_array['additional_content'])) {
  531. // D7 TODO: Check DBTNG changes work
  532. $is = db_query(
  533. "SELECT true as present FROM {tripal_views_field} WHERE column_name=:column AND setup_id=:setup",
  534. array(
  535. ':column' => $field_record['column_name'],
  536. ':setup' => $field_record['setup_id']
  537. )
  538. );
  539. $is = $is->fetchObject();
  540. if (!$is->present) {
  541. $status = drupal_write_record('tripal_views_field', $field_record);
  542. }
  543. else {
  544. $status = drupal_write_record('tripal_views_field', $field_record, array('setup_id', 'column_name'));
  545. }
  546. }
  547. else {
  548. $status = drupal_write_record('tripal_views_field', $field_record);
  549. }
  550. }
  551. else {
  552. drupal_set_message(t('Unable to integrate %name field due to missing required fields.', array('%name' => $field['name'])), 'error');
  553. $status = FALSE;
  554. }
  555. if ($status) {
  556. // Insert Handler Definitions
  557. foreach ($field['handlers'] as $handler_type => $handler) {
  558. $handler_record = array(
  559. 'setup_id' => $view_record['setup_id'],
  560. 'column_name' => $field['name'],
  561. 'handler_type' => $handler_type,
  562. 'handler_name' => $handler['name'],
  563. 'arguments' => serialize($handler)
  564. );
  565. if ($view_record['setup_id'] && $field['name'] && $handler_type && $handler['name'] && $handler) {
  566. $status = drupal_write_record('tripal_views_handlers', $handler_record);
  567. }
  568. else {
  569. $status = FALSE;
  570. }
  571. if (!$status) {
  572. drupal_set_message(t('Unable to integrate %handler_type handler: %handler_name', array('%handler_type' => $handler_type, '%handler_name' => $handler['name'])), 'error');
  573. $no_errors = FALSE;
  574. }
  575. }
  576. // Insert Joins
  577. if (!is_array($field['joins'])) {
  578. $field['joins'] = array();
  579. }
  580. foreach ($field['joins'] as $join) {
  581. $join_record = array(
  582. 'setup_id' => $view_record['setup_id'],
  583. 'base_table' => $defn_array['table'],
  584. 'base_field' => $field['name'],
  585. 'left_table' => $join['table'],
  586. 'left_field' => $join['field'],
  587. );
  588. $join_record['handler'] = (!empty($join['handler'])) ? $join['handler'] : 'views_join';
  589. $join_record['relationship_handler'] = (!empty($join['relationship_handler'])) ? $join['relationship_handler'] : 'views_handler_relationship';
  590. $join_record['relationship_only'] = (!empty($join['relationship_only'])) ? $join['relationship_only'] : 0;
  591. if ($view_record['setup_id'] && $defn_array['table'] && $field['name'] && $join['table'] && $join['field']) {
  592. $status = drupal_write_record('tripal_views_join', $join_record);
  593. }
  594. else {
  595. $status = FALSE;
  596. }
  597. if (!$status) {
  598. drupal_set_message(
  599. t(
  600. 'Unable to join %left_table.%left_field with %table.%field',
  601. array(
  602. '%left_table' => $join['table'],
  603. '%left_field' => $join['field'],
  604. '%table' => $defn_array['table'],
  605. '%field' => $field['name']
  606. )
  607. ),
  608. 'error'
  609. );
  610. $no_errors = FALSE;
  611. }
  612. }
  613. }
  614. else {
  615. drupal_set_message(t('Unable to integrate %field_name field', array('%field_name' => $field['name'])), 'error');
  616. $no_errors = FALSE;
  617. }
  618. }
  619. }
  620. else {
  621. drupal_set_message(t('Unable to set default tripal views integration'), 'error');
  622. $no_errors = FALSE;
  623. }
  624. return $no_errors;
  625. }
  626. /**
  627. * Export Views integration records.
  628. *
  629. * This is a great way to create your own integration since it returns an already defined
  630. * integration in array form that you can modify. After modifications simply set the
  631. * priority to something lighter (but still below 0) than any existing integrations
  632. * and use tripal_views_integration_add_entry() to add it to the list of integrations.
  633. *
  634. * @param $setup_id
  635. * The unique setup id of the tripal views integration
  636. *
  637. * @return
  638. * A views integration definition array as used by tripal_views_integration_add_entry()
  639. *
  640. * @ingroup tripal_views_api
  641. */
  642. function tripal_views_integration_export_entry($setup_id) {
  643. // Main setup details
  644. // D7 TODO: Check DBTNG changes work
  645. $r = db_query("SELECT * FROM {tripal_views} WHERE setup_id=:setup", array(':setup' => $setup_id));
  646. $r = $r->fetchObject();
  647. $defn_array = array(
  648. 'table' => $r->table_name,
  649. 'name' => $r->name,
  650. 'type' => ($r->mview_id) ? 'mview' : 'chado',
  651. 'description' => $r->comment,
  652. 'priority' => $r->priority,
  653. 'base_table' => $r->base_table,
  654. 'fields' => array(),
  655. );
  656. // Add fields
  657. // D7 TODO: Check DBTNG changes work
  658. $resource = db_query("SELECT * FROM {tripal_views_field} WHERE setup_id=:setup", array(':setup' => $setup_id));
  659. foreach ($resource as $r) {
  660. $defn_array['fields'][ $r->column_name ] = array(
  661. 'name' => $r->column_name,
  662. 'title' => $r->name,
  663. 'description' => $r->description,
  664. 'type' => $r->type,
  665. 'handlers' => array(),
  666. 'joins' => array()
  667. );
  668. }
  669. // Add handlers
  670. // D7 TODO: Check DBTNG changes work
  671. $resource = db_query("SELECT * FROM {tripal_views_handlers} WHERE setup_id=:setup", array(':setup' => $setup_id));
  672. foreach ($resource as $r) {
  673. $defn_array['fields'][ $r->column_name ]['handlers'][ $r->handler_type ] = array(
  674. 'name' => $r->handler_name
  675. );
  676. }
  677. // Add joins
  678. // D7 TODO: Check DBTNG changes work
  679. $resource = db_query("SELECT * FROM {tripal_views_join} WHERE setup_id=:setup", array(':setup' => $setup_id));
  680. foreach ($resource as $r) {
  681. $defn_array['fields'][ $r->base_field ]['joins'][ $r->left_table ] = array(
  682. 'table' => $r->left_table,
  683. 'field' => $r->left_field,
  684. 'handler' => $r->handler,
  685. );
  686. }
  687. return $defn_array;
  688. }
  689. /**
  690. * Removes a View Integration Entry when you only know the table the integration was
  691. * created for and the priority.
  692. *
  693. * This should only be used to remove integrations created by your own module (possibly
  694. * on uninstall of your module). To override existing integrations simply create your own
  695. * integration with a lighter priority using tripal_views_clone_integration() or
  696. * tripal_views_integration_export_entry() to create a template.
  697. *
  698. * @param $table_name
  699. * The name of the table to remove a views integration entry for
  700. * @param $priority
  701. * The priority of the of views integration entry
  702. *
  703. * @return
  704. * TRUE on Success; FALSE otherwise
  705. *
  706. * @ingroup tripal_views_api
  707. */
  708. function tripal_views_integration_remove_entry_by_table_name($table_name, $priority) {
  709. // D7 TODO: Check DBTNG changes work
  710. $views = db_query(
  711. "SELECT * FROM {tripal_views} WHERE table_name=:table AND priority=:priority",
  712. array(
  713. ':table' => $table_name,
  714. ':priority' => $priority
  715. )
  716. );
  717. $views = $views->fetchObject();
  718. if ($views->setup_id) {
  719. tripal_views_integration_remove_entry_by_setup_id($views->setup_id);
  720. return TRUE;
  721. }
  722. else {
  723. return FALSE;
  724. }
  725. }
  726. /**
  727. * Removes a View Integration Entry when you know the setup_id
  728. *
  729. * This should only be used to remove integrations created by your own module (possibly
  730. * on uninstall of your module). To override existing integrations simply create your own
  731. * integration with a lighter priority using tripal_views_clone_integration() or
  732. * tripal_views_integration_export_entry() to create a template.
  733. *
  734. * @param $setup_id
  735. * The setup ID of the views integration entry to remove
  736. *
  737. * @ingroup tripal_views_api
  738. */
  739. function tripal_views_integration_remove_entry_by_setup_id($setup_id) {
  740. // D7 TODO: Check DBTNG changes work
  741. db_query('DELETE FROM {tripal_views} WHERE setup_id=:setup', array(':setup' => $setup_id));
  742. db_query('DELETE FROM {tripal_views_field} WHERE setup_id=:setup', array(':setup' => $setup_id));
  743. db_query('DELETE FROM {tripal_views_handlers} WHERE setup_id=:setup', array(':setup' => $setup_id));
  744. db_query('DELETE FROM {tripal_views_join} WHERE setup_id=:setup', array(':setup' => $setup_id));
  745. }
  746. /**
  747. * Clone an integration. This is often a great way to create your own module-specific
  748. * integration while still benifiting from an existing (or even the lightest priority)
  749. * integration.
  750. *
  751. * @param $table_name
  752. * The table for which you'd like to clone an integration
  753. * @param $new_priority
  754. * The priority of the clone; this is the integration which will be created.
  755. * If no priority is supplied then one lighter then the $template_priority will be used.
  756. * @param $template_priority
  757. * The priority of the template to be used for the clone; this is an existing integration.
  758. * If no priority is supplied then the lightest priority will be used.
  759. *
  760. * @ingroup tripal_views_api
  761. */
  762. function tripal_views_clone_integration($table_name, $new_priority = NULL, $template_priority = NULL) {
  763. if (empty($template_priority)) {
  764. $template_setup_id = tripal_views_get_lightest_priority_setup($table_name);
  765. }
  766. else {
  767. $template_setup_id = tripal_views_get_setup_id($table_name, $template_priority);
  768. }
  769. $defn_array = tripal_views_integration_export_entry($template_setup_id);
  770. if (empty($new_priority)) {
  771. $defn_array['priority'] = $new_priority;
  772. }
  773. else {
  774. $new_priority = $defn_array['priority'] - 1;
  775. $defn_array['priority'] = $defn_array['priority'] - 1;
  776. }
  777. // D7 TODO: Check DBTNG changes work
  778. tripal_views_integration_add_entry($defn_array);
  779. $setup_id = db_query(
  780. "SELECT setup_id FROM {tripal_views} WHERE table_name=:table AND priority=:priority",
  781. array(
  782. ':table' => $table_name,
  783. ':priority' => $new_priority
  784. )
  785. );
  786. $setup_id = $setup_id->fetchObject();
  787. if (empty($setup_id)) {
  788. tripal_report_error('tripal_views', TRIPAL_ERROR, 'Unable to clone the setup for %table in order to add the following field to the integration: %field.',
  789. array('%table' => $table_name, '%field' => print_r($field_array,TRUE)));
  790. return FALSE;
  791. }
  792. else {
  793. return $setup_id;
  794. }
  795. }
  796. /**
  797. * Adds the given field to an existing or cloned integration. In the case of a cloned
  798. * integration, the lightest integration is used as the template for the clone.
  799. *
  800. * NOTE: If that field already exists in the specified integration then it will first be
  801. * deleted and the new one added.
  802. *
  803. * @param $table_name
  804. * The name of the table the integration is for
  805. * @param $priority
  806. * The priority of the integration to use; pass NULL to use the lightest integration
  807. * @param $field
  808. * An array describing the field ot add; uses the same format as the $defn_array
  809. *
  810. * @return
  811. * TRUE if the field was added successfully; FALSE otherwise
  812. *
  813. * @ingroup tripal_views_api
  814. */
  815. function tripal_views_add_field_to_integration($table_name, $priority, $field) {
  816. $no_errors = TRUE;
  817. // If no priority is supplied then add the field to the lightest integration
  818. if (empty($priority)) {
  819. $priority = tripal_views_get_table_lightest_priority($table_name);
  820. }
  821. // First get the setup_id
  822. // D7 TODO: Check DBTNG changes work
  823. $setup_id = db_query(
  824. "SELECT setup_id FROM {tripal_views} WHERE table_name=:table AND priority=:priority",
  825. array(
  826. ':table' => $table_name,
  827. ':priority' => $priority
  828. )
  829. );
  830. $setup_id = $setup_id->fetchObject();
  831. // If there isn't an integration matching that table/priority combination
  832. // then clone the lightest priority integration
  833. if (empty($setup_id)) {
  834. $setup_id = tripal_views_clone_integration($table_name, $priority);
  835. }
  836. // Now delete any existing field
  837. db_query("DELETE FROM {tripal_views_field} WHERE setup_id=:setup AND column_name=:column",
  838. array(':setup' => $setup_id, 'column' => $field['name'])
  839. );
  840. db_query("DELETE FROM {tripal_views_handlers} WHERE setup_id=:setup AND column_name=:column",
  841. array(':setup' => $setup_id, 'column' => $field['name'])
  842. );
  843. db_query("DELETE FROM {tripal_views_join} WHERE setup_id=:setup AND base_table=:table AND base_field=:field",
  844. array(':setup' => $setup_id, ':table' => $table_name, ':field' => $field['name'])
  845. );
  846. // Now we need to add/update the field
  847. $field_record = array(
  848. 'setup_id' => $setup_id,
  849. 'column_name' => $field['name'],
  850. 'name' => $field['title'],
  851. 'description' => $field['description'],
  852. 'type' => $field['type'],
  853. );
  854. if ($setup_id && $field['name'] && $field['title'] && $field['description'] && $field['type']) {
  855. if ($defn_array['additional_content']) {
  856. // D7 TODO: Check DBTNG changes work
  857. $is = db_query(
  858. "SELECT true as present FROM {tripal_views_field} WHERE column_name=:column AND setup_id=:setup",
  859. array(':column' => $field_record['column_name'], ':setup' => $field_record['setup_id'])
  860. );
  861. $is = $is->fetchObject();
  862. if (!$is->present) {
  863. $status = drupal_write_record('tripal_views_field', $field_record);
  864. }
  865. else {
  866. $status = drupal_write_record('tripal_views_field', $field_record, array('setup_id', 'column_name'));
  867. }
  868. }
  869. else {
  870. $status = drupal_write_record('tripal_views_field', $field_record);
  871. }
  872. }
  873. else {
  874. drupal_set_message(t('Unable to integrate %name field due to missing required fields.', array('%name' => $field['name'])), 'error');
  875. $status = FALSE;
  876. }
  877. if ($status) {
  878. // Insert Handler Definitions
  879. foreach ($field['handlers'] as $handler_type => $handler) {
  880. $handler_record = array(
  881. 'setup_id' => $setup_id,
  882. 'column_name' => $field['name'],
  883. 'handler_type' => $handler_type,
  884. 'handler_name' => $handler['name'],
  885. 'arguments' => serialize($handler)
  886. );
  887. if ($setup_id && $field['name'] && $handler_type && $handler['name'] && $handler) {
  888. $status = drupal_write_record('tripal_views_handlers', $handler_record);
  889. }
  890. else {
  891. $status = FALSE;
  892. }
  893. if (!$status) {
  894. drupal_set_message(t('Unable to integrate %handler_type handler: %handler_name', array('%handler_type' => $handler_type, '%handler_name' => $handler['name'])), 'error');
  895. $no_errors = FALSE;
  896. }
  897. }
  898. // Insert Joins
  899. if (!is_array($field['joins'])) {
  900. $field['joins'] = array();
  901. }
  902. foreach ($field['joins'] as $join) {
  903. $join_record = array(
  904. 'setup_id' => $setup_id,
  905. 'base_table' => $defn_array['table'],
  906. 'base_field' => $field['name'],
  907. 'left_table' => $join['table'],
  908. 'left_field' => $join['field'],
  909. );
  910. if (!empty($join['handler'])) {
  911. $join_record['handler'] = $join['handler'];
  912. }
  913. else {
  914. $join_record['handler'] = 'views_join';
  915. }
  916. if ($setup_id && $defn_array['table'] && $field['name'] && $join['table'] && $join['field']) {
  917. $status = drupal_write_record('tripal_views_join', $join_record);
  918. }
  919. else {
  920. $status = FALSE;
  921. }
  922. if (!$status) {
  923. drupal_set_message(
  924. t(
  925. 'Unable to join %left_table.%left_field with %table.%field',
  926. array(
  927. '%left_table' => $join['table'],
  928. '%left_field' => $join['field'],
  929. '%table' => $defn_array['table'],
  930. '%field' => $field['name']
  931. )
  932. ),
  933. 'error'
  934. );
  935. $no_errors = FALSE;
  936. }
  937. }
  938. }
  939. else {
  940. drupal_set_message(t('Unable to integrate %field_name field', array('%field_name' => $field['name'])), 'error');
  941. $no_errors = FALSE;
  942. }
  943. return $no_errors;
  944. }
  945. /**
  946. * Remove a join from an integration. This is usually done after cloning an existing
  947. * integration using tripal_views_clone_integration().
  948. *
  949. * @param $setup_id
  950. * The setup_id of the integration to delete the join from
  951. * @param $base_table
  952. * The name of the base table involved the join
  953. * @param $base_field
  954. * The field from the base table involved in the join
  955. * @param $left_table
  956. * The name of the other table involved in the join
  957. * @param $left_field
  958. * The name of the field from the other table involved in the join
  959. *
  960. * @ingroup tripal_views_api
  961. */
  962. function tripal_views_remove_join_from_integration($setup_id, $base_table, $base_field, $left_table, $left_field) {
  963. db_query(
  964. "DELETE FROM {tripal_views_join} WHERE setup_id=:setup AND base_table=:base-table AND base_field=:base-field AND left_table=:left-table AND left_field=:left-field",
  965. array(
  966. ':setup' => $setup_id,
  967. ':base-table' => $base_table,
  968. ':base-field' => $base_field,
  969. ':left-table' => $left_table,
  970. ':left-field' => $left_field
  971. )
  972. );
  973. }