【问题标题】:Document serialization with Doctrine MongoDB ODM使用 Doctrine MongoDB ODM 进行文档序列化
【发布时间】:2012-12-05 09:46:30
【问题描述】:

我正在尝试code a class 通过读取文档的元数据来处理文档的序列化。我受到 this implementation 的启发,用于使用 Doctrine ORM 的实体,并对其进行了修改以匹配 Doctrine ODM 处理文档的方式。不幸的是,有些东西不能正常工作,因为一个文档永远不会被序列化超过一次,即使它被第二次引用,从而导致序列化不完整。

例如,它为属于某个地点 1(请参阅 Place document)的用户 1(请参阅 User document)输出此(以 json 格式)。然后它输出地点和属于它的用户,我们应该再次看到 user1 但我们没有:

{
  id: "505cac0d6803fa1e15000004",
  login: "user1",
  places: [
    {
      id: "505cac0d6803fa1e15000005",
      code: "place1",
      users: [
        {
          id: "505c862c6803fa6812000000",
          login: "user2"
        }
      ]
    }
  ]
}

我猜这可能与阻止循环引用的事情有关,但有没有办法解决它?

另外,我在 ZF2 应用程序中使用它,有没有更好的方法来使用 ZF2 序列化器来实现它?

感谢您的帮助。

【问题讨论】:

  • 为了回答我的问题,@superdweebie 制作了一个很棒的 Doctrine 库,他在下面描述了它包含一个序列化程序。如果您使用急切获取,那么您将返回所有文档。目前,虽然您可能会遇到循环引用问题,但我们正在处理 a feature 以实现最大嵌套深度选项。

标签: serialization zend-framework2 doctrine-odm doctrine-mongodb


【解决方案1】:

我已经为 DoctrineODM 编写了一个序列化程序。您可以在 http://github.com/superdweebie/DoctrineExtensions 中找到它 - 查看 lib/Sds/DoctrineExtensions/Serializer

如果您使用的是 zf2,那么您可能还喜欢 http://github.com/superdweebie/DoctrineExtensionsModule,它配置 DoctrineExtensions 以在 zf2 中使用。

要使用该模块,请使用 composer 安装它,就像安装任何其他模块一样。然后将以下内容添加到您的 zf2 配置中:

'sds' => [
    'doctrineExtensions' => [
        'extensionConfigs' => [
            'Sds\DoctrineExtensions\Serializer' => null,
        ),
    ),
),

要获取序列化程序,请使用:

$serializer = $serivceLocator->get('Sds\DoctrineExtensions\Serializer');

使用序列化器:

$array = $serializer->toArray($document)
$json = $serializer->toJson($document)

$document = $serializer->fromArray($array)
$document = $serializer->fromJson($json)

如果您想使用它们,还有一些额外的注释可用于控制序列化:

@Sds\Setter - specify a non standard setter for a property
@Sds\Getter - specify a non standard getter fora  property
@Sds\Serializer(@Sds\Ignore) - ignore a property when serializing

这一切仍在进行中,因此任何 cmets/改进将不胜感激。当您遇到这些库的问题时,只需将它们记录在 github 上,它们就会得到及时解决。

最后是关于序列化嵌入文档和引用文档的说明 - 嵌入文档应该与它们的父文档一起序列化,而引用文档不应该。这反映了数据在数据库中的保存方式。这也意味着循环引用不是问题。

更新

我已将更新推送到 Sds/DoctrineExtensions/Serializer,以便它现在可以正确处理引用。以下三(五)种方法已更新:

toArray/toJson
fromArray/fromJson
applySerializeMetadataToArray

前两个是自我解释 - 最后一个是允许应用序列化规则,而不必将数据库结果水合到文档中。

默认情况下,引用将被序列化为这样的数组:

[$ref: 'CollectionName/DocumentId']

$ref 引用风格是 Mongo 内部使用的,所以它看起来很合适。给出引用的格式,期望它可以用作 REST API 的 URL。

可以通过定义替代ReferenceSerializer 来覆盖默认行为,如下所示:

