Skip to content

Conversation

DarkGhostHunter
Copy link
Contributor

@DarkGhostHunter DarkGhostHunter commented Sep 20, 2025

What?

This is basically a refactoring of the Eloquent Casts that allows to expressively configure a casts, and standardize features like encryption, caching and mapping (for iterable casts like Collections or even Fluent).

This PR solves some problems for the built-in casts:

  • Cannot disable object caching. To do that, the developer must create its own cast.
  • AsFluent, AsHtmlString and AsUri are not encryptable.
  • Cannot use map or using on an AsArrayObject, while AsCollection does.

This is opt-in, meaning, there are no changes to the already included casts, but I believe the new way to declare casts should be preferred when possible when the developer requires the new features. Aka, this PR is non breaking.

How?

The way it works is by introducing an entry-point class called To, with static methods that return an object that configure the selected cast enabled by #56687.

Note

As is reserved by PHP and won't work, that's why I decanted to use To.

use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Casts\To;

// Before
public function casts()
{
    return [
         'colors' => AsCollection::of(Color::class)   
    ];   
}

// After
public function casts()
{
    return [
         'colors' => To::collection()->of(Color::class)
    ];   
}

The static methods are:

Method Equivalent
To::fluent() AsFluent
To::htmlString() AsHtmlString
To::stringable() AsStringable
To::uri() AsUri
To::arrayObject() AsArrayObject
To::collection() AsCollection

For example, we can now fluently configure an ArrayObject to use a custom Array Object class and items or even disable caching for a Fluent object.

use Illuminate\Database\Eloquent\Casts\To;

// An Array Object using a custom class and custom item instances.
To::arrayObject()->using(MyCustomArrayObject::class)->of(Color::class);

// An HTML String instance that is not cached.
To::fluent()->withoutCaching();

// An encrypted collection that maps "KeyParser" using the `fromArray()` static method.
To::collection()->encrypted()->mappedFromArray(KeyParser::class);

To achieve all this, the To class instances two objects depending on what is being casted: ToIterable or ToString. Once these are set into the cast array, these will serialize into strings with the cast configuration.

A minor adjustment had to be made for the ArrayObject. Due to the serialize() method present in the original cast, the ArrayObjectCast had to be created. Aside from that, I believe this implementation is cleaner in the sense that one Cast handles iterable objects, while other does for stringable objects.

Finally, if the developer is using a custom class with using(), the class check is deferred until the cast is used, like currently is done.

Extensibility

The ToIterable can also be extended by developers since both mapping and final instantiation is done using mapItems() and makeIterableObject(), respectively.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant