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 Eloquent Morph To One Laravel Package

fidum/laravel-eloquent-morph-to-one

Adds a MorphToOne relationship to Laravel's Eloquent ORM, letting a model own a single polymorphic related record. Useful when a parent has exactly one morph child, mirroring MorphMany but returning a single model with lazy and eager loading support.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package via Composer:

composer require fidum/laravel-eloquent-morph-to-one

The package adds a morphToOne relationship method to Eloquent. Use it on the model that holds the polymorphic foreign key (e.g. commentable_id / commentable_type) when you want a relationship that targets one specific morph type instead of any type.

First use – define a typed relation on a Comment model:

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    public function post()
    {
        return $this->morphToOne(Post::class, 'commentable');
    }
}

Now $comment->post returns the related Post model only when commentable_type is Post::class; otherwise it returns null. This is the package’s core value: type-safe, eager-loadable relations out of a polymorphic column.

Look first at the package’s README for the exact morphToOne signature. The release 2.6.0 adds support for Laravel 13.x and PHP 8.5 – if you are on those versions, use this release or later.

Implementation Patterns

Multiple typed relations on the same morph column

class Comment extends Model
{
    public function post()
    {
        return $this->morphToOne(Post::class, 'commentable');
    }

    public function video()
    {
        return $this->morphToOne(Video::class, 'commentable');
    }
}

Eager loading

$comments = Comment::with('post')->get();

Only comments whose commentable_type matches Post will have a non-null post.

Query constraints

$comments = Comment::whereHas('post', function ($query) {
    $query->where('published', true);
})->get();

Saving through the relation

$comment->post()->associate($post);
$comment->save();

This sets both commentable_id and commentable_type to the Post model. Use dissociate() to clear the relation.

Mixing with standard morphTo

Keep a generic morphTo for cases where you need the mixed type:

public function commentable()
{
    return $this->morphTo();
}

Then add typed morphToOne relations for convenience and type-hinting.

Gotchas and Tips

  • Not a native Eloquent method. morphToOne is provided by this package. Ensure the service provider is auto-discovered (standard for Laravel 5.5+).
  • Morph type must match the class name. If you use morph maps (Relation::enforceMorphMap()), verify the package resolves the mapped type correctly. In most cases it uses the underlying morphTo logic, so maps should work, but test if you rely on them.
  • Associating overwrites other typed relations. Because all typed relations share the same morph columns, associating a Post will make video return null. This is expected – a model can only belong to one morph target at a time.
  • Eager loading returns null for non-matching types. That’s the intended behaviour; use whereHas if you need to filter only matching records.
  • Compatibility: Version 2.6.0 supports Laravel 13.x and PHP 8.5. If you are on older Laravel/PHP versions, check the package’s composer.json for the supported range – earlier releases may still work.
  • Debugging null results: Inspect the raw *_type column value ($comment->commentable_type). A common mistake is storing a fully qualified class name while the package expects a morph alias, or vice versa.
  • Extension points: The package is intentionally small. If you need custom behaviour (e.g. additional global scopes), you can extend the returned relationship or fall back to a standard morphTo with a where clause on the type column.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource