Skip to content

Basic Usage Examples ​

This page provides practical examples of using Laravel Nusa in common scenarios. These examples demonstrate the most frequent use cases and patterns you'll encounter when working with Indonesian administrative data.

Finding Administrative Regions ​

By Code ​

php
use Creasi\Nusa\Models\{Province, Regency, District, Village};

// Find by exact code
$province = Province::find('33');              // Central Java
$regency = Regency::find('33.75');            // Pekalongan City
$district = District::find('33.75.01');       // West Pekalongan
$village = Village::find('33.75.01.1002');    // Medono Village

// Check if found
if ($province) {
    echo "Found: {$province->name}";
} else {
    echo "Province not found";
}
php
// Case-insensitive search
$provinces = Province::search('jawa')->get();
$regencies = Regency::search('semarang')->get();
$districts = District::search('pekalongan')->get();
$villages = Village::search('medono')->get();

// Get first result
$jateng = Province::search('jawa tengah')->first();
$semarang = Regency::search('kota semarang')->first();

Multiple Search Terms ​

php
// Search multiple provinces
$javaProvinces = Province::where(function ($query) {
    $query->search('jawa barat')
          ->orWhere(function ($q) { $q->search('jawa tengah'); })
          ->orWhere(function ($q) { $q->search('jawa timur'); });
})->get();

// Search with code alternatives
$results = Province::search('33')
    ->orWhere(function ($query) {
        $query->search('jawa tengah');
    })->get();

Working with Relationships ​

php
use Creasi\Nusa\Models\Province;

$province = Province::find('33');

// Get all regencies in the province
$regencies = $province->regencies;
echo "Regencies in {$province->name}: {$regencies->count()}";

// Get all districts in the province
$districts = $province->districts;
echo "Districts in {$province->name}: {$districts->count()}";

// Get all villages in the province
$villages = $province->villages;
echo "Villages in {$province->name}: {$villages->count()}";

Eager Loading for Performance ​

php
// Load province with its regencies
$province = Province::with('regencies')->find('33');

// Load multiple relationships
$province = Province::with(['regencies', 'districts'])->find('33');

// Load nested relationships
$provinces = Province::with(['regencies.districts.villages'])->get();

// Load specific columns only
$provinces = Province::with(['regencies:code,province_code,name'])->get();

Reverse Relationships ​

php
use Creasi\Nusa\Models\Village;

$village = Village::find('33.75.01.1002');

// Get parent administrative levels
$district = $village->district;
$regency = $village->regency;
$province = $village->province;

echo "Full address: {$village->name}, {$district->name}, {$regency->name}, {$province->name}";

Address Form Integration ​

For building complete address forms with cascading dropdowns, see the dedicated Address Forms guide which covers:

  • Complete backend controller implementation
  • Frontend JavaScript integration with multiple frameworks
  • Form validation and error handling
  • Styling and UX considerations

Quick Address Form Data ​

php
// Simple cascading dropdown data endpoints
class AddressController extends Controller
{
    public function getRegencies(Request $request)
    {
        return Regency::where('province_code', $request->province_code)
            ->orderBy('name')
            ->get(['code', 'name']);
    }

    public function getDistricts(Request $request)
    {
        return District::where('regency_code', $request->regency_code)
            ->orderBy('name')
            ->get(['code', 'name']);
    }

    public function getVillages(Request $request)
    {
        return Village::where('district_code', $request->district_code)
            ->orderBy('name')
            ->get(['code', 'name', 'postal_code']);
    }
}

Geographic Data Usage ​

Working with Coordinates ​

php
use Creasi\Nusa\Models\Province;

$province = Province::find('33');

// Get center coordinates
$latitude = $province->latitude;
$longitude = $province->longitude;

// Get boundary coordinates (if available)
$boundaries = $province->coordinates;

if ($boundaries) {
    echo "Province has " . count($boundaries) . " boundary points";
    
    // Use with mapping libraries
    $geoJson = [
        'type' => 'Polygon',
        'coordinates' => [$boundaries]
    ];
}

