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

Model Shared Laravel Package

inisiatif/model-shared

Shared Laravel models for Inisiatif Zakat Indonesia covering occupation, education level, geographic regions (country down to village), and marital status, plus a Donor model with configurable branch and employee relations.

View on GitHub
Deep Wiki
Context7

Getting Started

This is an internal, domain-specific package for Indonesian zakat/NGO apps. Treat the changelog as the primary documentation — the README only covers installation and the dynamic-relation trick.

1. Install and pin

composer require inisiatif/model-shared:^2.10

Pin a minor version. Releases land frequently and several have been pure typo/bug fixes (2.7.5/2.7.6 table-key typos, 2.9.1 migration-registrar typo, 2.8.3 id/uuid fix), so ^2.10.6 is safer than *. 2.10.6 is purely additive (new models), so it's a low-risk bump from 2.10.x — but it still adds migrations to your batch (see Gotchas).

2. Find out what you actually got, before migrating

The package auto-registers a service provider (and migrations) via Laravel discovery. Before running php artisan migrate against anything real:

php artisan vendor:publish --provider="Inisiatif\ModelShared\ModelSharedServiceProvider"  # if supported
ls vendor/inisiatif/model-shared/src/Models
ls vendor/inisiatif/model-shared/database/migrations

Read the migrations. The provider is named ...Registrar classes per model group (Donor, Partner, Account/FundingSource, etc. per the release notes), so migrations ship inside the package and run as part of your app's migration batch. Use php artisan migrate --pretend first on an existing database.

2.10.6 ("menambahkan beberapa model baru") is the case where this matters most: the release note doesn't name the new models, so ls src/Models and git diff the migrations directory against 2.10.5 is the only way to know what tables and columns you just inherited.

3. Look at these files first

  • src/Models/ — Donor, Partner, Degree, Occupation, MaritalStatus, Region/Province/District/Village, Bank, Outflow, Donation, FundingCategory, FundingType — plus whatever 2.10.6 added.
  • src/Models/Concerns/ or a base model — check $table, $primaryKey, $incrementing, $keyType, $timestamps. Release 2.7.4 added getTable()-style helpers and getPackageRegistered(); those are the cheapest way to introspect what's registered.

4. First use case: the donor form

Reference data (occupation, degree, marital status, region) is the lowest-risk entry point — read-only lookups with no coupling to your schema:

use Inisiatif\ModelShared\Models\Degree;
use Inisiatif\ModelShared\Models\Province;

$degrees   = Cache::rememberForever('ref.degrees', fn () => Degree::orderBy('urutan')->get(['id', 'name']));
$provinces = Cache::rememberForever('ref.provinces', fn () => Province::orderBy('name')->get(['id', 'name']));

Wire these into Blade/Inertia selects first. Only then tackle Donor and the financial models (Donation, Outflow, FundingCategory), which are opinionated and much harder to bend.

Implementation Patterns

Dynamic relations for Donor — do it once, in AppServiceProvider::boot()

The package deliberately doesn't know about your Branch or Employee models. Register the relations in your application provider, not a package provider, and before anything queries Donor:

use Inisiatif\ModelShared\Models\Donor;

public function boot(): void
{
    Donor::resolveRelationUsing('branch', fn (Donor $m) =>
        $m->belongsTo(\App\Models\Branch::class, 'branch_id'));

    Donor::resolveRelationUsing('employee', fn (Donor $m) =>
        $m->belongsTo(\App\Models\Employee::class, 'employeeid'));
}

The FK names (branch_id vs employeeid) are inconsistent in the upstream example — confirm against the actual migration columns, don't copy the README blindly.

Region cascade

Build province → regency → district → village as a dependent-select chain, one query per level:

$regencies = Regency::where('province_id', $request->integer('province_id'))->orderBy('name')->get();

For search boxes (release 2.5.0 added a region search API), check vendor/inisiatif/model-shared/routes/ — if routes are auto-loaded you may be exposing public endpoints unintentionally. Disable/scope them in your provider if so.

Reference data as an enum-like layer

Wrap shared reference models in your own thin accessors so a future package swap or schema change touches one file:

