PHPackages                             wzije/indo-area - 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. wzije/indo-area

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

wzije/indo-area
===============

Library untuk mengambil data wilayah Indonesia

2.0.1(2mo ago)133MITPHP ^8.2

Since May 13Compare

[ Source](https://github.com/wzije/indo-area)[ Packagist](https://packagist.org/packages/wzije/indo-area)[ RSS](/packages/wzije-indo-area/feed)WikiDiscussions Synced 3w ago

READMEChangelogDependencies (2)Versions (6)Used By (0)

IndoArea - Laravel Indonesia Regional Data Library
==================================================

[](#indoarea---laravel-indonesia-regional-data-library)

IndoArea is a self-contained Laravel package providing comprehensive Indonesian regional administrative data (BPS standard). It utilizes an internal offline SQLite database, making it exceptionally fast, lightweight, and perfect for high-traffic environments without putting any stress on your primary database (e.g., MySQL).

Laravel Compatibility
---------------------

[](#laravel-compatibility)

Laravel VersionPHP VersionStatus**Laravel 10.x**`^8.3`Supported**Laravel 11.x**`^8.3`Supported**Laravel 12.x**`^8.3`Supported**Laravel 12.x**`^8.3`SupportedFeatures
--------

[](#features)

- **Zero Configuration:** Automatically injects and registers the internal SQLite connection.
- **No Database Migration Needed:** No messy imports of 80,000+ village rows into your production tables.
- **BPS Standard Code:** Uses pure numeric regional identification codes without dots.
- **HasArea Trait:** Easily link your models to regional data with built-in relationships and full address formatting.

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

[](#installation)

```
composer require wzije/indo-area
```

---

Available API Endpoints
-----------------------

[](#available-api-endpoints)

The library automatically registers the following REST API routes under the `api/indo-area` prefix:

MethodEndpointDescriptionJSON Response Keys**GET**`/api/indo-area/provinces`Get all provinces`id`, `name`**GET**`/api/indo-area/provinces/{code}/regencies`Get regencies by province code`id`, `name`**GET**`/api/indo-area/regencies/{code}/districts`Get districts by regency code`id`, `name`**GET**`/api/indo-area/districts/{code}/villages`Get villages by district code`id`, `name`---

Usage Guide
-----------

[](#usage-guide)

### 1. Linking Your Models (HasArea Trait)

[](#1-linking-your-models-hasarea-trait)

You can use the `HasArea` trait in your models (e.g., `User` or `Address`) to instantly gain relationships to the regional data.

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Wzije\IndoArea\Models\Traits\HasArea;

class Address extends Model
{
    use HasArea;

    /**
     * Optional: Map your custom column names if they differ from defaults
     * Defaults: province, regency, district, village
     */
    public function areaColumnMap(): array
    {
        return [
            'province' => 'province_id',
            'regency'  => 'city_id',
            'district' => 'district_id',
            'village'  => 'village_id',
        ];
    }
}
```

**Benefits of HasArea:**

- **Relationships:** Access via `$model->province`, `$model->city`, `$model->subDistrict`, and `$model->village`.
- **Full Address:** Get a formatted string via `$model->full_address`.

---

### 2. Backend Eloquent Model Queries

[](#2-backend-eloquent-model-queries)

#### Fetch All Provinces

[](#fetch-all-provinces)

```
use Wzije\IndoArea\Models\Province;

$provinces = Province::all();
```

#### Fetch Regencies Belonging to a Province

[](#fetch-regencies-belonging-to-a-province)

```
use Wzije\IndoArea\Models\Province;

$province = Province::find($provinceId);
$regencies = $province->regencies;
```

---

### 3. Frontend Integration (Chained Dropdowns)

[](#3-frontend-integration-chained-dropdowns)

#### HTML Structure

[](#html-structure)

```

  Select Province

  Select Regency

  Select District

  Select Village

```

#### JavaScript Logic

[](#javascript-logic)

```
document.addEventListener("DOMContentLoaded", function () {
  const provinceSelect = document.getElementById("region-province");
  const regencySelect = document.getElementById("region-regency");
  const districtSelect = document.getElementById("region-district");
  const villageSelect = document.getElementById("region-village");

  if (provinceSelect) loadProvinces();

  function loadProvinces() {
    fetch("/api/indo-area/provinces")
      .then((res) => res.json())
      .then((data) => {
        populateSelect(provinceSelect, data, "id", "name");
        if (provinceSelect.dataset.selected) {
          provinceSelect.value = provinceSelect.dataset.selected;
          loadRegencies(provinceSelect.value);
        }
      });

    provinceSelect.addEventListener("change", function () {
      resetSelect(regencySelect, "Select Regency");
      resetSelect(districtSelect, "Select District");
      resetSelect(villageSelect, "Select Village");
      if (this.value) loadRegencies(this.value);
    });
  }

  function loadRegencies(provinceCode) {
    enableSelect(regencySelect);
    fetch(`/api/indo-area/provinces/${provinceCode}/regencies`)
      .then((res) => res.json())
      .then((data) => {
        populateSelect(regencySelect, data, "id", "name");
        if (regencySelect.dataset.selected) {
          regencySelect.value = regencySelect.dataset.selected;
          regencySelect.dataset.selected = "";
          loadDistricts(regencySelect.value);
        }
      });

    regencySelect.addEventListener("change", function () {
      resetSelect(districtSelect, "Select District");
      resetSelect(villageSelect, "Select Village");
      if (this.value) loadDistricts(this.value);
    });
  }

  function loadDistricts(regencyCode) {
    enableSelect(districtSelect);
    fetch(`/api/indo-area/regencies/${regencyCode}/districts`)
      .then((res) => res.json())
      .then((data) => {
        populateSelect(districtSelect, data, "id", "name");
        if (districtSelect.dataset.selected) {
          districtSelect.value = districtSelect.dataset.selected;
          districtSelect.dataset.selected = "";
          loadVillages(districtSelect.value);
        }
      });

    districtSelect.addEventListener("change", function () {
      resetSelect(villageSelect, "Select Village");
      if (this.value) loadVillages(this.value);
    });
  }

  function loadVillages(districtCode) {
    if (!villageSelect) return;
    enableSelect(villageSelect);
    fetch(`/api/indo-area/districts/${districtCode}/villages`)
      .then((res) => res.json())
      .then((data) => {
        populateSelect(villageSelect, data, "id", "name");
        if (villageSelect.dataset.selected) {
          villageSelect.value = villageSelect.dataset.selected;
          villageSelect.dataset.selected = "";
        }
      });
  }

  function populateSelect(element, data, codeField, nameField) {
    const placeholder = element.options[0].text;
    element.innerHTML = `${placeholder}`;
    data.forEach((item) => {
      const option = document.createElement("option");
      option.value = item[codeField];
      option.textContent = item[nameField];
      element.appendChild(option);
    });
  }

  function enableSelect(element) {
    element.disabled = false;
    element.classList.remove("bg-gray-50");
  }

  function resetSelect(element, placeholder) {
    if (!element) return;
    element.innerHTML = `${placeholder}`;
    element.disabled = true;
    element.classList.add("bg-gray-50");
  }
});
```

---

Available Models
----------------

[](#available-models)

- `Wzije\IndoArea\Models\Province`
- `Wzije\IndoArea\Models\Regency`
- `Wzije\IndoArea\Models\District`
- `Wzije\IndoArea\Models\Village`

License
-------

[](#license)

This library is open-sourced software licensed under the [MIT license](https://www.google.com/search?q=LICENSE).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance86

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

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 ~0 days

Total

4

Last Release

71d ago

Major Versions

1.0.1 → 2.0.02026-05-14

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5558411?v=4)[Jee Afwazi A](/maintainers/wzije)[@wzije](https://github.com/wzije)

### Embed Badge

![Health badge](/badges/wzije-indo-area/health.svg)

```
[![Health](https://phpackages.com/badges/wzije-indo-area/health.svg)](https://phpackages.com/packages/wzije-indo-area)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[wearepixel/laravel-cart

A cart implementation for Laravel

1374.8k](/packages/wearepixel-laravel-cart)

PHPackages © 2026

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