NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Addresses for Laravel

Country codes & resolvers

Country codes are normalised on the way in: trimmed, upper-cased and checked to be two or three letters — the shape of an ISO 3166-1 alpha-2 or alpha-3 code. Anything else throws InvalidCountryException:

use RoundlyConsulting\Addresses\Support\CountryNormaliser;

CountryNormaliser::normalise(' sk ');   // 'SK'
CountryNormaliser::normalise('usa');    // 'USA'
CountryNormaliser::normalise('XX1');    // throws InvalidCountryException

The check is shape-only — the package bundles no country list, so a well-formed but unassigned code such as XX passes. Normalisation runs inside AddressData::make(), which covers every package write path: the builder, addAddress(), createAddress() and UpdateAddressAction with a make()-built DTO.

To store country codes exactly as given (trimmed only, never shape-checked), switch it off — false, or a string such as 'false', '0' or 'off'. inCountry() then matches them case-insensitively:

// config/addresses.php — store country codes as given (trimmed only, never shape-checked)
'normalise_country' => false,

Country names

The package ships no country-name list and no geocoder. To resolve names — or coordinates — implement the CountryResolver contract in your app:

namespace App\Support;

use RoundlyConsulting\Addresses\Contracts\CountryResolver;
use RoundlyConsulting\Addresses\DataTransferObjects\AddressData;
use RoundlyConsulting\Addresses\DataTransferObjects\Coordinates;

final class AppCountryResolver implements CountryResolver
{
    public function name(string $iso): ?string
    {
        return ['SK' => 'Slovakia', 'CZ' => 'Czechia', 'AT' => 'Austria'][$iso] ?? null;
    }

    public function coordinates(AddressData $data): ?Coordinates
    {
        // call your own geocoder here; return null when the address cannot be resolved
        return null;
    }
}

Register it in config. The service provider binds it as a singleton on CountryResolver when it registers; with null or a blank value, nothing is bound. Any other value is checked when the resolver is first resolved — it must name a CountryResolver class, or that throws InvalidConfigurationException naming the key, so a typo never silently leaves country names unresolved:

// config/addresses.php
'country_resolver' => \App\Support\AppCountryResolver::class,

With a resolver bound, country_name returns the resolved name; without one it is null. The same value appears in AddressResource. Addresses::countryName() resolves any code and falls back to the normalised ISO code when no resolver is bound or it does not know the code:

use RoundlyConsulting\Addresses\Contracts\CountryResolver;
use RoundlyConsulting\Addresses\Facades\Addresses;

$address->country_name;      // 'Slovakia' with a resolver bound, otherwise null
$address->countryName();     // the same value as a method

Addresses::countryName('sk');   // 'Slovakia' — or the normalised 'SK' without a resolver

if (app()->bound(CountryResolver::class)) {
    $name = app(CountryResolver::class)->name('SK');
}

Geocoding

The package never calls coordinates() itself — it is there for your code, and returns a Coordinates value object (latitude, longitude) or null. For example, geocode an address before you store it:

use RoundlyConsulting\Addresses\Contracts\CountryResolver;
use RoundlyConsulting\Addresses\DataTransferObjects\AddressData;

$data = AddressData::make(
    city: 'Bratislava',
    street: 'Somewhere 1',
    postalCode: '81101',
    countryIso: 'SK',
);

if (app()->bound(CountryResolver::class)) {
    $point = app(CountryResolver::class)->coordinates($data);   // ?Coordinates
    $point?->latitude;
    $point?->longitude;
}

$customer->addAddress($data);

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.