使用嵌套的 child 元素对 clone/duplicate TYPO3 8.7 extbase object 创建自己的操作
Create own action to clone/duplicate TYPO3 8.7 extbase object with nested child elements
我在 TYPO3 8.7 中构建基于 extbased 的 TYPO3 扩展。这是一个Backend-Module。在控制器中,我编写了自己的操作来克隆 object。
在此示例中,我想 clone/duplicate object 'Campaign' 并使用修改后的标题对其进行保护,例如将 'copy' 文本添加到标题中。
但是新的 object 也应该有它自己的新的 child 元素,这些元素必须是精确的副本。
调用操作时,我只得到 Object 的副本,但没有 child。是否有如何处理此任务的示例或最佳案例?我没有找到,甚至我发现了一些关于同一主题但旧版本的问题和答案。我希望更新到最新,有一个更直接的解决方案。感谢您给我指出正确想法的每一个提示,也许还有一个最新版本的示例。这是我的控制器。我如何实现所有 child 元素的递归复制(有些 child 也有 child )?
/**
* 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');
}
有一种方法可以从不同的 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');
}
我知道这个问题很久以前就有人回答了。但我想提供我的解决方案来创建深拷贝以供进一步参考。在 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;
}
if ($v !== null) {
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $v);
}
}
return $clone;
}
如果您的对象中有“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;
}
我在 TYPO3 8.7 中构建基于 extbased 的 TYPO3 扩展。这是一个Backend-Module。在控制器中,我编写了自己的操作来克隆 object。 在此示例中,我想 clone/duplicate object 'Campaign' 并使用修改后的标题对其进行保护,例如将 'copy' 文本添加到标题中。 但是新的 object 也应该有它自己的新的 child 元素,这些元素必须是精确的副本。 调用操作时,我只得到 Object 的副本,但没有 child。是否有如何处理此任务的示例或最佳案例?我没有找到,甚至我发现了一些关于同一主题但旧版本的问题和答案。我希望更新到最新,有一个更直接的解决方案。感谢您给我指出正确想法的每一个提示,也许还有一个最新版本的示例。这是我的控制器。我如何实现所有 child 元素的递归复制(有些 child 也有 child )?
/**
* 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');
}
有一种方法可以从不同的 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');
}
我知道这个问题很久以前就有人回答了。但我想提供我的解决方案来创建深拷贝以供进一步参考。在 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;
}
if ($v !== null) {
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $v);
}
}
return $clone;
}
如果您的对象中有“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;
}