akaunting/laravel-menu
A Laravel package for building and rendering menus with a fluent API. Define nested menu items, attach routes or URLs, manage active states, and render via Blade views with customizable ordering and markup.
composer require <vendor>/<package> and publish config only if you need to override defaults (php artisan vendor:publish --tag=<package>-config). Most day-to-day use works with zero config.$fillable property. As of 3.1.2 these are public, so you can read them at runtime without reflection — this is the single most useful entry point for understanding what the package will and won't mass-assign.$fillable = (new Vendor\Package\Models\Thing)->getFillable(); // or ->fillable now that it's public
create() through the package service or repository, and confirm the persisted attributes match $fillable.$fillable is public, derive validation rules or form fields directly from it instead of duplicating the attribute list:$rules = collect($model->fillable)
->mapWithKeys(fn ($attr) => [$attr => ['sometimes', 'nullable', 'string']])
->all();
if ($tenant->hasFeature('extended_profile')) {
$model->fillable = [...$model->fillable, 'vip_note', 'internal_ref'];
}
$this->assertContains('email', (new User)->fillable);
$fillable array rather than hand-maintained lists, so package upgrades propagate into your API docs automatically.$fillable from the container-resolved model to build index/create/edit screens without reflection or config duplication.protected $fillable in a class extending a package model, upgrading to 3.1.2 causes a fatal error: Access level to X::$fillable must be public (as in class Y). Change your override to public $fillable (or better, merge in the constructor/boot).$fillable is per-class state, not per-instance-per-request in a meaningful sense — mutating it in one place affects every instance resolved afterwards in that request. Mutate early (service provider boot, dedicated configurator) and never inside a loop over heterogeneous records.$fillable is a convenience for tooling, not a security boundary. Keep $guarded, casts, and FormRequest authorization doing the real work — never accept user-supplied attribute names and assume $fillable filters them appropriately.$fillable from a freshly resolved instance before any runtime mutation, and compare against what your request payload sends. Divergence there is the usual culprit.getFillable()/setFillable()), which is the likely next step if the property keeps growing.$fillable into accessor methods; that would be breaking for anyone reading the property directly, and would require moving to getFillable().How can I help you explore Laravel packages today?