Skip to content

Model Alamat ​

Model Address menyediakan sistem manajemen alamat lengkap yang terintegrasi dengan data administratif Indonesia. Model ini dirancang untuk menyimpan alamat pengguna dengan validasi dan relasi yang tepat ke wilayah administratif.

Referensi Kelas ​

php
namespace Creasi\Nusa\Models;

class Address extends Model
{
    // Implementasi model
}

Atribut ​

Atribut Utama ​

AtributTipeDeskripsiContoh
idbigintKunci utama (auto-increment)1
user_idbigintKunci asing ke tabel pengguna123
namestringNama penerima"John Doe"
phonestringNomor telepon kontak"081234567890"
province_codestringKode provinsi (Kunci Asing)"33"
regency_codestringKode kabupaten/kota (Kunci Asing)"33.75"
district_codestringKode kecamatan (Kunci Asing)"33.75.01"
village_codestringKode desa/kelurahan (Kunci Asing)"33.75.01.1002"
address_linetextAlamat rinci"Jl. Merdeka No. 123"
postal_codestringKode pos 5 digit"51111"
is_defaultbooleanTanda alamat utamatrue

Atribut Terkomputasi ​

AtributTipeDeskripsi
full_addressstringAlamat lengkap yang diformat

Relasi ​

Belongs To ​

php
// Dapatkan pengguna yang memiliki alamat ini
$address->user; // Model User

// Dapatkan wilayah administratif
$address->province; // Model Province
$address->regency;  // Model Regency
$address->district; // Model District
$address->village;  // Model Village

Metode Relasi ​

php
// Relasi pengguna
public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}

// Relasi wilayah administratif
public function province(): BelongsTo
{
    return $this->belongsTo(Province::class, 'province_code', 'code');
}

public function regency(): BelongsTo
{
    return $this->belongsTo(Regency::class, 'regency_code', 'code');
}

public function district(): BelongsTo
{
    return $this->belongsTo(District::class, 'district_code', 'code');
}

public function village(): BelongsTo
{
    return $this->belongsTo(Village::class, 'village_code', 'code');
}

Scope ​

Scope Alamat Utama ​

php
// Dapatkan alamat utama
Address::default()->get();

// Dapatkan alamat bukan utama
Address::notDefault()->get();

Scope Pengguna ​

php
// Dapatkan alamat untuk pengguna tertentu
Address::forUser($userId)->get();

Contoh Penggunaan ​

Membuat Alamat ​

php
use Creasi\Nusa\Models\Address;

// Buat alamat baru
$address = Address::create([
    'user_id' => 1,
    'name' => 'John Doe',
    'phone' => '081234567890',
    'province_code' => '33',
    'regency_code' => '33.75',
    'district_code' => '33.75.01',
    'village_code' => '33.75.01.1002',
    'address_line' => 'Jl. Merdeka No. 123',
    'postal_code' => '51111',
    'is_default' => true,
]);

// Buat melalui relasi pengguna
$user = User::find(1);
$address = $user->addresses()->create([
    'name' => 'Jane Doe',
    'phone' => '081234567891',
    'province_code' => '33',
    'regency_code' => '33.75',
    'district_code' => '33.75.01',
    'village_code' => '33.75.01.1002',
    'address_line' => 'Jl. Sudirman No. 456',
    'is_default' => false,
]);

Mengambil Data Alamat ​

php
// Dapatkan semua alamat untuk seorang pengguna
$userAddresses = Address::where('user_id', 1)->get();

// Dapatkan alamat utama pengguna
$defaultAddress = Address::where('user_id', 1)
    ->where('is_default', true)
    ->first();

// Dapatkan alamat dengan data administratif
$addresses = Address::with(['province', 'regency', 'district', 'village'])
    ->where('user_id', 1)
    ->get();

// Cari alamat berdasarkan nama atau telepon
$addresses = Address::where('user_id', 1)
    ->where(function ($query) use ($search) {
        $query->where('name', 'like', "%{$search}%")
              ->orWhere('phone', 'like', "%{$search}%");
    })
    ->get();

Bekerja dengan Alamat Lengkap ​

php
$address = Address::with(['village', 'district', 'regency', 'province'])
    ->find(1);

// Dapatkan alamat lengkap yang diformat
$fullAddress = $address->full_address;
// "Jl. Merdeka No. 123, Medono, Pekalongan Barat, Kota Pekalongan, Jawa Tengah 51111"

// Membangun alamat secara manual
$addressParts = [
    $address->address_line,
    $address->village->name,
    $address->district->name,
    $address->regency->name,
    $address->province->name,
    $address->postal_code
];
$fullAddress = implode(', ', array_filter($addressParts));

Manajemen Alamat ​

Penanganan Alamat Utama ​

php
// Atur alamat sebagai utama (batalkan yang lain)
function setDefaultAddress($userId, $addressId) {
    // Batalkan utama saat ini
    Address::where('user_id', $userId)
        ->where('is_default', true)
        ->update(['is_default' => false]);
    
    // Atur utama baru
    Address::where('id', $addressId)
        ->where('user_id', $userId)
        ->update(['is_default' => true]);
}

// Dapatkan alamat utama pengguna
function getDefaultAddress($userId) {
    return Address::where('user_id', $userId)
        ->where('is_default', true)
        ->with(['province', 'regency', 'district', 'village'])
        ->first();
}

Validasi Alamat ​

