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

Nova Tab Laravel Package

arsenaltech/nova-tab

ArsenalTech Nova Tab adds configurable tabs to Laravel Nova resource detail pages, letting you group fields into cleaner, navigable sections. Define tabs and assign fields to reduce clutter and make complex resource views easier to scan.

View on GitHub
Deep Wiki
Context7

Getting Started

What changed in 0.2 and why it matters first

The single breaking change — replacing an abstract base class with a trait — is the first thing to internalise. If you were on 0.1, your integration point was class Foo extends PackageAbstractClass. On 0.2 it is class Foo { use PackageTrait; }. There is no upgrade path that preserves both, so plan the bump as a deliberate refactor rather than a composer update.

Minimal steps

  1. composer require <vendor>/<package>:^0.2 (pin explicitly — see the versioning note below).
  2. Open the trait source file itself before anything else. With an abstract class the public/protected surface was at least partially discoverable via the parent's method signatures; with a trait, the contract lives in the trait body and in whatever interfaces the package tells you to implement alongside it. Read the trait top to bottom, plus any @property / @method docblocks, since static analysis will lean on those.
  3. Check the package's own test suite for the canonical "host class" — the fixture class that uses the trait is effectively the reference implementation and is usually more accurate than the README.
  4. Check the CHANGELOG/UPGRADE notes for 0.2 for any interface you are now expected to implement that previously came for free via the abstract parent.
  5. Wire it into a single, low-risk class first (a throwaway test double or an isolated model), not your most-inherited model.

First use case

The typical shape post-0.2:

class Order extends Model
{
    use PackageTrait;
}

Because your class no longer extends a package class, it can extend whatever it needs to — Model, FormRequest, Mailable, Command, your own base class. That is the whole point of the change: the package no longer occupies your single inheritance slot. Traits in Laravel are the idiomatic answer for exactly this, which is why the maintainer made the switch.

Implementation Patterns

Trait on Eloquent models

The most common landing spot. If the trait assumes model context (attributes, $this->getAttribute(), casts, relationships), confirm it declares its requirements in a docblock or an abstract-method-style contract. Traits cannot declare abstract methods enforced at the language level in the way an abstract class can — the enforcement usually moves to a runtime method_exists check or an interface you must implement. Look for either.

Trait on non-model classes

The upside of the change: the same trait can now be mixed into a Job, a Console Command, a FormRequest, or a plain service object. If your 0.1 code had a wrapper class solely to work around the base-class requirement, delete it.

Layering your own base class underneath

The standard pattern now:

abstract class BaseModel extends Model
{
    // your app-wide model concerns
}

class Order extends BaseModel
{
    use PackageTrait;
}

This is the migration you could not do in 0.1. If you were previously forced to choose between the package base class and your own, 0.2 removes that constraint — worth calling out to your team as a net win despite the breaking change.

Conflict resolution and aliasing

With traits, method collisions are now your problem rather than resolved by the inheritance chain. Use the insteadof / as syntax to disambiguate and to keep a method's original visibility:

use PackageTrait, HasAuditLog {
    PackageTrait::boot insteadof HasAuditLog;
    HasAuditLog::boot as bootAuditLog;
}

If the package trait defines a method your class already has, PHP fatal-errors on the collision. On 0.1 the subclass simply overrode the parent. Audit for method-name overlap when you roll this out — especially generic names like boot, initialize, scope*, toArray, getAttribute.

Boot logic

If the abstract class had a constructor doing setup, that work has to live somewhere in the trait. The Laravel-idiomatic version is a boot{TraitName} method picked up by Model::bootTraits(). Check whether 0.2 follows that convention; if it instead relies on an initialize{TraitName} hook or a plain constructor, your instantiation path matters.

Testing

Trait-based packages are easiest to test by mixing the trait into an anonymous or fixture class. If the package ships its own fixture, reuse it rather than inventing one.

Gotchas and Tips

instanceof no longer works. Any code doing $thing instanceof PackageAbstractClass is now dead. There is no trait type. The replacement is an interface — check whether 0.2 ships one and type-hint that instead. If it does not, you will need to add a marker interface of your own and apply it to every host class.

Type-hints and DI. A trait cannot be a parameter type, cannot be resolved from the container, and cannot be bound in a service provider. If 0.1 code injected or resolved the base class, that call site needs rethinking — usually you now inject whatever dependency the trait's methods actually need.

Constructor conflicts. If the trait declares __construct and your class already has one, they collide. Laravel models, controllers, and commands all define constructors, so this bites immediately. Confirm the trait has no constructor; if it does, use insteadof/as or move to a boot hook.

Property conflicts. Traits can declare properties, and redeclaring an identical property in both trait and class is a fatal error in older PHP (allowed only if compatible in more recent versions). If you have a $guarded, $table, or $fillable on your class and the trait declares the same, expect a hard failure rather than a silent merge.

parent:: is gone. Every parent::foo() call in your 0.1 host classes must become $this->foo() or an aliased call. Grep for parent:: in any class that previously extended the package.

Static analysis regressions. Larastan/PHPStan understand traits but do not infer property/method provenance as reliably as they do inheritance. Expect a spike in "undefined method" reports right after the bump. @mixin and @property docblocks on the host class are the usual workaround; @use on the trait is the other. Budget time for this — it is the most common source of "the upgrade works but the CI is red" frustration.

IDE and autocomplete. Same root cause. Methods injected via a trait show up once the IDE's index catches up; the trait's @method annotations drive the quality of the experience. If completion is poor, it is usually a missing docblock in the package, not your setup.

0.2 is pre-1.0. Under semver, 0.x minor bumps are permitted to break, so ^0.1 → ^0.2 is a legitimate breaking release and not a maintainer error. Pin to ^0.2 deliberately, and read every subsequent 0.x changelog before bumping — the class→trait migration is unlikely to be the last structural change before 1.0.

Debugging checklist when the trait "does nothing".

  • Trait not used in the class actually being instantiated (common with inheritance: a parent uses it, the child is fine — but a sibling branch isn't).
  • Trait used inside a class that also aliases the method away.
  • Boot hook named incorrectly (bootPackageTrait vs the actual trait basename) so Laravel never calls it — trait boot methods are matched by name, so renaming the trait or aliasing the import silently disables setup.
  • Method visibility changed by an as protected alias, making it invisible to the caller.
  • Cached config/routes: php artisan optimize:clear after the upgrade, since a stale cached class map can mask the change.

Extension points. Without a base class there is no longer an obvious "override this method" seam. If the package relies on protected methods intended for overriding, those are now reachable only by defining the same method in your host class — you cannot call through to the trait's version without aliasing it first (use PackageTrait { foo as protected traitFoo; }). That aliasing trick is the replacement for parent::foo() and is worth standardising on across your codebase.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect