Gedmo 时间戳在使用 JMS 序列化程序反序列化时始终更新引用



我在我的Symfony2项目中有一个一对一的关系,其中Question引用了一个Video - 两者都有一个创建和更新Gedmo\Timestampable行为,基本上按预期工作。但有点太多了:

使用附加的Video反序列化Question时(仅作为 ID 以避免视频元数据中的其他更改(,Video文档始终createdupdated字段上获得更新。这似乎不对。我可能理解为什么更新的字段会获得新日期 - 即使实际上对象本身没有任何变化,但为什么要创建

这是我的代码(简单(:

课堂问题:

<?php
/**
 * Class Question
 *
 * @SerializerAccessorOrder("alphabetical")
 * @MongoDBDocument(
 *   collection="Quiz",
 *   repositoryClass="MyNamespaceBundleQuizBundleRepositoryQuestionRepository",
 * )
 * @package MyNamespaceBundleQuizBundleDocument
 */
class Question
{
    /**
     * @var MongoId
     * @MongoDBId(strategy="auto")
     * @SerializerType("string")
     * @SerializerGroups({
     *   "quiz_admin_list",
     *   "quiz_admin_detail"
     * })
     */
    protected $id;
    /**
     * @var DateTime
     *
     * @AssertDate(
     *   message = "quiz:constraints.model.question.created.invalid"
     * )
     * @SerializerType("DateTime<'U'>")
     * @SerializerAccessor(getter="getCreated", setter="setCreatedEmpty")
     * @SerializerGroups({
     *   "quiz_admin_list",
     *   "quiz_admin_detail"
     * })
     * @GedmoTimestampable(on="create")
     * @MongoDBDate
     */
    protected $created;

    /**
     * @var DateTime
     *
     * @AssertDate(
     *   message = "quiz:constraints.model.question.updated.invalid"
     * )
     * @SerializerType("DateTime<'U'>")
     * @SerializerAccessor(getter="getUpdated", setter="setUpdatedEmpty")
     * @SerializerGroups({
     *   "quiz_admin_list",
     *   "quiz_admin_detail"
     * })
     * @GedmoTimestampable(on="update")
     * @MongoDBDate
     */
    protected $updated;
    /**
     * @var Video
     *
     * @SerializerType("MyNamespaceBundleCoreMediaAdminBundleDocumentVideo")
     * @SerializerGroups({
     *   "quiz_admin_list",
     *   "quiz_admin_detail"
     * })
     * @MongoDBReferenceOne(
     *   targetDocument="MyNamespaceBundleCoreMediaAdminBundleDocumentVideo",
     *   cascade={"all"}
     * )
     */
    protected $answerVideo;
}

课堂视频:

<?php
/**
 * Class Video
 * @SerializerAccessorOrder("alphabetical")
 * @MongoDBDocument(
 *   collection="CoreMediaAdminVideo",
 *   repositoryClass="MyNamespaceBundleCoreMediaAdminBundleRepositoryVideoRepository",
 * )
 * @VichUploadable
 * @package MyNamespaceBundleCoreMediaAdminBundleDocument
 */
class Video 
{
    /**
     * @MongoDBId(strategy="auto")
     * @SerializerType("string")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     */
    protected $id;
    /**
     * @VichUploadableField(
     *   mapping = "core_media_admin_video",
     *   fileNameProperty = "fileName"
     * )
     * @SerializerExclude
     * @var File $file
     */
    protected $file;
    /**
     * @MongoDBField(type="string")
     * @SerializerType("string")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     */
    protected $mimeType;
    /**
     * @var String
     *
     * @AssertNotBlank(
     *   message = "core.media.admin:constraints.model.base.title.not_blank"
     * )
     * @SerializerType("string")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     * @MongoDBField(type="string")
     */
    protected $title;
    /**
     * @var DateTime
     *
     * @AssertDate(
     *   message = "core.media.admin:constraints.model.base.date.invalid"
     * )
     * @SerializerType("DateTime<'U'>")
     * @SerializerAccessor(getter="getCreated", setter="setCreatedEmpty")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     * @GedmoTimestampable(on="create")
     * @MongoDBDate
     */
    protected $created;
    /**
     * @var DateTime
     *
     * @AssertDate(
     *   message = "core.media.admin:constraints.model.base.date.invalid"
     * )
     * @SerializerType("DateTime<'U'>")
     * _SerializerAccessor(getter="getUpdated", setter="setUpdatedEmpty")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     * @GedmoTimestampable(on="update")
     * @MongoDBDate
     */
    protected $updated;
    /**
     * @var DateTime
     *
     * @AssertDate(
     *   message = "core.media.admin:constraints.model.base.date.invalid"
     * )
     * @SerializerType("DateTime<'U'>")
     * @SerializerGroups({
     *   "core_media_list",
     *   "core_media_search",
     *   "core_media_video_list",
     *   "core_media_video_detail"
     * })
     * @GedmoTimestampable(on="update", field={"title", "tags", "comment", "dataOrigin", "description", "videoMetaData", "mimeType", "fileName", "file" })
     * @MongoDBDate
     */
    protected $updatedContent;
}

有趣的是,在反序列化期间没有对Video对象进行任何更改 - 只有更新查询来设置视频的createdupdated字段。我还测试了 Timestampable 的字段参数,以便仅在其中一个字段获得更新时才强制更新,但这似乎被完全忽略了。

这里也是反序列化的JSON和相应的MongoDB查询:

{
  "id": "547f31e650e56f2c26000063",
  "question_id": 12,
  "question_text": "Wer einen Gemüsegarten hat, sollte wissen, dass Schnecken…?",
  "answer_text": "test",
  "answer_video": {
    "id": "547f31d850e56f2c26000031"
  },
  "tags": [
    "Schnecken",
    "Basilikum",
    "Thymian",
    "Garten"
  ]
}

查询:

db.QuizQuestion.find({
  "_id": ObjectId("547f31e650e56f2c26000063")
}).limit(1).limit();
db.CoreMediaAdminVideo.update({
  "_id": ObjectId("547f31d850e56f2c26000031")
},
{
  "$set": {
    "created": newISODate("2014-12-03T21:30:02+01:00"),
    "updated": newISODate("2014-12-03T21:30:02+01:00"),
    "updatedContent": newISODate("2014-12-03T21:30:02+01:00")
  }
});
db.ARDBuffetQuizQuestion.update({
  "_id": ObjectId("547f31e650e56f2c26000063")
},
{
  "$set": {
    "created": newISODate("2014-12-03T21:30:02+01:00"),
    "updated": newISODate("2014-12-03T21:30:02+01:00"),
    "questionText": "Wer einen Gemüsegarten hat, sollte wissen, dass Schnecken…?",
    "answerText": "test",
    "answerVideo": {
      "$ref": "CoreMediaAdminVideo",
      "$id": ObjectId("547f31d850e56f2c26000031"),
      "$db": "my-database"
    }
  }
});
db.ARDBuffetQuizQuestion.update({
  "_id": ObjectId("547f31e650e56f2c26000063")
},
{
  "$set": {
    "tags": [
      {
        "value": "Schnecken",
        "normalized": "schnecken"
      },
      {
        "value": "Basilikum",
        "normalized": "basilikum"
      },
      {
        "value": "Thymian",
        "normalized": "thymian"
      },
      {
        "value": "Garten",
        "normalized": "garten"
      }
    ]
  }
});
db.ARDBuffetQuizQuestion.find({
  "_id": ObjectId("547f31e650e56f2c26000063")
}).limit(1).limit();
db.CoreMediaAdminVideo.find({
  "_id": ObjectId("547f31d850e56f2c26000031")
}).limit(1).limit();

Gedmo\Timestampable 将为 $created$updated 设置(新(值,因为在刷新 ObjectManager 时不存在该数据。

尽管类 Video 中的注释定义了序列化此类对象时应包含$created$updated,但显示的 JSON 不包含这些键/属性。

以下是发生的情况:

  • JSON 不包含键/属性createdupdated
  • 反序列化时,生成的对象将具有 $created$updatednull值。
  • 将对象merge()到对象管理器中时,它没有任何反应。对象只是变为"托管",这意味着在刷新期间,ObjectManager 将为其计算更改集并在必要时对其进行更新。
  • 刷新 ObjectManager 时,Gedmo\Timestampable 将启动(由于事件侦听器PreUpdate(。它将看到$created$updated包含null值,因此它将分配新值。
  • 然后,ObjectManager 将从数据库中检索"当前"数据,因为它需要它来计算更改集。通常,当find()对象时,它不会这样做,因为数据已经在该find()期间检索。
  • 由于 $created$updated的值现在与从数据库中检索的值不同,因此它将更新它们。

因此,您将有 2 个选项:

  1. 首先find()对象,然后根据 JSON 进行更改。
  2. 确保 JSON 包含映射的所有属性(包括 createdupdated (。

另外,我注意到setter="setCreatedEmpty"setter="setUpdatedEmpty".我不确定这些方法的作用(因为您没有向我们展示(,但方法名称表示其他简单地分配值的东西。

回答您的意见

当将对象merge()到对象管理器中时,它被标记为"脏",这将触发更改集的计算。并且由于 DateTime 对象的引用已更改(Doctrine 从数据库获取的实例始终与通过反序列化 JSON 创建的实例不同(,因此对象将被更新。然后 Gedmo\Timestampable 将启动并相应地更改$updated属性。

如果不希望发生这种情况,则需要find()当前对象,并且仅在值对象表示的值实际更改时才更改值对象。标量值没有问题:您可以设置相同的值,而 Doctrine 不会将其视为更改。但是对于值对象(如日期时间(对象,当引用发生更改(设置不同的实例时(,Doctrine 将看到更改。

相关内容

  • 没有找到相关文章

最新更新