final class MaritalStatuses
{
    public static function options(): array
    {
        return MaritalStatus::query()->pluck('name', 'id')->all();
    }
}

Extending rather than editing

Prefer subclassing with an explicit table when your app needs extra columns:

class Donor extends \Inisiatif\ModelShared\Models\Donor
{
    protected $table = 'donors';        // verify via (new \Inisiatif\ModelShared\Models\Donor)->getTable()
    protected $fillable = [...];        // shared models are usually $guarded = []
}

If you already have a donors table, do not install the package's donor migration; subclass and keep your schema, then use resolveRelationUsing for the joins.

Testing

There are no factories. Build your own fixtures and use RefreshDatabase so the package migrations run in CI, which is also your earliest warning that a version bump changes a column — or, as in 2.10.6, adds whole new tables:

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

Upgrades

Read the release notes as a migration checklist (they are written as commit subjects: "menambahkan email donor", "menambahkan donor_phone_id ke dalam migrasi donor", "menambahkan beberapa model baru"). Diff the package's database/migrations between tags, then run php artisan migrate --pretend in staging. "Added models" releases add tables — decide per model whether you want the package's table or will disable that registrar because your app already owns it.

Gotchas and Tips

  • Migrations run inside your app's batch. This is the biggest operational risk. A package upgrade can add columns to your tables (e.g. donor_phone_id, email on donors) or create entirely new tables you never asked for — 2.10.6 is exactly this, dressed up as a feature release. Take a backup and review diffs; never let composer update and migrate happen together unreviewed in production.
  • "New models" is never only new PHP classes. Expect a migration and a registrar entry per model, plus possibly a new dynamic-relation or enum-ish reference table. Budget review time for an additive bump; the changelog line tells you nothing about the schema delta.
  • Mixed primary key types. Partner got HasUuids in 2.8.2, then 2.8.3 "fixed id and uuid". Assume inconsistency across models — including the freshly added 2.10.6 ones: check $keyType/$incrementing on each model before adding a FK column, or you'll get integer-vs-char join mismatches that fail silently or throw on strict MySQL.
  • Dynamic relation pitfalls. resolveRelationUsing is invisible to static analysis and IDEs, collides with an existing branch()/employee() method if one exists, and must be registered before with('branch') is used — including in queued jobs, where the app provider does re-boot, but in any custom-bootstrapped console command it may not. Add a test asserting Donor::first()->branch resolves.
  • Table name / key typos have shipped repeatedly (2.7.5→2.7.6 rolled back a table key change; 2.8.1 fixed a PartnerModelRegistrar typo). If a model suddenly queries the wrong table after an upgrade, check the registrar class first. Newly added models are the least battle-tested — a typo in one of them is the most likely failure mode in 2.10.6.
  • Env-dependent config. 2.9.2 was "perbaikan salah env" — a config value reads the wrong env key. After install, dump the package config (config/model-shared.php if published) and confirm every value resolves in your .env before debugging application code.
  • spatie/laravel-query-builder is a hard dependency. If your app pins a different major, Composer will fight you. Resolve that conflict at install time rather than patching around it.
  • Village table is large (~83k rows). Never Region::all(). Index province_id/regency_id lookups and paginate any admin UI. Consider caching province/regency lists only.
  • Don't use shared models as your aggregate root for money. Donation, DonationDetail, Outflow, FundingCategory encode someone else's accounting assumptions. Read the migrations, then either adopt them wholesale (including their status columns) or keep your own and only reuse Donor, Region, and the reference tables.
  • Vendor risk is real. Zero stars, one organisation, Indonesian-only docs, no external dependents. Mitigate with a thin anti-corruption layer (your own accessor classes/subclasses) so replacing it means editing one directory, and keep a fork branch ready — you will likely need to patch a typo yourself rather than wait for a release.
  • Extension points worth knowing: resolveRelationUsing for inbound relations, subclassing with $table/$fillable overrides, getTable()/getPackageRegistered() from 2.7.4 for introspection (use the latter to enumerate what 2.10.6 registered), and the per-model registrar classes if you need to disable a migration on a project that already owns that table.
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.
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support