PHPackages                             hdaklue/laravel-dto-morph-cast - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. hdaklue/laravel-dto-morph-cast

ActiveLibrary[Database &amp; ORM](/categories/database)

hdaklue/laravel-dto-morph-cast
==============================

MorphCast for Laravel Validated DTO - Dynamic polymorphic casting for Eloquent models

v1.1.2(10mo ago)39MITPHPPHP ^8.2CI passing

Since Aug 28Pushed 10mo agoCompare

[ Source](https://github.com/hdaklue/laravel-dto-morph-cast)[ Packagist](https://packagist.org/packages/hdaklue/laravel-dto-morph-cast)[ RSS](/packages/hdaklue-laravel-dto-morph-cast/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (5)Versions (5)Used By (0)

Laravel DTO MorphCast
=====================

[](#laravel-dto-morphcast)

This package is a plugin for the [WendellAdriel/laravel-validated-dto](https://github.com/WendellAdriel/laravel-validated-dto) package.

[![Latest Version on Packagist](https://camo.githubusercontent.com/21a831336015c402531b7062dd4222708ca83d3d60ed7ca16aa94f638cd3cd67/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6864616b6c75652f6c61726176656c2d64746f2d6d6f7270682d636173742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hdaklue/laravel-dto-morph-cast)[![Tests](https://github.com/hdaklue/laravel-dto-morph-cast/workflows/run-tests/badge.svg)](https://github.com/hdaklue/laravel-dto-morph-cast/actions)[![Total Downloads](https://camo.githubusercontent.com/9788f48f4063be3551afcb748d054a80537b2cf6c5495e33515ff745056e3feb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6864616b6c75652f6c61726176656c2d64746f2d6d6f7270682d636173742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/hdaklue/laravel-dto-morph-cast)

A powerful MorphCast plugin for Laravel Validated DTO that provides dynamic polymorphic casting for Eloquent models. This package allows you to dynamically cast data to different Eloquent model instances based on morphable type information within your DTOs.

Features
--------

[](#features)

- **Dynamic Model Resolution**: Automatically resolves model classes using Laravel's morph map
- **Polymorphic Casting**: Cast data to different model types based on morph type keys
- **Sensitive Data Protection**: Hide sensitive fields from being cast to model instances
- **Seamless Integration**: Works perfectly with Laravel Validated DTO package
- **Type Safety**: Validates model classes and throws meaningful exceptions
- **Convention Based**: Follows Laravel's morphable naming conventions

Installation
------------

[](#installation)

You can install the package via Composer:

```
composer require hdaklue/laravel-dto-morph-cast
```

Requirements
------------

[](#requirements)

- PHP 8.2 or higher
- Laravel 11.0 or higher
- Laravel Validated DTO 4.0 or higher

Usage
-----

[](#usage)

### Basic Usage

[](#basic-usage)

The MorphCast class automatically resolves polymorphic relationships in your DTOs. Here's how to use it:

```
use HDaklue\LaravelDTOMorphCast\MorphCast;
use WendellAdriel\ValidatedDTO\ValidatedDTO;
use WendellAdriel\ValidatedDTO\Casting\Castable;

class MyDTO extends ValidatedDTO implements Castable
{
    public function casts(): array
    {
        return [
            'commentable' => new MorphCast(), // Will look for 'commentable_type' key
            'user' => new MorphCast(['password', 'api_token']), // Hide sensitive fields
        ];
    }
}
```

### Setting Up Morph Maps

[](#setting-up-morph-maps)

First, define your morph map in a service provider:

```
use Illuminate\Database\Eloquent\Relations\Relation;

// In a service provider boot method
Relation::morphMap([
    'post' => App\Models\Post::class,
    'video' => App\Models\Video::class,
    'user' => App\Models\User::class,
]);
```

### DTO Data Structure

[](#dto-data-structure)

Your DTO data should include the morph type key:

```
$data = [
    'commentable_type' => 'post', // This maps to App\Models\Post via morph map
    'commentable' => [
        'id' => 1,
        'title' => 'My Post Title',
        'content' => 'Post content...',
        'created_at' => '2024-01-01 00:00:00'
    ]
];

$dto = new MyDTO($data);

// The 'commentable' property will be cast to a Post model instance
$post = $dto->commentable; // instanceof App\Models\Post
echo $post->title; // "My Post Title"
```

### Hiding Sensitive Data

[](#hiding-sensitive-data)

You can hide sensitive fields from being cast to the model by passing them as an array to the constructor:

```
use HDaklue\LaravelDTOMorphCast\MorphCast;
use WendellAdriel\ValidatedDTO\ValidatedDTO;
use WendellAdriel\ValidatedDTO\Casting\Castable;

class MyDTO extends ValidatedDTO implements Castable
{
    public function casts(): array
    {
        return [
            'user' => new MorphCast(), // Normal casting
            'sensitive_user' => new MorphCast(['password', 'secret_key']), // Hide sensitive fields
        ];
    }
}
```

You can also use Laravel's array-based casting syntax:

```
public function casts(): array
{
    return [
        'user' => MorphCast::class,
        'sensitive_user' => [MorphCast::class, ['password', 'api_token', 'secret']],
    ];
}
```

When sensitive fields are specified, they will be excluded from the `forceFill()` operation:

```
$data = [
    'sensitive_user_type' => 'user',
    'sensitive_user' => [
        'id' => 1,
        'name' => 'John Doe',
        'email' => 'john@example.com',
        'password' => 'secret123',        // This will be hidden
        'api_token' => 'token123',        // This will be hidden
        'created_at' => '2024-01-01 00:00:00'
    ]
];

$dto = new MyDTO($data);
$user = $dto->sensitive_user;

// Only non-sensitive data is available
echo $user->name; // "John Doe"
echo $user->email; // "john@example.com"
// $user->password and $user->api_token are not set
```

### Naming Conventions

[](#naming-conventions)

By default, MorphCast follows Laravel's polymorphic relationship conventions:

- For a property named `commentable`, it looks for `commentable_type`
- For a property named `imageable`, it looks for `imageable_type`

### Custom Key Resolution

[](#custom-key-resolution)

You can extend MorphCast to customize key resolution:

```
class CustomMorphCast extends MorphCast
{
    protected function resolveMorphKeys(string $property): array
    {
        return [
            "custom_{$property}_type", // Custom type key format
            "custom_{$property}_id",   // Custom ID key format
        ];
    }
}
```

### Error Handling

[](#error-handling)

MorphCast provides clear error messages for common issues:

```
// Missing morph type key
// Throws: "MorphCast: Missing morph type key [commentable_type] in DTO data."

// Invalid model class
// Throws: "MorphCast: Invalid model class [InvalidClass]."
```

How It Works
------------

[](#how-it-works)

1. **Trace Analysis**: Uses debug backtrace to access the parent DTO's data array
2. **Key Resolution**: Automatically determines morph type keys based on property names
3. **Model Resolution**: Uses Laravel's morph map to resolve the actual model class
4. **Validation**: Ensures the resolved class exists and extends Eloquent Model
5. **Instantiation**: Creates and fills the model instance with the provided data

Performance Considerations
--------------------------

[](#performance-considerations)

### Minimal Debug Backtrace Usage

[](#minimal-debug-backtrace-usage)

This package uses `debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2)` with a strict limit of 2 levels to access the parent DTO's data array. This approach provides several benefits:

- **Minimal Overhead**: Only traces 2 stack frames (current + parent), not the entire call stack
- **Targeted Access**: Specifically retrieves only the object data needed for casting
- **Auto-Resolution**: Eliminates the need for manual configuration or explicit passing of morph type information
- **Clean API**: Maintains a simple, intuitive interface without complex setup requirements

The small performance cost of this limited backtrace is offset by the significant flexibility gain of automatic morph type resolution, making polymorphic casting seamless and convention-based.

Testing
-------

[](#testing)

```
composer test
```

Code Style
----------

[](#code-style)

This package uses Laravel Pint for code formatting:

```
composer lint
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

If you discover a security vulnerability, please send an e-mail to .

Credits
-------

[](#credits)

- [Hassan Ibrahim](https://github.com/hdaklue)
- Built as an extension for [Laravel Validated DTO](https://github.com/WendellAdriel/laravel-validated-dto)

License
-------

[](#license)

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

Related
-------

[](#related)

- [Laravel Validated DTO](https://github.com/WendellAdriel/laravel-validated-dto) - The main package this extends

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance54

Moderate activity, may be stable

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

4

Last Release

305d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/107682410?v=4)[Hassan Ibrahim](/maintainers/hdaklue)[@hdaklue](https://github.com/hdaklue)

---

Top Contributors

[![hdaklue](https://avatars.githubusercontent.com/u/107682410?v=4)](https://github.com/hdaklue "hdaklue (8 commits)")

---

Tags

data-transfer-objectlaravel-packagelaraveleloquentdata-transfer-objectdtocastingmorphpolymorphic

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/hdaklue-laravel-dto-morph-cast/health.svg)

```
[![Health](https://phpackages.com/badges/hdaklue-laravel-dto-morph-cast/health.svg)](https://phpackages.com/packages/hdaklue-laravel-dto-morph-cast)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.4M96](/packages/mongodb-laravel-mongodb)[kirschbaum-development/eloquent-power-joins

The Laravel magic applied to joins.

1.6k32.6M46](/packages/kirschbaum-development-eloquent-power-joins)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k332.0k1](/packages/cybercog-laravel-love)[cybercog/laravel-ownership

Laravel Ownership simplify management of Eloquent model's owner.

9029.2k3](/packages/cybercog-laravel-ownership)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.3M18](/packages/reedware-laravel-relation-joins)[esensi/model

The base model traits of Esensi

20167.0k1](/packages/esensi-model)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
