Symfony - PHP - 深度克隆对象
我有一个对象,它是实体类Workflow
的一个实例。该工作流程具有属性$states
,该属性是学说实体类别ArrayCollection
的实例。Symfony - PHP - 深度克隆对象
我Workflow
类的部分:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class Workflow {
/**
* @var integer
*/
private $id;
/**
* @var Collection
*/
private $states;
/**
* Workflow constructor.
* @param ...t
*/
public function __construct(...) {
$this->states = new ArrayCollection();
...
}
/**
* Get states
*
* @return Collection
*/
public function getStates() {
return $this->states;
}
public function addState(State $state) {
$state->setWorkflow($this);
$this->states->add($state);
return $this;
}
...
}
Workflow
S和States
s的映射,并获取存储到数据库中。这部分是.orm.yml
映射文件:
Workflow.orm.yml
:
MyBundle\Entity\Workflow:
type: entity
id:
id:
type: integer
generator: {strategy: AUTO}
oneToMany:
states:
targetEntity: MyBundle\Entity\State
mappedBy: workflow
cascade: [persist, remove]
orphanRemoval: true
...
State.orm.yml
:
MyBundle\Entity\State:
type: entity
id:
id:
type: integer
generator: {strategy: AUTO}
manyToOne:
workflow:
targetEntity: MyBundle\Entity\Workflow
inversedBy: states
cascade: [persist]
...
都知道,我有一个Workflow
名为测试存储与State
名为发布。我有一个使用Symfonys ParamConverter和类型提示的对象参数路由。
这里是routing.yml
的一部分:
my_route:
path: /project/{project}/editWorkflow/{workflow}
defaults: { _controller: "MyBundle:Test:createEditWorkflowFirstPart", workflow: 0 }
现在,我打电话与现有项目路线和现有的工作流程例如http://localhost/app_dev.php/de/testpra/project/79/editWorkflow/first/19
,并期望Symfony在我的操作方法中加载workflow
。
我的目标是到loaded
工作流程存储为我的会话深克隆,当用户提交一个相应的按钮WorkflowStatesType::NEXT_FORM_PART
重新加载它在第二组成部分的操作方法。
现在的问题
调用当createEditWorkflowFirstPartAction
通过路径的方法确实持有$workflow
对象,它是Workflow
一个实例,但是当我通过dump($workflow->getStates()
转储所有国家中有没有元素的ArrayCollection
但是当在循环中运行状态foreach ($workflow->getStates() as $state) dump($state);
Symfony转储存储在数据库中的工作流的状态。
我从未有过的Symfony的这样一个奇怪的行为让我真的鸵鸟政策知道,如果它是不转储权,或者如果ArrayCollection
只是用来加载状态,当它认为他们需要的dump
。
当现在呼吁unserialize(serialize($workflow));
到deep clone的$workflow
的序列化对象通过各国在foreach
循环时不会倾倒任何状态。
这里是createEditWorkflowFirstPartAction
方法:
public function createEditWorkflowFirstPartAction(Request $request, Project $project, Workflow $workflow = null) {
$newWorkflow = false;
if(!$workflow) {
$workflow = new Workflow($project);
$newWorkflow = true;
}
$workflowBeforeSubmit = unserialize(serialize($workflow));
dump($workflow->getStates()); // Line 106 - Contains no elements
dump($workflowBeforeSubmit->getStates()); // Line 107 - Contains no elements
foreach ($workflow->getStates() as $state) dump($state); // Line 108 - Will print out my stored State
foreach ($workflowBeforeSubmit->getStates() as $state) dump($state); // No states
$firstFormPart = $this->createForm(WorkflowStatesType::class, $workflow);
$firstFormPart->submit($request->get($firstFormPart->getName()), false);
if($firstFormPart->isSubmitted() && $firstFormPart->isValid()) {
...
}
die();
return $this->render('@MyBundle/Workflow/workflow_edit_create_first_part.html.twig', array(
'form' => $firstFormPart->createView(),
));
}
这里是根据输出(PraWorkflow
= Workflow
,PraTestController
= TestController
):
- 为什么在
ArrayCollection
s空着,并不持有State
(这里是26号)? - 为什么使用foreach循环时会得到状态?
ArrayCollection
访问数据库吗? - 是否
unserialize(serialize(...))
工作到深克隆一个包含所有子对象的对象?如果没有,我应该如何做,而不涉及$workflow
对象的对象部分之一?
每一个关系(而OnetoOne)都是惰性加载,这就是为什么教义不能填充你的关系。
如果您需要它,请在存储库中添加自定义查询,并使用连接部件添加addSelect(alias.releationField),并且您的集合将不会为空。
您也可以改变一个提取模式的实体在默认情况下FETCH_EAGER
在我的'Workflow.orm.yml'映射文件中为''状态映射添加'fetch:EAGER'像魅力一样工作。 – goulashsoup
@goulashsoup它取决于你的收藏,但如果你不需要每次都加载它(在我的例子中,我不想每个'find'都有地址),取模LAZY是你的朋友...... – ceadreak
这是我实现深克隆与收藏:
/**
* @ORM\Entity
* @ORM\Table(name="clients")
*/
class Client
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(type="integer")
*/
protected $id;
// ...
/**
* @ORM\OneToMany(targetEntity="Address", mappedBy="client", cascade={"persist", "remove", "merge"}, orphanRemoval=true), fetch="EXTRA_LAZY")
* @ORM\OrderBy("title"="ASC"})
*/
protected $addresses;
// ...
public function __construct()
{
$this->addresses = new ArrayCollection();
}
// ...
public function __clone()
{
if ($this->id)
{
$this->setId(null);
}
// cloning addresses
$addressesClone = new ArrayCollection();
foreach ($this->addresses as $address)
{
/* @var Address $address */
$addressClone = clone $address;
$addressClone->setClient($this);
$addressesClone->add($addressClone);
}
$this->addresses = $addressesClone;
}
// ...
}
在控制器,只需拨打$copy = clone $client;
得到完美复制您的实体与收藏。
为什么不使用JMS序列化程序包,它只需调用$ this-> get('jms_serializer') - > toArray($ workflow-> getStates())打印集合,当然之后添加所需的注释,查看文档:http://jmsyst.com/libs/serializer/master/reference/annotations –