Skip to content

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

Merged
taylorotwell merged 3 commits into
laravel:12.xfrom
DarkGhostHunter:feat/12.x/as-collection-map
Apr 18, 2025
Merged

[12.x] Extends AsCollection to map items into objects or other values#55383
taylorotwell merged 3 commits into
laravel:12.xfrom
DarkGhostHunter:feat/12.x/as-collection-map

Conversation

@DarkGhostHunter

@DarkGhostHunter DarkGhostHunter commented Apr 13, 2025

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
@mathieutu

Copy link
Copy Markdown
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>
@DarkGhostHunter DarkGhostHunter deleted the feat/12.x/as-collection-map branch May 30, 2025 22:56
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