calais_geo.module

Tracking 6.x-3.x branch
  1. drupal
    1. 6 contributions/opencalais/contrib/calais_geo/calais_geo.module

Functions & methods

NameDescription
calais_geo_blockImplementation of hook_block().
calais_geo_block_contentsRender the body of the geo block.
calais_geo_calc_map_centerFind a center point between all markers. Pretty basic approach, take the max & min of lat/lon and average it.
calais_geo_form_alterImplementation of hook_form_alter().
calais_geo_loadFetch the geo data for a node
calais_geo_menuImplementation of hook_menu().
calais_geo_nodeapiImplementation of hook_nodeapi().
calais_geo_permImplementation of hook_perm().
calais_geo_saveSave the geo data for this particular node id.
calais_geo_themeImplementation of hook_theme().
template_preprocess_calais_geo_markerDefault theme function to rendering the text that goes in the Google Map marker bubble.
theme_calais_geo_render_mapBuild the map.
_calais_geo_block_listProvide block listing.
_calais_geo_block_viewDisplay geo block.
_calais_geo_should_modify_formShould we provide mapping configuration for this node type
_cg_fix_d_w_r_null

File

View source
  1. <?php
  2. /*
  3. Copyright (C) 2008 by Phase2 Technology.
  4. Author(s): Frank Febbraro
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY. See the LICENSE.txt file for more details.
  9. */
  10. /**
  11. * @file
  12. */
  13. /**
  14. * Implementation of hook_perm().
  15. */
  16. function calais_geo_perm() {
  17. return array('administer calais geo');
  18. }
  19. /**
  20. * Implementation of hook_theme().
  21. */
  22. function calais_geo_theme() {
  23. return array(
  24. 'calais_geo_marker' => array(
  25. 'arguments' => array('node' => NULL, 'term' => NULL),
  26. 'path' => drupal_get_path('module', 'calais_geo'),
  27. 'template' => "calais-geo-marker",
  28. ),
  29. 'calais_geo_render_map' => array(
  30. 'arguments' => array('node' => NULL, 'geo_data' => NULL),
  31. ),
  32. );
  33. }
  34. /**
  35. * Implementation of hook_menu().
  36. */
  37. function calais_geo_menu() {
  38. $items['admin/settings/calais/geo'] = array(
  39. 'title' => 'Calais Geo Settings',
  40. 'description' => 'Configuration for Calais based Geomapping.',
  41. 'page callback' => 'drupal_get_form',
  42. 'page arguments' => array('calais_geo_settings_form'),
  43. 'access arguments' => array('administer calais geo'),
  44. 'file' => 'calais_geo.admin.inc',
  45. );
  46. return $items;
  47. }
  48. /**
  49. * Implementation of hook_block().
  50. */
  51. function calais_geo_block($op = 'list', $delta = 0, $edit = array()) {
  52. switch ($op) {
  53. case 'list':
  54. return _calais_geo_block_list();
  55. break;
  56. case 'view':
  57. return _calais_geo_block_view($delta);
  58. break;
  59. }
  60. }
  61. /**
  62. * Provide block listing.
  63. */
  64. function _calais_geo_block_list(){
  65. $blocks = array();
  66. $blocks[0] = array(
  67. 'info' => t('Calais Geo Block'),
  68. );
  69. return $blocks;
  70. }
  71. /**
  72. * Display geo block.
  73. */
  74. function _calais_geo_block_view($delta){
  75. switch ($delta) {
  76. case 0:
  77. if(arg(0) == 'node' && is_numeric(arg(1))) {
  78. $block['subject'] = t('Calais Geo Block');
  79. $block['content'] = calais_geo_block_contents($delta, arg(1));
  80. }
  81. break;
  82. }
  83. return $block;
  84. }
  85. /**
  86. * Render the body of the geo block.
  87. */
  88. function calais_geo_block_contents($delta, $nid){
  89. $node = node_load($nid);
  90. $geo_data = calais_geo_load($node->vid);
  91. return theme('calais_geo_render_map', $node, $geo_data);
  92. }
  93. /**
  94. * Fetch the geo data for a node
  95. *
  96. * @param vid
  97. * The Node Revision ID
  98. * @return
  99. * An object with the geo data to render
  100. */
  101. function calais_geo_load($vid) {
  102. $geo_data = db_fetch_object(db_query('SELECT * FROM {calais_geo} WHERE vid = %d', $vid));
  103. if($geo_data) {
  104. $geo_data->terms = array();
  105. $result = db_query('SELECT ct.* FROM {calais_geo_term} cgt INNER JOIN {calais_term} ct ON ct.tid = cgt.tid WHERE cgt.vid = %d', $vid);
  106. while ($geoterm = db_fetch_object($result)) {
  107. calais_load_term_extra($geoterm);
  108. $geo_data->terms[] = $geoterm;
  109. }
  110. }
  111. return $geo_data;
  112. }
  113. /**
  114. * Save the geo data for this particular node id.
  115. *
  116. * @param node
  117. * The Node to save
  118. * @param $data
  119. * The geo data to save. Can be an object or an array.
  120. */
  121. function calais_geo_save($node, $data) {
  122. $data = (array)$data;
  123. $data['nid'] = $node->nid;
  124. $data['vid'] = $node->vid;
  125. // Process the map center (if needed)
  126. $center = $data['term_center'];
  127. switch ($center) {
  128. case 'latlon':
  129. $data['center_tid'] = NULL;
  130. break;
  131. case 'default':
  132. $data['center_latitude'] = NULL;
  133. $data['center_longitude'] = NULL;
  134. $data['center_tid'] = NULL;
  135. break;
  136. default:
  137. $data['center_latitude'] = NULL;
  138. $data['center_longitude'] = NULL;
  139. $data['center_tid'] = $center;
  140. break;
  141. }
  142. if(db_result(db_query('SELECT count(*) FROM {calais_geo} WHERE vid = %d', $node->vid)) == 1) {
  143. drupal_write_record('calais_geo', $data, 'vid');
  144. }
  145. else {
  146. drupal_write_record('calais_geo', $data);
  147. }
  148. _cg_fix_d_w_r_null($node->vid, $data);
  149. db_query('DELETE FROM {calais_geo_term} WHERE vid = %d', $node->vid);
  150. foreach ($data['terms'] as $term) {
  151. $geoterm = array('nid' => $node->nid, 'vid' => $node->vid, 'tid' => $term);
  152. drupal_write_record('calais_geo_term', $geoterm);
  153. }
  154. }
  155. // Need to do this b/c of http://drupal.org/node/227677
  156. // Fix the fact that NULLs can;t be saved via drupal_write_record
  157. function _cg_fix_d_w_r_null($vid, $data) {
  158. $nulls = array();
  159. $fields = array('center_latitude', 'center_longitude', 'center_tid');
  160. foreach ($fields as $field) {
  161. if (is_null($data[$field])) {
  162. $nulls[] = "$field = NULL";
  163. }
  164. }
  165. if(!empty($nulls)) {
  166. db_query("UPDATE {calais_geo} SET " . implode($nulls, ',') . " WHERE vid = $vid");
  167. }
  168. }
  169. /**
  170. * Implementation of hook_form_alter().
  171. */
  172. function calais_geo_form_alter(&$form, $form_state, $form_id) {
  173. if (_calais_geo_should_modify_form($form, $form_id)) {
  174. $node = $form['#node'];
  175. // Load Calais Terms here with tid -> name, but only if they have geo coords.
  176. $geo_vocabs = variable_get('calais_geo_vocabularies', array());
  177. $vocabs = array_filter(array_values($geo_vocabs));
  178. $options = array();
  179. foreach ($vocabs as $vid) {
  180. $vocab = taxonomy_vocabulary_load($vid);
  181. $terms = calais_get_keywords($node->nid, $node->tytpe, $vid);
  182. foreach ($terms[$vid] as $term) {
  183. if($term->resolved_type == 'geo') {
  184. $options[$vocab->name][$term->tid] = $term->name;
  185. }
  186. }
  187. }
  188. $form['calais_geo'] = array(
  189. '#type' => 'fieldset',
  190. '#title' => t('Calais Geotagging'),
  191. '#tree' => TRUE,
  192. '#collapsible' => TRUE,
  193. '#collapsed' => TRUE,
  194. );
  195. // No options to maps
  196. if(empty($options)) {
  197. $form['calais_geo']['message'] = array(
  198. '#type' => 'item',
  199. '#title' => t('Message'),
  200. '#value' => t('There are no Calais Terms with geo coordinates available for mapping.'),
  201. );
  202. return;
  203. }
  204. $default_terms = array();
  205. $geo_data = calais_geo_load($node->vid);
  206. if ($geo_data) {
  207. foreach($geo_data->terms as $term){
  208. $default_terms[] = $term->tid;
  209. }
  210. }
  211. $form['calais_geo']['terms'] = array(
  212. '#type' => 'select',
  213. '#title' => t('Select the terms to map'),
  214. '#description' => t('You can select multiple terms by ctrl+click or apple+click.'),
  215. '#multiple' => TRUE,
  216. '#size' => 5,
  217. '#default_value' => $default_terms,
  218. '#options' => $options,
  219. );
  220. $center = 'default';
  221. if(!empty($geo_data->center_tid)) {
  222. $center = $geo_data->center_tid;
  223. }
  224. else if (!empty($geo_data->center_latitude) || !empty($geo_data->center_longitude)) {
  225. $center = 'latlon';
  226. }
  227. $form['calais_geo']['term_center'] = array(
  228. '#type' => 'select',
  229. '#title' => t('Center map on this specific term'),
  230. '#description' => t('Optionally, the map could be centered on the most relevant mapped term. Select <default> to use the map default which centers the map amongst your term markers, or <manual> to specify a latitude and longitude using the Manual center field below.'),
  231. '#default_value' => $center,
  232. '#options' => array_merge(array('default' => '<default>', 'latlon' => '<manual>'), $options),
  233. );
  234. $form['calais_geo']['center_latitude'] = array(
  235. '#type' => 'textfield',
  236. '#title' => t('Manual center latitude'),
  237. '#default_value' => $geo_data->center_latitude,
  238. '#size' => 25,
  239. '#maxlength' => 25,
  240. '#description' => t('The default center latitude coordinates of the map. This will be used if values are entered and the Term Center is set to <manual>. Leave blank to allow the map to auto center itself amongst your term markers.'),
  241. );
  242. $form['calais_geo']['center_longitude'] = array(
  243. '#type' => 'textfield',
  244. '#title' => t('Manual center longitude'),
  245. '#default_value' => $geo_data->center_longitude,
  246. '#size' => 25,
  247. '#maxlength' => 25,
  248. '#description' => t('The default center latitude coordinates of the map. This will be used if values are entered and the Term Center is set to <manual>. Leave blank to allow the map to auto center itself amongst your term markers.'),
  249. );
  250. $form['calais_geo']['width'] = array(
  251. '#type' => 'textfield',
  252. '#title' => t('Map width'),
  253. '#default_value' => $geo_data->width,
  254. '#size' => 10,
  255. '#maxlength' => 25,
  256. '#description' => t('The default width of a Google map, as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>. Leave blank to use the defaults.'),
  257. );
  258. $form['calais_geo']['height'] = array(
  259. '#type' => 'textfield',
  260. '#title' => t('Map height'),
  261. '#default_value' => $geo_data->height,
  262. '#size' => 10,
  263. '#maxlength' => 25,
  264. '#description' => t('The default height of the map, expressed as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>. Leave blank to use the defaults.'),
  265. );
  266. drupal_add_js(drupal_get_path('module', 'calais_geo') . '/calais_geo.js', 'module');
  267. }
  268. }
  269. /**
  270. * Should we provide mapping configuration for this node type
  271. */
  272. function _calais_geo_should_modify_form($form, $form_id) {
  273. $enabled = variable_get('calais_geo_nodes_enabled', array());
  274. return isset($form['type'])
  275. && isset($form['#node'])
  276. && $form['type']['#value'] .'_node_form' == $form_id
  277. && $enabled[$form['type']['#value']];
  278. }
  279. /**
  280. * Implementation of hook_nodeapi().
  281. */
  282. function calais_geo_nodeapi(&$node, $op) {
  283. switch ($op) {
  284. case 'insert':
  285. case 'update':
  286. if(property_exists($node, 'calais_geo') && !empty($node->calais_geo)) {
  287. calais_geo_save($node, $node->calais_geo);
  288. }
  289. break;
  290. case 'delete':
  291. db_query('DELETE FROM {calais_geo} WHERE nid = %d', $node->nid);
  292. db_query('DELETE FROM {calais_geo_term} WHERE nid = %d', $node->nid);
  293. break;
  294. case 'view':
  295. $geo = calais_geo_load($node->vid);
  296. if($geo) {
  297. $node->calais_geo_map = theme('calais_geo_render_map', $node, $geo);
  298. }
  299. break;
  300. }
  301. }
  302. /**
  303. * Build the map.
  304. */
  305. function theme_calais_geo_render_map($node, $geo_data) {
  306. $geo_data = (array)$geo_data;
  307. if(empty($geo_data['terms']))
  308. return; // Nothing to map
  309. foreach($geo_data['terms'] as $term) {
  310. $marker = array(
  311. 'text' => theme('calais_geo_marker', $node, $term),
  312. 'latitude' => floatval($term->extra['latitude']),
  313. 'longitude' => floatval($term->extra['longitude']),
  314. );
  315. $markers[] = $marker;
  316. }
  317. $settings = array(
  318. 'markers' => $markers
  319. );
  320. if(!empty($geo_data['width'])) {
  321. $settings['width'] = $geo_data['width'];
  322. }
  323. if(!empty($geo_data['height'])) {
  324. $settings['height'] = $geo_data['height'];
  325. }
  326. // Setup the
  327. if(!empty($geo_data['zoom'])) {
  328. $settings['zoom'] = $geo_data['zoom'];
  329. }
  330. // Setup default center if configured
  331. if(!empty($geo_data['center_tid'])) {
  332. $center = calais_get_term(NULL, $geo_data['center_tid']);
  333. $settings['latitude'] = $center->extra['latitidue'];
  334. $settings['longitude'] = $center->extra['longitude'];
  335. }
  336. else if(!empty($geo_data['center_latitude']) || !empty($geo_data['center_longitude'])){
  337. if(!empty($geo_data['center_latitude'])) {
  338. $settings['latitude'] = $geo_data['center_latitude'];
  339. }
  340. if(!empty($geo_data['center_longitude'])) {
  341. $settings['longitude'] = $geo_data['center_longitude'];
  342. }
  343. }
  344. else {
  345. list($lat, $lon) = calais_geo_calc_map_center($markers);
  346. $settings['latitude'] = $lat;
  347. $settings['longitude'] = $lon;
  348. }
  349. $map_data = array(
  350. '#settings' => $settings,
  351. );
  352. // Hook to allow other modules/themes to make modifications before rendering
  353. foreach (module_implements('calais_geo_map') as $module) {
  354. $function = $module .'_calais_geo_map';
  355. call_user_func_array($function, array(&$map_data));
  356. }
  357. $output = theme('gmap', $map_data);
  358. return $output;
  359. }
  360. /* Example of implementing this hook
  361. function calais_geo_calais_geo_map(&$map_data) {
  362. foreach ($map_data['#settings']['markers'] as $key => &$marker) {
  363. $marker['markername'] = "orange";
  364. }
  365. }
  366. */
  367. /**
  368. * Find a center point between all markers. Pretty basic approach,
  369. * take the max & min of lat/lon and average it.
  370. */
  371. function calais_geo_calc_map_center($markers) {
  372. if(empty($markers))
  373. return array(0, 0);
  374. $latitude = array();
  375. $longitude = array();
  376. foreach ($markers as $marker) {
  377. $latitude[] = $marker['latitude'];
  378. $longitude[] = $marker['longitude'];
  379. }
  380. $lat = (min($latitude) + max($latitude)) / 2;
  381. $lon = (min($longitude) + max($longitude)) / 2;
  382. return array($lat, $lon);
  383. }
  384. /**
  385. * Default theme function to rendering the text that goes in the Google Map marker bubble.
  386. */
  387. function template_preprocess_calais_geo_marker(&$vars) {
  388. $node = $vars['node'];
  389. $term = $vars['term'];
  390. $vars['title'] = check_plain($term->name);
  391. }