如何修改Spatie DTO转换逻辑实现Laravel模型数组字段直接下标访问
你只需要修改两处核心代码,即可实现期望的数组式访问效果:
1. 修改MappedFields类,实现ArrayAccess接口
通过接口方法将数组访问操作全部代理到内部的$mappedField属性,同时可按需新增Countable、IteratorAggregate接口支持计数、遍历操作:
use Illuminate\Contracts\Database\Eloquent\Castable; use Spatie\DataTransferObject\DataTransferObject; use ArrayAccess; use Countable; use IteratorAggregate; class MappedFields extends DataTransferObject implements Castable, ArrayAccess, Countable, IteratorAggregate { #[CastWith(ArrayCaster::class, itemType: MappedField::class)] public array $mappedField; public static function castUsing(array $arguments) { return MappedFieldsCast::class; } // ArrayAccess接口实现 public function offsetExists($offset): bool { return isset($this->mappedField[$offset]); } public function offsetGet($offset): mixed { return $this->mappedField[$offset]; } public function offsetSet($offset, $value): void { $this->mappedField[$offset] = $value; } public function offsetUnset($offset): void { unset($this->mappedField[$offset]); } // Countable接口实现(可选,支持count($obj->fields_mapping)调用) public function count(): int { return count($this->mappedField); } // IteratorAggregate接口实现(可选,支持foreach遍历$obj->fields_mapping) public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->mappedField); } }
2. 修正MappedFieldsCast的set方法
避免序列化MappedFields对象时带入额外结构,保证存储格式正确:
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; } // 新增类型判断,提取实际存储的数组内容 if ($value instanceof MappedFields) { $value = $value->mappedField; } return json_encode($value); } }
修改完成后即可直接使用$obj->fields_mapping[0]->theField的方式访问属性,原有$obj->fields_mapping->mappedField[0]->theField的写法也可以继续兼容,不会影响旧代码逻辑。
内容的提问来源于stack exchange,提问作者Mistre83
相关产品推荐
相关产品推荐

