我在TYPO3 8.7中构建了基于扩展的TYPO3扩展。这是一个后端模块。在控制器中,我编写了自己的操作来克隆对象。 在此示例中,我想克隆/复制对象“ Campaign”并使用修改后的标题对其进行保护,例如在标题中添加“复制”文本。 但是,新对象还应该具有自己的新子元素,这些子元素必须是精确的副本。 调用该操作时,我仅获得对象的副本,而没有任何子对象。有没有一个例子或最好的情况下如何处理此任务?我没有找到,甚至我找到了与同一主题有关的一些问题和答案,但是版本较旧。我希望最新的解决方案更加直接。感谢您为我提供正确想法的每一个提示,也许是最新的版本示例。这是我的控制器。如何实现所有子元素的递归复制(有些子元素也有子元素)?
/**
* action clone
* @param \ABC\Copytest\Domain\Model\Campaign $campaign
* @return void
* @var \ABC\Copytest\Domain\Model\Campaign $newCampaign
*/
public function cloneAction(\ABC\Copytest\Domain\Model\Campaign $campaign) {
$newCampaign = $this->objectManager->get("ABC\Copytest\Domain\Model\Campaign");
$properties = $campaign->_getProperties();
unset($properties['uid']);
foreach ($properties as $key => $value) {
$newCampaign->_setProperty($key, $value);
}
$newCampaign->_setProperty('title', $properties['title']. ' COPY');
$this->campaignRepository->add($newCampaign);
$this->addFlashMessage('Clone was created', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::OK);
$this->redirect('list');
}
答案 0 :(得分:0)
有一种方法可以从不同的POV处理此用例,即将没有标识的请求参数值自动放入新对象中,然后可以将其持久化。这基本上是克隆原始对象。这是您需要做的:
edit
视图,以调用您的clone
操作。initializeCloneAction()
并通过$this->request->getArguments()
获取原始请求参数。unset($arguments[<argumentName>]['__identity']);
,如果要复制而不是共享引用,请对对象具有的每个关系进行相同的操作。$this->request->setArguments($arguments)
重新存储原始请求参数。完整的initializeCloneAction()
如下所示:
public function initializeCloneAction()
{
$arguments = $this->request->getArguments();
unset(
$arguments['campaign']['__identity'],
$arguments['campaign']['singleRelation']['__identity'],
);
foreach (array_keys($arguments['campaign']['multiRelation']) as $i) {
unset($arguments['campaign']['multiRelation'][$i]['__identity']);
}
$this->request->setArguments($arguments);
// Allow object creation now that we have new objects
$this->arguments->getArgument('campaign')->getPropertyMappingConfiguration()
->setTypeConverterOption(PersistentObjectConverter::class, PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, true)
->allowCreationForSubProperty('singleRelation')
->getConfigurationFor('multiRelation')
->allowCreationForSubProperty('*');
}
现在,如果您使用clone
操作提交表单,您的clone
操作将获得一个完全填充但新的对象,您可以像往常一样将其存储在存储库中。您的cloneAction()
将非常简单:
public function cloneAction(Campaign $campaign)
{
$this->campaignRepository->add($campaign);
$this->addFlashMessage('Campaign was copied successfully!');
$this->redirect('list');
}
答案 1 :(得分:0)
我知道这个问题已经很久了。但是,我想提供我的解决方案以创建深层副本,以供进一步参考。在TYPO3 9.5.8上进行了测试。
private function deepcopy($object) {
$clone = $this->objectManager->get(get_class($object));
$properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($object);
foreach ($properties as $propertyName => $propertyValue) {
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
$v = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\ObjectStorage::class);
foreach($propertyValue as $subObject) {
$subClone = $this->deepcopy($subObject);
$v->attach($subClone);
}
} else {
$v = $propertyValue;
}
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $v);
}
return $clone;
}
答案 2 :(得分:0)
如果您的对象中有“ LazyLoadingProxy”实例,则需要再添加一个条件。
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$objectStorage = $propertyValue->_loadRealInstance();
}
这是我对“深度复制”功能的解决方案:
private function deepcopy($object)
{
$clone = $this->objectManager->get(get_class($object));
$properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($object);
foreach ($properties as $propertyName => $propertyValue) {
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
$objectStorage = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\ObjectStorage::class);
foreach ($propertyValue as $subObject) {
$subClone = $this->deepcopy($subObject);
$objectStorage->attach($subClone);
}
} elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$objectStorage = $propertyValue->_loadRealInstance();
} else {
$objectStorage = $propertyValue;
}
if ($objectStorage !== null) {
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $objectStorage);
}
}
return $clone;
}