Cast array of elements with Data Transfer Object

Viewed 843

In my application, I have a field that contains an array of objects, and I would like to cast it to access it more easily.

I found https://github.com/spatie/data-transfer-object/ and following some examples i wrote all the classes and cast and now i can access to the object like this:

$val1 = $obj->fields_mapping->mappedField[0]->theField;
$val2 = $obj->fields_mapping->mappedField[1]->theField;

What I would prefeer is to access fields_mapping directly, and not using mappedField again, so something like this:

$val1 = $obj->fields_mapping[0]->theField;
$val2 = $obj->fields_mapping[1]->theField;

Below i show you the code i wrote to accomplish the first version. What i need to change to obtain the "desidered" notation? So:

$val1 = $obj->fields_mapping[0]->theField;

Model

class MyModel extends Model
{
    use HasFactory;

    protected $casts = [
        "fields_mapping" => MappedFields::class,
    ];
}

DTO Using DataTransferObject

use Illuminate\Contracts\Database\Eloquent\Castable;
use Spatie\DataTransferObject\DataTransferObject;

class MappedFields extends DataTransferObject implements Castable
{
    #[CastWith(ArrayCaster::class, itemType: MappedField::class)]
    public array $mappedField;

    public static function castUsing(array $arguments)
    {
        return MappedFieldsCast::class;
    }
}

AND

use Spatie\DataTransferObject\DataTransferObject;

class MappedField extends DataTransferObject
{
    public string $theField;
}

CastsAttributes implementation

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class MappedFieldsCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        if (is_null($value)) {
            return;
        }

        $decoded = json_decode($value, true);
        return new MappedFields([
            "mappedField" => $decoded,
        ]);
    }

    public function set($model, $key, $value, $attributes)
    {
        if (is_null($value)) {
            return;
        }

        return json_encode($value);
    }
}

AND a little factory to populate the object, just for test

class MyModelFactory extends Factory
{
    protected $model = MyModel::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            "fields_mapping" => [
                new MappedField([
                    "theField" => 23,
                ]),
                new MappedField([
                    "theField" => 47,
                ]),
            ],
        ];
    }
}
0 Answers
Related