framework icon indicating copy to clipboard operation
framework copied to clipboard

[12.x] Add a Custom for `AsFluent` Cast Implementation

Open michaelnabil230 opened this issue 7 months ago • 1 comments

This PR introduces a new Eloquent castable class Illuminate\Database\Eloquent\Casts\AsFluent that enables casting JSON columns into Illuminate\Support\Fluent objects (or any custom subclass of Fluent). This feature provides developers with a fluent, object-like interface for interacting with JSON attributes stored in the database, with optional support for invoking a method on the Fluent instance after hydration.


📌 Why This Is Useful

Laravel currently offers JSON casting through native array, object, or custom cast classes, but it lacks a built-in way to cast JSON directly into a Fluent object or a custom class extending Fluent. This cast implementation addresses that by:

  • Allowing developers to wrap JSON attributes in a Fluent or custom Fluent-like class.
  • Optionally invoking a method on the hydrated instance immediately after casting.
  • Providing a clean, reusable way to handle dynamic data structures while keeping the type safety and clarity of Laravel's Eloquent casting system.

📦 Usage Example

In your Eloquent model:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\AsFluent;

class User extends Model
{
    protected $casts = [
        'preferences' => AsFluent::using(CustomFluent::class),
        'settings'    => AsFluent::using(CustomFluent::class, 'transformSettings'),
    ];
}

AsFluent::using(string $class, ?string $method = null): string

A convenience static method for generating the cast definition string in the format:

AsFluent::class . ':' . $class . ',' . $method;

✅ Example Custom Fluent Class

use Illuminate\Support\Fluent;

class CustomFluent extends Fluent
{
    public function transformSettings()
    {
        // Example transformation logic
        return $this->map(fn ($value) => strtoupper($value));
    }
}

📋 Benefits

  • Provides a native, reusable cast class for JSON-to-Fluent mapping.
  • Keeps Laravel's casting ecosystem consistent and flexible.
  • Simplifies working with dynamic data structures stored as JSON.
  • Adds optional transformation step via method invocation.

michaelnabil230 avatar Jun 16 '25 23:06 michaelnabil230

Your description might be off. It looks like you are adding AsFluent case, which has already been added in #56046. However, what your code actually does, is adding a using() method to the existing class. Maybe you could make this more clear—that would be great 😉

shaedrich avatar Jun 16 '25 23:06 shaedrich

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!

taylorotwell avatar Jun 17 '25 13:06 taylorotwell

May I offer a quick suggestion: maybe, add another caster, named like AsAlwaysFluent::class?

The difference is that the attribute would always be Fluent instance, even if the database has null in this field. To get rid of constant checking if the field is not null…

// before:
$err = $file->report?->get('uploaded.error');

// after:
$err = $file->report->get('uploaded.error');

mityukov avatar Aug 19 '25 12:08 mityukov