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

Laravel Model Schema Laravel Package

hnhdigital-os/laravel-model-schema

Laravel Model Schema adds schema introspection to Eloquent models, letting you read column names, types, and related metadata directly from the model. Handy for generating forms, filters, validation rules, and admin scaffolding without querying the database manually.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require hnhdigital-os/laravel-model-schema

The package ships with Laravel package discovery, so no manual provider registration should be needed on supported versions — verify in config/app.php/bootstrap/providers.php if you're on an older or custom setup.

Where to look first

  1. The package README — the exact trait name and the supported keys inside $schema (fillable vs. hidden vs. cast vs. appends flags) are defined there, and the API surface is small enough to read in one sitting.
  2. The trait's boot/initialize method in vendor/ if the README is thin — this is where $fillable, $hidden, and $casts are derived from $schema, and it's the thing you'll be debugging.
  3. An existing "rich" model in your app that already has $fillable, $hidden, and $casts — that's your conversion candidate.

First use case (conversion smoke test) Pick one model, apply the trait to your base model (or the model directly), and replace its three arrays with a single $schema. Then write a throwaway test asserting parity:

$m = new YourModel();
$this->assertSame([/* expected */], $m->getFillable());
$this->assertSame([/* expected */], $m->getCasts());
$this->assertSame([/* expected */], $m->getHidden());

If those three assertions pass, the schema is wired correctly and you can start rolling it out. Don't convert everything at once — the value of the package only shows up once most models follow the same convention.

Implementation Patterns

Base-model trait, per-model schema. Apply the package trait to an abstract App\Models\Model and declare $schema on each concrete model. This is the pattern that actually pays off day-to-day: every new model is a single readable array describing its attribute contract, and reviewers stop hunting for whether a field was forgotten in $casts or $fillable.

Schema-as-source-of-truth for tooling. Because the schema encodes name + type + visibility + mass-assignment in one place, it's a natural feed for:

  • Generating validation rules (string → nullable|string|max:255, boolean → boolean, datetime → date).
  • Building frontend form definitions / admin table column lists.
  • Producing @property docblocks via a small generator instead of running laravel-ide-helper after every change.

Keep the generator thin and outside the package — the package won't do this for you.

Incremental migration. Don't delete $casts/$fillable/$hidden in the same PR you add the trait. Leave legacy properties in place initially (the package's derived values either merge or override — confirm which by reading the trait), then remove them once the parity test above is green.

Mixing with $guarded. If your codebase uses $guarded = [] broadly, schema-defined fillable/hidden flags are meaningless unless you also remove the blanket guard. Decide per model whether mass assignment is driven by $guarded or by the schema, not both.

Testing pattern. Add a single test that loops over every model using the trait and asserts getFillable(), getCasts(), and getHidden() are non-empty / match expectations. This catches the common failure where a typo in $schema silently produces a model with no casts at all.

Factories and seeders are unaffected. The schema doesn't generate fake data; keep your existing factories and use the schema only to document what attributes exist.

Gotchas and Tips

Maintenance risk is the headline. Twelve stars and a last release in September 2023 mean you are effectively adopting a small, likely single-maintainer utility. Pin the version ("^x.y") and wrap it: apply the trait to your base model only, so if you have to fork or replace it, the blast radius is one file, not every model.

PHP / Laravel version compatibility. A 2023 package may not have been tested against PHP 8.3/8.4 or Laravel 10/11. Run the parity test above on your actual stack before committing. If it breaks on getCasts() behavior or boot timing, that's a package-internals problem, not yours.

Boot/initialize timing. Trait boot{Trait} and initialize{Trait} run at different points. If your $schema is computed dynamically (from config, a DB table, or a static:: call to another service), it may not be available at the moment the trait reads it. Prefer a static array literal; if you must be dynamic, verify getCasts() is correct on a freshly instantiated model, not just after a query.

Attribute-name collisions. Laravel already uses $attributes, $appends, $with, $dates (legacy), and $visible. The package will define its own $schema and may derive $appends — check the README that a key named appends or hidden inside your schema isn't being interpreted two different ways.

Hidden vs. visible asymmetry. $hidden and $visible are opposites in Laravel; if you set $visible on a model, hidden flags from the schema may be irrelevant. Pick one strategy per model and stick to it — this bites hardest on JSON API resources where you assumed hidden would win.

Mass-assignment errors after refactor are almost always "the field wasn't flagged fillable in the schema." The failure mode is a MassAssignmentException at runtime, not at boot, so write the parity test rather than finding out in staging.

Debugging recipe.

$m = new YourModel();
dump($m->getFillable(), $m->getCasts(), $m->getHidden());

If all return empty, the trait isn't booting (wrong trait name, applied to the wrong class, or $schema named differently than expected). If only getCasts() is wrong, your cast syntax doesn't match what the package parses — fall back to copying an example verbatim from the README.

Enums and custom casts. Custom cast classes (AsEnumCollection, AsArrayObject) are string references in $casts; make sure the schema preserves literal class strings untouched and doesn't try to interpret them.

Static analysis. PHPStan/Psalm and IDEs will still see these as magic attributes. Pair the package with generated @property docblocks or IDE-helper, otherwise you trade $fillable/$casts duplication for a wave of "undefined property" warnings.

Don't let the schema drift from migrations. The package makes attributes explicit, not safe — there's no verification against the actual table columns. If you want that guarantee, add a test that asserts Schema::getColumnListing() matches the schema keys (minus timestamps/soft-deletes).

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console