Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Provinces Laravel Package

open-afghanistan/provinces

Open Afghanistan Provinces is a Laravel/PHP package offering structured, ready-to-use data for Afghanistan's provinces, including names, codes, and helpful lookups for seeding databases and building location-aware applications. Lightweight and easy to integrate into any PHP project.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require open-afghanistan/provinces

The package is a data-oriented Laravel add-on: expect a service provider, a migration for provinces (and usually districts), a seeder, and optionally publishable config. Because it has no dependents and a small star count, treat the published files as your source of truth rather than the README — read the migration and seeder before you run anything.

Sequence for a first integration:

php artisan vendor:publish --provider="OpenAfghanistan\Provinces\ProvincesServiceProvider"
php artisan migrate
php artisan db:seed --class="OpenAfghanistan\Provinces\Database\Seeders\ProvincesSeeder"

Check config/provinces.php (if published) for table names, model class overrides, and locale settings; check the migration for column names (name, name_dari, name_pashto, code, foreign keys); check the seeder for whether IDs are hard-coded (this matters a lot — see Gotchas).

First use case: an address form. Pull provinces once, render a <select>, then load districts for the selected province via a small JSON endpoint. That single flow exercises models, relationships, validation, and caching — the four things this package touches.

If no service provider is auto-discovered, register it manually in bootstrap/providers.php (Laravel 11+) or config/app.php. Verify with php artisan about or a tinker query against the Province model before wiring UI.

Implementation Patterns

Model access and relationships. Assume Province::with('districts')->get() and District::where('province_id', $id) as the core surface. Wrap these in your own repository or query scope rather than sprinkling package model calls through controllers — the package is small and unpinned semantically, so a thin adapter layer (App\Support\Geo) lets you swap or fork the data source later without touching views.

Cascading selects. Expose one route returning districts for a province:

Route::get('/geo/districts/{province}', fn (Province $province) =>
    DistrictResource::collection($province->districts()->orderBy('name')->get())
);

Use route-model binding on the package model directly if its primary key is stable; otherwise bind by code with getRouteKeyName() on a subclass.

Validation. Prefer Rule::exists(Province::class, 'id') / Rule::exists(District::class, 'id') over string table names so table renaming via config doesn't break validation. Add a cross-field rule that the district actually belongs to the submitted province — the package won't enforce that for you:

'district_id' => [
    'nullable',
    Rule::exists('districts', 'id')->where('province_id', $request->province_id),
],

Caching. Province/district data is effectively static. Cache the full list forever and bust only on deploy:

$provinces = Cache::rememberForever('geo.provinces', fn () =>
    Province::orderBy('name')->get(['id', 'name', 'code'])
);

For districts, cache per-province (geo.districts.{id}) to keep entries small and invalidatable individually. If you support both Dari and Pashto labels, cache per-locale.

Localized output. If the table carries name_dari / name_pashto, resolve at the resource layer via app()->getLocale() rather than duplicating rows. Add a fallback chain (name_{locale} → name) so a partially translated dataset never renders blanks in production.

Testing. Seed the package data in your test suite rather than hand-creating provinces, so ID assumptions match production:

protected function setUp(): void {
    parent::setUp();
    $this->seed(\OpenAfghanistan\Provinces\Database\Seeders\ProvincesSeeder::class);
}

If the seeder is slow or noisy, snapshot the two tables into a fixture and insert() them in setUp under RefreshDatabase.

API surface. If you expose geo data publicly, version it (/api/v1/geo/...) — the dataset's shape (ISO codes, district counts) is a compatibility concern for mobile clients regardless of what the package does.

Gotchas and Tips

  • Hard-coded IDs are the biggest risk. Many region packages seed with fixed primary keys so districts can reference provinces. That means IDs can shift between releases. Never store a province name; store id plus code, or denormalize the name onto your address record.
  • code vs id. Afghanistan uses ISO 3166-2 (AF-KAB, AF-HER, …). Validate against code if you need stability across reseeding; join on id internally. Confirm the seeder actually populates code before relying on it.
  • Seeder idempotency. db:seed run twice often fails on duplicate keys or silently doubles rows if it uses insert() without truncation. Wrap in truncate()/upsert() in your own wrapper seeder, and gate it behind --force in production deploys.
  • Published migrations are immutable. Once shipped, don't edit the published migration — add a follow-up migration for indexes (province_id, code unique) and any column changes. Otherwise migrate on a fresh clone diverges from existing environments.
  • District name collisions. Names repeat across provinces and across transliterations. Any search or "find district by name" helper must scope to a province; never rely on name uniqueness.
  • Persian/Arabic script and ZWNJ. Dari strings contain zero-width non-joiners (U+200C) and Arabic presentation variants. Search, dedupe, and title-casing will misbehave unless you normalize (NFKC + strip ZWNJ) before comparing.
  • Stale or ahead-of-schedule release metadata. The listed last release date is in the future relative to typical registry timelines — verify the actual tag against Packagist and pin an exact version ("open-afghanistan/provinces": "1.x"). With zero dependents, you are effectively the first integration test; budget time to read the source.
  • Completeness is not guaranteed. District lists for Afghanistan are politically and administratively contested and change. Treat the dataset as a starting point, add a geo_sources note or a config flag, and plan for admin-editable records (or a custom table you control) if accuracy is business-critical.
  • Foreign keys in your own tables. Use restrictOnDelete or nullable province_id — a cascading delete from a reseeded geo table could take your addresses with it. Safest: no FK at all, validate in the app layer.
  • Extension point to watch for. If config allows swapping the model class or table names, exploit it — subclass Province, add scopes/accessors, and point config at your subclass instead of forking the package.
  • Cache invalidation on deploy. If you cache geo lists forever, include the package version in the cache key (geo.provinces.v{appVersion}) so a dataset update actually surfaces.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core