Weave Code
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

Morphism Laravel Package

cline/morphism

Central registry for Laravel polymorphic key mapping. Define which primary key column (id/uuid/ulid) each model uses in morph relations, with migration macros, optional strict enforcement, and config-based setup—ideal for package authors.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require cline/morphism
    

    Add to config/app.php under providers if not auto-discovered:

    Cline\Morphism\MorphismServiceProvider::class,
    
  2. First Use Case: Define polymorphic mappings in a config file (e.g., config/morphism.php):

    'mappings' => [
        'user' => [
            'App\Models\User' => 'id',
            'App\Models\Admin' => 'admin_id',
        ],
        'post' => [
            'App\Models\Post' => 'post_id',
            'App\Models\Draft' => 'draft_id',
        ],
    ],
    

    Use the facade in a controller or service:

    use Cline\Morphism\Facades\Morphism;
    
    $mappedId = Morphism::map('user', 1, App\Models\User::class); // Returns `1` if `User` uses `id`
    

Where to Look First

  • Config: config/morphism.php for default mappings.
  • Facade: Morphism facade for quick usage.
  • Manager: Cline\Morphism\Contracts\MorphismManager for custom implementations.
  • Tests: tests/ for edge-case examples (e.g., fallback logic).

Implementation Patterns

Core Workflows

  1. Polymorphic Key Mapping:

    • Use Morphism::map($type, $value, $modelClass) to resolve keys dynamically.
    • Example: Map a legacy user_id to Eloquent’s id or a custom admin_id:
      $userId = Morphism::map('user', $legacyId, App\Models\Admin::class);
      
  2. Reverse Mapping:

    • Use Morphism::reverseMap($type, $modelClass, $value) to convert back:
      $legacyId = Morphism::reverseMap('user', App\Models\Admin::class, 42);
      
  3. Dynamic Mappings:

    • Override mappings via config or runtime:
      Morphism::extend('user', [
          'App\Models\Guest' => 'guest_token',
      ]);
      
  4. Integration with Eloquent:

    • Use in boot() for model events:
      public function boot()
      {
          \App\Models\User::created(function ($user) {
              Morphism::map('user', $user->id, self::class); // Log mapping
          });
      }
      
  5. API Responses:

    • Normalize responses with polymorphic keys:
      $response = [
          'user' => Morphism::map('user', $user->id, get_class($user)),
          'posts' => array_map(fn ($post) => Morphism::map('post', $post->id, get_class($post)), $posts),
      ];
      

Best Practices

  • Type Safety: Prefer strongly typed map() calls with Model::class.
  • Fallbacks: Configure defaults in config/morphism.php:
    'fallback' => [
        'default_key' => 'id',
        'throw_on_missing' => false,
    ],
    
  • Caching: Enable Redis caching for performance:
    Morphism::enableCache();
    

Gotchas and Tips

Common Pitfalls

  1. Missing Mappings:

    • If throw_on_missing is false, unmapped types return null. Debug with:
      Morphism::hasMapping('user', App\Models\Unknown::class); // Returns bool
      
    • Fix: Add explicit mappings or set throw_on_missing to true.
  2. Circular Dependencies:

    • Avoid recursive mappings (e.g., UserAdminUser). Use reverseMap() sparingly.
  3. Case Sensitivity:

    • Model class names are case-sensitive. Use get_class($model) instead of hardcoded strings.
  4. Octane/Static State:

    • Avoid: Storing Morphism instances in static properties (e.g., static::$morpher).
    • Use: Dependency injection or facades (thread-safe).
  5. Configuration Overrides:

    • Runtime extensions (extend()) take precedence over config. Clear cache after changes:
      php artisan config:clear
      

Debugging Tips

  • Log Mappings:
    Morphism::debug(function ($type, $model, $key) {
        \Log::debug("Mapped $type:$model->id to $key");
    });
    
  • Inspect All Mappings:
    dd(Morphism::getMappings('user')); // Returns array of [Model => key]
    
  • Test Edge Cases:
    • Null values, non-existent models, and empty configs.

Extension Points

  1. Custom Resolvers: Implement Cline\Morphism\Contracts\Resolver for logic beyond key mapping:

    class CustomResolver implements Resolver {
        public function resolve($type, $value, $modelClass) {
            // Custom logic (e.g., API token generation)
        }
    }
    

    Register via:

    Morphism::resolver(new CustomResolver());
    
  2. Event Hooks: Listen for morphism.mapping events to intercept/reset mappings:

    event(new MorphismMappingEvent('user', App\Models\User::class, 1));
    
  3. Testing: Mock the MorphismManager in unit tests:

    $this->partialMock(MorphismManager::class, function ($mock) {
        $mock->shouldReceive('map')->andReturn(999);
    });
    

Performance

  • Cache Invalidation: Clear cache after dynamic extend() calls:
    Morphism::clearCache();
    
  • Batch Operations: Use Morphism::batchMap() for bulk conversions:
    $mapped = Morphism::batchMap('user', [1, 2, 3], App\Models\User::class);
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky