openlayers.module 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. <?php
  2. /**
  3. * @defgroup openlayers OpenLayers provides an API and
  4. * Modules to interface with OpenLayers
  5. */
  6. /**
  7. * @file
  8. * Main OpenLayers API File
  9. *
  10. * This file holds the main Drupal hook functions,
  11. * and the openlayers API functions for the openlayers module.
  12. *
  13. * @ingroup openlayers
  14. */
  15. /**
  16. * OpenLayers hosted default library.
  17. */
  18. define('OPENLAYERS_DEFAULT_LIBRARY', 'http://openlayers.org/api/2.12/OpenLayers.js');
  19. /**
  20. * OpenLayers library compatible suggestion.
  21. */
  22. define('OPENLAYERS_SUGGESTED_LIBRARY', 2.12);
  23. /**
  24. * OpenLayers hosted API version. What version is used when going to
  25. * http://openlayers.org/api/OpenLayers.js
  26. */
  27. define('OPENLAYERS_HOSTED_API_LIBRARY', 2.12);
  28. /**
  29. * Implements hook_help().
  30. */
  31. function openlayers_help($path, $arg) {
  32. switch ($path) {
  33. case 'admin/help#openlayers':
  34. return '<p>' . t('The OpenLayers module is the base module for the
  35. OpenLayers suite of modules, and provides the main API.') . '</p>';
  36. }
  37. return '';
  38. }
  39. /**
  40. * Implements hook_theme().
  41. */
  42. function openlayers_theme($existing, $type, $theme, $path) {
  43. return array(
  44. 'openlayers_map' => array(
  45. 'arguments' => array(
  46. 'map' => array(),
  47. ),
  48. 'file' => 'includes/openlayers.theme.inc',
  49. 'template' => '/templates/openlayers-map'
  50. ),
  51. 'openlayers_styles' => array(
  52. 'arguments' => array(
  53. 'styles' => array(),
  54. 'map' => array(),
  55. ),
  56. 'file' => 'includes/openlayers.theme.inc',
  57. ),
  58. );
  59. }
  60. /**
  61. * Implements hook_ctools_plugin_directory().
  62. */
  63. function openlayers_ctools_plugin_directory($module, $plugin) {
  64. if ($plugin == 'content_types' && !empty($plugin)) {
  65. return 'includes/' . $plugin;
  66. }
  67. if ($module == 'openlayers' && !empty($plugin)) {
  68. return 'plugins/' . $plugin;
  69. }
  70. }
  71. /**
  72. * Implements hook_ctools_plugin_type().
  73. */
  74. function openlayers_ctools_plugin_type() {
  75. // For backwards compatability, we allow for the use
  76. // of hooks to define these plugins.
  77. //
  78. // This should be removed in 7.x-3.x
  79. return array(
  80. 'behaviors' => array(
  81. 'use hooks' => TRUE,
  82. 'classes' => array('behavior'),
  83. ),
  84. 'layer_types' => array(
  85. 'use hooks' => TRUE,
  86. 'classes' => array('layer_types'),
  87. )
  88. );
  89. }
  90. /**
  91. * Include necessary CSS and JS for rendering maps
  92. *
  93. * @ingroup openlayers_api
  94. */
  95. function openlayers_include() {
  96. // Use a static variable to prevent running URL check code repeatedly.
  97. static $once;
  98. if (!isset($once)) {
  99. $once = TRUE;
  100. $path = check_plain(variable_get('openlayers_source', OPENLAYERS_DEFAULT_LIBRARY));
  101. // Correctly handle URLs beginning with a double backslash, see RFC 1808 Section 4
  102. if (substr($path, 0, 2) == '//') {
  103. $http_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
  104. $path = $http_protocol .':'. $path;
  105. }
  106. // Check for full URL and include it manually if external.
  107. if (valid_url($path, TRUE)) {
  108. drupal_add_js($path, 'external');
  109. }
  110. else {
  111. drupal_add_js($path);
  112. }
  113. drupal_add_css(drupal_get_path('module', 'openlayers') .
  114. '/css/openlayers.css', 'file');
  115. drupal_add_js(drupal_get_path('module', 'openlayers') .
  116. '/js/openlayers.js', 'file');
  117. }
  118. }
  119. /**
  120. * Prepare a map for rendering.
  121. *
  122. * Takes a map array and builds up the data given the
  123. * reference to objects like styles, layers, and behaviors.
  124. *
  125. * @ingroup openlayers_api
  126. *
  127. * @param $map
  128. * Array of map settings
  129. * @return
  130. * Filled in map array.
  131. */
  132. function openlayers_build_map($map = array()) {
  133. // Get the necessary parts
  134. openlayers_include();
  135. module_load_include('inc', 'openlayers', 'includes/openlayers.render');
  136. // If no map is specified, use the default map.
  137. if (empty($map)) {
  138. if ($loaded_map = openlayers_map_load(
  139. variable_get('openlayers_default_map', 'default'))) {
  140. $map = $loaded_map->data;
  141. }
  142. }
  143. // Create ID for map as this will help with alters.
  144. $map['id'] = !isset($map['id']) ?
  145. _openlayers_create_map_id() : $map['id'];
  146. // Hook to alter map before main processing. Styles, behaviors,
  147. // layers may all be added here.
  148. // hook_openlayers_map_preprocess_alter($map)
  149. drupal_alter('openlayers_map_preprocess', $map);
  150. // Styles and layer styles are not required parameters
  151. $map['styles'] = isset($map['styles']) ? $map['styles'] : array();
  152. $map['layer_styles'] = isset($map['layer_styles']) ? $map['layer_styles'] : array();
  153. $map['layer_styles_select'] = isset($map['layer_styles_select']) ? $map['layer_styles_select'] : array();
  154. // Process map parts.
  155. $map['layers'] = _openlayers_layers_process($map['layers'], $map);
  156. $map['behaviors'] = _openlayers_behaviors_render($map['behaviors'], $map);
  157. $map['styles'] = _openlayers_styles_process($map['styles'], $map['layer_styles'], $map['layer_styles_select'], $map);
  158. // Hook to alter map one last time. Final modification to existing
  159. // styles, behaviors, layers can happen here, but adding new styles,
  160. // behaviors will not get rendered.
  161. // hook_openlayers_map_alter($map)
  162. drupal_alter('openlayers_map', $map);
  163. // Check map for errors
  164. $map['errors'] = openlayers_error_check_map($map);
  165. return $map;
  166. }
  167. /**
  168. * Render map array
  169. *
  170. * Given a map array, render into HTML to display
  171. * a map.
  172. *
  173. * @ingroup openlayers_api
  174. *
  175. * @param $map
  176. * Associative array of map paramters.
  177. * @return
  178. * Map HTML.
  179. */
  180. function openlayers_render_map_data($map = array()) {
  181. // Run map through build process
  182. $map = openlayers_build_map($map);
  183. $output = '';
  184. // Given hide_empty_map flag, check if the map has any features
  185. // defined. If not, assume it is an empty map and shouldn't be displayed.
  186. if (isset($map['hide_empty_map']) && $map['hide_empty_map'] == TRUE) {
  187. $empty = TRUE;
  188. foreach ($map['layers'] as $layer) {
  189. if (isset($layer['features']) && count($layer['features'])) {
  190. $empty = FALSE;
  191. }
  192. }
  193. if ($empty) {
  194. return '';
  195. }
  196. }
  197. // Return themed map if no errors found
  198. if (empty($map['errors'])) {
  199. $js = array('openlayers' => array('maps' => array($map['id'] => $map)));
  200. drupal_add_js($js, 'setting');
  201. // Push map through theme function and return
  202. $output = theme('openlayers_map', array(
  203. 'map' => $map,
  204. ));
  205. }
  206. return $output;
  207. }
  208. /**
  209. * Render a map by name
  210. *
  211. * Given a map name render it into a full map object.
  212. *
  213. * @ingroup openlayers_api
  214. *
  215. * @param $map
  216. * Name of the map
  217. * @return
  218. * Map HTML.
  219. */
  220. function openlayers_render_map($map = '') {
  221. // If it's an array, then we have been passed the map data array
  222. if (is_array($map)) {
  223. return openlayers_render_map_data($map);
  224. }
  225. // If it's a string, then we are passing a map name instead of the whole map object
  226. // so we need to load the object
  227. if (!$map || is_string($map)) {
  228. $map_name = $map;
  229. if (!$map_name) {
  230. $map_name = variable_get('openlayers_default_map', 'default');
  231. }
  232. $map = openlayers_map_load($map_name);
  233. }
  234. return openlayers_render_map_data($map->data);
  235. }
  236. /**
  237. * Get layer object
  238. *
  239. * @ingroup openlayers_api
  240. * @param $reset
  241. * Boolean whether to reset cache or not
  242. * @return array
  243. * array of layer info
  244. */
  245. function openlayers_get_layer_object($layer, $map = array()) {
  246. // Static cache because this function will possibly be called in big loops
  247. static $layer_types;
  248. if (!isset($layer_types)) {
  249. $layer_types = openlayers_layer_types();
  250. }
  251. $layer->title = t($layer->title);
  252. $layer->description = t($layer->description);
  253. // Attempt to get ctool class
  254. if (isset($layer_types[$layer->data['layer_type']]) &&
  255. $class = ctools_plugin_get_class(
  256. $layer_types[$layer->data['layer_type']],
  257. 'layer_type')
  258. ) {
  259. $layer_object = new $class($layer, $map);
  260. return $layer_object;
  261. }
  262. else {
  263. watchdog('openlayers', 'Layer !layer_name is unavailable because its
  264. layer type or the module that provides its layer type is missing',
  265. array('!layer_name' => $layer->title),
  266. WATCHDOG_ERROR);
  267. return FALSE;
  268. }
  269. }
  270. /**
  271. * Menu loader for layers. (%openlayers_layer)
  272. * @ingroup openlayers_api
  273. *
  274. * @param $name
  275. * Layer name
  276. * @return array
  277. * Layer export
  278. */
  279. function openlayers_layer_load($name, $reset = FALSE) {
  280. ctools_include('export');
  281. if ($reset) ctools_export_load_object_reset('openlayers_layers');
  282. $layer = ctools_export_load_object('openlayers_layers', 'names', array($name));
  283. if (is_array($layer) && isset($layer[$name])) {
  284. $layer_object = openlayers_get_layer_object($layer[$name]);
  285. if (openlayers_layer_sanity_check($layer_object)) {
  286. // Automatic layer load for layers.
  287. /*
  288. $definitions = ctools_get_plugins('openlayers', 'layer_types');
  289. $type = get_class($layer_object);
  290. $base = basename($definitions[$type]['file'], '.inc');
  291. $js = $definitions[$type]['path'] . '/' . $base .'.js';
  292. $css = $definitions[$type]['path'] . '/' . $base .'.css';
  293. drupal_add_js($js);
  294. drupal_add_css($css);
  295. */
  296. return $layer_object;
  297. }
  298. }
  299. else {
  300. return FALSE;
  301. }
  302. }
  303. /**
  304. * Get all openlayers layers as objects.
  305. * @ingroup openlayers_api
  306. *
  307. * @param $reset
  308. * Boolean whether to reset cache or not
  309. * @return array
  310. * array of layer info
  311. */
  312. function openlayers_layers_load($reset = FALSE) {
  313. ctools_include('export');
  314. $layer_objects = array();
  315. if ($reset) ctools_export_load_object_reset('openlayers_layers');
  316. $layers = ctools_export_load_object('openlayers_layers', 'all', array());
  317. foreach ($layers as $layer) {
  318. $layer_objects[$layer->name] = openlayers_get_layer_object($layer);
  319. }
  320. return array_filter($layer_objects, 'openlayers_layer_sanity_check');
  321. }
  322. /**
  323. * Check the plugin definition of a layer.
  324. * Some field *MUST* be there to work correctly with OL.
  325. *
  326. * @ingroup openlayers_api
  327. * @param $definition
  328. * @return bool
  329. */
  330. function openlayers_layer_definition_check($definition) {
  331. $mandatory_fields = array(
  332. array('title'),
  333. array('description'),
  334. array('name'),
  335. array('path'),
  336. array('layer_type', 'file'),
  337. array('layer_type', 'class'),
  338. array('layer_type', 'parent'),
  339. );
  340. foreach ($mandatory_fields as $field) {
  341. $missing = drupal_array_nested_key_exists($definition, $field);
  342. if (!$missing) {
  343. drupal_set_message(t("There's a problem in the plugin definition of the layer type <em>!type</em>. The layer will be disabled.", array('!type' => $definition['name'])), 'warning');
  344. watchdog('openlayers', 'Layer !layer is unavailable because its
  345. plugin definition is incomplete.',
  346. array('!layer' => $definition['name']),
  347. WATCHDOG_ERROR);
  348. return FALSE;
  349. }
  350. }
  351. return TRUE;
  352. }
  353. /**
  354. * Check the plugin definition of a behavior.
  355. * Some field *MUST* be there to work correctly with OL.
  356. *
  357. * @ingroup openlayers_api
  358. * @param $definition
  359. * @return bool
  360. */
  361. function openlayers_behavior_definition_check($definition) {
  362. $mandatory_fields = array(
  363. array('title'),
  364. array('description'),
  365. array('name'),
  366. array('path'),
  367. array('type'),
  368. array('behavior', 'file'),
  369. array('behavior', 'class'),
  370. array('behavior', 'parent'),
  371. );
  372. foreach ($mandatory_fields as $field) {
  373. $missing = drupal_array_nested_key_exists($definition, $field);
  374. if (!$missing) {
  375. drupal_set_message(t("There's a problem in the definition of the behavior <em>!behavior</em>. The behavior will be disabled.", array('!behavior' => $definition['name'])), 'warning');
  376. watchdog('openlayers', 'Behavior !behavior is unavailable because its
  377. plugin definition is incomplete.',
  378. array('!behavior' => $definition['name']),
  379. WATCHDOG_ERROR);
  380. return FALSE;
  381. }
  382. }
  383. return TRUE;
  384. }
  385. /**
  386. * Check layer to determine whether it has all the
  387. * necessary attributes to be rendered. This is necessary
  388. * because of API changes, and is a consolidation from other
  389. * layer-error-checking in this module
  390. *
  391. * @param $layer
  392. * Layer object
  393. * @param $projection
  394. * Projection number (EPSG) to check compatibility with
  395. * @param $strict
  396. * reject invalid layers
  397. * @return boolean
  398. * layer validity if strict is set, otherwise always true
  399. */
  400. function openlayers_layer_sanity_check($layer, $projection = FALSE, $strict = FALSE) {
  401. // Handle layers after they've been rendered for a map
  402. $layer = (is_array($layer)) ? (object) $layer : $layer;
  403. if (!isset($layer->name)) {
  404. return !$strict;
  405. }
  406. if (!isset($layer->data['projection']) || !is_array($layer->data['projection'])) {
  407. watchdog('openlayers', 'Layer %name does not have a projection set.',
  408. array('%name' => $layer->name));
  409. drupal_set_message(
  410. t('OpenLayers layers failed the sanity check. See the
  411. <a href="@drupallog">Drupal log</a> for details',
  412. array('@drupallog' => url('admin/reports/dblog')))
  413. );
  414. return !$strict;
  415. }
  416. if (!isset($layer->data['layer_type'])) {
  417. watchdog('openlayers', 'Layer %name does not have its layer_type set.',
  418. array('%name' => $layer->name));
  419. drupal_set_message(
  420. t('OpenLayers layers failed the sanity check. See the
  421. <a href="@drupallog">Drupal log</a> for details',
  422. array('@drupallog' => url('admin/reports/dblog')))
  423. );
  424. return !$strict;
  425. }
  426. if ($projection && empty($layer->data['vector']) &&
  427. (!in_array($projection, $layer->data['projection']))) {
  428. watchdog('openlayers',
  429. 'The layer %layer_name cannot be reprojected to the map projection: EPSG: %map_proj',
  430. array(
  431. '%layer_name' => $layer->name,
  432. // TODO: $map is not defined.
  433. '%map_proj' => $map['projection'],
  434. )
  435. );
  436. return !$strict;
  437. }
  438. return TRUE;
  439. }
  440. /**
  441. * Delete a layer object from the database.
  442. *
  443. * @ingroup openlayers_api
  444. *
  445. * @param $layer
  446. * String identifier of a layer or layer object with name.
  447. * @return
  448. * The results of DB delete.
  449. */
  450. function openlayers_layer_delete($layer) {
  451. return openlayers_object_delete($layer, 'layer');
  452. }
  453. /**
  454. * Get all layer types.
  455. *
  456. * @ingroup openlayers_api
  457. *
  458. * @param $reset
  459. * Boolean whether to reset cache or not.
  460. * @return
  461. * Array of layer type info.
  462. */
  463. function openlayers_layer_types($reset = FALSE) {
  464. ctools_include('plugins');
  465. $layers = ctools_get_plugins('openlayers', 'layer_types');
  466. return array_filter($layers, 'openlayers_layer_definition_check');
  467. }
  468. /**
  469. * Menu loader for layer types.
  470. *
  471. * @ingroup openlayers_api
  472. *
  473. * @param $name
  474. * String identifier of layer type.
  475. * @param $reset
  476. * Boolean whether to reset cache or not.
  477. * @return
  478. * An instantiated layer type object or FALSE if not found.
  479. */
  480. function openlayers_layer_type_load($name, $reset = FALSE) {
  481. ctools_include('plugins');
  482. if ($layer_type_class = ctools_plugin_load_class(
  483. 'openlayers',
  484. 'layer_types',
  485. $name,
  486. 'layer_type')) {
  487. $layer_type = new $layer_type_class();
  488. return $layer_type;
  489. }
  490. return FALSE;
  491. }
  492. /**
  493. * Get all behaviors.
  494. *
  495. * @ingroup openlayers_api
  496. *
  497. * @param $reset
  498. * Boolean whether to reset cache or not.
  499. * @return
  500. * Array of behavior info.
  501. */
  502. function openlayers_behaviors($reset = FALSE) {
  503. ctools_include('plugins');
  504. $behaviors = ctools_get_plugins('openlayers', 'behaviors');
  505. return array_filter($behaviors, 'openlayers_behavior_definition_check');
  506. }
  507. /**
  508. * Get all openlayers styles.
  509. *
  510. * @ingroup openlayers_api
  511. *
  512. * @param $reset
  513. * Boolean whether to reset cache or not.
  514. * @return
  515. * Array of all available styles.
  516. */
  517. function openlayers_styles($reset = FALSE) {
  518. ctools_include('export');
  519. if ($reset) {
  520. ctools_export_load_object_reset('openlayers_styles');
  521. }
  522. $styles = ctools_export_load_object('openlayers_styles', 'all', array());
  523. return $styles;
  524. }
  525. /**
  526. * Load a style object by name.
  527. *
  528. * This function can also be used as a
  529. * menu loader for a style.
  530. *
  531. * @ingroup openlayers_api
  532. *
  533. * @param $name
  534. * The string identifier of the style.
  535. * @param $reset
  536. * Boolean whether to reset the cache or not.
  537. * @return
  538. * A style object or FALSE if not found.
  539. */
  540. function openlayers_style_load($name, $reset = FALSE) {
  541. $styles = openlayers_styles($reset);
  542. return !empty($styles[$name]) ? $styles[$name] : FALSE;
  543. }
  544. /**
  545. * Save style.
  546. *
  547. * @ingroup openlayers_api
  548. *
  549. * @param $style
  550. * The style object to save.
  551. * @return
  552. * The results of DB write or FALSE if no name.
  553. */
  554. function openlayers_style_save($style) {
  555. if (!empty($style->name)) {
  556. return (db_select('openlayers_styles')
  557. ->fields('openlayers_styles', array('name'))
  558. ->condition('name', $style->name)
  559. ->execute()
  560. ->fetchCol()) ?
  561. drupal_write_record('openlayers_styles', $style, 'name') :
  562. drupal_write_record('openlayers_styles', $style);
  563. }
  564. return FALSE;
  565. }
  566. /**
  567. * Delete a style object from the database.
  568. *
  569. * @ingroup openlayers_api
  570. *
  571. * @param $style
  572. * String identifier of a style or style object with name.
  573. * @return
  574. * The results of DB delete.
  575. */
  576. function openlayers_style_delete($style) {
  577. return openlayers_object_delete($style, 'style');
  578. }
  579. /**
  580. * Get maps from DB or code, via cache.
  581. *
  582. * @ingroup openlayers_api
  583. *
  584. * @param $reset
  585. * Boolean whether to reset or not.
  586. * @return
  587. * Return array of maps.
  588. */
  589. function openlayers_maps($reset = FALSE) {
  590. ctools_include('export');
  591. if ($reset) {
  592. ctools_export_load_object_reset('openlayers_maps');
  593. }
  594. $maps = ctools_export_load_object(
  595. 'openlayers_maps', 'all', array());
  596. return $maps;
  597. }
  598. /**
  599. * Given a map name, get full map object.
  600. *
  601. * This function can also be used as a
  602. * menu loader for a style.
  603. *
  604. * @ingroup openlayers_api
  605. *
  606. * @param $name
  607. * String identifier of the map.
  608. * @param $reset
  609. * Boolean whether to reset cache.
  610. * @return
  611. * map object or FALSE if not found.
  612. */
  613. function openlayers_map_load($name = '', $reset = FALSE) {
  614. ctools_include('export');
  615. if ($reset) {
  616. ctools_export_load_object_reset('openlayers_maps');
  617. }
  618. $maps = ctools_export_load_object('openlayers_maps', 'names', array($name));
  619. if (empty($maps[$name])) {
  620. return FALSE;
  621. } else {
  622. $map = $maps[$name];
  623. $map->data['map_name'] = $name;
  624. return clone $map;
  625. }
  626. }
  627. /**
  628. * Save a map object to the database.
  629. *
  630. * @ingroup openlayers_api
  631. *
  632. * @param $map
  633. * map object.
  634. * @return
  635. * The results of DB write or FALSE if no name.
  636. */
  637. function openlayers_map_save($map) {
  638. if (!empty($map->name)) {
  639. return (db_select('openlayers_maps')
  640. ->fields('openlayers_maps', array('name'))
  641. ->condition('name', $map->name)
  642. ->execute()
  643. ->fetchCol()) ?
  644. drupal_write_record('openlayers_maps', $map, 'name') :
  645. drupal_write_record('openlayers_maps', $map);
  646. }
  647. return FALSE;
  648. }
  649. /**
  650. * Delete a map object from the database.
  651. *
  652. * @ingroup openlayers_api
  653. *
  654. * @param $map
  655. * String identifier of a map or map object with name.
  656. * @return
  657. * The results of DB delete.
  658. */
  659. function openlayers_map_delete($map) {
  660. return openlayers_object_delete($map, 'map');
  661. }
  662. /**
  663. * Get map options in an array suitable for a FormAPI element.
  664. *
  665. * @ingroup openlayers_api
  666. *
  667. * @param $reset
  668. * Boolean whether to reset or not.
  669. * @return
  670. * Return array of formatted data.
  671. */
  672. function openlayers_map_options($reset = FALSE) {
  673. $maps = openlayers_maps($reset);
  674. $options = array();
  675. foreach ($maps as $map) {
  676. $options[$map->name] = $map->title;
  677. }
  678. return $options;
  679. }
  680. /**
  681. * Delete an object from the database.
  682. *
  683. * @ingroup openlayers_api
  684. *
  685. * @param $ol_object
  686. * String identifier of an object or the object with name.
  687. * @param $type
  688. * Type of object to delete. The options are the following:
  689. * - 'layer'
  690. * - 'style'
  691. * = 'map'
  692. * @return
  693. * The results of the DB delete.
  694. */
  695. function openlayers_object_delete($ol_object, $type) {
  696. // Check for object or name
  697. $tables = array(
  698. 'style' => 'openlayers_styles',
  699. 'layer' => 'openlayers_layers',
  700. 'map' => 'openlayers_maps');
  701. if (is_object($ol_object) && isset($ol_object->name) && isset($tables[$type])) {
  702. $ol_object = $ol_object->name;
  703. return db_delete($tables[$type])->condition('name', $ol_object)->execute();
  704. }
  705. }
  706. /**
  707. * Checks map array for incompatibilities or errors.
  708. *
  709. * @ingroup openlayers_api
  710. *
  711. * @param $map
  712. * Map array
  713. * @param $log_errors
  714. * Boolean whether to log errors.
  715. * @return
  716. * FALSE if passed. Array of descriptive errors if fail.
  717. */
  718. function openlayers_error_check_map($map, $log_errors = TRUE) {
  719. $errors = array();
  720. // Check for layers
  721. if (!is_array($map['layers'])) {
  722. $errors[] = t('Map contains no renderable layers.');
  723. }
  724. else {
  725. // Check layer projections
  726. foreach ($map['layers'] as $layer) {
  727. openlayers_layer_sanity_check(
  728. array('data' => $layer),
  729. $map['projection'],
  730. TRUE);
  731. }
  732. }
  733. // Check if any errors found to log
  734. if (count($errors) > 0 && $log_errors) {
  735. // Log the Error(s)
  736. watchdog('openlayers', implode(', ', $errors), array(), WATCHDOG_ERROR);
  737. }
  738. // Check if errors and return
  739. return (count($errors) > 0) ? $errors : FALSE;
  740. }
  741. /**
  742. * Get extent given projection
  743. *
  744. * Returns standard world-max-extents for common projections.
  745. * Layers implementing other projections and subsets of the
  746. * world should define their maxExtent in the layer array.
  747. *
  748. * @ingroup openlayers_api
  749. *
  750. * @param $projection
  751. * String of the projection value. Currently
  752. * supports 900913, 4326.
  753. * @return
  754. * Array of maxExtent in OpenLayers toArray() format.
  755. */
  756. function openlayers_get_extent($projection) {
  757. switch ($projection) {
  758. case '900913':
  759. return array(-20037508, -20037508, 20037508, 20037508);
  760. case '4326':
  761. return array(-180, -90, 180, 90);
  762. }
  763. }
  764. /**
  765. * Get resolution given projection
  766. *
  767. * Returns a default set of resolutions for standard
  768. * TMS, WMS, etc servers serving up common projections.
  769. * Layers supporting less common projections and resolutions
  770. * can easily define custom resolutions arrays.
  771. *
  772. * @ingroup openlayers_api
  773. *
  774. * @param $projection
  775. * String specifying which projection this should take, like 900913.
  776. * @param $zoom_start
  777. * Integer of first zoom level, default 0.
  778. * @param $zoom_end
  779. * Integer of last zoom level, default FALSE.
  780. * @return
  781. * Array of resolutions.
  782. */
  783. function openlayers_get_resolutions($projection, $zoom_start = 0, $zoom_end = FALSE) {
  784. switch ($projection) {
  785. case '900913':
  786. // 16 zoom levels, taken from
  787. // openlayers.org TMS map
  788. $res = array(
  789. 156543.0339,
  790. 78271.51695,
  791. 39135.758475,
  792. 19567.8792375,
  793. 9783.93961875,
  794. 4891.969809375,
  795. 2445.9849046875,
  796. 1222.99245234375,
  797. 611.496226171875,
  798. 305.7481130859375,
  799. 152.87405654296876,
  800. 76.43702827148438,
  801. 38.21851413574219,
  802. 19.109257067871095,
  803. 9.554628533935547,
  804. 4.777314266967774,
  805. 2.388657133483887,
  806. 1.1943285667419434,
  807. 0.5971642833709717,
  808. 0.29858214169740677,
  809. 0.14929107084870338,
  810. 0.07464553542435169
  811. );
  812. break;
  813. case '4326':
  814. // 16 zoom levels, taken from
  815. // openlayers.org default WMS map
  816. $res = array(
  817. 0.703125,
  818. 0.3515625,
  819. 0.17578125,
  820. 0.087890625,
  821. 0.0439453125,
  822. 0.02197265625,
  823. 0.010986328125,
  824. 0.0054931640625,
  825. 0.00274658203125,
  826. 0.001373291015625,
  827. 0.0006866455078125,
  828. 0.00034332275390625,
  829. 0.000171661376953125,
  830. 0.0000858306884765625,
  831. 0.00004291534423828125,
  832. 0.000021457672119140625,
  833. 0.000010728836059570312,
  834. );
  835. break;
  836. default:
  837. $res = array();
  838. break;
  839. }
  840. $length = ($zoom_end == FALSE) ? NULL : $zoom_end - $zoom_start;
  841. // By default this will not actually clip the array
  842. $resolutions = array_slice($res, $zoom_start, $length);
  843. return $resolutions;
  844. }
  845. /**
  846. * We define base classes in the core module.
  847. * All other parent classes can be autoloaded through ctools.
  848. */
  849. class openlayers_behavior {
  850. var $options, $map;
  851. function __construct($options = array(), $map = array()) {
  852. $this->options = $options + $this->options_init();
  853. $this->map = $map;
  854. }
  855. /*
  856. * @return array of JavaScript functions required to be defined
  857. * in order for this function to work
  858. */
  859. function js_dependency() {
  860. return array();
  861. }
  862. function options_init() {
  863. return array();
  864. }
  865. /*
  866. * @param $defaults default values for the form as an array
  867. * @return a FormAPI form
  868. */
  869. function options_form($defaults = array()) {
  870. return array();
  871. }
  872. function render(&$map) {}
  873. }
  874. /**
  875. * We define base classes in the core module.
  876. * All other parent classes can be autoloaded through ctools.
  877. */
  878. class openlayers_layer_type {
  879. /**
  880. * Stores the options for this layer.
  881. * @var array
  882. */
  883. public $data = array();
  884. /**
  885. * Stores the current map.
  886. * @var array
  887. */
  888. public $map;
  889. /**
  890. * Set configuration and store map.
  891. *
  892. * @param $layer
  893. * Configuration object with the options for the layer.
  894. * @param $map
  895. * Array with the current map.
  896. */
  897. function __construct($layer = array(), $map = array()) {
  898. foreach (array('name', 'title', 'description', 'data', 'export_type') as $k) {
  899. if (isset($layer->{$k})) {
  900. $this->{$k} = $layer->{$k};
  901. }
  902. }
  903. // Extend options with the defaults.
  904. $this->data += $this->options_init();
  905. $this->map = $map;
  906. }
  907. /**
  908. * Provides the default options for the layer.
  909. *
  910. * @return
  911. * An associative array with the default options.
  912. */
  913. function options_init() {
  914. return array(
  915. 'layer_type' => get_class($this),
  916. 'isBaseLayer' => TRUE,
  917. 'projection' => array('900913'),
  918. 'serverResolutions' => openlayers_get_resolutions('900913'),
  919. 'maxExtent' => openlayers_get_extent('900913'),
  920. 'resolutions' => openlayers_get_resolutions('900913'),
  921. 'base_url' => NULL,
  922. 'transitionEffect' => 'resize',
  923. 'weight' => 0
  924. );
  925. }
  926. /**
  927. * Options form to configure layer instance options.
  928. *
  929. * @return
  930. * Array with form elements.
  931. */
  932. function options_form($default = array()) {
  933. return array(
  934. 'projection' => array(
  935. '#type' => 'select',
  936. '#title' => t('Projection'),
  937. '#multiple' => TRUE,
  938. '#options' => array(
  939. '900913' => '900913',
  940. '4326' => '4326'
  941. ),
  942. '#default_value' => isset($default->data['projection']) ?
  943. $default->data['projection'] :
  944. '900913'
  945. ),
  946. 'isBaseLayer' => array(
  947. '#type' => 'checkbox',
  948. '#title' => t('Base Layer'),
  949. '#description' => t('Uncheck to make this map an overlay'),
  950. '#default_value' => !empty($default->data['isBaseLayer']) ?
  951. $default->data['isBaseLayer'] : FALSE
  952. ),
  953. );
  954. }
  955. /**
  956. * Validate the options_form().
  957. *
  958. * @param array $default
  959. */
  960. function options_form_validate($form, &$form_state) {
  961. }
  962. /**
  963. * Submit the options_form().
  964. *
  965. * @param array $default
  966. */
  967. function options_form_submit($form, &$form_state) {
  968. }
  969. /**
  970. * Options form to configure layer-type-wide options.
  971. *
  972. * @return
  973. * Array with form elements.
  974. */
  975. function settings_form() {
  976. return array();
  977. }
  978. /**
  979. * Render the layer and return the layer options.
  980. *
  981. * Has no return value.
  982. *
  983. * @param $map
  984. */
  985. function render(&$map) {}
  986. }
  987. /**
  988. * Implements hook_ctools_plugin_api().
  989. */
  990. function openlayers_ctools_plugin_api($module, $api) {
  991. if ($module == "openlayers") {
  992. switch ($api) {
  993. case 'openlayers_maps':
  994. return array('version' => 1);
  995. case 'openlayers_layers':
  996. return array('version' => 1);
  997. case 'openlayers_styles':
  998. return array('version' => 1);
  999. case 'openlayers_layer_types':
  1000. return array('version' => 1);
  1001. case 'openlayers_behaviors':
  1002. return array('version' => 1);
  1003. }
  1004. }
  1005. elseif ($module == 'boxes' && $api == 'plugins') {
  1006. return array('version' => 1);
  1007. }
  1008. }
  1009. /**
  1010. * Implements hook_openlayers_layers().
  1011. */
  1012. function openlayers_openlayers_layers() {
  1013. module_load_include('inc', 'openlayers', 'includes/openlayers.layers');
  1014. return _openlayers_openlayers_layers();
  1015. }
  1016. /**
  1017. * Implements hook_openlayers_styles().
  1018. */
  1019. function openlayers_openlayers_styles() {
  1020. module_load_include('inc', 'openlayers', 'includes/openlayers.styles');
  1021. return _openlayers_openlayers_styles();
  1022. }
  1023. /**
  1024. * Implements hook_openlayers_maps().
  1025. */
  1026. function openlayers_openlayers_maps() {
  1027. module_load_include('inc', 'openlayers', 'includes/openlayers.maps');
  1028. return _openlayers_openlayers_maps();
  1029. }
  1030. /**
  1031. * Implements hook_boxes_plugins().
  1032. */
  1033. function openlayers_boxes_plugins() {
  1034. return array(
  1035. 'openlayers_simple' => array(
  1036. 'title' => 'OpenLayers',
  1037. 'handler' => array(
  1038. 'parent' => 'boxes_box',
  1039. 'class' => 'openlayers_simple',
  1040. 'file' => 'openlayers_simple.inc',
  1041. 'path' => drupal_get_path('module', 'openlayers') . '/includes/boxes'
  1042. )
  1043. )
  1044. );
  1045. }
  1046. /**
  1047. * Alias Functions
  1048. *
  1049. * These functions temporarily map the alias the renamed 'map' functions to their
  1050. * previous 'preset' functions to allow time for contrib modules to catch up.
  1051. * These will eventually be removed
  1052. *
  1053. * These should be removed in 7.x-3.x
  1054. */
  1055. function openlayers_build_preset($map = array()) { return openlayers_build_map($map); }
  1056. function openlayers_preset_load($name = '', $reset = FALSE) { return openlayers_map_load($name, $reset); }
  1057. function openlayers_render_preset_data($map = array(), $map_name = '') { return openlayers_render_map_data($map, $map_name); }
  1058. function openlayers_presets($reset = FALSE) { return openlayers_maps($reset); }
  1059. function openlayers_preset_save($map) { return openlayers_map_save($map); }
  1060. function openlayers_preset_delete($map) { return openlayers_map_delete($map); }
  1061. function openlayers_preset_options($reset = FALSE) { return openlayers_map_options($reset); }
  1062. function openlayers_error_check_preset($map, $log_errors = TRUE) { return openlayers_error_check_map($map, $log_errors); }
  1063. function openlayers_render_preset($map = '', $map_name = '') {
  1064. if (is_array($map)) {
  1065. return openlayers_render_preset_data($map, $map_name);
  1066. }
  1067. else {
  1068. return openlayers_render_map($map);
  1069. }
  1070. }