awalhadi / addressable
A modern, feature-rich Laravel package for managing addresses with geocoding, validation, caching, and spatial operations. Perfect for e-commerce, CRM systems, and any application requiring robust address management.
v3.0.0
2025-08-12 15:12 UTC
Requires
- php: ^7.4|^8.0|^8.1|^8.2|^8.3|^8.4
- illuminate/database: ^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0
- jackpopp/geodistance: ^1.2.3
- rinvex/countries: ^8.1.1
Requires (Dev)
- fakerphp/faker: ^1.0
- laravel/pint: ^1.0
- mockery/mockery: ^1.0
- nunomaduro/collision: ^7.0
- orchestra/testbench: ^8.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpunit/phpunit: ^10.0
README
A modern, feature-rich Laravel package for managing addresses with geocoding, validation, caching, and spatial operations. Perfect for e-commerce, CRM systems, and any application requiring robust address management.
β¨ Features
- π Polymorphic Relationships - Attach addresses to any model
- π Geocoding Support - Google Maps, OpenStreetMap, HERE APIs
- β Address Validation - Postal codes, phone numbers, email validation
- πΊοΈ Spatial Operations - Distance calculations, geofencing, bounding boxes
- β‘ Smart Caching - Multi-level caching for performance
- π Security Features - Data masking, GDPR compliance, encryption
- π Bulk Operations - Efficient mass address management
- π― Multiple Address Types - Home, work, billing, shipping addresses
- π± Mobile Optimized - Responsive design considerations
- π§ͺ Comprehensive Testing - 100% test coverage with Pest
π Requirements
- PHP: 7.4, 8.0, 8.1, 8.2, 8.3, 8.4+
- Laravel: 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0+
- Database: MySQL 5.7+, PostgreSQL 10+, SQLite 3.8+
π Installation
1. Install via Composer
composer require awalhadi/addressable
2. Publish Configuration (Optional)
php artisan vendor:publish --provider="Awalhadi\Addressable\Providers\AddressableServiceProvider"
3. Run Migrations
php artisan migrate
π― Quick Start
1. Add Trait to Your Model
<?php namespace App\Models; use Awalhadi\Addressable\Traits\Addressable; use Illuminate\Database\Eloquent\Model; class User extends Model { use Addressable; // Your existing model code... }
2. Create Your First Address
$user = User::find(1); $address = $user->addresses()->create([ 'type' => 'home', 'label' => 'My Home', 'given_name' => 'John', 'family_name' => 'Doe', 'organization' => 'Acme Corp', 'phone' => '+1-555-123-4567', 'email' => 'john@example.com', 'street' => '123 Main Street', 'street_2' => 'Apt 4B', 'city' => 'New York', 'state' => 'NY', 'postal_code' => '10001', 'country_code' => 'US', 'latitude' => 40.7128, 'longitude' => -74.0060, 'is_primary' => true, 'is_billing' => false, 'is_shipping' => true, ]);
3. Query Addresses
// Get all addresses $addresses = $user->addresses; // Get primary address $primaryAddress = $user->primaryAddress(); // Get addresses by type $homeAddresses = $user->addresses()->ofType('home')->get(); $billingAddresses = $user->addresses()->isBilling()->get(); // Get addresses within radius $nearbyAddresses = $user->addresses() ->withCoordinates() ->get() ->filter(fn($address) => $address->isWithinRadius(40.7128, -74.0060, 10));
π API Reference
Address Model
Properties
Property | Type | Description |
---|---|---|
id |
UUID | Primary key |
addressable_type |
string | Polymorphic model class |
addressable_id |
UUID | Polymorphic model ID |
type |
string | Address type (home, work, billing, shipping) |
label |
string | Custom label |
given_name |
string | First name |
family_name |
string | Last name |
organization |
string | Company name |
phone |
string | Phone number |
email |
string | Email address |
street |
string | Street address |
street_2 |
string | Secondary address line |
city |
string | City |
state |
string | State/province |
postal_code |
string | Postal/ZIP code |
country_code |
string | ISO country code |
neighborhood |
string | Neighborhood |
district |
string | District |
latitude |
decimal | Latitude coordinate |
longitude |
decimal | Longitude coordinate |
is_primary |
boolean | Primary address flag |
is_billing |
boolean | Billing address flag |
is_shipping |
boolean | Shipping address flag |
is_verified |
boolean | Verification status |
metadata |
json | Additional data |
verified_at |
timestamp | Verification timestamp |
Accessors
// Get full name $address->full_name; // "John Doe" // Get formatted address $address->full_address; // "123 Main Street, Apt 4B, New York, NY 10001, US" // Get country name $address->country_name; // "United States" // Get formatted phone $address->formatted_phone; // "(555) 123-4567" // Get masked phone (for privacy) $address->masked_phone; // "(555) ***-4567" // Get masked email (for privacy) $address->masked_email; // "j***@example.com"
Scopes
// Filter by type Address::ofType('home')->get(); // Filter by country Address::inCountry('US')->get(); // Filter by city Address::inCity('New York')->get(); // Filter by state Address::inState('NY')->get(); // Filter by postal code Address::inPostalCode('10001')->get(); // Only verified addresses Address::isVerified()->get(); // Only addresses with coordinates Address::withCoordinates()->get(); // Recent addresses (last 30 days) Address::recent()->get();
Addressable Trait
Methods
// Get all addresses $user->addresses; // Get primary address $user->primaryAddress(); // Get billing address $user->billingAddress(); // Get shipping address $user->shippingAddress(); // Check if has addresses $user->hasAddresses(); // Check if has primary address $user->hasPrimaryAddress(); // Get addresses by type $user->getAddressesByType('home'); // Get addresses in country $user->getAddressesInCountry('US'); // Get addresses within radius $user->getAddressesWithinRadius($lat, $lng, $radius); // Create multiple addresses $user->createManyAddresses([ ['type' => 'home', 'street' => '123 Home St'], ['type' => 'work', 'street' => '456 Work Ave'], ]); // Update multiple addresses $user->updateManyAddresses([ 'home' => ['street' => '789 New Home St'], 'work' => ['street' => '012 New Work Ave'], ]);
Spatial Operations
// Calculate distance between two addresses $distance = $address1->distanceTo($address2); // Check if address is within radius $isNearby = $address->isWithinRadius($lat, $lng, 10); // Calculate distance using Haversine formula $distance = $address->calculateDistance($lat, $lng); // Calculate distance using Vincenty formula (more accurate) $distance = $address->calculateDistanceVincenty($lat, $lng); // Check if point is in polygon (geofencing) $isInside = $address->isPointInPolygon($polygon); // Create bounding box $bbox = $address->createBoundingBox($radius); // Convert decimal to DMS format $dms = $address->decimalToDMS($latitude); // Convert DMS to decimal $decimal = $address->dmsToDecimal($dms); // Calculate midpoint between two coordinates $midpoint = $address->calculateMidpoint($lat1, $lng1, $lat2, $lng2);
Address Validation
// Validate entire address $isValid = $address->isValid(); // Get validation errors $errors = $address->getValidationErrors(); // Validate postal code $isValid = $address->validatePostalCode(); // Validate phone number $isValid = $address->validatePhoneNumber(); // Validate email $isValid = $address->validateEmail(); // Validate country code $isValid = $address->validateCountryCode(); // Format postal code $formatted = $address->formatPostalCode(); // Format phone number $formatted = $address->formatPhoneNumber();
Geocoding
// Geocode address (get coordinates) $address->geocode(); // Reverse geocode (get address from coordinates) $address->reverseGeocode(); // Check if address has coordinates $hasCoords = $address->hasCoordinates(); // Check if address is complete $isComplete = $address->isComplete();
Caching
// Cache address data $address->cacheAddressData(); // Get cached address data $cached = $address->getCachedAddressData(); // Clear address cache $address->clearAddressCache(); // Cache geocoding results $address->cacheGeocodingResult($result); // Get cached geocoding result $cached = $address->getCachedGeocodingResult(); // Clear all related caches $address->clearAllRelatedCaches(); // Warm cache for addressable $user->warmAddressCache();
βοΈ Configuration
The package configuration file (config/addressable.php
) provides extensive customization options:
Database Configuration
'database' => [ 'table' => 'addresses', 'primary_key' => 'id', // 'id' or 'uuid' 'uuid_version' => 4, 'soft_deletes' => true, 'timestamps' => true, ],
Address Types
'types' => [ 'default' => 'general', 'available' => [ 'home' => 'Home Address', 'work' => 'Work Address', 'billing' => 'Billing Address', 'shipping' => 'Shipping Address', 'general' => 'General Address', ], ],
Geocoding
'geocoding' => [ 'enabled' => env('ADDRESSABLE_GEOCODING_ENABLED', true), 'provider' => env('ADDRESSABLE_GEOCODING_PROVIDER', 'google'), 'providers' => [ 'google' => [ 'api_key' => env('GOOGLE_MAPS_API_KEY'), 'enabled' => true, ], 'nominatim' => [ 'base_url' => 'https://nominatim.openstreetmap.org', 'enabled' => true, ], 'here' => [ 'app_id' => env('HERE_APP_ID'), 'app_code' => env('HERE_APP_CODE'), 'enabled' => false, ], ], 'cache_duration' => 86400, // 24 hours ],
Validation
'validation' => [ 'enabled' => env('ADDRESSABLE_VALIDATION_ENABLED', true), 'strict_mode' => false, 'auto_verify' => false, 'postal_code_validation' => true, 'phone_validation' => true, 'email_validation' => true, 'country_code_validation' => true, ],
Caching
'caching' => [ 'enabled' => env('ADDRESSABLE_CACHING_ENABLED', true), 'store' => env('ADDRESSABLE_CACHE_STORE', 'default'), 'prefix' => 'addressable', 'ttl' => [ 'address' => 3600, // 1 hour 'geocoding' => 86400, // 24 hours 'validation' => 7200, // 2 hours 'distance' => 1800, // 30 minutes ], ],
π§ Development
Prerequisites
- PHP 8.1+
- Composer
- Git
π€ Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
π License
This package is open-sourced software licensed under the MIT license.
π Support
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
π Acknowledgments
- Laravel team for the amazing framework
- Pest team for the testing framework
- All contributors who helped improve this package
Made with β€οΈ by the Laravel community