kusaasira / uganda-geo
Identity-safe Uganda administrative geography for PHP, with district-to-village lookups and optional GIS tooling
Requires
- php: ^8.2
- ext-json: *
Requires (Dev)
- doctrine/orm: ^2.12
- fakerphp/faker: ^1.19
- phpstan/phpstan: ^1.8
- phpunit/phpunit: ^9.5
- symfony/cache: ^5.4
- symfony/yaml: ^5.4
- symplify/easy-coding-standard: ^11.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v2.0.0
- v2.0.0-rc.1
- 1.0.0
- dev-perf/v2.0.1-core-engine-hardening
- dev-docs/v2-stable-package-launch
- dev-next/2.x
- dev-feature/v2-release-notes-curation
- dev-feature/v2-final-main-release-gates
- dev-feature/v2-release-qa-evidence
- dev-feature/v2-parish-ogr-distributions
- dev-feature/v2-final-release-readiness
- dev-feature/v2-explorer-reviewed-geometry-coverage
- dev-feature/v2-deterministic-dataset-build
- dev-feature/v2-location-performance-gates
- dev-feature/v2-geometry-archive-packaging
- dev-feature/v2-release-candidate-automation
- dev-feature/v2-complete-sdk-reference
- dev-feature/v2-consumer-install-matrix
- dev-feature/v2-release-supply-chain-gates
- dev-fix/v2-integrated-lowest-phpstan
- dev-feature/v2-php-ci
- dev-feature/v2-release-artifact-checks
- dev-feature/v2-static-dataset-explorer
- dev-feature/v2-geometry-topology
- dev-feature/v2-hierarchy-navigation
- dev-feature/v2-geojson-distribution
- dev-feature/v2-docs-migration
- dev-feature/v2-oss-governance
- dev-feature/v2-package-metadata
- dev-feature/v2-point-in-polygon
- dev-feature/ugeo-014-canonical-snapshot-diffs
- dev-feature/ugeo-013-canonical-id-crosswalk
- dev-feature/ugeo-018-strict-dataset-errors
- dev-feature/ugeo-016-scoped-ambiguity-safe-search
- dev-feature/ugeo-016-ambiguity-safe-search
- dev-feature/ugeo-011-ubos-2024-reconciliation
- dev-feature/ugeo-027-parish-geometry-identity-matching
- dev-feature/ugeo-027-parish-boundary-reconciliation
- dev-feature/ugeo-012-official-source-freshness
- dev-feature/ugeo-012-ubos-2025-source-review
- dev-feature/ugeo-015-id-keyed-lossless-tree
- dev-feature/ugeo-013-verified-id-crosswalk
- dev-feature/ugeo-014-canonical-snapshot-diff
- dev-feature/ugeo-026-geojson-acquisition
- dev-feature/ugeo-010-canonical-integrity-validation
- dev-feature/ugeo-034-evidence-backed-corrections
- dev-feature/ugeo-009-deterministic-legacy-import
- dev-feature/ugeo-025-spatial-contract
- dev-feature/ugeo-008-canonical-identity-schema
- dev-feature/ugeo-024-public-boundary-endpoints
- dev-feature/ugeo-007-source-inventory
- dev-ft-refactor-namespace
- dev-fix-add-requests-output
This package is auto-updated.
Last update: 2026-11-12 05:32:59 UTC
README
Identity-safe administrative geography for Uganda, built for modern PHP.
Uganda Geo is an open-source, framework-independent PHP library for navigating districts, counties, subcounties, parishes and villages. Version 2.0.0 introduces ID-keyed collections, explicit ambiguity handling, deterministic source validation and separate tools for administrative-data review and geospatial processing.
Data scope: The default PHP API uses a historical bundled administrative snapshot. Its capture date and current completeness have not been independently established. Official statistics from the Uganda Bureau of Statistics (UBOS) are credited as comparison and reconciliation sources, not automatically substituted into the runtime dataset. See Data sources and attribution.
At a glance
| Uganda Geo 2.0 | |
|---|---|
| Package | kusaasira/uganda-geo |
| Language | PHP 8.2+ with JSON extension |
| Dependencies | No mandatory framework or spatial extension |
| API | Typed administrative models and ID-based lookups |
| Coverage | District → county → subcounty → parish → village, as represented in the bundled snapshot |
| Data integrity | Preserves duplicate names by distinct source IDs |
| Integrations | Plain PHP and optional Laravel container use |
| GIS tools | Optional public endpoint acquisition, reviewed polygon matching, topology checks and local GeoJSON/Shapefile/GeoPackage export |
| Versioning | SemVer for code, separately identified source snapshots for data |
| License | MIT for the package code; third-party dataset rights may differ |
Why 2.0?
Administrative place names are not unique identifiers. Two different parishes may share the same name, even within a larger area. A name-keyed collection can hide legitimate records if one name overwrites another.
Version 2 changes that contract:
- Preserves identity: Districts and their descendants are indexed by source IDs, not normalized names.
- Handles ambiguity: Global singular name lookups reject multiple matches. Parent-scoped searches let callers choose the intended locality.
- Navigates ancestry: Find a unit, retrieve its direct children or resolve its complete chain of administrative parents.
- Fails loudly: Invalid or missing packaged data raises an exception rather than pretending the dataset is empty.
- Audits changes: Optional import and reconciliation tools preserve source provenance, detect broken parent relationships and produce reproducible data manifests.
- Keeps GIS optional: No GDAL, Laravel or geospatial extension is required just to use administrative lookups.
Installation
Install the stable 2.x package from Packagist:
composer require "kusaasira/uganda-geo:^2.0"
Requirements: PHP 8.2 or newer, Composer 2 and PHP's JSON extension. Release-specific install availability can be checked on Packagist.
Version 2 is a breaking upgrade from v1. Read the migration guide before upgrading an existing integration.
Quick start
<?php require __DIR__ . '/vendor/autoload.php'; use Uganda\Uganda; $geo = new Uganda(); // Obtain a typed district model. $district = $geo->district('Mukono'); echo $district->id() . ': ' . $district->name() . PHP_EOL; // Look up that exact district by source identity. $exact = $geo->findById('district', $district->id()); // Navigate direct child units. $counties = $geo->childrenOf('county', $district->id()); // A name can match several places. Do not discard candidates. $matches = $geo->searchByName('parish', 'Central'); foreach ($matches as $parish) { echo $parish->id() . ' - ' . $parish->name() . PHP_EOL; }
Or execute the versioned example in a local repository checkout:
composer install php examples/standalone-v2.php
Resolve an ambiguous place safely
<?php use Uganda\Uganda; use Uganda\Exceptions\AmbiguousLocationException; $geo = new Uganda(); try { $parish = $geo->parish('Central'); } catch (AmbiguousLocationException $exception) { // Ask the caller to select the intended parent or a source ID. $candidates = $geo->searchByName('parish', 'Central'); } // Select a real parent ID before a scoped lookup. $district = $geo->district('Mukono'); foreach ($district->counties() as $county) { foreach ($county->subCounties() as $subcounty) { $parishes = $geo->searchByName('parish', 'Central', $subcounty->id()); // Handle every matching parish in this particular subcounty. } }
An ID is meaningful within its administrative level and source snapshot. Numeric package source IDs are not guaranteed to be official UBOS administrative codes. Use a verified crosswalk when matching IDs from external systems.
Navigate parents and children
<?php use Uganda\Uganda; $geo = new Uganda(); $district = $geo->district('Mukono'); $county = reset($district->counties()); if ($county instanceof \Uganda\County) { $subcounties = $geo->childrenOf('subcounty', $county->id()); foreach ($subcounties as $subcounty) { $ancestors = $geo->ancestorsOf('subcounty', $subcounty->id()); echo $subcounty->name() . ' has ' . count($ancestors) . " ancestors\n"; } }
For examples that must work regardless of a particular source name, use examples/standalone-v2.php.
API reference
| Method | Behavior |
|---|---|
districts(), counties(), subCounties(), parishes(), villages() |
Collect each level from the bundled hierarchy |
district($name), county($name), subCounty($name), parish($name), village($name) |
Return a unique named unit or throw |
findById($level, $id) |
Find an exact level-specific integer ID or return null |
searchByName($level, $name, $parentId = null) |
Return every exact normalized-name match, optionally scoped to a parent |
childrenOf($childLevel, $parentId) |
Return direct children of a known parent |
ancestorsOf($level, $id) |
Return ancestors from root to immediate parent |
Supported levels: district, county, subcounty, parish and village. A name is a display property, never a globally unique lookup key.
See the complete v2 API reference for return contracts, errors and more examples.
Laravel integration
The production library has no Illuminate dependency and does not register a service provider. Use it directly through Composer autoloading:
use Uganda\Uganda; $geo = app(Uganda::class); $districts = $geo->districts();
Laravel container integration is covered by independent consumer smoke tests. No service-provider configuration or auto-discovery is required.
Data sources and attribution
UBOS is the official publisher of the 2024 census and statistical references used to evaluate administrative-geography currency. We acknowledge and credit the Uganda Bureau of Statistics for those publications.
| Source | Role | What it establishes |
|---|---|---|
| Uganda passport portal | Reported original source of the legacy bundled package data | Historical package locality rows; capture date not verified |
| UBOS NPHC 2024 reports | Official census geography and statistical reference | 2024 census classifications and dated published counts |
| UBOS 2024 Statistical Abstract | Official published administrative statistics | Its own reference-date and classification context |
| UBOS 2025 Statistical Abstract | Updated official reference publication | Newer reported indicators, subject to each indicator's reference period |
| Public ArcGIS parish feature layer | Candidate optional polygon source | Public GIS service; UBOS ownership and redistribution permission not established |
The NPHC 2024 reports identify 135 districts and 11 cities, 312 counties, 2,191 subcounty/division/town-council units and 10,717 parishes/wards for the census reference. These are official census figures, not counts certified for the package's historical JSON snapshot and not automatically equivalent to current legal administrative units.
We credit UBOS for UBOS-authored publications without misattributing the passport-derived legacy dataset or unrelated third-party ArcGIS polygons. See source inventory, official-source assessment and public GIS endpoints.
Optional geospatial tooling
The repository includes tooling to inspect and acquire public polygon endpoints, reconcile parish identities against a canonical snapshot, validate geometry and export reviewed data to GIS formats.
The PHP runtime does not ship a verified national parish boundary archive. GIS tooling requires separately acquired source data and, for format conversion, GDAL. Example operator commands:
# Create a local output parent before downloading source files. mkdir -p build # Inspect the catalogued public feature service. php tools/geo/inspect-arcgis.php arcgis-parishes-2024 # Download a provenance-aware copy to a NEW local directory. php tools/geo/download-arcgis.php arcgis-parishes-2024 ./build/arcgis-2024 # After human-reviewed identity matching, export verified GeoJSON to a NEW directory. php tools/geo/export-formats.php reviewed-parishes.geojson ./build/parish-formats
The generated local formats include GeoJSON, GeoPackage and an ESRI Shapefile set with .shp, .shx, .dbf, .prj and .cpg.
Publication distinction: Public access is enough to discover and ingest an endpoint under applicable access terms. It does not by itself grant redistribution rights. Local GIS conversion and sample topology tests do not prove nationwide completeness. Unverified third-party geometry files are not attached to the v2.0.0 source release.
Read public endpoint guidance, coverage audit and geometry archive policy.
Development and verification
composer install
composer test
composer cs-test
./vendor/bin/phpstan analyse src --level 9
php examples/standalone-v2.php
CI covers PHP 8.2, 8.3, 8.4 and 8.5, the lowest-supported dependency set, standalone/Laravel consumers, data validation and optional GIS workflows. Test fixtures prove code behavior, not external administrative currentness or source publication rights.
Security reporting: SECURITY.md. Contributions and data corrections: CONTRIBUTING.md.
Versioning, releases and migration
- v2.0.0 release: stable major release with public API breaking changes.
- CHANGELOG.md: historical release notes and versioned changes.
- Migration guide: required v1-to-v2 upgrade steps.
- Source attribution and licenses: provenance and redistribution boundaries.
Package versions describe the software release. Administrative datasets require their own reference dates, source identities and checksums. A newer Composer tag does not mean every included geographic name is current.
Credits and license
Created and maintained by Joshua Kusaasira. Thanks to all contributors.
Administrative statistical references are credited to the Uganda Bureau of Statistics (UBOS). The historical packaged locality dataset was originally attributed to Uganda's passport portal. Third-party geometry sources retain their own rights and attribution requirements.
The package source code is released under the MIT License. This license does not automatically cover externally sourced administrative publications or GIS feature datasets.