Skip to content

Extending Atlas

Atlas is designed to be extended. The core geocoder implements the GeocoderDriver interface, making it easy to wrap, decorate, or replace.

The GeocoderDriver Interface

php
namespace ArielMejiaDev\Atlas\Contracts;

use ArielMejiaDev\Atlas\Support\Result;

interface GeocoderDriver
{
    public function geocode(array $input): ?Result;
}

Adding an Online Fallback

A common pattern is to wrap Atlas with an online geocoder that handles country_centroid or null results:

php
namespace App\Geocoding;

use ArielMejiaDev\Atlas\Contracts\GeocoderDriver;
use ArielMejiaDev\Atlas\Support\Result;

class HybridGeocoder implements GeocoderDriver
{
    public function __construct(
        private GeocoderDriver $offline,
        private OnlineGeocoderService $online,
    ) {}

    public function geocode(array $input): ?Result
    {
        $result = $this->offline->geocode($input);

        // If the offline result is low-confidence, try online
        if ($result === null || in_array($result->method, [
            'country_centroid',
            'text_extract_country_centroid',
            'global_big_city_match',
        ])) {
            $onlineResult = $this->online->geocode($input);

            if ($onlineResult !== null) {
                return $onlineResult;
            }
        }

        return $result;
    }
}

Register it in your service provider:

php
use ArielMejiaDev\Atlas\Contracts\GeocoderDriver;
use ArielMejiaDev\Atlas\OfflineGeocoder;

$this->app->singleton(GeocoderDriver::class, function ($app) {
    return new HybridGeocoder(
        $app->make(OfflineGeocoder::class),
        $app->make(OnlineGeocoderService::class),
    );
});

Custom Normalizer

The Normalizer is a regular class that you can extend:

php
namespace App\Geocoding;

use ArielMejiaDev\Atlas\Support\Normalizer;

class CustomNormalizer extends Normalizer
{
    public function normalize(string $s): string
    {
        // Pre-process: expand known abbreviations
        $s = str_replace(['St.', 'Ave.', 'Blvd.'], ['Street', 'Avenue', 'Boulevard'], $s);

        return parent::normalize($s);
    }
}

Bind it in your service provider:

php
$this->app->singleton(Normalizer::class, CustomNormalizer::class);

WARNING

If you customize the normalizer, you must rebuild the database so that the name_norm values in SQLite match your runtime normalization. The builder uses the same Normalizer class.

Listening to Geocode Events

Subscribe to AddressGeocoded to run side effects:

php
use ArielMejiaDev\Atlas\Events\AddressGeocoded;

// In EventServiceProvider
protected $listen = [
    AddressGeocoded::class => [
        NotifyGeocodeComplete::class,
        UpdateSearchIndex::class,
    ],
];

Managing the Database Connection

By default, Atlas registers its own SQLite connection. If you need custom settings:

php
// config/atlas.php
'manage_connection' => false, // Disable auto-registration
'connection_name' => 'my_geocoder',

Then add the connection yourself in config/database.php:

php
'connections' => [
    'my_geocoder' => [
        'driver' => 'sqlite',
        'database' => database_path('geocoding.sqlite'),
        'prefix' => '',
        'foreign_key_constraints' => false,
    ],
],

Released under the MIT License.