Skip to content

[12.x] Extends AsCollection to map items into objects or other values #55383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

DarkGhostHunter
Copy link
Contributor

@DarkGhostHunter DarkGhostHunter commented Apr 13, 2025

What?

Rework of #55377. This extends AsCollection and AsEncryptedCollection to accept a class to map each item into, or a callable as [class, method] or class@method notation, without or without a custom collection class.

For example, I expect the most common to be using the map() static method to set a Class to map each item into, using the base Collection class.

use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Support\Fluent;

public function casts()
{
    return [
        'colors' => AsCollection::map(Fluent::class)
    ];
}

// Same as
Collection::make($this->attributes['colors'])->mapInto(Fluent::class);

If the developer sets an array callable, it gets normalized into class@method notation.

use Illuminate\Database\Eloquent\Casts\AsCollection;
use App\ValueObject\Color;

public function casts()
{
    return [
        'colors' => AsCollection::map([Color::class, 'make']),
    ];
}

// Same as
Collection::make($this->attributes['colors'])->map([Color::class, 'make']);

If the developer wants to use a custom Collection class, the using() can be used with a second parameter and either a class or array callable / class@method.

return [
    'colors' => AsCollection::using(CustomCollection::class, [Color::class, 'make']),
];

// Same as
CustomCollection::make($this->attributes['colors'])->map([Color::class, 'make']);

Caution

Because the nature of the casts declaration, there is no support to using a Closure. The developer can use castUsing() directly with a Closure if desired.

This logic is also extended to the AsEncryptedCollection class, which works in the same way.

use Illuminate\Database\Eloquent\Casts\AsEncryptedCollection;
use App\ValueObject\Color;

public function casts()
{
    return [
        'colors' => AsEncryptedCollection::map([Color::class, 'make']), 
    ];
}

@DarkGhostHunter DarkGhostHunter force-pushed the feat/12.x/as-collection-map branch from fd91472 to 4d31559 Compare April 13, 2025 00:06
DarkGhostHunter added a commit to DarkGhostHunter/laravel-docs that referenced this pull request Apr 13, 2025
@DarkGhostHunter
Copy link
Contributor Author

Does make more sense lexically to use of() rather than map()?

AsCollection::of(Option::class);

AsCollection::of([Option::class, 'make']);

@DarkGhostHunter DarkGhostHunter changed the title [12.x] Extends AsCollection for map [12.x] Extends AsCollection to map items into objects or other values Apr 14, 2025
@shaedrich
Copy link
Contributor

Does make more sense lexically to use of() rather than map()?

While I think, map() might imply something being mapped on the spot rather than just being assigned and mapped later, of() reads like the first parameter is the actual raw iterable/arrayable being passed to the constructor 🤔

But you raise a good point here. Maybe, it could be something along the lines of mapUsing() or withMapping()/withMapper()

@DarkGhostHunter
Copy link
Contributor Author

Does make more sense lexically to use of() rather than map()?

While I think, map() might imply something being mapped on the spot rather than just being assigned and mapped later, of() reads like the first parameter is the actual raw iterable/arrayable being passed to the constructor 🤔

But you raise a good point here. Maybe, it could be something along the lines of mapUsing() or withMapping()/withMapper()

What about ofItems() (for classes) and ofMap() (for callables)?

@shaedrich
Copy link
Contributor

Does make more sense lexically to use of() rather than map()?

While I think, map() might imply something being mapped on the spot rather than just being assigned and mapped later, of() reads like the first parameter is the actual raw iterable/arrayable being passed to the constructor 🤔
But you raise a good point here. Maybe, it could be something along the lines of mapUsing() or withMapping()/withMapper()

What about ofItems() (for classes) and ofMap() (for callables)?

To me, ofItems() would have pretty much the same implication as of, however, ofMap() might work 👍🏻

@taylorotwell taylorotwell merged commit 60125ea into laravel:12.x Apr 18, 2025
58 checks passed
@mathieutu
Copy link
Contributor

This is brilliant, thanks @DarkGhostHunter! I need that right now, and was making a small research before working on to for a PR.

taylorotwell added a commit to laravel/docs that referenced this pull request Apr 22, 2025
* Adds `AsColection::map()` section

As part of [#55383](laravel/framework#55383).

* Added more clarification

* More clarification

* Update eloquent-mutators.md

Co-authored-by: Sebastian Hädrich <11225821+shaedrich@users.noreply.github.com>

* Adds openinh PHP on full class

* Better, almost final, clarification.

* Minor change to the Option example so it makes sense

* Better clarification about serialization

* formatting

---------

Co-authored-by: Sebastian Hädrich <11225821+shaedrich@users.noreply.github.com>
Co-authored-by: Taylor Otwell <taylor@laravel.com>
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.

4 participants