Node Locations not geocoding, no errors given.

lance.gliser - March 23, 2009 - 20:11
Project:Location
Version:6.x-3.x-dev
Component:Code
Category:bug report
Priority:normal
Assigned:Unassigned
Status:needs work
Issue tags:location bdragon check
Description

I truly hope I'm not duplicating on you with this. I was having trouble with my site's geocoding failing to run automatically. I googled for a few issues and found multiple people never quite got their answers. I believe the issue is caused by 3 separate bugs, or maybe I just thing the module should work differently. For people looking for answers, it's important you understand that the location module is attempting to run for you if the coordinates are not user submitted. It just doesn't return any information about success or failures. This leads to a lot of head scratching for people. To that end, I recommend adding some drupal set messages. I've added them in the code I'll post here. First, a generic fallback:

In location.module, function: _location_geo_logic

<?php
else {
 
$location['source'] = LOCATION_LATLON_UNDEFINED;
 
$location['latitude'] = 0;
 
$location['longitude'] = 0;
 
//A generic fall back for when address geolocation fails
 
drupal_set_message(t('The location could not be identified based on the address, or zip code provided.'), 'warning');
}
?>

But the actual bugs need to be addressed more than messages. In location.module, function: _location_geo_logic, an if statement currently reads:

<?php
if ($changed['street'] || $changed['additional'] || $changed['city'] || $changed['province'] || $changed['country'] || $changed['postal_code'] || $location['source'] == LOCATION_LATLON_USER_SUBMITTED) {
?>

But later in the file it sets $location['source'] to LOCATION_LATLON_UNDEFINED (0). If the user saves the node again, without changing the address hoping to fire geoencoding, the if statement does not allow for the check (and gives no warning). I would suggest adding LOCATION_LATLON_UNDEFINED to the if statement. I know that it will only come up while testing like I am, or maybe if you hit your limit on geoencodes from google for a day, but it keeps the behavior more predicable. New if statement:
<?php
if ($changed['street'] || $changed['additional'] || $changed['city'] || $changed['province'] || $changed['country'] || $changed['postal_code'] || $location['source'] == LOCATION_LATLON_USER_SUBMITTED || $location['source'] == LOCATION_LATLON_UNDEFINED) {
?>

Also in location.module, function: location_strip, the current stripping patterns were removing the ['locpick'], ['user_latitude'], and ['user_longitude'] arrays. If those are stripped out, the checks for differences that fire geoencoding fail to see a difference from the merged location array to the old location array. Please consider altering $tmp or changing the function to something similar to:

<?php
function location_strip(&$location) {
  static
$tmp;
if (!isset(
$tmp)) {
   
$tmp = array();
   
$defaults = location_invoke_locationapi($location, 'defaults');
    foreach (
$defaults as $k => $v) {
      if (!isset(
$v['nodiff'])) {
       
$tmp[$k] = TRUE;
      }
    }
  }
  foreach (
$location as $k => $v) {
    if (!isset(
$tmp[$k])) {
      if(!(
$location[$k] == "locpick" || $location[$k] == "user_latitude" || $location[$k] == "user_longitude")) {
    unset(
$location[$k]);
      }
    }
  }
}
?>

In location.inc, function: location_get_postalcode_data, I found that the $country_specific_function was failing everytime. For me, at least, the required location.xx.inc file was not loaded at the time the function checked for it's existence. All that needed done was to include_once the country file. I've got code for that below, along with the drupal_set_messages if there are errors.

<?php
function location_get_postalcode_data($location = array()) {
 
$location['country'] = isset($location['country']) ? trim($location['country']) : NULL;
 
$location['postal_code'] = isset($location['postal_code']) ? trim($location['postal_code']) : NULL;
  if (
is_null($location['postal_code']) || is_null($location['country']) || empty($location['country']) || empty($location['postal_code']) || $location['postal_code'] == 'xx') {
    return
NULL;
  }
 
$country_specific_function = 'location_get_postalcode_data_'. $location['country'];
    if (
function_exists($country_specific_function)) {
      return
$country_specific_function($location);
    }
    else {
      if (
$cache = cache_get('location:supported-countries', 'cache_location')) {
       
$country = $location['country'];
          if (
$cache->data[$country]) {
           
$include = drupal_get_path('module', 'location') .'/supported/location.'. $location['country'] .'.inc';
              if (
file_exists($include)){
                include_once(
$include);
                  if (
function_exists($country_specific_function)) {
                    return
$country_specific_function($location);
                  } else {
                   
drupal_set_message(t('The support file for: ' . $location['country']. ' found at <i>' . $include .'</i>. does not have a function to support zip code look ups. Missing funtion: <i>' . $country_specific_function . '</i>'), 'error');
                  }
            } else {
             
drupal_set_message(t('The support file for: ' . $location['country']. ' could not be found at <i>' . $include .'</i>.'), 'error');
            }
          } else {
           
drupal_set_message(t('The country code requested: ' . $location['country']. ' is not supported by this site.'), 'warning');
          }
        } else {
         
drupal_set_message(t('There are no supported countries in the site cache.'), 'warning');
        }
      return
NULL;
    }
}
?>

#1

lance.gliser - March 23, 2009 - 21:24

My generic fallback message has an issue.
If you set the location as optional, and the user fills in nothing, the message prints warning them it wasn't saved.
It needs an if statement checking if the user even entered a zip or street. Something like:

<?php
 
if (! ( empty($location['street']) || empty($location['postal_code']) ) ){
?>

#2

SeanBannister - March 24, 2009 - 10:31

+1 been trying to get this working :)

#3

pacesolutions - March 27, 2009 - 05:20

As per my installation I did not found any problems. Everything is working as it suppose to work. Here how you can work around the problem.

Packages:

- Latest Drupal - http://ftp.drupal.org/files/projects/drupal-6.10.tar.gz
- Latest Location Module - http://drupal.org/project/location (6.x-3.1-rc1)
- Latest GMap Module - http://drupal.org/project/gmap (6.x-1.1-rc1)

- Install or Upgrade to latest Drupal 6.10

- Download and place modules in the modules directory of your Drupal.

- Now activate the following modules from Administrator section (admin/build/modules)
* User Locations
* Node Locations
* Location Search
* Location
* GMap
* GMap Location

- Once modules are enabled. Get Google Maps API and configure the Location module (admin/settings/location).
* In Main settings tab, make sure you select United States as default country.
* Toggle location display: Enable
* Use a Google Map to set latitude and longitude is checked.
* Now in Geocoding Options tab, under United States choose Google Maps.
* Hit saves Configuration
* Now again under United States choose Configure Parameters (This is where you put your Google API key).

- Now configure GMap module (admin/settings/gmap).
* Put your API key here (If not already there.)
* Set default width & height as you like and choose also the default center (e.g.: 39.9434364619742,-77.2998046875), you can also configure more settings as you like.
* Now hit Save Configurations to save them.

- Now configure GMap Location (admin/settings/gmap_location)
* For each Macro put something like this: [gmap zoom=3 |center=39.9434364619742,-77.2998046875 |width=100% |height=300px |control=Small |type=Physical]

- Now most important part is to enable Location block in the content or sidebar to display the map correctly.
* Enable 'Location map' block (admin/build/block) and set to display in sidebar or content - now a small map will be displayed next to nodes that have a location.

- You can create a new content type or modify the existing to display and enter the location/map data. I will modify the default Page content type (admin/content/node-type/page)
* Under Locative Information click on Number of locations
* Set 1 for Minimum number of locations, Maximum number of locations and Number of locations that can be added at once.
* Under Collection Settings, choose the fields you want to display in the form for adding/editing.
* Now hit Save Content Type.

- Now create a new test page (node/add/page) to see if Google maps are working or not.
* Fill the details as you like,
* Double click on the map to place the marker and auto fill the Latitude & Longitude
* Save the Page node.

- You should be able to see the Google Map with marker in right place under your block. You can free place Location block anywhere as you like.

There is no need for CCK or any other module to work around. CCK module is not working.

#4

lance.gliser - March 27, 2009 - 20:49

I'm not entirely sure you have understood want I was after, pacesolutions.

You're suggesting that the user:

Double click on the map to place the marker and auto fill the Latitude & Longitude

My current goal is let the user choose their own coordinates, like you suggest, or leave them unselected to fire geolocation automatically based off their address.
Your solution would end with all user entered coordinates, not what I'm after.

Also the purpose of this posting is to address your last line:

There is no need for CCK or any other module to work around. CCK module is not working.

I have posted solutions to multiple bugs in the location module.
When fixed, the CCK module does work. I user multiple working CCK Location fields over multiple content types on the site I'm building. And they all work fantastically. (Well... it get's sketchy when you try to pull the view.)

I have a working copy solution. I'm trying to give back since the developers did the majority of the heavy lifting.

#5

ajevans85 - March 28, 2009 - 21:56

Just trying this module and was unable to get automatic population of lng/lat fields.

Applying the patch from lance.gliser lead me to track the issue down to the location.uk.inc not having the function 'location_get_postalcode_data_uk' . Thats only half my problem as 'location_get_postalcode_data_uk' should be a fallback function if geocaching isn't working (and i had set up geocaching). I haven't had chance to implement 'location_get_postalcode_data_uk' yet as I am more concerned with the google geocaching and feasability of integrating this module with the apache solr module with solr local searching. As I am uk based and things are looking promising when just playing about with this I'll probably have a patch soon as it's fairly trivial.

Any way back to my problem... further tracking lead me to the '_google_geocode_flatten' function. It was generating a invalid query string for uk geo caching. The function applies the province code 'CHS' for Cheshire, this meant nothing to Google as 'CHS' it's not a valid UK county (province). Changing the flatten function to use province name also didn't work, it was a valid address but google was still providing a status 602 (no valid address found). Dropping the province filed worked so my function now looks like:

<?php
function _google_geocode_flatten($location = array()) {

 
// Check if its a valid address
 
if (empty($location)) {
    return
'';
  }

 
$query= array();


  if (!empty(
$location['street'])) {
   
$query[] = $location['street'];
  }

  if (!empty(
$location['city'])) {
      
$query[]= $location['city'];
  }

  if (
$location['country'] != 'uk' && !empty($location['province'])) {
   
   
// @@@ Fix this!
   
if (substr($location['province'], 0, 3) == $location['country'] .'-') {
     
$query[]= substr($location['province'], 3);
     
watchdog('Location', 'BUG: Country found in province attribute.');
    }
    else {
     
$query[]= $location['province_name']; //Google doesn't map CHS back to Cheshire for uk so we get a 602 error
   
}
  }

  if (!empty(
$location['postal_code'])) {
   
$query[]=$location['postal_code'];
  }

  return
implode(',', $query);
}
?>

Works for me but not that elegant considering theres 242 supported locations in the supported directory and they may all need to structure the query sting differently. What would probably be better is checking if a function such as 'location_geocode_flatten_$country' exists to flattern the string otherwise fall back to the default implementation.

I agree with lance that some error messages are needed and without his patch it probably would of took me longer tracking down my issue.

#6

pacesolutions - March 31, 2009 - 05:20

Above fixes seems to work with CCK and Location module.

I have a working copy solution. I'm trying to give back since the developers did the majority of the heavy lifting.

If you can provide the complete location.module file, that will be more helpful.

#7

lance.gliser - March 31, 2009 - 18:43

I'll upload the two file's I've altered.
Look for //emfluence on the functions I've altered.

Also, to get CCK working with views I had to do the work around in http://drupal.org/node/366880
It's a nasty hack, acknowledged by the author and myself. You have to theme out locations and theme in location CCK.
I'm waiting for his proper fix. But for now it all works when you put it together.

AttachmentSize
location.inc_.txt 28.9 KB
location.module_.txt 59.11 KB

#8

YesCT - April 18, 2009 - 05:29

the idea in the original post about messages seems reasonable.

#9

kevin riggen - August 17, 2009 - 06:59

Subscribing - will edit w/ results

#10

kevin riggen - September 6, 2009 - 18:28

Prompting the User , and preventing the form from being submitted if (latitude, longitude) can not be found

Line 574, location.module

      //Test if city is valid - ADDED BY TIM 9/6
      if (!empty($obj['city'])) {

            //Create Array
            $location = array("city"=>$obj['city'], "province"=>$obj['province'], "country"=>$obj['country']);
            if ($data = location_latlon_exact($location)) { //City is valid - don't do anything right now
              
            } else { //City is not valid
                form_error($a3['city'], t('We were not able to geocode your location.'));
            }
      }

I prefer this to the #1's initial code sample, because it stops the form from saving information in the database. Obviously, it would be best to have a map for the user to manually enter a location after this, instead of not allowing non-supported cities.

#11

SocialNicheGuru - September 15, 2009 - 21:38

subscribing

#12

wretched sinner... - September 18, 2009 - 12:12
Version:6.x-3.1-rc1» 6.x-3.x-dev
Status:needs review» reviewed & tested by the community

I have tested the replacement files from lance in #7, and my maps are now displaying (I'm in Australia)

I can roll a patch if required...

#13

Summit - November 1, 2009 - 20:21

Yes please, roll a patch!
Thanks in advance! Greetings, Martijn

#14

wretched sinner... - November 2, 2009 - 09:02
Status:reviewed & tested by the community» needs review

I have attached a patch for the files in #411360-7: Node Locations not geocoding, no errors given.

AttachmentSize
411360-14.patch 64.9 KB

#15

Jax - November 25, 2009 - 15:39
Status:needs review» needs work

The patch completely replaces location.inc with lines that end in CR LF in stead of only LF. Please configure your text editor correctly and reroll the patch.

#16

wretched sinner... - November 26, 2009 - 21:22
Status:needs work» needs review

Sorry about that. I just copied the files in #411360-7: Node Locations not geocoding, no errors given. over and diffed from there. I didn't think to check the line endings, and that would explain the trouble I had last time.

Attached is a patch with correct line endings.

AttachmentSize
411360-16.patch 9.21 KB

#17

Jax - December 2, 2009 - 15:39
Status:needs review» needs work

This is meaningless:

<?php
function location_map_link($location = array(), $link_text = 'See map: ') {
-  if (!isset(
$location['country']) || $location['country'] == 'xx') {
+  if (!isset(
$location['country']) && $location['country'] != 'xx') {
     return
'';
   }
?>

Is $location['country'] is not set then $location['country'] will be different than 'xx' … Also I'm not sure this even should be modified.

Please remove:

<?php
+ // emfluence
?>

 
 

Drupal is a registered trademark of Dries Buytaert.