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 Smart Relations Laravel Package

masterfri/laravel-smart-relations

Laravel Smart Relations streamlines Eloquent relationship management in Laravel with smarter helpers and conventions for defining, querying, and working with model relations, reducing boilerplate and keeping model code cleaner and easier to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and publish assets — composer require <vendor>/<package>, then php artisan vendor:publish --provider="<Vendor>\<Package>\<Package>ServiceProvider" (config + migrations). Run php artisan migrate before touching the API.
  2. Read these three files first, in order:
    • config/<package>.php — every behavior toggle lives here; skim keys and defaults before writing code.
    • The migration stub — tells you which tables/columns the package owns and which morph columns v1.2 added.
    • The contract/interface the package resolves from the container — that's your extension surface.
  3. First use case (v1.2 flow): attach the package trait to two different parent models, create one child record against each, then reload with the polymorphic relation eager loaded. If both resolve and eager loading produces a constant query count, your wiring is correct.
// app/Models/Post.php and app/Models/Video.php
use Vendor\Package\Concerns\HasAttachments;

class Post extends Model
{
    use HasAttachments;
}
// Tinker / first smoke test
$post  = Post::factory()->create();
$video = Video::factory()->create();

$post->attach($file);   // or whatever the package's write API is
$video->attach($file);

Post::with('attachments')->first();   // must not lazy-load per row

Implementation Patterns

Enforce the morph map immediately. Polymorphic support is only stable if you register aliases before any rows exist. Do this in a service provider, not in a model:

use Illuminate\Database\Eloquent\Relations\Relation;

public function boot(): void
{
    Relation::enforceMorphMap([
        'post'  => \App\Models\Post::class,
        'video' => \App\Models\Video::class,
    ]);
}

With enforceMorphMap, a missing alias throws instead of silently writing a FQCN into the database.

Migrations — pick the right morph helper. v1.2 relations require the composite (type, id) pair to be indexed; Laravel's helpers do this for you, and the choice matters:

$table->morphs('attachable');          // unsignedBigInteger + index (default)
$table->nullableMorphs('attachable');  // when the child can be orphaned
$table->uuidMorphs('attachable');      // UUID parents
$table->ulidMorphs('attachable');      // ULID parents

If your parent keys are uuid/ulid, the package's default migration will produce a type mismatch — swap the helper before running migrations in any environment you care about.

Eager-load the polymorphic side explicitly. morphTo cannot be solved in one query; it needs one query per distinct type. Batch it at the controller level:

$items = Attachment::query()
    ->with('attachable')
    ->latest()
    ->paginate(50);

Constrain on the type, not the class, when filtering:

Attachment::query()
    ->whereHasMorph('attachable', [Post::class], fn ($q) => $q->published())
    ->get();

Passing a narrowed array of types to whereHasMorph is the difference between two targeted queries and a full scan.

Wrap writes in a transaction when a parent and its polymorphic children are created together. Morph rows have no FK constraint, so a failed child insert leaves a half-populated parent with no database-level complaint.

Policy/authorization pattern: resolve authorization through the parent, not the child. A AttachmentPolicy@view that delegates to $attachment->attachable keeps rules in one place and survives new parent types being added.

Testing: one factory per morph type plus a shared trait test that asserts the relation round-trips. A polymorphic feature that works for Post and breaks for Video is the most common regression class in packages with this shape.

Gotchas and Tips

  • Never change a morph alias after data exists. post → App\Models\Post is a one-way door; renaming the alias orphans every existing row. Treat the map in the provider as a schema.
  • No foreign keys, no cascades. Polymorphic columns cannot use constrained(). Deleting a parent silently leaves orphan children. Add a scheduled prune job or model deleting hooks — the package won't do it for you.
  • morphTo is always N+1 when lazy loaded, and Laravel won't warn you. Model::preventLazyLoading() in AppServiceProvider::boot() (non-production) catches this early; treat the resulting exception as a real defect.
  • $morphClass / getMorphClass() overrides are the escape hatch when you must rename a class without rewriting rows — but they interact badly with enforceMorphMap if you forget one. Keep the alias identical to the map key.
  • Nullable morph columns are a trap in queries. whereHasMorph on a nullable relation excludes rows where the morph pair is null; use orWhereDoesntHaveMorph (or explicit orWhereNull) to keep them.
  • Global scopes on parent models don't propagate to the morph query. A soft-deleted parent will still be returned by $child->attachable unless you handle it; withTrashed()/withoutGlobalScopes() on the relation is usually needed.
  • Index the query direction you actually use. The default index is (type, id). If you mostly query "all children of this parent", add a composite index on (attachable_type, attachable_id, created_at) for paginated listings.
  • Debugging: dump the resolved map with Relation::morphMap(), and log the pair with $child->getAttributes()['attachable_type']. A stale config cache (php artisan config:clear) is a frequent cause of "the map isn't taking effect" — the morph map is registered in a provider, but a cached config bootstraps the provider before your map is applied in some setups.
  • Extension points to prefer over forking: the config file's model/table overrides, the container binding for the package's contract, and published migrations. Reach for class extension only after all three.
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.
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
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style