ujamii/geocoder-neos

There is no license information available for the latest version (v0.1.0) of this package.

This package provides a very flexible way of geocoding your node properties.

Installs: 4 419

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 2

Forks: 0

Open Issues: 0

Type:neos-package

v0.1.0 2021-01-20 22:07 UTC

This package is auto-updated.

Last update: 2024-04-11 14:03:20 UTC


README

Packagist

This package provides a very flexible way of geocoding your node properties. Imagine you have a document or content type with some physical address data (street, zip code, city) and you want to display this data on a map (for instance with WebExcess.OpenStreetMap) or you need the geo data for some calculations.

Installation

composer req ujamii/geocoder-neos php-http/guzzle6-adapter

Usage

The package provides a new node type mixin "Ujamii.Geocoder:Mixin.AddressData". Add this mixin to the desired NodeType in your package:

'Your.Package:Document.BranchLocation':
    superTypes:
        'Neos.Neos:Document': true
        'Ujamii.Geocoder:Mixin.AddressData': true

This will add some new properties to the node inspector. When you add address data there, the geodata will be added after you safe your changes. This is done by a pretty feature rich package

Where is the difference to FormatD.GeoIndexable or Wwwision.Neos.AddressEditor?

you may ask. Well, tha latter one also uses the geocoder package, but only make use of exactly one geocoding service: Google Maps. In contrast, this very package just integrates the geocoder package without any restrictions in its configuration. Although I included the Nominatim/OpenStreetMap data provider as default here, you can use something completely different, or with just a different config. This is what this makes this package a little more flexible.

In the Configuration/Objects.yaml file, the object management feature of NEOS is used to configure the geocoder/data provider used to get coordinates from your address data.

Geocoder\StatefulGeocoder:
  className: 'Geocoder\StatefulGeocoder'
Geocoder\Provider\Nominatim\Nominatim:
  className: 'Geocoder\Provider\Nominatim\Nominatim'

Ujamii\Geocoder\Service\GeocodingService:
  properties:
    geocoder:
      object:
        name: 'Geocoder\StatefulGeocoder'
        arguments:
          1:
            object:
              name: 'Geocoder\Provider\Nominatim\Nominatim'
              arguments:
                1:
                  object: 'Http\Adapter\Guzzle6\Client'
                2:
                  value: 'https://nominatim.openstreetmap.org'
                3:
                  value: 'NEOS CMS Ujamii.Geocoder'
          2:
            value: 'de'

As you can see, all the constructor arguments for the used objects are provided and can, of course, be changed by your own package and config.

In the Configuration/Settings.yaml file, the property config can also be changed. So let's say you need some more properties, like a country or state. You can just add those to your NodeType or create your own mixin, which may have Ujamii.Geocoder:Mixin.AddressData as supertype again. The properties will be joined by a space character when sent to the data provider.

But you are even free to exchange this part as well. The event after saving your node will check for a configured type, so if you created your own one, just set it in your settings:

Ujamii:
  Geocoder:
    GeocodingService:
      observedNodeType: 'Ujamii.Geocoder:Mixin.AddressData'
      observedProperties: ['street', 'zip', 'city']
      mandatoryProperties: ['street', 'zip', 'city']

Now, let's assume everything is configured the way you like, and you want to display a nice map with those documents added as map markers along with nice tooltips and an info popup (we also added some more properties):

(for this example, install WebExcess.OpenStreetMap, but any other map will work as well)

prototype(Your.Package:Content.BranchLocationMap) < prototype(Neos.Neos:ContentComponent) {
    @context.branches = Neos.Fusion:Loop {
        items = ${q(site).find('[instanceof Your.Package:Document.BranchLocation]').get()}
        @glue = ','
        itemRenderer = Neos.Fusion:RawArray {
            type = "Feature"
            properties {
                tooltip = ${q(item).property('title')}
                popup = Your.Package:Component.Molecule.BranchLocationMapPopup {
                    company = ${q(item).property('company')}
                    street = ${q(item).property('street')}
                    zip = ${q(item).property('zip')}
                    city = ${q(item).property('city')}
                    phone = ${q(item).property('phone')}
                    email = ${q(item).property('email')}
                }
            }
            geometry {
                type = "Point"
                coordinates = ${[q(item).property('longitude'), q(item).property('latitude')]}
            }
            @process.json = ${Json.stringify(value)}
        }
    }

    map = WebExcess.OpenStreetMap:Map.Component {
        json = ${'[' + branches + ']'}
    }

    renderer = afx`
        <div>
            {props.map}
        </div>
    `
}

prototype(Your.Package:Component.Molecule.BranchLocationMapPopup) < prototype(Neos.Fusion:Component) {
    company = ''
    street = ''
    zip = ''
    city = ''
    phone = ''
    email = ''

    renderer = afx`
        <p>
            {String.nl2br(props.company)}<br/>
            {props.street}<br/>
            {props.zip} {props.city}
        </p>
        <p>
            {props.phone}
            {props.email}
        </p>
    `
}

Using a different provider

Say, you want to use Google Maps as data provider. First, install the package:

composer require geocoder-php/google-maps-provider

Next, adjust the config:

Geocoder\StatefulGeocoder:
  className: 'Geocoder\StatefulGeocoder'
Geocoder\Provider\GoogleMaps\GoogleMaps:
  className: 'Geocoder\Provider\GoogleMaps\GoogleMaps'

Ujamii\Geocoder\Service\GeocodingService:
  properties:
    geocoder:
      object:
        name: 'Geocoder\StatefulGeocoder'
        arguments:
          1:
            object:
              name: 'Geocoder\Provider\GoogleMaps\GoogleMaps'
              arguments:
                1:
                  object: 'Http\Adapter\Guzzle6\Client'
                2:
                  value: null
                3:
                  value: '<your-api-key>'
          2:
            value: 'de'

The same steps if you, for instance, dont want to use the default Guzzle 6 adapter. Just add your desired library:

composer require ...

and then configure it in the Objects.yaml providing optional config as constructor parameters, if you want.

TODOs

  • feature: multi language
  • feature: add an eel helper with methods for geocoding and reverse geocoding
  • feature: Command Controller for filling empty values (like for imported nodes)

License and Contribution

GPLv3

As this is OpenSource, you are very welcome to contribute by reporting bugs, improve the code, write tests or whatever you are able to do to improve the project.

If you want to do me a favour, buy me something from my Amazon wishlist.