我想创建一种情况,其中我有两个集合,一个用于文章,另一个用于草稿。文章是一个文档,其中包含一些属性和一组名为 features 的嵌入文档。草稿是一个具有一些属性的文档,它嵌入了一篇文章文档。
为了实现这一点,我创建了一个名为BaseArticle的基础对象,Article对象和DraftArticle继承该对象。我创建了以下对象和映射:
此类包含Article和DraftArticle对象的所有getter和setter方法。 BaseArticle.mongodb.yml包含:
BaseArticle:
type: document
inheritanceType: COLLECTION_PER_CLASS
fields:
id:
id: true
propertyOne:
type: string
propertyTwo:
type: string
features:
embedded: true
type: many
targetDocument: Feature
这是一个扩展BaseArticle的空PHP类。 Article.mongodb.yml包含:
Article:
collection: article
type: document
带有getter和setter方法的基本PHP类。 Draft.mongodb.yml看起来像这样:
Draft:
collection: drafts
fields:
id:
id: true
owner:
type: string
length: 255
index: true
status:
type: string
length: 255
index: true
data:
embedded: true
type: one
targetDocument: DraftArticle
这是一个扩展BaseArticle的空PHP类。 DraftArticle.mongodb.yml包含:
DraftArticle:
type: embeddedDocument
Feature.mongodb.yml包含:
Feature:
type: embeddedDocument
fields:
id:
id: true
name:
type: string
value:
type: string
我让用户编辑文章,这些编辑可以保存为草稿。创建草稿的工作流程为:http://i.stack.imgur.com/PwbMZ.png
为了能够将文章保存为嵌入文档而不是文章集合,我需要将Article对象从Article转换为DraftArticle。 PHP无法转换对象,因此我创建了一个新对象,并使用以下代码进行深层复制。
protected function cast($destination, $sourceObject)
{
$sourceClone = clone $sourceObject;
if (is_string($destination)) {
$destination = new $destination();
}
$sourceReflection = new \ReflectionObject($sourceClone);
$destinationReflection = new \ReflectionObject($destination);
$sourceProperties = $sourceReflection->getProperties();
foreach ($sourceProperties as $sourceProperty) {
$sourceProperty->setAccessible(true);
$name = $sourceProperty->getName();
$value = $sourceProperty->getValue($sourceClone);
if ($destinationReflection->hasProperty($name)) {
$propDest = $destinationReflection->getProperty($name);
$propDest->setAccessible(true);
$propDest->setValue($destination, $value);
}
else {
$destination->$name = $value;
}
}
return $destination;
}
现在,我可以创建草稿并将文章另存为嵌入文档,而无需更改原始文档。
$draft = new Draft();
// PHP does not support user type casting. Therefore we use a custom cast function
// which creates a new object of the target type and copies all properties.
$draftArticle = $this->cast('DraftArticle', $article);
// This will unset _id
$draftArticle->clearId();
$draft->setArticle(draftArticle);
$this->entityManager->persist($draft);
$this->entityManager->flush();
在保存之前更改draftArticle中的draftArticle或功能时,也会保存更改。 但是,当我向draftArticle添加新功能时,这些功能也将存储在原始文章文档中。
这是为什么?如何通知学说完全忘记DraftArticle与其原始文章之间的任何联系?有没有更好的方法来复制/克隆文档并将其作为嵌入文档存储在另一个集合中?
答案 0 :(得分:1)
我的建议含糊不清,因为我不知道我是否一直遇到与你完全相同的问题。但我有一个场景,我需要克隆"使用Doctrine ODM从一个集合到另一个集合的文档......我收到了许多令人头疼的问题,其行为与您描述的类似。我特别难以克隆包含引用文档的哈希数组,但看起来我终于让它工作了(现在,谁知道什么时候会出现更多错误)。
最后我发现有两件事有助于摆脱时髦的行为。第一件事是使用$ documentManager-> clear();在某些关键点。
在我的项目中,我初始化$ documentManager对象,然后使用全局$ documentManager通过我的控制器使用它。我发现,如果我不做$ documentManager-> clear();在某些地方,我得到了非常奇怪的行为,在某种意义上我很难解释为什么它会这样做,但这可能是因为我缺乏理解。
这是我使用克隆文件的代码。不知道它是否会帮助你......
在我的情况下,图像/文件/视频是存储在哈希数组中的引用文档..所以我做了一些特别的事情来让那些被克隆的#34;。我也一直在寻找你的解决方案......它看起来比我的清晰得多......但是我对使用ReflectionObject和entityManager的知识还不够......我希望我能理解它们的用途。现在我严格使用$ documentManager。无论如何,如果你发现这有用,并且不要介意回答一下我在做什么和做什么之间的差异......使用entityManager vs documentManager和使用ReflectionObject克隆..好吧,我当然会很感激。干杯:)
public function cloneDocument($document) {
$classVars = self::getObjectVars();
foreach ($classVars as $key => $value) {
if(in_array($key, array("images", "files", "videos")))
{
switch($key)
{
case "images":
foreach ($document->images as $image) {
$this->images[] = $image;
}
break;
case "files":
foreach ($document->files as $file) {
$this->files[] = $file;
}
break;
case "videos":
foreach ($document->videos as $video) {
$this->videos[] = $video;
}
break;
}
}
else
{
$this->$key = $document->$key;
}
}
}