BazingaGeocoderBundle

repository·master·Indexed 43 days ago

https://github.com/geocoder-php/bazingageocoderbundle

A Symfony integration for the Geocoder PHP library that provides geocoding capabilities with built-in Symfony profiler support, PSR-16 caching, and automatic geocoding for Doctrine entities via attributes.

Tokens
8.9K
Snippets
31
Records
37
Agent score
53%

What's inside BazingaGeocoderBundle

  1. Overview of BazingaGeocoderBundle

    master

    BazingaGeocoderBundle is a Symfony bundle that integrates the Geocoder library into the Symfony framework. It provides seamless integration with the Symfony profiler, allowing developers to monitor geocoding activities. Through the profiler, you can inspect:

    • The number of queries executed by each provider.
    • Total execution time for geocoding requests.
    • The actual geocoding results returned by providers.
  2. Chain multiple providers using ChainFactory

    master

    You can pass a request through multiple providers sequentially using the ChainFactory. This is useful for fallback mechanisms. In the options for the ChainFactory, provide a services array containing the service IDs (using Symfony's @ syntax) or the aliases defined for your individual providers.

    bazinga_geocoder:
        providers:
            acme:
                aliases:
                    - my_geocoder
                factory: Bazinga\GeocoderBundle\ProviderFactory\GoogleMapsFactory
                options:
                    api_key: 'xxxx'
            acme_ii:
                factory: Bazinga\GeocoderBundle\ProviderFactory\TomTomFactory
                options:
                    api_key: 'xxyy'
            chain:
                factory: Bazinga\GeocoderBundle\ProviderFactory\ChainFactory
                options:
                    services: ['@my_geocoder', '@bazinga_geocoder.provider.acme_ii']
  3. Fake local IP for development

    master

    When developing locally, geocoding requests based on REMOTE_ADDR (like 127.0.0.1) often fail to return location data. You can use the fake_ip configuration to replace local IPs with a specific address.

    • Simple usage: Set fake_ip to a string to replace 127.0.0.1.
    • Advanced usage: Use local_ip to specify which IP should be replaced (default is 127.0.0.1) and ip for the replacement value.
    • Faker integration: Set use_faker: true to have Faker generate a random IP.
    # config/packages/bazinga_geocoder.yaml
    
    when@dev:
        bazinga_geocoder:
            fake_ip: 123.123.123.123
    
    # OR
    
    when@dev:
        bazinga_geocoder:
            fake_ip:
                local_ip: 192.168.99.1
                ip: 123.123.123.123
    
    # OR
    
    when@dev:
        bazinga_geocoder:
            fake_ip:
                use_faker: true
  4. Configure Custom HTTP Clients

    master

    The bundle supports any PSR-18 compatible HTTP client. While symfony/http-client is recommended for Symfony applications, you can use others like Guzzle by passing the service ID via the options.http_client key in your provider configuration.

    services:
        guzzle.client:
            class: GuzzleHttp\Client
    
    bazinga_geocoder:
        providers:
            acme:
                factory: ...
                options:
                    http_client: '@guzzle.client'
  5. Make a custom provider visible in the Web Profiler

    master

    To make a custom provider appear in the Web Profiler, you must implement a custom factory by extending Bazinga\GeocoderBundle\ProviderFactory\AbstractFactory and then register that factory in your bazinga_geocoder configuration.

    1. Create a factory class that implements getProvider(array $config).
    2. Register the factory in config/packages/bazinga_geocoder.yaml under the providers key, providing the factory class name and an alias for your provider.
    namespace Acme\​Demo\​Geocoder\​Factory;
    
    use Bazinga\\GeocoderBundle\\ProviderFactory\\AbstractFactory;
    use Acme\\Demo\\Geocoder\\Provider\\MyProvider;
    use Acme\\Demo\\Service\\Foo;
    
    final class MyFactory extends AbstractFactory
    {
        private $fooService;
    
        public function __construct(Foo $service)
        {
            $this->fooService = $service;
        }
    
        protected function getProvider(array $config)
        {
            return new MyProvider($this->fooService);
        }
    }
    # config/packages/bazinga_geocoder.yaml
    bazinga_geocoder:
        providers:
            acme:
                factory: Acme\Demo\Geocoder\Factory\MyFactory
                aliases: ['acme_demo.geocoder.my_provider']
  6. Register a custom Geocoder provider

    master

    To use a custom provider in your application, define it as a service in your Symfony configuration and tag it with bazinga_geocoder.provider. The bundle will automatically add this service to the Geocoder\ProviderAggregator service.

    Note: Providers registered this way will function correctly in your code, but they will not appear in the Symfony Web Profiler.

    <service id="acme_demo.geocoder.my_provider" class="Acme\Demo\Geocoder\Provider\MyProvider">
        <argument type="service" id="foo_service" />
        <tag name="bazinga_geocoder.provider" />
    </service>
  7. Install BazingaGeocoderBundle

    master

    To install the bundle, first ensure you have installed the core Geocoder library and your desired providers. Then, install the bundle via Composer:

    composer require willdurand/geocoder-bundle:^5.0

    If you are not using Symfony Flex, you must manually register the bundle in your application configuration (e.g., config/bundles.php or app/AppKernel.php).

  8. Configure Symfony cache as a PSR-16 service

    master

    In Symfony (>= 3.3), you can use the Symfony\Component\Cache\Simple\Psr6Cache adapter to turn a PSR-6 cache pool into a PSR-16 service compatible with the Geocoder bundle.

    1. Define a PSR-6 cache pool in cache.yaml.
    2. Register the Psr6Cache adapter in services.yaml using your pool.
    3. Reference that adapter service in your bazinga_geocoder configuration.
    # config/services.yaml
    app.simple_cache:
        class: Symfony\Component\Cache\Simple\Psr6Cache
        arguments: ['@app.cache.acme']
    # config/packages/cache.yaml
    framework:
        cache:
            app: cache.adapter.redis
            pools:
                app.cache.acme:
                    adapter: cache.app
                    default_lifetime: 600
    # config/packages/bazinga_geocoder.yaml
    bazinga_geocoder:
        providers:
            my_google_maps:
                factory: Bazinga\GeocoderBundle\ProviderFactory\GoogleMapsFactory
                cache: 'app.simple_cache'
                cache_lifetime: 3600
                cache_precision: 4
  9. Register and use custom plugins with the `plugins` key

    master

    To use plugins that are not covered by the built-in configuration keys (such as QueryDataPlugin), you must follow a two-step process:

    1. Register the plugin as a service in config/services.yaml.
    2. Attach the plugin to a provider by adding its service ID to the plugins list under that provider in config/packages/bazinga_geocoder.yaml.

    For example, to use a QueryDataPlugin that adds 'foo': 'bar' to every query, register the service and then reference it in the provider configuration.

    # config/services.yaml
    services:
        app.query_data_plugin:
            class: Geocoder\Plugin\Plugin\QueryDataPlugin
            arguments:
                - ['foo': 'bar']
                - true
    
    # config/packages/bazinga_geocoder.yaml
    bazinga_geocoder:
        providers:
            acme:
                factory: Bazinga\GeocoderBundle\ProviderFactory\GoogleMapsFactory
                plugins:
                    - 'app.query_data_plugin'
  10. Use a PSR-6 to PSR-16 bridge for older Symfony versions

    master

    For older Symfony versions that do not natively support SimpleCache, you can install the cache/simple-cache-bridge to bridge PSR-6 and PSR-16.

    1. Install the bridge: composer require cache/simple-cache-bridge

    2. Use Cache\Bridge\SimpleCache\SimpleCacheBridge in your service definitions to wrap your PSR-6 cache.

    composer require cache/simple-cache-bridge
  11. Use the CacheProvider decorator pattern

    master

    If you prefer not to use the built-in CachePlugin, you can manually wrap your existing provider using the geocoder-php/cache-provider package. This follows the Decorator pattern, where you create a new service that wraps your original provider and a PSR-16 cache service.

    1. Install the package: composer require geocoder-php/cache-provider

    2. Define the cached service in your services.yaml, passing the original provider service ID, the cache service ID, and the lifetime as arguments.

    composer require geocoder-php/cache-provider
    # config/services.yaml
    services:
        my_cached_geocoder:
            class: Geocoder\Provider\Cache\ProviderCache
            arguments: ['@bazinga_geocoder.provider.acme', '@any.psr16.service', 3600]
  12. Enable automatic geocoding for Doctrine entities

    master

    You can automatically geocode addresses and save coordinates (latitude and longitude) to your Doctrine entities using attributes and an ORM listener.

    1. Annotate your Entity: Use #[Geocoder\Geocodeable] on the class to specify which provider to use. Use #[Geocoder\Address], #[Geocoder\Latitude], and #[Geocoder\Longitude] to mark the relevant properties or getters.
    2. Enable the ORM Listener: You must explicitly enable the ORM feature in your Symfony configuration.
    3. Usage: When you persist and flush the entity, the bundle will automatically trigger the geocoding process and populate the marked fields.
    use Bazinga\GeocoderBundle\Mapping\Attributes as Geocoder;
    
    #[Geocoder\Geocodeable(provider: 'acme')]
    class User
    {
        #[Geocoder\Address()]
        private $address;
    
        #[Geocoder\Latitude()]
        private $latitude;
    
        #[Geocoder\Longitude()]
        private $longitude;
    }
    
    // Configuration
    bazinga_geocoder:
        orm:
            enabled: true