Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony-PHP-深度克隆对象_Php_Symfony_Serialization_Doctrine Orm_Deep Copy - Fatal编程技术网

Symfony-PHP-深度克隆对象

Symfony-PHP-深度克隆对象,php,symfony,serialization,doctrine-orm,deep-copy,Php,Symfony,Serialization,Doctrine Orm,Deep Copy,我有一个对象,它是实体类工作流的实例。此工作流有一个属性$states,它是doctrines实体类ArrayCollection的实例 我的工作流程的一部分课程: use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; class Workflow { /** * @var integer */ private $id;

我有一个对象,它是实体类
工作流
的实例。此工作流有一个属性
$states
,它是doctrines实体类
ArrayCollection
的实例

我的
工作流程的一部分
课程:

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;
    }

    ...

}
工作流
s和
状态
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
  ...
MyBundle\Entity\State:
  type: entity
  id:
    id:
      type: integer
      generator: {strategy: AUTO}
  manyToOne:
    workflow:
      targetEntity: MyBundle\Entity\Workflow
      inversedBy: states
      cascade: [persist]
  ...
my_route:
    path: /project/{project}/editWorkflow/{workflow}
    defaults: { _controller: "MyBundle:Test:createEditWorkflowFirstPart", workflow: 0 }
State.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
  ...
MyBundle\Entity\State:
  type: entity
  id:
    id:
      type: integer
      generator: {strategy: AUTO}
  manyToOne:
    workflow:
      targetEntity: MyBundle\Entity\Workflow
      inversedBy: states
      cascade: [persist]
  ...
my_route:
    path: /project/{project}/editWorkflow/{workflow}
    defaults: { _controller: "MyBundle:Test:createEditWorkflowFirstPart", workflow: 0 }
我知道我有一个
工作流
命名测试,它与
状态
命名发布一起存储。我有一个带有对象参数的路由,使用带有类型提示的Symfonys

以下是
路由.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
  ...
MyBundle\Entity\State:
  type: entity
  id:
    id:
      type: integer
      generator: {strategy: AUTO}
  manyToOne:
    workflow:
      targetEntity: MyBundle\Entity\Workflow
      inversedBy: states
      cascade: [persist]
  ...
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在我的操作方法中加载
工作流

我的目标是在会话中将
加载的
工作流存储为深度克隆,并在用户提交相应按钮
workflowstatepe::NEXT_form_part
时,以第二种表单部分操作方法重新加载它。
现在问题来了 当通过路由调用
createEditWorkflowFirstPartAction
时,该方法确实持有一个
$workflow
对象,它是
工作流的一个实例,但当我通过
转储($workflow->getStates()转储所有状态时
数组集合中没有元素,但在循环中运行状态时,
foreach($workflow->getStates()as$state)dump($state);
Symfony转储存储在数据库中的工作流状态

我从未有过如此奇怪的Symfony行为,所以我真的不知道是
dump
没有正确转储,还是
ArrayCollection
只是在它认为需要的时候加载状态

现在调用
unserialize(serialize($workflow));
$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(),
  ));
}
下面是相应的输出(
praworflow
=
Workflow
PraTestController
=
TestController
):


  • 为什么
    ArrayCollection
    s是空的,并且不保存
    状态(此处为id 26)
  • 为什么在使用foreach循环时获取状态?
    ArrayCollection
    是否访问数据库
  • unserialize(serialize(…)
    是否可以对包含所有子对象的对象进行深度克隆操作?如果不行,我应该如何操作而不引用
    $workflow
    对象的某个对象部分
  • 每个关系(而OnetoOne)都是惰性加载的,这就是为什么条令不能填充您的关系

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

    默认情况下,您还可以更改实体中的获取模式,以获取每个关系(而OnetoOne)都是延迟加载的,这就是条令不填充关系的原因

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


    您还可以在默认情况下更改实体中的获取模式以获取\u EAGER

    以下是我对集合进行深度克隆的实现:

    /**
     * @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;
        }
    
        // ...
    
    }
    

    在controller中,只需调用
    $copy=clone$client;
    即可获得集合实体的完美副本。

    以下是我对集合深度克隆的实现:

    /**
     * @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;
        }
    
        // ...
    
    }
    

    在controller中,只需调用
    $copy=clone$client;
    即可获得集合实体的完美副本。

    为什么不使用JMS序列化程序包,只需调用$this->get('JMS\u serializer')->toArray($workflow->getStates())即可打印集合,当然,在添加了所需的注释之后,请查看文档:我知道已经很晚了,但这确实可以帮助其他人调试doctrine中的延迟加载。正如您所说的,它没有被填充,这是因为您已经按照@Mocrates指出的设置了延迟加载,但是如果您想转储它(var_dump或dump),您可以像我一样使用迭代器_to_数组例如dump(迭代器到数组($workflow->getStates())为什么不使用JMS序列化程序包,只需调用$this->get('JMS\u serializer')->toArray($workflow->getStates())即可打印集合,当然,在添加了所需的注释之后,请查看文档:我知道已经很晚了,但这确实可以帮助其他人调试doctrine中的延迟加载。正如您所说的,它没有被填充,这是因为您已经按照@Mocrates指出的设置了延迟加载,但是如果您想转储它(var_dump或dump),您可以像我一样使用迭代器_to_数组例如dump(迭代器数组($workflow->getStates())在my
    workflow.orm.yml
    映射文件中将
    fetch:EAGER
    添加到我的
    状态
    映射,效果非常好。@goulashsoup这取决于你的集合,但如果你不需要每次都加载它的话(在我的示例中,我不希望每个
    查找
    )都有地址,fetch mode LAZY是你的朋友…在我的
    工作流中添加
    fetch:EAGER
    到我的
    状态
    映射。orm.yml
    映射文件工作起来很有魅力。@goulashsoup这取决于你的收藏,但如果你不需要每次都加载它的话(在我的示例中,我不需要每个
    查找
    )的地址,fetch mode LAZY是您的朋友。。。