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

This package is auto-updated.

Last update: 2025-08-12 15:14:12 UTC


README

Latest Version on Packagist Total Downloads License PHP Version

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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This package is open-sourced software licensed under the MIT license.

πŸ†˜ Support

πŸ™ 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