jessarcher / laravel-castable-data-transfer-object

Automatically cast JSON columns to rich PHP objects in Laravel using Spatie's data-transfer-object class
https://jessarcher.com/blog/casting-json-columns-to-value-objects/
MIT License
328 stars 23 forks source link

Dealing with arrays of Value objects #4

Open arrilot opened 3 years ago

arrilot commented 3 years ago

Hello, what if we have a jsonb column addresses with [ {...}. {...}, {...} ] Is there any way to cast it to [ Address(...), Address(...), Address(...), ] ?

danielbehrendt commented 3 years ago

Same here, I'd also like to do that.

jessarcher commented 3 years ago

Hi @arrilot and @danielbehrendt, I can definitely see how that would be useful. It's currently only possible when the array of DTOs is nested within another DTO using the functionality provided by Spatie at https://github.com/spatie/data-transfer-object/#automatic-casting-of-nested-array-dtos.

To have the array as the top-level, we'd need to create an object to represent the array, and thankfully Spatie seems to have us covered there too, with their DataTransferObjectCollection class https://github.com/spatie/data-transfer-object/#working-with-collections, although I haven't needed that one myself yet so I'm not 100% sure how it works.

To get that working within the casts provided by this package, I think we'd just need to create a CastableDataTransferObjectCollection that implements Laravel's Castable interface, similar to how I've created the CastableDataTransferObject class. I don't have time to look into creating that right now, but I'd welcome a PR.

morrislaptop commented 3 years ago

@arrilot @danielbehrendt I've ported this package for POPOs using Symfony's serializer, which can support casting objects, dates and arrays.

https://github.com/morrislaptop/laravel-castable-object

I'd love to hear if this suits your needs! Basically it works like this

namespace App\Models;

use App\Values\Address;
use Illuminate\Database\Eloquent\Model;
use Morrislaptop\Caster\Caster;

/**
 * @property Address[] $addresses
 */
class User extends Model
{
    protected $casts = [
        'addresses' => Caster::class . ':' . Address::class . '[]',
    ];
}

I haven't tried it yet, but it could also potentially work for DTO's as well by adding a DataTransferObjectNormalizer into Symfony's Serializer. https://github.com/spatie/data-transfer-object/issues/93#issuecomment-738023471

@jessarcher would love your feedback on my package as well!