symfony doctrine将实体对象移动到另一个实体类型

时间:2015-11-04 08:18:07

标签: php mysql symfony doctrine-orm

有没有办法用Doctrine将行移动到另一个mysql表?

我正在搜索以下mysql的等价物:

INSERT myTableCopy (
   SELECT * FROM myTable WHERE id = 2
)

我期待这样的事情:

// $first is an object from  myTable
$this->getDoctrine()->getRepository('MyBundle:MyTable')->findOneBy(array('id' => 2));
$second = new myTableCopy();
$second = clone $first;

不幸的是(但逻辑上),$ second实体的类型为myTable ......

我该怎么做?

我知道我可以使用prepare语句,但我想知道我是否可以使用其中一个Doctrine函数执行此操作。

仅供参考:我有一张巨大的桌子(几百万行),我想把旧数据移到一个不会那么用的“备份表”

PS:我知道this thread提出了以下解决方案,但我认为应该有更好的方法来使用序列化器/规范化器...

 // now loop over the properties of each post array...
    foreach ($post as $property => $value) {
        // create a setter
        $method = sprintf('set%s', ucwords($property)); // or you can cheat and omit ucwords() because PHP method calls are case insensitive
        // use the method as a variable variable to set your value
        $post->$method($value);
    }

2 个答案:

答案 0 :(得分:2)

我从@Colin M中读到this post后终于找到了错误。

以下是我的问题的最终解决方案:

$myOriginalObject = $this->getDoctrine()->getRepository('MyBundle:MyTable')->findOneBy(array('id' => 2));
// Here modify the original object if needed...

$myTableCopyObject = new myTableCopy();

$oldReflection = new \ReflectionObject($myOriginalObject);
$newReflection = new \ReflectionObject($myTableCopyObject);

foreach ($oldReflection->getProperties() as $property) {
    if ($newReflection->hasProperty($property->getName())) {
        $newProperty = $newReflection->getProperty($property->getName());
        $newProperty->setAccessible(true);
        $property->setAccessible(true);
        $newProperty->setValue($myTableCopyObject, $property->getValue($doi_tmp));
    }
}               

$this->em->persist($myTableCopyObject);
$this->em->remove($myOriginalObject);
$this->em->flush();

注意:当您拥有自动递增ID时,只有ID似乎不会被保存

答案 1 :(得分:1)

这可以通过反射来实现

您的$ oldEntity已经具有(例如)日期对象的情况(因此规范化将不起作用,并且将引发错误)

在这种情况下,symfony的方法不起作用,因为我的$ oldEntity已经有一个日期对象并不断出现错误

这假设您同时拥有两个实体的getter / setter,并且$ newEntityh中存在$ oldEntity公共方法getter / setter,但可以很容易地适应任何情况

$reflectionClass = new \ReflectionClass($oldEntity);
//get all the methods that start with get
$methods = array_filter($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC), function(ReflectionMethod $method){
     return strpos($method->name, "get") === 0;
});

foreach ($methods as $method) {
   $methodName = $method->name;
   //replace the 'get' string of method with 'set'
   $setter = str_replace("get", "set", $methodName);
   $value = $oldEntity->$methodName();
   $newEntity->$setter($value);
}

//new entity is populated

这可以通过normalizer来实现。

新实体已经存在的情况:

  /** create newEntity */
  $newEntity = new User();
  /** populate it ? */

  $normalizer = new GetSetMethodNormalizer();

  $normalizer->denormalize(
      $normalizer->normalize($oldEntity),
      //Could use instead of get_class: User::class 
      get_class($newEntity), null, ['object_to_populate' => $newEntity]
  );
  //$newEntity updated;

需要创建新实体的情况:

  $normalizer = new GetSetMethodNormalizer();

  $newEntity = $normalizer->denormalize(
      $normalizer->normalize($oldEntity),
      $newEntityClassName //use User::class for example to get the name
  );