php
// Validasi konsistensi alamat
function validateAddressConsistency($addressData) {
    $village = Village::find($addressData['village_code']);
    
    if (!$village) {
        return false;
    }
    
    return $village->district_code === $addressData['district_code'] &&
           $village->regency_code === $addressData['regency_code'] &&
           $village->province_code === $addressData['province_code'];
}

// Isi otomatis kode pos dari desa/kelurahan
function autoFillPostalCode($addressData) {
    if (empty($addressData['postal_code'])) {
        $village = Village::find($addressData['village_code']);
        if ($village && $village->postal_code) {
            $addressData['postal_code'] = $village->postal_code;
        }
    }
    
    return $addressData;
}

Integrasi Trait ​

Trait HasAddresses ​

Untuk model yang dapat memiliki banyak alamat:

php
use Creasi\Nusa\Contracts\HasAddresses;
use Creasi\Nusa\Models\Concerns\WithAddresses;

class User extends Model implements HasAddresses
{
    use WithAddresses;
}

// Penggunaan
$user = User::find(1);
$addresses = $user->addresses;
$defaultAddress = $user->defaultAddress;
$user->setDefaultAddress($address);

Trait HasAddress ​

Untuk model dengan satu alamat:

php
use Creasi\Nusa\Contracts\HasAddress;
use Creasi\Nusa\Models\Concerns\WithAddress;

class Store extends Model implements HasAddress
{
    use WithAddress;
    
    protected $fillable = [
        'name',
        'description',
        'province_code',
        'regency_code',
        'district_code',
        'village_code',
        'address_line',
        'postal_code',
    ];
}

// Penggunaan
$store = Store::create([
    'name' => 'My Store',
    'province_code' => '33',
    'regency_code' => '33.75',
    'district_code' => '33.75.01',
    'village_code' => '33.75.01.1002',
    'address_line' => 'Jl. Toko No. 789',
]);

echo $store->full_address;

Validasi Formulir ​

Validasi Request ​

php
use Illuminate\Foundation\Http\FormRequest;

class StoreAddressRequest extends FormRequest
{
    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'phone' => 'required|string|max:20',
            'province_code' => 'required|exists:nusa.provinces,code',
            'regency_code' => [
                'required',
                'exists:nusa.regencies,code',
                function ($attribute, $value, $fail) {
                    $regency = Regency::find($value);
                    if (!$regency || $regency->province_code !== $this->province_code) {
                        $fail('Kabupaten/kota yang dipilih tidak valid untuk provinsi ini.');
                    }
                },
            ],
            'district_code' => [
                'required',
                'exists:nusa.districts,code',
                function ($attribute, $value, $fail) {
                    $district = District::find($value);
                    if (!$district || $district->regency_code !== $this->regency_code) {
                        $fail('Kecamatan yang dipilih tidak valid untuk kabupaten/kota ini.');
                    }
                },
            ],
            'village_code' => [
                'required',
                'exists:nusa.villages,code',
                function ($attribute, $value, $fail) {
                    $village = Village::find($value);
                    if (!$village || $village->district_code !== $this->district_code) {
                        $fail('Desa/kelurahan yang dipilih tidak valid untuk kecamatan ini.');
                    }
                },
            ],
            'address_line' => 'required|string|max:500',
            'postal_code' => 'nullable|string|size:5',
            'is_default' => 'boolean',
        ];
    }
}

Aturan Validasi Kustom ​

php
use Illuminate\Contracts\Validation\Rule;

class ValidIndonesianAddress implements Rule
{
    public function passes($attribute, $value)
    {
        $village = Village::find($value['village_code']);
        
        return $village &&
               $village->district_code === $value['district_code'] &&
               $village->regency_code === $value['regency_code'] &&
               $village->province_code === $value['province_code'];
    }
    
    public function message()
    {
        return 'Komponen alamat tidak konsisten.';
    }
}

Skema Database ​

sql
CREATE TABLE addresses (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    name VARCHAR(255) NOT NULL,
    phone VARCHAR(20) NOT NULL,
    province_code VARCHAR(2) NOT NULL,
    regency_code VARCHAR(5) NOT NULL,
    district_code VARCHAR(8) NOT NULL,
    village_code VARCHAR(13) NOT NULL,
    address_line TEXT NOT NULL,
    postal_code VARCHAR(5) NULL,
    is_default BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    INDEX idx_addresses_user (user_id),
    INDEX idx_addresses_default (user_id, is_default),
    INDEX idx_addresses_province (province_code),
    INDEX idx_addresses_regency (regency_code),
    INDEX idx_addresses_district (district_code),
    INDEX idx_addresses_village (village_code),
    INDEX idx_addresses_postal (postal_code)
);

Tips Kinerja ​

Kueri yang Efisien ​

php
// Baik: Muat dengan relasi tertentu
$addresses = Address::with(['province:code,name', 'regency:code,name'])
    ->where('user_id', $userId)
    ->get();

// Baik: Pilih kolom tertentu
$addresses = Address::select('id', 'name', 'address_line', 'is_default')
    ->where('user_id', $userId)
    ->get();

// Hindari: Memuat semua relasi
$addresses = Address::with(['province', 'regency', 'district', 'village'])
    ->get(); // Memuat terlalu banyak data

Caching ​

php
// Cache alamat pengguna
function getUserAddresses($userId) {
    $cacheKey = "user.{$userId}.addresses";
    
    return Cache::remember($cacheKey, 1800, function () use ($userId) {
        return Address::with(['province', 'regency', 'district', 'village'])
            ->where('user_id', $userId)
            ->get();
    });
}

Model Terkait ​

Released under the MIT License.