PHP/MongoDB:Persistable模型无法自动反序列化问题咨询
解决自定义Persistable类无法自动反序列化的问题
jenssegers/mongodb默认仅自动处理MongoDB原生BSON类型(如ObjectId),自定义Persistable类不会触发自动反序列化,需通过以下两种方案实现自动转换:
方案一:自定义Eloquent类型转换(推荐,精准可控)
1. 创建类型转换类
<?php namespace App\Casts; use Domain\Media\Models\MediaUid; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; class MediaUidCast implements CastsAttributes { // 读取字段时转换为MediaUid实例 public function get($model, string $key, $value, array $attributes) { if (is_null($value)) { return null; } $convert = fn($item) => isset($item['val']) ? new MediaUid($item['val']) : $item; return is_array($value) ? array_map($convert, $value) : $convert($value); } // 保存字段时序列化为BSON结构 public function set($model, string $key, $value, array $attributes) { if (is_null($value)) { return null; } $serialize = fn($item) => $item instanceof MediaUid ? $item->bsonSerialize() : $item; return is_array($value) ? array_map($serialize, $value) : $serialize($value); } }
2. 在模型中配置字段转换
修改SomeModel,通过$casts属性指定需要转换的字段:
<?php namespace Domain\Collection\Models; use Jenssegers\Mongodb\Eloquent\Model; use App\Casts\MediaUidCast; class SomeModel extends Model { protected $connection = 'mongodb'; protected $casts = [ 'someMedia' => MediaUidCast::class, // 如有多个字段或数组类型的MediaUid,依次添加 'someMediaList' => MediaUidCast::class, ]; }
该方案支持单值、嵌套数组等场景,完全符合Laravel Eloquent规范,可精准控制转换范围。
方案二:全局BSON类型映射(批量处理)
若需全局自动转换所有符合结构的文档,可通过MongoDB扩展的TypeMap实现,在Laravel服务提供者中配置:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use MongoDB\BSON\TypeMap; use Domain\Media\Models\MediaUid; class AppServiceProvider extends ServiceProvider { public function boot() { // 获取MongoDB连接实例 $connection = $this->app['db']->connection('mongodb'); $mongoClient = $connection->getMongoClient(); $database = $mongoClient->selectDatabase($connection->getDatabaseName()); // 配置TypeMap自动识别MediaUid结构 $typeMap = new TypeMap([ 'root' => 'array', 'document' => 'array', 'array' => 'array', 'object' => function(array $data) { // 精准判断MediaUid存储结构 if (count($data) === 1 && isset($data['val']) && is_string($data['val'])) { $mediaUid = new MediaUid($data['val']); $mediaUid->bsonUnserialize($data); return $mediaUid; } return $data; }, ]); $database->setTypeMap($typeMap); } }
注意:全局映射需确保判断条件足够精准,避免误转换其他结构类似的文档。
验证方法
重新读取模型后,可通过以下代码验证转换结果:
$model = SomeModel::find($id); var_dump($model->someMedia instanceof MediaUid); // 应返回true
内容的提问来源于stack exchange,提问作者Arno van Oordt
相关产品推荐
相关产品推荐