/**
 * @ODM\ReferenceMany(targetDocument="MyTargetDocument")
 * @Sds\Serializer(@Sds\ReferenceSerializer('MyAlternativeSerializer'))
 */
protected $myDocumentProperty;

lib 中已包含一个备用ReferenceSerializer。它是急切的序列化器——它将序列化引用,就好像它们是嵌入的文档一样。可以这样使用:

/**
 * @ODM\ReferenceMany(targetDocument="MyTargetDocument")
 * @Sds\Serializer(@Sds\ReferenceSerializer('Sds\DoctrineExtensions\Serializer\Reference\Eager'))
 */
protected $myDocumentProperty;

或提供替代的速记注释:

/**
 * @ODM\ReferenceMany(targetDocument="MyTargetDocument")
 * @Sds\Serializer(@Sds\Eager))
 */
protected $myDocumentProperty;

备用ReferenceSerializers 必须实现Sds\DoctrineExtensions\Serializer\Reference\ReferenceSerializerInterface

另外,我清理了忽略注释,因此可以将以下注释添加到属性中,以对序列化进行更细粒度的控制:

@Sds\Serializer(@Sds\Ignore('ignore_when_serializing'))
@Sds\Serializer(@Sds\Ignore('ignore_when_unserializing'))
@Sds\Serializer(@Sds\Ignore('ignore_always'))
@Sds\Serializer(@Sds\Ignore('ignore_never'))

例如,将@Sds\Serializer(@Sds\Ignore('ignore_when_serializing')) 放在电子邮件属性上 - 这意味着电子邮件可以发送到服务器进行更新,但永远不能序列化到客户端以确保安全。

最后,如果您没有注意到,sds 注释支持继承和覆盖,因此它们可以很好地处理复杂的文档结构。

【讨论】:

  • 嗨@superdweebie,感谢您在这里的帮助。我尝试了您的序列化程序,但遇到了引用文档仍被序列化并作为对象检索的问题,因为here 似乎没有检查$mapping['reference'] 是否不添加它们。还有那些不返回字符串(例如日期对象)的 getter 呢?
  • 附带说明,如果您不在序列化程序本身中检索这些文件,您将如何公开某种 API 来访问您的应用程序的数据以及对文档的引用?
  • 嘿@jhuet,感谢您抽出宝贵时间试一试。我将为序列化程序引用文档添加一个测试用例(我想我没有)。至于 API,我正在考虑使用这样的东西:dojotoolkit.org/reference-guide/1.8/dojox/json/ref.html。我实际上还没有需要这样做(还),这就是为什么代码不是全部 100%。但这是一个很好的改变,可以让 lib 更加坚固。
  • 没问题 :) dojox.json.ref 看起来是一个有趣的方法,你知道它被广泛采用了吗?到目前为止,在我遇到的任何 API 上,引用的文档都只是作为普通文档输出。顺便说一句,它似乎并没有解决您将如何首先检索那些引用的文档。如果这是第一次发送,您如何在服务器端知道该文档应该作为参考还是作为普通文档提供?我怀疑客户是否应该在每次请求时发送他所知道的所有文件?
  • @jhuet 我刚刚推送了一些更改,如上所述。他们可能会有所帮助。
【解决方案2】:

将 Doctrine ODM 文档转换为数组或 JSON 的另一种非常简单、独立于框架的方法 - http://ajaxray.com/blog/converting-doctrine-mongodb-document-tojson-or-toarray

此解决方案为您提供了一个为您的 ODM 文档提供 toArray()toJSON() 函数的特征。在你的文档中useing trait 之后,你可以这样做 -

<?php
// Assuming in a Symfony2 Controller
// If you're not, then make your DocmentManager as you want
$dm = $this->get('doctrine_mongodb')->getManager();
$report = $dm->getRepository('YourCoreBundle:Report')->find($id);

// Will return simple PHP array
$docArray = $report->toArray();

// Will return JSON string
$docJSON = $report->toJSON();

顺便说一句,它只适用于 PHP 5.4 及更高版本。

【讨论】:

  • @laalto,我添加了使用此解决方案的代码示例。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多