PHPackages                             maxiewright/laravel-tt-addresses - 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. maxiewright/laravel-tt-addresses

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

maxiewright/laravel-tt-addresses
================================

Trinidad and Tobago address management for Laravel applications - divisions, cities, and address formatting

v0.3.0(1mo ago)2116↓50%MITPHPPHP ^8.4CI passing

Since Dec 17Pushed 1mo agoCompare

[ Source](https://github.com/maxiewright/laravel-tt-addresses)[ Packagist](https://packagist.org/packages/maxiewright/laravel-tt-addresses)[ Docs](https://github.com/maxiewright/laravel-tt-addresses)[ GitHub Sponsors](https://github.com/MaxieWright)[ RSS](/packages/maxiewright-laravel-tt-addresses/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (26)Versions (20)Used By (0)

Laravel Trinidad &amp; Tobago Addresses
=======================================

[](#laravel-trinidad--tobago-addresses)

[![Latest Version on Packagist](https://camo.githubusercontent.com/1988d4bbcbc594ae36e4501012c2443aac06d850058acbbbf9ef99ee88596d6f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d617869657772696768742f6c61726176656c2d74742d6164647265737365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/maxiewright/laravel-tt-addresses)[![GitHub Tests Action Status](https://camo.githubusercontent.com/1597839eca2a1c1389e9d7a186c83d9e7247d7596b70bd9ce6bb6525a1a5b5e8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d617869657772696768742f6c61726176656c2d74742d6164647265737365732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/maxiewright/laravel-tt-addresses/actions?query=workflow%3Arun-tests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/7af5dadd1188a9e0c8fa6602f148ba7bab702aea97e18ffab7d856320ad8821c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d617869657772696768742f6c61726176656c2d74742d6164647265737365732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/maxiewright/laravel-tt-addresses)

A Laravel package providing Trinidad and Tobago administrative divisions and cities/towns/villages for address management. Includes all 15 administrative divisions and 500+ communities.

Features
--------

[](#features)

- 🏛️ **15 Administrative Divisions** - All Regional Corporations, Boroughs, City Corporations, and Tobago
- 🏘️ **500+ Cities/Towns/Villages** - Comprehensive coverage of Trinidad and Tobago communities
- 🔗 **Eloquent Relationships** - Ready-to-use models with proper relationships
- 📍 **Geolocation Support** - Latitude and longitude for cities with distance calculations
- 🎨 **Filament Support** - Enums implement `HasLabel` for seamless Filament integration
- ⚙️ **Configurable** - Customise table names to avoid conflicts
- 🧪 **Tested** - Full test coverage with Pest

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 10.x, 11.x, or 12.x

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

[](#installation)

Install the package via Composer:

```
composer require maxiewright/laravel-tt-addresses
```

### Quick Install (Recommended)

[](#quick-install-recommended)

Run the install command which will guide you through the setup:

```
php artisan tt-addresses:install
```

This will:

1. Publish the configuration file
2. Publish the migrations
3. Optionally run the migrations

### Manual Installation

[](#manual-installation)

If you prefer to install manually:

```
# Publish the config file
php artisan vendor:publish --tag="laravel-tt-addresses-config"

# Publish the migrations
php artisan vendor:publish --tag="laravel-tt-addresses-migrations"

# Run migrations
php artisan migrate
```

### Seed the Data

[](#seed-the-data)

After running migrations, seed the divisions and cities:

```
php artisan db:seed --class="MaxieWright\TrinidadAndTobagoAddresses\Database\Seeders\DivisionSeeder"
php artisan db:seed --class="MaxieWright\TrinidadAndTobagoAddresses\Database\Seeders\CitySeeder"
```

Or add them to your `DatabaseSeeder.php`:

```
use MaxieWright\TrinidadAndTobagoAddresses\Database\Seeders\DivisionSeeder;
use MaxieWright\TrinidadAndTobagoAddresses\Database\Seeders\CitySeeder;

public function run(): void
{
    $this->call([
        DivisionSeeder::class,
        CitySeeder::class,
        // ... your other seeders
    ]);
}
```

Configuration
-------------

[](#configuration)

The configuration file is located at `config/tt-addresses.php`:

```
return [
    // Customise table names if they conflict with existing tables
    'tables' => [
        'divisions' => 'tt_divisions',
        'cities' => 'tt_cities',
    ],

    // ISO country code
    'country_code' => 'TT',
];
```

Usage
-----

[](#usage)

### Basic Queries

[](#basic-queries)

```
use MaxieWright\TrinidadAndTobagoAddresses\Models\Division;
use MaxieWright\TrinidadAndTobagoAddresses\Models\City;
use MaxieWright\TrinidadAndTobagoAddresses\Enums\DivisionType;

// Get all divisions
$divisions = Division::all();

// Get only Trinidad divisions
$trinidadDivisions = Division::trinidad()->get();

// Get only Tobago
$tobago = Division::tobago()->first();

// Get divisions by type
$boroughs = Division::ofType(DivisionType::Borough)->get();
$regionalCorporations = Division::ofType(DivisionType::RegionalCorporation)->get();

// Get all cities in a division
$chaguanasCities = Division::where('abbreviation', 'CHA')
    ->first()
    ->cities;

// Find a city
$portOfSpain = City::where('name', 'Port-of-Spain')->first();
$portOfSpain->division->name; // "Port of Spain"
$portOfSpain->island; // "Trinidad"

// Get full location string
$city = City::where('name', 'Scarborough')->first();
$city->full_location; // "Scarborough, Tobago"
```

### Division Types

[](#division-types)

The package includes a `DivisionType` enum with the following values:

ValueLabelIsland`RegionalCorporation`Regional CorporationTrinidad`Borough`BoroughTrinidad`CityCorporation`City CorporationTrinidad`Ward`WardTobago```
use MaxieWright\TrinidadAndTobagoAddresses\Enums\DivisionType;

$type = DivisionType::RegionalCorporation;
$type->label();  // "Regional Corporation"
$type->island(); // "Trinidad"

// Filament support
$type->getLabel(); // "Regional Corporation"
```

### Adding Addresses to Your Models

[](#adding-addresses-to-your-models)

Use the `HasTrinidadAndTobagoAddress` trait on any model that needs Trinidad and Tobago address fields:

```
use Illuminate\Database\Eloquent\Model;
use MaxieWright\TrinidadAndTobagoAddresses\Concerns\HasTrinidadAndTobagoAddress;

class Customer extends Model
{
    use HasTrinidadAndTobagoAddress;

    protected $fillable = [
        'name',
        'address_line_1',
        'address_line_2',
        'division_id',
        'city_id',
    ];
}
```

Create a migration for your model:

```
Schema::create('customers', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('address_line_1')->nullable();
    $table->string('address_line_2')->nullable();
    $table->foreignId('division_id')
          ->nullable()
          ->constrained(config('laravel-tt-addresses.tables.divisions'))
          ->nullOnDelete();
    $table->foreignId('city_id')
          ->nullable()
          ->constrained(config('laravel-tt-addresses.tables.cities'))
          ->nullOnDelete();
    $table->timestamps();
});
```

Then use it:

```
$customer = Customer::create([
    'name' => 'John Doe',
    'address_line_1' => '123 Main Street',
    'division_id' => 11, // Chaguanas
    'city_id' => 88,     // Chaguanas city
]);

$customer->division->name;       // "Chaguanas"
$customer->city->name;           // "Chaguanas"
$customer->formatted_address;    // "123 Main Street, Chaguanas, Chaguanas"
$customer->island;               // "Trinidad"
```

### Geolocation Features

[](#geolocation-features)

The package includes coordinates for cities, enabling location-based queries:

```
use MaxieWright\TrinidadAndTobagoAddresses\Models\City;

// Get coordinates
$city = City::where('name', 'Port-of-Spain')->first();
$city->latitude;    // 10.6596
$city->longitude;   // -61.5086
$city->coordinates; // ['latitude' => 10.6596, 'longitude' => -61.5086]

// Calculate distance between cities (in kilometers)
$pos = City::where('name', 'Port-of-Spain')->first();
$sfo = City::where('name', 'San Fernando')->first();
$distance = $pos->distanceTo($sfo); // ~47km

// Find cities within 20km of a point
$nearbyCities = City::query()
    ->withinRadius(10.6596, -61.5086, 20)
    ->get();

// Find the nearest city to coordinates
$nearest = City::findNearest(10.5, -61.4);

// Order cities by distance from a point
$cities = City::query()
    ->orderByDistanceFrom(10.6596, -61.5086)
    ->take(10)
    ->get();

// Get map URLs
$city->getGoogleMapsUrl();      // https://www.google.com/maps?q=...
$city->getOpenStreetMapUrl();   // https://www.openstreetmap.org/?mlat=...
```

#### Using with Address Models

[](#using-with-address-models)

Models using `HasTrinidadAndTobagoAddress` automatically get location methods:

```
$customer = Customer::find(1);

// Get coordinates from associated city
$customer->coordinates;  // ['latitude' => ..., 'longitude' => ...]
$customer->latitude;
$customer->longitude;

// Check if has coordinates
if ($customer->hasCoordinates()) {
    // Calculate distance to another customer
    $distance = $customer->distanceTo($otherCustomer);

    // Find nearby cities
    $nearbyCities = $customer->findNearbyCities(radiusKm: 15, limit: 5);
}
```

### Search Enhancements

[](#search-enhancements)

The package includes powerful search and autocomplete features designed for high-performance applications:

#### Autocomplete Search

[](#autocomplete-search)

```
use MaxieWright\TrinidadAndTobagoAddresses\Models\City;

// Fast autocomplete search (optimized for prefix matching)
$results = City::autocomplete('Port', limit: 5)->get();
// Returns cities starting with "Port" (like "Port of Spain")

// Convert to API format
$searchResults = $results->map->toSearchResult();
// [
//   'id' => 1,
//   'name' => 'Port of Spain',
//   'division' => 'Port of Spain',
//   'full_location' => 'Port of Spain, Port of Spain',
//   'island' => 'Trinidad',
//   'coordinates' => ['latitude' => 10.6596, 'longitude' => -61.5089],
//   'division_type' => 'City Corporation'
// ]

// Convert to autocomplete options
$options = $results->map->toAutocompleteOption();
// [
//   'value' => 1,
//   'label' => 'Port of Spain',
//   'description' => 'Port of Spain, Trinidad',
//   'coordinates' => ['latitude' => 10.6596, 'longitude' => -61.5089]
// ]
```

#### Popular Cities

[](#popular-cities)

```
// Get popular/major cities (configured in config file)
$popular = City::popular()->get();

// With caching (recommended for production)
$popularCached = City::getPopularCached(ttl: 3600); // Cache for 1 hour
```

#### Search Radius Filtering

[](#search-radius-filtering)

```
use MaxieWright\TrinidadAndTobagoAddresses\Enums\SearchRadius;

// Find cities within predefined search radii
$walking = City::withinSearchRadius($lat, $lng, SearchRadius::WALKING)->get();     // 2km
$driving = City::withinSearchRadius($lat, $lng, SearchRadius::DRIVING)->get();     // 10km
$regional = City::withinSearchRadius($lat, $lng, SearchRadius::REGIONAL)->get();   // 25km
$islandWide = City::withinSearchRadius($lat, $lng, SearchRadius::ISLAND_WIDE)->get(); // 100km

// Search radius labels for UI
SearchRadius::WALKING->label();      // "2 km (Walking Distance)"
SearchRadius::DRIVING->description(); // "Short drive, local area"
```

#### Nearby Location Suggestions

[](#nearby-location-suggestions)

```
// Get suggested nearby cities for any location
$suggestions = City::getSuggestedNearbyCities(
    latitude: 10.6596,
    longitude: -61.5089,
    maxCities: 10
);
```

#### Performance Optimization

[](#performance-optimization)

```
// Clear and warm search caches
php artisan tt-addresses:optimize-search --clear-cache --warm-cache

// Or just optimize (clear + warm)
php artisan tt-addresses:optimize-search
```

### Configuration for Search

[](#configuration-for-search)

Update your `config/tt-addresses.php` for search optimization:

```
return [
    // ... existing config ...

    'search' => [
        'autocomplete_limit' => 10,           // Max results for autocomplete
        'cache_ttl' => 900,                   // 15 minutes
        'popular_cities_cache_ttl' => 3600,   // 1 hour
    ],

    'popular_cities' => [
        'Port of Spain',
        'San Fernando',
        'Chaguanas',
        'Arima',
        'Point Fortin',
        'Couva',
        'Sangre Grande',
        // ... add your most searched cities
    ],
];
```

### Filament Integration

[](#filament-integration)

The models and enums are designed to work seamlessly with [FilamentPHP](https://filamentphp.com/).

#### Select Fields

[](#select-fields)

```
use Filament\Forms\Components\Select;
use MaxieWright\TrinidadAndTobagoAddresses\Models\Division;
use MaxieWright\TrinidadAndTobagoAddresses\Models\City;

// Division select
Select::make('division_id')
    ->label('Division')
    ->options(Division::pluck('name', 'id'))
    ->searchable()
    ->preload()
    ->live(),

// City select (filtered by division)
Select::make('city_id')
    ->label('City/Town/Village')
    ->options(function (callable $get) {
        $divisionId = $get('division_id');
        if (!$divisionId) {
            return City::pluck('name', 'id');
        }
        return City::where('division_id', $divisionId)
            ->pluck('name', 'id');
    })
    ->searchable()
    ->preload(),
```

#### Using the Enum in Filters

[](#using-the-enum-in-filters)

```
use Filament\Tables\Filters\SelectFilter;
use MaxieWright\TrinidadAndTobagoAddresses\Enums\DivisionType;

SelectFilter::make('type')
    ->options(DivisionType::class),
```

### Administrative Divisions Reference

[](#administrative-divisions-reference)

IDNameTypeAbbreviation1Couva/Tabaquite/TalparoRegional CorporationCTT2Diego MartinRegional CorporationDMN3Mayaro/Rio ClaroRegional CorporationMRC4Penal/DebeRegional CorporationPED5Princes TownRegional CorporationPRT6Sangre GrandeRegional CorporationSGE7San Juan/LaventilleRegional CorporationSJL8SipariaRegional CorporationSIP9Tunapuna/PiarcoRegional CorporationTUP10ArimaBoroughARI11ChaguanasBoroughCHA12Point FortinBoroughPTF13Port of SpainCity CorporationPOS14San FernandoCity CorporationSFO15TobagoWardTOBAPI Reference
-------------

[](#api-reference)

### Division Model

[](#division-model)

#### Attributes

[](#attributes)

- `name` - Division name
- `type` - DivisionType enum
- `abbreviation` - Short code (e.g., "POS", "CHA")
- `island` - "Trinidad" or "Tobago"

#### Relationships

[](#relationships)

- `cities()` - HasMany relationship to City

#### Scopes

[](#scopes)

- `scopeTrinidad()` - Filter to Trinidad divisions only
- `scopeTobago()` - Filter to Tobago only
- `scopeOfType(DivisionType $type)` - Filter by division type
- `scopeSearch(string $search)` - Search by name or abbreviation

#### Methods

[](#methods)

- `isTobago(): bool` - Check if division is in Tobago
- `isTrinidad(): bool` - Check if division is in Trinidad

#### Accessors

[](#accessors)

- `full_name` - Returns "Division Name (Type Label)"

### City Model

[](#city-model)

#### Attributes

[](#attributes-1)

- `name` - City/town/village name
- `division_id` - Foreign key to Division

#### Relationships

[](#relationships-1)

- `division()` - BelongsTo relationship to Division

#### Scopes

[](#scopes-1)

- `scopeTrinidad()` - Filter to Trinidad cities only
- `scopeTobago()` - Filter to Tobago cities only
- `scopeInDivision(int|Division $division)` - Filter by division
- `scopeSearch(string $search)` - Search by name

#### Methods

[](#methods-1)

- `isTobago(): bool` - Check if city is in Tobago
- `isTrinidad(): bool` - Check if city is in Trinidad

#### Accessors

[](#accessors-1)

- `full_location` - Returns "City Name, Division Name"
- `island` - Returns "Trinidad" or "Tobago" via division

### HasTrinidadAndTobagoAddress Trait

[](#hastrinidadandtobagoaddress-trait)

#### Relationships

[](#relationships-2)

- `division()` - BelongsTo relationship to Division
- `city()` - BelongsTo relationship to City

#### Methods

[](#methods-2)

- `isInTobago(): bool` - Check if address is in Tobago
- `isInTrinidad(): bool` - Check if address is in Trinidad
- `hasCompleteAddress(): bool` - Check if address has all required fields

#### Accessors

[](#accessors-2)

- `formatted_address` - Returns formatted single-line address string
- `formatted_address_multiline` - Returns formatted multi-line address string
- `island` - Returns "Trinidad" or "Tobago"
- `country_code` - Returns "TT"

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

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

[](#contributing)

Contributions are welcome! Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

### Adding Missing Cities

[](#adding-missing-cities)

If you notice a city/town/village is missing, please submit a pull request with:

1. The city name (correctly spelled)
2. The correct `division_id` (see Administrative Divisions Reference)

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Maxie Wright](https://github.com/maxiewright)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

---

Made with ❤️ for 🇹🇹 developers.

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance90

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 92.9% 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 ~8 days

Total

14

Last Release

44d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/01df7160f037b372732c65fc33626f5e3ace6ad1b8afe1d5cbdb1bb3e372b818?d=identicon)[MaxieWright](/maintainers/MaxieWright)

---

Top Contributors

[![maxiewright](https://avatars.githubusercontent.com/u/32748178?v=4)](https://github.com/maxiewright "maxiewright (39 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (3 commits)")

---

Tags

laraveladdressesMaxie Wrightlaravel-tt-addressestrinidadtobago

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/maxiewright-laravel-tt-addresses/health.svg)

```
[![Health](https://phpackages.com/badges/maxiewright-laravel-tt-addresses/health.svg)](https://phpackages.com/packages/maxiewright-laravel-tt-addresses)
```

###  Alternatives

[spatie/laravel-data

Create unified resources and data transfer objects

1.7k28.9M627](/packages/spatie-laravel-data)[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[hirethunk/verbs

An event sourcing package that feels nice.

513162.9k6](/packages/hirethunk-verbs)[worksome/exchange

Check Exchange Rates for any currency in Laravel.

123544.7k](/packages/worksome-exchange)[ralphjsmit/livewire-urls

Get the previous and current url in Livewire.

82270.3k4](/packages/ralphjsmit-livewire-urls)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)

PHPackages © 2026

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