PHPackages                             mgamadeus/ddd-common-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. mgamadeus/ddd-common-geo

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

mgamadeus/ddd-common-geo
========================

Addresses, geocoding, GeoRegions, GeoTypes for mgamadeus/ddd

1.0.11(1mo ago)0131↓25%MITPHP

Since Apr 14Pushed 1mo agoCompare

[ Source](https://github.com/mgamadeus/ddd-geo)[ Packagist](https://packagist.org/packages/mgamadeus/ddd-common-geo)[ RSS](/packages/mgamadeus-ddd-common-geo/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (2)Versions (13)Used By (0)

mgamadeus/ddd-common-geo
========================

[](#mgamadeusddd-common-geo)

Addresses, geocoding, reverse geocoding, GeoRegion hierarchy, and Google Places integration for the [mgamadeus/ddd](https://github.com/mgamadeus/ddd) framework.

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

[](#installation)

```
composer require mgamadeus/ddd-common-geo
```

This pulls in [ddd-common-political](https://github.com/mgamadeus/ddd-political) automatically.

What It Does
------------

[](#what-it-does)

Full geocoding and address management layer built on DDD patterns:

- **PostalAddress** -- comprehensive address ValueObject with structured fields, geocoding via Argus, precision tracking, and fallback chains for ambiguous Google responses
- **GeoRegion** -- hierarchical administrative regions replacing rigid City/State/County, with self-referencing parent chain, translatable names, and N:N GeoType relationships
- **GeoType** -- Google Maps address component types (40+ types: LOCALITY, ADMINISTRATIVE\_AREA\_LEVEL\_1, etc.) stored UPPERCASE
- **GeoRegionType** -- junction entity linking GeoRegion to GeoType (a region can have multiple types)
- **GeocodableGeoPoint** -- extends DDD Core's GeoPoint with reverse geocoding (coordinates to PostalAddress via Argus)
- **GeoGooglePlace** -- Google Place with placeId and geocoded address
- **AddressComponent** -- raw geocoding response components

GeoRegion Hierarchy
-------------------

[](#georegion-hierarchy)

The core design pattern -- a self-referencing tree replacing rigid models:

```
Country (via countryId FK)
  +-- admin_area_level_1 (State/Province)
      +-- admin_area_level_2 (County/District)
          +-- admin_area_level_3 (Municipality)
              +-- locality (City/Town)
                  +-- sublocality_level_1 (Borough)
                      +-- sublocality_level_2 (Neighborhood)

```

Each GeoRegion has a `parentGeoRegionId`, translatable `name`, `placeId` (Google), `slug` (derived from hierarchy), and N:N types via GeoRegionType junction.

Services
--------

[](#services)

ServicePurpose**PostalAddressService**Address creation factory, forward geocoding (by string, Place ID, multi-result), geocode anti-spam tracking (Redis), country/locality resolution**GeoPointsService**Reverse geocoding: coordinates or GeoPoint to PostalAddress**GeoRegionsService**Hierarchy-aware find-or-create, type assignment, localized name updates, slug generation**GeoTypesService**Import 40+ types from constants, find-or-create by name (normalizes to UPPERCASE)**GoogleGeoService**Google Geocoding API wrapper (batch layer)**GooglePlacesService**Google Places API wrapper (batch layer)### Quick Usage

[](#quick-usage)

```
// Forward geocoding
$postalAddressService = PostalAddressService::instance();
$address = $postalAddressService->geocodeAddressByAddressString('42 Main St, New York, NY 10001');
echo $address->formattedAddress;
echo $address->geoPoint->lat . ', ' . $address->geoPoint->lng;
echo $address->precision;  // ROOFTOP

// Reverse geocoding
$geoPointsService = GeoPointsService::instance();
$address = $geoPointsService->reverseGeocodeCoordinates(40.7128, -74.0060, 'en');

// GeoRegion lookup
$geoRegionsService = GeoRegions::getService();
$region = $geoRegionsService->findByPlaceId('ChIJCSF8lBZEwokRhngABHRcdoJ');
$state = $region->findAncestorByType(GeoType::TYPE_ADMINISTRATIVE_AREA_LEVEL_1);

// Address creation
$address = $postalAddressService->createAddress(
    street: 'Main St', streetNo: '42', postalCode: '10001',
    localityName: 'New York', countryShortCode: 'US', geocode: true
);
```

Argus Integration (Geocoding API)
---------------------------------

[](#argus-integration-geocoding-api)

Argus RepoEndpointCache TTL`ArgusPostalAddress``POST:/common/geodata/geocodeAddress`1 month`ArgusGeocodableGeoPoint``POST:/common/geodata/reverseGeocodePoint`12 hours`ArgusGeoGooglePlaceById``POST:/rc-locations/geocode_by_placeid`1 month`ArgusGeoRegion``POST:/common/geodata/geocodeGeoRegion`1 monthAll require `ARGUS_API_ENDPOINT` to be configured.

Setup
-----

[](#setup)

### Service Registration

[](#service-registration)

The module auto-registers via `DDDModule` when installed as a Composer package. If manual registration is needed, add to `services.yaml`:

```
DDD\Domain\Common\Services\GeoEntities\:
    resource: '%kernel.project_dir%/vendor/mgamadeus/ddd-common-geo/src/Domain/Common/Services/GeoEntities/*'
    public: true

DDD\Domain\Batch\Services\Geo\:
    resource: '%kernel.project_dir%/vendor/mgamadeus/ddd-common-geo/src/Domain/Batch/Services/Geo/*'
    public: true
```

### Batch Controller (Geocoding Endpoints)

[](#batch-controller-geocoding-endpoints)

Import in `routes.yaml`:

```
batch_geocoding:
    resource: '%kernel.project_dir%/vendor/mgamadeus/ddd-common-geo/src/Presentation/Api/Batch/Common'
    type: annotation
    prefix: '/api/batch'
```

### Security

[](#security)

Batch endpoints require `ROLE_SUPER_ADMIN`:

```
# security.yaml
security:
    access_control:
        - { path: ^/api/batch, roles: ROLE_SUPER_ADMIN }
```

### Environment Variables

[](#environment-variables)

```
ARGUS_API_ENDPOINT=https://...              # Argus API base URL (required)
CLI_DEFAULT_ACCOUNT_ID_FOR_CLI_OPERATIONS=1 # Account with SUPER_ADMIN for Argus auth
GOOGLE_GEOCODING_API_KEY=...                # Google API key (for batch services)
```

Batch Endpoints
---------------

[](#batch-endpoints)

`BatchGeocodingController` at `/api/batch/common/geodata/`:

MethodPathInputPurposePOST`/geocodeAddress``address`, `country?`, `language?`Forward geocode address stringPOST`/reverseGeocode``lat`, `lng`, `language?`Reverse geocode coordinatesPOST`/reverseGeocodePoint``latlng` (comma-sep)Reverse geocode (v4beta)POST`/geocodeGeoRegion``name`, `language?`, `country?`, `lat?`, `lng?`Geocode any hierarchy levelPOST`/geocodeCity``name?`, `lat?`, `lng?`, `language`Forward/reverse geocode cityPOST`/geocodeState``name`, `language?`, `country?`Forward geocode stateKey Design Patterns
-------------------

[](#key-design-patterns)

**Hierarchical self-referencing** -- GeoRegion with `parentGeoRegionId` replaces rigid models. Walk the hierarchy with `findAncestorByType()`.

**N:N type system** -- GeoRegionType junction allows a region to have multiple Google component types simultaneously.

**Argus-backed geocoding** -- External API calls cached in memory + DB via Argus repos, abstracted from business logic.

**Settlement fallback chains** -- PostalAddress uses deterministic chains to extract city from ambiguous responses:

```
locality -> postal_town -> admin_area_level_3 -> sublocality_level_1 -> admin_area_level_2

```

**Geocode tracking** -- Redis-based attempt tracking prevents spam (max 5 attempts/60s before cache bypass).

**Precision tracking** -- PostalAddress records geocoding accuracy (ROOFTOP, RANGE\_INTERPOLATED, GEOMETRIC\_CENTER, APPROXIMATE, NOT\_FOUND).

**Political entity resolution** -- PostalAddressService resolves countries via CountriesService and localities via LocalitiesService from ddd-common-political.

GeoPoint vs GeocodableGeoPoint
------------------------------

[](#geopoint-vs-geocodablegeopoint)

DDD Core provides `GeoPoint` -- lightweight lat/lng with Haversine distance and Doctrine spatial mapping. No external dependencies.

This module adds `GeocodableGeoPoint extends GeoPoint` with:

- `reverseGeocodedAddress` (PostalAddress) via Argus reverse geocoding
- `reverseGeocode(?string $languageCode)` trigger
- `#[LazyLoadRepo(LazyLoadRepo::ARGUS, ArgusGeocodableGeoPoint::class)]`

Use `GeoPoint` when you only need coordinates. Use `GeocodableGeoPoint` when you need reverse geocoding.

Overriding Entities
-------------------

[](#overriding-entities)

```
namespace App\Domain\Common\Entities\Addresses;

use DDD\Domain\Common\Entities\Addresses\PostalAddress as BasePostalAddress;

class PostalAddress extends BasePostalAddress
{
    public ?string $apartment = null;
    // Project-specific extensions
}
```

The framework resolves app overrides automatically via `DDDService::getContainerServiceClassNameForClass()`.

Conventions
-----------

[](#conventions)

All [mgamadeus/ddd conventions](https://github.com/mgamadeus/ddd) apply. Module-specific rules:

- GeoType names are UPPERCASE -- use `GeoType::normalizeFromGoogle()` for conversion
- PostalAddress is a ValueObject (not Entity) -- embedded in other entities, not persisted standalone
- GeoRegion slugs are auto-derived from hierarchy -- never set manually
- Always use `GeoRegionsService::findOrCreateGeoRegionAndUpdateLocalizedName()` for region creation
- GeoRegion is `#[NoRecursiveUpdate]` -- updating a parent region does not cascade to children
- Use `PostalAddressService` for forward geocoding, `GeoPointsService` for reverse geocoding

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

Every ~0 days

Total

12

Last Release

52d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2896811?v=4)[mgamadeus](/maintainers/mgamadeus)[@mgamadeus](https://github.com/mgamadeus)

---

Top Contributors

[![mgamadeus](https://avatars.githubusercontent.com/u/2896811?v=4)](https://github.com/mgamadeus "mgamadeus (12 commits)")

### Embed Badge

![Health badge](/badges/mgamadeus-ddd-common-geo/health.svg)

```
[![Health](https://phpackages.com/badges/mgamadeus-ddd-common-geo/health.svg)](https://phpackages.com/packages/mgamadeus-ddd-common-geo)
```

PHPackages © 2026

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