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

Distance & matrix

distance() walks the pipeline for a DistanceProvider — Google’s Routes API, out of the box — and returns a Distance, or null when no provider can resolve the query (an unreachable or refusing provider is skipped, and DistanceResolutionFailed says why):

use RoundlyConsulting\Geolocation\DataTransferObjects\Coordinates;
use RoundlyConsulting\Geolocation\DataTransferObjects\DistanceQuery;
use RoundlyConsulting\Geolocation\Enum\DistanceType;
use RoundlyConsulting\Geolocation\Facades\Geolocation;

$distance = Geolocation::distance(
    DistanceQuery::between(
        from: new Coordinates(48.1482, 17.1067),
        to:   new Coordinates(49.2000, 16.6068),
        type: DistanceType::Driving,
    ),
);

$distance?->humanReadableDistance; // "133 km"
$distance?->distanceInMeters;      // 133000
$distance?->durationInSeconds;     // 5400
// Skip the query object — distanceBetween() builds it for you (driving by default)
$distance = Geolocation::distanceBetween(
    new Coordinates(48.1482, 17.1067),
    new Coordinates(49.2000, 16.6068),
    DistanceType::Walking,
);

The Distance object

PropertyTypeContents
humanReadableDistancestringProvider-formatted distance, e.g. “133 km”.
distanceInMetersintDistance in metres.
humanReadableDurationstringProvider-formatted travel time.
durationInSecondsintTravel time in seconds.
typeDistanceTypeWalking or Driving.

Travel mode from user input

DistanceType’s validationRule() makes the travel mode safe to accept from a form:

$data = $request->validate([
    'mode' => ['required', DistanceType::validationRule()],   // 'in:Walking,Driving'
]);

$distance = Geolocation::distance(DistanceQuery::between(
    from: new Coordinates(48.1482, 17.1067),
    to: new Coordinates(48.1486, 17.1077),
    type: DistanceType::from($data['mode']),
));

$distance?->humanReadableDuration; // e.g. "6 mins"

Distance matrix

Resolve a grid of distances between several origins and destinations in one call, through the Routes API’s computeRouteMatrix. A leg without a route degrades to null, and so does every cell of a request Google can’t serve (unreachable or refused):

use RoundlyConsulting\Geolocation\DataTransferObjects\Coordinates;
use RoundlyConsulting\Geolocation\Enum\DistanceType;

$matrix = Geolocation::distanceMatrix(
    origins: [new Coordinates(48.14, 17.10)],
    destinations: [new Coordinates(49.20, 16.60), new Coordinates(50.07, 14.43)],
    type: DistanceType::Driving,   // optional — Driving is the default
);

$matrix->get(0, 1)?->distanceInMeters;   // origin 0 → destination 1, null when that leg is unavailable
$matrix->origins;                        // list<Coordinates>
$matrix->rows;                           // array<int, array<int, Distance|null>>

The matrix comes from the bundled Google provider. A grid over the Routes API’s cap of 625 elements (origins × destinations) is split into requests that fit and merged back in order; a request that fails leaves only its own cells null. If Google isn’t in the (scoped) pipeline, or every request fails, you get an empty grid where every get() returns null. Matrices are not cached and dispatch no events.

For a straight-line distance without any API call, use Coordinates::distanceTo().

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.