ftw.geo

HomePage: https://github.com/4teamwork/ftw.geo

Author: Lukas Graf

Download: https://pypi.python.org/packages/source/f/ftw.geo/ftw.geo-1.3.zip

        Introduction
============

This product helps integrating the ``collective.geo.*`` packages and aims to
provide some sensible defaults. Besides some integration glue it defines a new
interface ``IGeocodableLocation`` that can be used to create adapters that knows
how to represent the location of a content type with address-like fields as a
string suitable for passing to a geocoding API.


Purpose
========

- Automatic geocoding of ``IGeoreferenceable`` content types via an
  ``IGeocodableLocation`` adapter
- Caching of geocoding responses
- Only trigger geocoding lookups if location related fields on the content item
  changed
- Facilitate doing automatic geocoding based on location fields and still allow
  for manually setting custom coordinates


Usage
=====


Automatically geocoding your content types
------------------------------------------

In order for your content types to be automatically geocoded on ``ObjectEdited``
or ``ObjectInitialized`` events, you need to create an adapter for your content
type that implements ``IGeocodableLocation`` and knows how to build a geocodable
location string from the content type's location related fields.

In order to implement the interface you need to define a ``getLocationString``
method on your adapter that returns the complete location as a comma separated
string, with the location parts getting less specific from left to right.

For example::

    '1600 Amphitheatre Parkway, Mountain View, CA, US'
    'Engehaldestr. 53, 3012 Bern, Switzerland'

If the ``getLocationString`` method returns the empty string or ``None``, the
event handler won't attempt to do a geocode lookup, so this is the suggested way
to abort geocoding if not enough location information is available.

Example code::

    from ftw.geo.interfaces import IGeocodableLocation
    from zope.component import adapts
    from zope.interface import implements


    class MyTypeLocationAdapter(object):
        """Adapter that is able to represent the location of an MyType in
        a geocodable string form.
        """
        implements(IGeocodableLocation)
        adapts(IMyType)

        def __init__(self, context):
            self.context = context

        def getLocationString(self):
            """Build a geocodable location string from the MyType's address
            related fields.
            """
            street = self.context.getAddress()
            zip_code = self.context.getZip()
            city = self.context.getCity()
            country = self.context.getCountry()

            location = ', '.join([street, zip_code, city, country])
            return location


Register the adapter with ZCML::

    <adapter
        factory=".mytpe.MyTypeLocationAdapter"
        />


Caching of geocoding responses
------------------------------

Responses from the geocoding API are being RAM cached. The cache key being used
is the result of the ``getLocationString`` method, which means that for every
unique location string the geocoding lookup is only done once and subsequently
fetched from the cache.


Only triggering geocoding when location fields changed
------------------------------------------------------

If we were to do a geocode lookup on every ``ObjectEdited`` event, any custom
coordinates that have been set would be overriden every time *any* field on
the content item is changed (even if the geocoding response itself was fetched
from the cache).

To avoid this, ``ftw.geo`` stores the result of ``getLocationString`` as an
annotation on the object and on ``ObjectEdited`` checks if the location string
(and therefore the location related fields) actually changed, and only does the
lookup when necessary. This means:

On ``ObjectInitialized`` the content type will first be geocoded initally
(unless ``getLocationString`` returned ``None`` or the empty string). If you
manually set coordinates after that through the 'Coordinates' tab provided by
``collective.geo.contentlocations`` they will be saved and overwrite the
coordinates determined previously by geocoding. After that, if you edit the
content item an