PHPackages                             azaharizaman/nexus-geo - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. azaharizaman/nexus-geo

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

azaharizaman/nexus-geo
======================

Framework-agnostic geographic and location services for the Nexus ERP system with cost-optimized geocoding and geospatial calculations

v0.1.0-alpha1(2mo ago)023MITPHP ^8.3

Since May 5Compare

[ Source](https://github.com/azaharizaman/nexus-geo)[ Packagist](https://packagist.org/packages/azaharizaman/nexus-geo)[ RSS](/packages/azaharizaman-nexus-geo/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (4)Versions (2)Used By (3)

Nexus\\Geo
==========

[](#nexusgeo)

Framework-agnostic geographic and location services package for the Nexus ERP system.

Overview
--------

[](#overview)

`Nexus\Geo` provides comprehensive geospatial capabilities including:

- **Geocoding**: Address-to-coordinates conversion with provider abstraction
- **Reverse Geocoding**: Coordinates-to-address lookup
- **Distance Calculations**: Haversine formula-based distance computations
- **Geofencing**: Territory boundary validation
- **Polygon Simplification**: Douglas-Peucker algorithm for optimizing storage
- **Cost Optimization**: 90-day caching with &gt;80% hit rate target
- **Multi-Provider Support**: Google Maps (primary) + OpenStreetMap Nominatim (fallback)

Features
--------

[](#features)

### Cost-Optimized Geocoding

[](#cost-optimized-geocoding)

- **Aggressive Caching**: 90-day TTL with SHA-256 address hashing
- **Provider Chain**: Google Maps for real-time, Nominatim for batch/fallback
- **Metrics Tracking**: Cache hit rate monitoring (target: &gt;80%)
- **Cost Alerting**: Integration with `Nexus\Notifier` for budget thresholds
- **Smart Fallback**: Automatic provider switching on circuit breaker activation

### Geospatial Calculations

[](#geospatial-calculations)

- **Distance Calculator**: Uses `league/geotools` Haversine formula
- **Bearing Calculations**: Get direction between two points
- **Destination Points**: Calculate point at distance/bearing from origin
- **Radius Checks**: Fast proximity queries

### Territory Management

[](#territory-management)

- **Polygon Storage**: JSONB format with max 100 vertices
- **Auto-Simplification**: Douglas-Peucker algorithm when exceeding limits
- **Accuracy Tracking**: Loss percentage calculation
- **Geofence Checks**: Point-in-polygon validation

Installation
------------

[](#installation)

```
composer require azaharizaman/nexus-geo:"*@dev"
```

Dependencies
------------

[](#dependencies)

### Required Packages

[](#required-packages)

- `geocoder-php/geocoder`: ^4.0 - Multi-provider geocoding abstraction
- `league/geotools`: ^2.0 - Geospatial math library
- `azaharizaman/nexus-party`: \*@dev - For `PostalAddress` integration
- `azaharizaman/nexus-connector`: \*@dev - For resilient external API calls
- `psr/log`: ^3.0 - Logging interface

### External Services (Optional)

[](#external-services-optional)

- **Google Maps Geocoding API**: Primary geocoding provider ($5/1000 requests)
- **OpenStreetMap Nominatim**: Free fallback provider
- **Google Maps Distance Matrix API**: Real-world routing (via `Nexus\Routing`)

Architecture
------------

[](#architecture)

This package follows the **Nexus Architecture Principle**: "Logic in Packages, Implementation in Applications."

### Package Layer (Pure PHP)

[](#package-layer-pure-php)

- **Framework-agnostic**: No Laravel dependencies
- **Business Logic**: All geospatial calculations and geocoding logic
- **Interfaces**: Defines contracts for persistence and external services
- **Value Objects**: Immutable domain objects (Coordinates, Distance, etc.)
- **Services**: GeoManager, RegionManager, GeoCache for orchestration

### Application Layer (Laravel/Atomy)

[](#application-layer-laravelatomy)

- **Provider Adapters**: GoogleMapsGeocoder, NominatimGeocoder
- **Repository Implementations**: DbGeoRepository with Eloquent
- **Calculators**: LeagueGeotoolsCalculator implementation
- **Database Migrations**: geo\_cache, geo\_metrics, regions tables
- **Service Provider**: IoC container bindings
- **API Controllers**: RESTful endpoints for geo operations

Usage Examples
--------------

[](#usage-examples)

### 1. Geocode an Address

[](#1-geocode-an-address)

```
use Nexus\Geo\Services\GeoManager;
use Nexus\Party\ValueObjects\PostalAddress;

$geoManager = app(GeoManager::class);

$address = new PostalAddress(
    streetLine1: 'Jalan Song',
    city: 'Kuching',
    postalCode: '93350',
    country: 'MYS',
    state: 'Sarawak'
);

$result = $geoManager->geocode($address);

if ($result) {
    echo "Latitude: {$result->getCoordinates()->latitude}\n";
    echo "Longitude: {$result->getCoordinates()->longitude}\n";
    echo "Confidence: {$result->getConfidenceScore()}%\n";
    echo "Provider: {$result->getProviderName()}\n";
}
```

### 2. Calculate Distance Between Two Points

[](#2-calculate-distance-between-two-points)

```
use Nexus\Geo\ValueObjects\Coordinates;
use Nexus\Geo\ValueObjects\DistanceUnit;

$calculator = app(DistanceCalculatorInterface::class);

$origin = new Coordinates(1.5535, 110.3593); // Kuching
$destination = new Coordinates(4.8921, 114.9421); // Miri

$distance = $calculator->calculateDistance($origin, $destination, DistanceUnit::KILOMETERS);

echo "Distance: {$distance->getValue()} km\n";
```

### 3. Check if Point is Within Service Territory

[](#3-check-if-point-is-within-service-territory)

```
use Nexus\Geo\Services\RegionManager;

$regionManager = app(RegionManager::class);

$customerLocation = new Coordinates(1.5535, 110.3593);

if ($regionManager->isPointInRegion($customerLocation, 'kuching-service-area')) {
    echo "Customer is within service area\n";
} else {
    echo "Customer is outside service area\n";
}
```

### 4. Monitor Geocoding Costs

[](#4-monitor-geocoding-costs)

```
use Nexus\Geo\Services\GeoManager;

$geoManager = app(GeoManager::class);
$metrics = $geoManager->getMetrics();

echo "Cache Hit Rate: {$metrics->getHitRatePercentage()}%\n";
echo "Google API Calls: {$metrics->getGoogleCallCount()}\n";
echo "Nominatim Calls: {$metrics->getNominatimCallCount()}\n";
echo "Estimated Daily Cost: \${$metrics->getEstimatedDailyCost()}\n";

// Check if alert threshold breached
if ($metrics->getHitRatePercentage() < 80) {
    // Alert sent automatically via Nexus\Notifier
    echo "WARNING: Cache hit rate below target!\n";
}
```

### 5. Simplify Complex Polygon

[](#5-simplify-complex-polygon)

```
use Nexus\Geo\Services\RegionManager;

$regionManager = app(RegionManager::class);

$complexPolygon = [
    // 250 vertices from GeoJSON import
];

$simplificationResult = $regionManager->validatePolygonComplexity($complexPolygon);

echo "Original Vertices: {$simplificationResult->getOriginalVertexCount()}\n";
echo "Simplified Vertices: {$simplificationResult->getSimplifiedVertexCount()}\n";
echo "Accuracy Loss: {$simplificationResult->getAccuracyLossPercentage()}%\n";

// Auto-simplify if needed
if ($simplificationResult->getOriginalVertexCount() > 100) {
    $region->setBoundary($simplificationResult->getSimplifiedBoundary());
}
```

Cost Optimization Strategies
----------------------------

[](#cost-optimization-strategies)

### 1. Aggressive Caching

[](#1-aggressive-caching)

- **90-Day TTL**: Addresses rarely change, long cache duration reduces API calls
- **SHA-256 Hashing**: Prevents duplicates from formatting variations
- **Deduplication**: Multiple users entering same address hits cache

### 2. Provider Failover

[](#2-provider-failover)

- **Google Maps**: High accuracy, paid service ($5/1000 requests)
- **Nominatim**: Lower accuracy, free service
- **Smart Routing**: Real-time → Google, Batch jobs → Nominatim

### 3. Batch Processing

[](#3-batch-processing)

- Import historical addresses during off-peak hours using free provider
- Pre-geocode known locations (offices, warehouses, frequent customers)
- Queue non-urgent geocoding for async processing

### 4. Monitoring &amp; Alerting

[](#4-monitoring--alerting)

- **Target**: &gt;80% cache hit rate
- **Alerts**: Sent via `Nexus\Notifier` when:
    - Hit rate drops below 80%
    - Daily cost exceeds budget threshold
    - Provider experiencing high error rate

Polygon Simplification
----------------------

[](#polygon-simplification)

### Douglas-Peucker Algorithm

[](#douglas-peucker-algorithm)

The package uses the Douglas-Peucker algorithm to reduce polygon complexity while preserving shape:

```
use Nexus\Geo\Contracts\PolygonSimplifierInterface;

$simplifier = app(PolygonSimplifierInterface::class);

$vertices = [ /* 250 coordinate pairs */ ];
$tolerance = 0.0001; // ~11 meters

$simplified = $simplifier->simplify($vertices, $tolerance);
```

### Recommended Tolerances

[](#recommended-tolerances)

Use CaseToleranceAccuracyTypical ReductionCity boundaries0.001~111m60-70%Service territories0.0001~11m40-50%Precise geofencing0.00001~1.1m20-30%### Storage Limits

[](#storage-limits)

- **Max Vertices**: 100 per polygon (enforced)
- **Auto-Simplification**: Triggered when import exceeds limit
- **Visual Diff**: Admin UI shows accuracy loss overlay

Cache Metrics Interpretation
----------------------------

[](#cache-metrics-interpretation)

### Hit Rate Analysis

[](#hit-rate-analysis)

Hit RateStatusAction Required&gt;90%ExcellentMonitor costs, increase cache TTL if stable80-90%GoodTarget range, no action70-80%WarningReview address quality, check for retry loops&lt;70%CriticalInvestigate cache failures, verify cache is enabled### Cost Projections

[](#cost-projections)

```
// Example: Calculate monthly cost
$metrics = $geoManager->getMetrics();
$dailyCost = $metrics->getEstimatedDailyCost();
$monthlyCost = $dailyCost * 30;

if ($monthlyCost > $budgetLimit) {
    // Increase cache TTL or switch to Nominatim for batch jobs
}
```

Provider Failover Behavior
--------------------------

[](#provider-failover-behavior)

### Circuit Breaker Integration

[](#circuit-breaker-integration)

The package integrates with `Nexus\Connector` for resilient external API calls:

1. **Google Maps Primary**: Attempts geocoding via Google Maps API
2. **Circuit Breaker**: Monitors failure rate (5 failures in 60 seconds)
3. **Fallback Trigger**: If circuit opens, switches to Nominatim
4. **Recovery**: Circuit half-open after 30 seconds, full recovery after 2 successful calls

### Configuration

[](#configuration)

```
// config/geo.php
return [
    'providers' => [
        [
            'name' => 'google',
            'priority' => 1,
            'for' => 'realtime', // Use for real-time geocoding
        ],
        [
            'name' => 'nominatim',
            'priority' => 2,
            'for' => 'batch', // Use for batch processing
        ],
    ],
    'cache_hit_threshold' => 80, // Alert if below 80%
    'daily_budget_limit' => 100.00, // USD
];
```

Integration with Nexus\\Party
-----------------------------

[](#integration-with-nexusparty)

### PostalAddress Coordinates

[](#postaladdress-coordinates)

The package extends `Nexus\Party\ValueObjects\PostalAddress` to support optional geocoding:

```
use Nexus\Party\ValueObjects\PostalAddress;
use Nexus\Geo\ValueObjects\Coordinates;

// Create address without coordinates
$address = new PostalAddress(/* ... */);

// Geocode and attach coordinates
$result = $geoManager->geocode($address);
$addressWithCoords = $address->withCoordinates($result->getCoordinates());

// Check if needs geocoding
if ($address->needsGeocoding()) {
    // Queue geocoding job
}
```

Migration from Google-Only to Hybrid Setup
------------------------------------------

[](#migration-from-google-only-to-hybrid-setup)

### Step 1: Enable Nominatim Fallback

[](#step-1-enable-nominatim-fallback)

```
// config/geo.php
'providers' => [
    ['name' => 'google', 'priority' => 1, 'for' => 'realtime'],
    ['name' => 'nominatim', 'priority' => 2, 'for' => 'batch'], // Add this
],
```

### Step 2: Batch Re-Geocode with Nominatim

[](#step-2-batch-re-geocode-with-nominatim)

```
php artisan geo:batch-geocode --provider=nominatim --limit=1000
```

### Step 3: Monitor Cost Reduction

[](#step-3-monitor-cost-reduction)

```
php artisan geo:metrics --period=30days
```

Testing
-------

[](#testing)

```
# Run package tests (framework-agnostic)
cd packages/Geo
composer test

# Run Atomy integration tests
cd apps/Atomy
php artisan test --filter=Geo
```

Performance Benchmarks
----------------------

[](#performance-benchmarks)

OperationTargetTypicalCache lookup&lt;5ms2-3msGeocoding (cache hit)&lt;10ms5-8msGeocoding (Google API)&lt;500ms200-400msGeocoding (Nominatim)&lt;1000ms600-900msDistance calculation&lt;5ms1-2msPolygon simplification (100 vertices)&lt;20ms10-15msGeofence check&lt;10ms3-5msDocumentation
-------------

[](#documentation)

Comprehensive documentation is available in the `docs/` directory:

### Getting Started

[](#getting-started)

- **[Getting Started Guide](docs/getting-started.md)** - Prerequisites, installation, core concepts, and your first integration
- **[Quick Start](docs/getting-started.md#your-first-integration)** - Complete working example

### API Reference

[](#api-reference)

- **[API Reference](docs/api-reference.md)** - Complete interface and method documentation
    - All 7 interfaces (GeoRepositoryInterface, GeocoderInterface, GeofenceInterface, etc.)
    - All 6 services (GeocodingManager, DistanceCalculator, BearingCalculator, etc.)
    - All 8 value objects (Coordinates, Distance, BearingResult, Polygon, etc.)
    - All 5 exceptions with named constructors

### Integration Guides

[](#integration-guides)

- **[Integration Guide](docs/integration-guide.md)** - Framework-specific implementation examples
    - Laravel integration (complete with migrations, repositories, service providers)
    - Symfony integration (Doctrine entities, services.yaml configuration)
    - Common patterns (batch geocoding, delivery zones, nearest warehouse)

### Code Examples

[](#code-examples)

- **[Basic Usage](docs/examples/basic-usage.php)** - Essential operations
    - Geocoding and reverse geocoding
    - Distance calculations
    - Geofencing (point-in-polygon)
    - Complete delivery fee workflow
- **[Advanced Usage](docs/examples/advanced-usage.php)** - Complex scenarios
    - Batch geocoding with rate limiting
    - Polygon simplification
    - Bearing and compass direction
    - Travel time estimation
    - Multi-warehouse routing
    - Dynamic geofence validation

### Implementation Details

[](#implementation-details)

- **[Implementation Summary](IMPLEMENTATION_SUMMARY.md)** - Project metrics and progress tracking
- **[Requirements](REQUIREMENTS.md)** - 35 tracked requirements across 9 categories
- **[Test Suite Summary](TEST_SUITE_SUMMARY.md)** - Test coverage and strategy (target: 95%)
- **[Valuation Matrix](VALUATION_MATRIX.md)** - Package financial analysis ($46,848 value, 681% ROI)

### Quick Links

[](#quick-links)

What You NeedWhere to LookFirst-time setup[Getting Started Guide](docs/getting-started.md)Method signatures[API Reference](docs/api-reference.md)Laravel example[Integration Guide - Laravel](docs/integration-guide.md#laravel-integration)Symfony example[Integration Guide - Symfony](docs/integration-guide.md#symfony-integration)Working code[Basic Usage Examples](docs/examples/basic-usage.php)Complex patterns[Advanced Usage Examples](docs/examples/advanced-usage.php)License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

Contributing
------------

[](#contributing)

Follow Nexus architecture principles:

1. Keep the package framework-agnostic
2. Define all dependencies via interfaces
3. Use immutable Value Objects for domain concepts
4. Place all business logic in services
5. No database access or migrations in this package

Support
-------

[](#support)

For issues, questions, or contributions, please refer to the main Nexus monorepo documentation.

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance84

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

81d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/117408?v=4)[Azahari Zaman](/maintainers/azaharizaman)[@azaharizaman](https://github.com/azaharizaman)

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/azaharizaman-nexus-geo/health.svg)

```
[![Health](https://phpackages.com/badges/azaharizaman-nexus-geo/health.svg)](https://phpackages.com/packages/azaharizaman-nexus-geo)
```

###  Alternatives

[symfony/lock

Creates and manages locks, a mechanism to provide exclusive access to a shared resource

515139.2M711](/packages/symfony-lock)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k38.9k](/packages/matomo-matomo)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

564576.7k54](/packages/ecotone-ecotone)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

751291.4k46](/packages/civicrm-civicrm-core)[illuminate/broadcasting

The Illuminate Broadcasting package.

7127.2M221](/packages/illuminate-broadcasting)[logiscape/mcp-sdk-php

Model Context Protocol SDK for PHP

367116.8k12](/packages/logiscape-mcp-sdk-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
