You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:07:52