Symfony - PHP - 深度克隆对象

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 = WorkflowPraTestController = TestController):

Output


  1. 为什么在ArrayCollection s空着,并不持有State(这里是26号)?
  2. 为什么使用foreach循环时会得到状态? ArrayCollection访问数据库吗?
  3. 是否unserialize(serialize(...))工作到深克隆一个包含所有子对象的对象?如果没有,我应该如何做,而不涉及$workflow对象的对象部分之一?
+0

为什么不使用JMS序列化程序包,它只需调用$ this-> get('jms_serializer') - > toArray($ workflow-> getStates())打印集合,当然之后添加所需的注释,查看文档:http://jmsyst.com/libs/serializer/master/reference/annotations –

每一个关系(而OnetoOne)都是惰性加载,这就是为什么教义不能填充你的关系。

如果您需要它,请在存储库中添加自定义查询,并使用连接部件添加addSelect(alias.releationField),并且您的集合将不会为空。

您也可以改变一个提取模式的实体在默认情况下FETCH_EAGER

+0

在我的'Workflow.orm.yml'映射文件中为''状态映射添加'fetch:EAGER'像魅力一样工作。 – goulashsoup

+1

@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;得到完美复制您的实体与收藏。