ajangsupardi/laravel-postcode-my

Laravel package for seeding Malaysian address data (states, postcodes, locations) with postal codes from Pos Malaysia

Maintainers

Package info

github.com/ajangsupardi/laravel-postcode-my

pkg:composer/ajangsupardi/laravel-postcode-my

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-22 10:13 UTC

This package is auto-updated.

Last update: 2026-06-22 10:29:32 UTC


README

Laravel package for Malaysian address data (states, postcodes, locations) with postal codes — sourced from Pos Malaysia.

📄 Documentation

Data Source

This package uses postcode data from Pos Malaysia (api.pos.com.my).

Last updated: 2026-06-22 Data version: 1.0.0

The data is bundled as a static CSV file for instant seeding. To update data manually (requires ~30 minutes due to API limitations), see Update Data.

Features

  • Postcode lookup — Query locations by postcode with full address hierarchy.
  • Static data — Bundled CSV for instant seeding, no download required.
  • Idempotent seeder — Safe to run multiple times without duplicate data.
  • Hierarchical parsing — State → Postcode → Post Office → Location structure.
  • Custom models — Extend default models or use your own.
  • Laravel 11, 12, 13 support — Modern PHP 8.3+.

Requirements

  • PHP ^8.3
  • Laravel ^11.0 / ^12.0 / ^13.0

Installation

composer require ajangsupardi/laravel-postcode-my

Configuration (Optional)

Publish the config file:

php artisan vendor:publish --tag=postcode-config

This will create config/postcode.php where you can customize:

  • Storage path — Where CSV files are stored
  • Table prefix — Prefix for database table names
  • Models — Override default models with your own

Usage

1. Run Migrations & Seeder

php artisan migrate
php artisan postcode:seed

Or add to your DatabaseSeeder.php:

$this->call([
    \Ajangsupardi\PostcodeMy\Database\Seeders\PostcodeSeeder::class,
]);

The seeder uses the bundled static CSV file for instant seeding.

2. Update Data (Optional)

If you need the latest postcode data from Pos Malaysia:

php artisan postcode:download
php artisan postcode:seed

Note: The download command queries the Pos Malaysia API for each postcode (00000-99999). This process takes approximately 30 minutes due to API limitations.

After updating, consider bumping the data version in config/postcode.php:

'data_version' => '1.1.0',
'data_updated_at' => '2026-12-31',

3. Query Data

use Ajangsupardi\PostcodeMy\Models\Location;
use Ajangsupardi\PostcodeMy\Models\Postcode;
use Ajangsupardi\PostcodeMy\Models\State;

// Find locations by postcode
$locations = Location::whereHas('postcode', function ($query) {
    $query->where('postcode', '50000');
})->get();

// Find postcode with full hierarchy
$postcode = Postcode::with('state', 'locations')
    ->where('postcode', '50000')
    ->first();

// Find all postcodes in a state
$state = State::where('code', 'KL')->first();
$postcodes = $state->postcodes;

// Search locations by name
$locations = Location::name('Jalan')->get();

Database Schema

Table Columns Description
states id, name, code, timestamps Malaysian states (Johor, Kedah, etc.)
postcodes id, state_id, postcode, post_office, timestamps Postcode areas
locations id, postcode_id, name, timestamps Specific locations/streets

Hierarchical Structure

State (Negeri)
├── Postcode (Poskod)
│   ├── Post Office (Pejabat Pos)
│   └── Location (Lokasi)

Configuration Options

// config/postcode.php
return [
    'data_version' => '1.0.0',
    'data_updated_at' => '2026-06-22',
    'storage_path' => storage_path('app/postcode'),
    'table_prefix' => null,
    'models' => [
        'state' => Ajangsupardi\PostcodeMy\Models\State::class,
        'postcode' => Ajangsupardi\PostcodeMy\Models\Postcode::class,
        'location' => Ajangsupardi\PostcodeMy\Models\Location::class,
    ],
    'http' => [
        'timeout' => 60,
        'connect_timeout' => 10,
        'retry' => 3,
        'retry_delay' => 1000,
        'user_agent' => 'Mozilla/5.0 (compatible; LaravelPostcodeMy/1.0)',
    ],
];

Custom Models

You can extend the default models to add custom behavior:

namespace App\Models;

use Ajangsupardi\PostcodeMy\Models\State as BaseState;

class State extends BaseState
{
    // Add your custom methods here
}

Then update the config:

'models' => [
    'state' => App\Models\State::class,
],

License

The MIT License (MIT). Please see LICENSE for more information.