Postal Code Aggregation ​

php
// Get all postal codes in a province
$province = Province::find('33');
$postalCodes = $province->postal_codes;

echo "Postal codes in {$province->name}: " . implode(', ', $postalCodes);

// Get postal codes in a district
$district = District::find('33.75.01');
$districtPostalCodes = $district->postal_codes;

// Find villages by postal code
$villages = Village::where('postal_code', '51111')->get();

Data Validation ​

Form Request Validation ​

php
use Illuminate\Foundation\Http\FormRequest;
use Creasi\Nusa\Models\{Province, Regency, District, Village};

class AddressRequest extends FormRequest
{
    public function rules()
    {
        return [
            'province_code' => [
                'required',
                'string',
                function ($attribute, $value, $fail) {
                    if (!Province::find($value)) {
                        $fail('The selected province is invalid.');
                    }
                },
            ],
            'regency_code' => [
                'required',
                'string',
                function ($attribute, $value, $fail) {
                    $regency = Regency::find($value);
                    if (!$regency || $regency->province_code !== $this->province_code) {
                        $fail('The selected regency is invalid for this province.');
                    }
                },
            ],
            'district_code' => [
                'required',
                'string',
                function ($attribute, $value, $fail) {
                    $district = District::find($value);
                    if (!$district || $district->regency_code !== $this->regency_code) {
                        $fail('The selected district is invalid for this regency.');
                    }
                },
            ],
            'village_code' => [
                'required',
                'string',
                function ($attribute, $value, $fail) {
                    $village = Village::find($value);
                    if (!$village || $village->district_code !== $this->district_code) {
                        $fail('The selected village is invalid for this district.');
                    }
                },
            ],
        ];
    }
}

Custom Validation Rules ​

php
use Illuminate\Contracts\Validation\Rule;
use Creasi\Nusa\Models\Village;

class ValidIndonesianAddress implements Rule
{
    public function passes($attribute, $value)
    {
        // Validate that all address components are consistent
        $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 'The address components are not consistent.';
    }
}

Performance Optimization ​

Efficient Queries ​

php
// Good: Use specific columns
$provinces = Province::select('code', 'name')->get();

// Good: Use pagination for large datasets
$villages = Village::paginate(50);

// Good: Use whereIn for multiple codes
$regencies = Regency::whereIn('code', ['33.75', '33.76', '33.77'])->get();

// Avoid: Loading all villages at once
// $allVillages = Village::all(); // 83,762 records!

Caching Strategies ​

php
use Illuminate\Support\Facades\Cache;

class LocationService
{
    public function getProvinces()
    {
        return Cache::remember('nusa.provinces', 3600, function () {
            return Province::orderBy('name')->get(['code', 'name']);
        });
    }
    
    public function getRegenciesByProvince(string $provinceCode)
    {
        $cacheKey = "nusa.regencies.{$provinceCode}";
        
        return Cache::remember($cacheKey, 3600, function () use ($provinceCode) {
            return Regency::where('province_code', $provinceCode)
                ->orderBy('name')
                ->get(['code', 'name']);
        });
    }
}

Error Handling ​

Graceful Fallbacks ​

php
use Creasi\Nusa\Models\Province;

function getProvinceName(string $code): string
{
    try {
        $province = Province::find($code);
        return $province ? $province->name : "Unknown Province ({$code})";
    } catch (Exception $e) {
        Log::error("Failed to get province name for code: {$code}", [
            'error' => $e->getMessage()
        ]);
        return "Unknown Province";
    }
}

function buildFullAddress(array $codes): string
{
    $parts = [];
    
    if ($village = Village::find($codes['village_code'] ?? null)) {
        $parts[] = $village->name;
        $parts[] = $village->district->name;
        $parts[] = $village->regency->name;
        $parts[] = $village->province->name;
    }
    
    return implode(', ', array_filter($parts));
}

Next Steps ​

Released under the MIT License.