moneo/laravel-morphmap

Custom morphMap support for Laravel Framework

Installs: 1 602

Dependents: 0

Suggesters: 0

Security: 0

Stars: 35

Watchers: 1

Forks: 2

Open Issues: 1

pkg:composer/moneo/laravel-morphmap

v2.0.0 2026-02-16 11:26 UTC

This package is auto-updated.

Last update: 2026-02-16 11:27:41 UTC


README

Laravel Custom Morph Map

Tests Latest Stable Version License

Use different morph maps for different relationships on the same model.

By default, Laravel's Relation::morphMap() applies globally to all polymorphic relationships. This package lets you define a custom morph map per relationship, so different polymorphic relations on the same model can use different type aliases.

Requirements

Version PHP Laravel
2.x ^8.1 10, 11, 12
1.x >=8.0 8, 9, 10, 11

Installation

composer require moneo/laravel-morphmap

No service provider registration is needed. Just use the trait.

Usage

Add the HasCustomMorphMap trait to your model and define the $customMorphMap property in your constructor.

The array keys are the related model's fully qualified class name, and the values are the morph type alias you want stored in the database for that relationship:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Moneo\LaravelMorphMap\Database\Eloquent\Concerns\HasCustomMorphMap;

class Post extends Model
{
    use HasCustomMorphMap;

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);

        // Define custom morph types per related model.
        // Key: related model class, Value: morph type alias
        $this->customMorphMap = [
            Category::class => 'post',
        ];

        // Optional: override the default morph type for all other relationships.
        // If not set, defaults to the fully qualified class name (static::class).
        // $this->defaultMorphType = 'post';
    }

    /**
     * Tags relationship — no custom mapping defined for Tag,
     * so the default morph type (App\Models\Post) will be used.
     */
    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

    /**
     * Categories relationship — custom mapping defined above,
     * so 'post' will be stored as the morph type.
     */
    public function categories(): MorphToMany
    {
        return $this->morphToMany(Category::class, 'categoryable');
    }
}

Inverse Relationships (morphedByMany)

The trait also supports morphedByMany for inverse polymorphic many-to-many relationships:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Moneo\LaravelMorphMap\Database\Eloquent\Concerns\HasCustomMorphMap;

class Category extends Model
{
    use HasCustomMorphMap;

    public function posts(): MorphToMany
    {
        return $this->morphedByMany(Post::class, 'categoryable');
    }

    public function videos(): MorphToMany
    {
        return $this->morphedByMany(Video::class, 'categoryable');
    }
}

How It Works

The trait uses Laravel's initializeHasCustomMorphMap() convention to automatically set the default morph type when the model is constructed. No need to call parent::__construct() before setting properties -- the trait handles initialization automatically.

When you call morphToMany() or morphedByMany(), the trait:

  1. Looks up the related model class in your $customMorphMap array
  2. If found, registers that alias in Laravel's global morph map
  3. If not found, uses the $defaultMorphType (which defaults to the model's FQCN)
  4. Delegates to the parent relationship method

Example Scenario

Suppose your taggables table uses fully qualified class names, but your categoryables table uses short aliases:

taggables

tag_id taggable_id taggable_type
1 1 App\Models\Post
2 1 App\Models\Video

categoryables

category_id categoryable_id categoryable_type
1 1 post
2 1 video

With this package, both table structures work seamlessly on the same model.

Testing

composer test

Static Analysis

composer analyse

Code Style

# Check style
composer format:check

# Fix style
composer format

Contributing

Contributions are always welcome! Please see CONTRIBUTING.md for details.

Thanks to all of our contributors!

License

The MIT License (MIT). Please see License File for more information.