【问题标题】:Doctrine entity object to array教义实体对象到数组
【发布时间】:2014-08-06 10:54:14
【问题描述】:

想要将教义实体转换为普通数组,这是我目前的代码,

 $demo = $this->doctrine->em->find('Entity\User',2);

获取实体对象,

Entity\User Object
(
[id:Entity\User:private] => 2
[username:Entity\User:private] => TestUser
[password:Entity\User:private] => 950715f3f83e20ee154995cd5a89ac75
[email:Entity\User:private] => test@test.com
[firm_id:Entity\User:private] => Entity\Firm Object
    (
        [id:Entity\Firm:private] => 16
        [company_name:Entity\Firm:private] => TestFirm
        [company_detail:Entity\Firm:private] => India
        [created_at:Entity\Firm:private] => DateTime Object
            (
                [date] => 2014-08-01 18:16:08
                [timezone_type] => 3
                [timezone] => Europe/Paris
            )

        [user:Entity\Firm:private] => 
    )

[created_at:Entity\User:private] => DateTime Object
    (
        [date] => 2014-08-01 15:12:36
        [timezone_type] => 3
        [timezone] => Europe/Paris
    )

[updated_at:Entity\User:private] => DateTime Object
    (
        [date] => 2014-08-01 15:12:36
        [timezone_type] => 3
        [timezone] => Europe/Paris
    )

[firm:protected] => 
) ,

试过this,但根据我的requiremnet,不想使用doctrine_query。 谢谢。

【问题讨论】:

  • 试试这个var_dump(get_object_vars(object)); ?
  • 它不工作!谢谢顺便说一句:)
  • iswinky 的解决方案只有在您的成员被声明为public 时才有效。由于它们是私有的,因此无法访问它们。但是,您可以向您的实体添加一个返回 get_object_vars($this); 的函数并从外部调用它。

标签: php arrays doctrine-orm doctrine


【解决方案1】:

你可以试试这样的,

    $result = $this->em->createQueryBuilder();
    $app_code = $result->select('p')
            ->from('YourUserBundle:User', 'p')
            ->where('p.id= :id')
            ->setParameter('id', 2)
            ->getQuery()
            ->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

另一种方式,

 $this->em->getRepository('YourUserBundle:User')
      ->findBy(array('id'=>1));

上面将返回一个数组,但包含教义对象。返回数组的最佳方法是使用教义查询。

希望这会有所帮助。 干杯!

【讨论】:

  • 谢谢,但我已经提到过,不想使用学说查询的东西。
  • 哦。对于那个很抱歉。你不是不允许使用实体存储库吗?
  • 其实可以,你能给我举个例子吗?
  • 也就是说没有办法将实体对象转为数组?
  • 是的,这很奇怪。到目前为止,我还没有找到这样的。当我有这样的要求时,我使用学说查询生成器并将结果水合到一个数组中。干杯。
【解决方案2】:

注意:如果您想要一个实体的数组表示的原因是将其转换为 JSON 以进行 AJAX 响应,我建议您查看此问答: How to encode Doctrine entities to JSON in Symfony 2.0 AJAX application?。我特别喜欢使用与我的回答类似的内置 JsonSerializable 接口的那个。


由于 Doctrine 没有提供将实体转换为关联数组的方法,因此您必须自己完成。一种简单的方法是创建一个基类,该基类公开一个返回实体数组表示的函数。这可以通过在其自身上调用基类函数get_object_vars 来实现。此函数获取传入对象的 可访问 属性并将它们作为关联数组返回。然后,您只需在创建要转换为数组的实体时扩展此基类。

这是一个非常简单的例子:

abstract class ArrayExpressible {
    public function toArray() {
        return get_object_vars($this);
    }
}

/** @Entity */
class User extends ArrayExpressible {

    /** @Id @Column(type="integer") @GeneratedValue */
    protected $id = 1; // initialized to 1 for testing

    /** @Column(type="string") */
    protected $username = 'abc';

    /** @Column(type="string") */
    protected $password = '123';

}

$user = new User();
print_r($user->toArray());
// Outputs: Array ( [id] => 1 [username] => abc [password] => 123 )

注意:您必须保护实体的属性,以便基类可以使用 get_object_vars() 访问它们


如果由于某种原因您无法从基类扩展(可能是因为您已经扩展了基类),您至少可以创建一个interface 并确保您的实体实现该接口。然后你必须在每个实体中实现toArray 函数。

例子:

interface ArrayExpressible {
    public function toArray();
}

/** @Entity */
class User extends SomeBaseClass implements ArrayExpressible {

    /** @Id @Column(type="integer") @GeneratedValue */
    protected $id = 1; // initialized to 1 for testing

    /** @Column(type="string") */
    protected $username = 'abc';

    /** @Column(type="string") */
    protected $password = '123';

    public function toArray() {
        return get_object_vars($this);
        // alternatively, you could do:
        // return ['username' => $this->username, 'password' => '****']
    }

}

$user = new User;
print_r($user->toArray());
// Outputs: Array ( [id] => 1 [username] => abc [password] => 123 )

【讨论】:

    【解决方案3】:

    如果您已经从数据库中提取了对象实体,您也可以使用DoctrineModule\Stdlib\Hydrator\DoctrineObject

    /**
     * Assume your entity for which you want to create an array is in $entityObject.
     * And it is an instance of YourEntity::class.
     */
    $tmpObject = new DoctrineObject($this->entityManager, YourEntity::class);
    $data = $tmpObject->extract($entityObject);
    

    现在$data 将包含您的对象作为数组。

    附言当被问到这个问题时,我不确定这是否可能。

    【讨论】:

      【解决方案4】:

      我是 Symfony 的新手,但有一些可行的(但奇怪的)方法:

      json_decode($this->container->get('serializer')->serialize($entity, 'json'))

      【讨论】:

      • 小心,因为如果序列化程序试图从它的实体关系中获取数据,你会得到一个讨厌的递归
      • 谢谢@le0diaz,我正在使用排除jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies 来避免一些递归
      • 我遇到了同样的问题,最终也使用了排除项。我需要它来使用 @MaxDepth(n) 注释,但它不能开箱即用。我必须更新我的控制器(从 FOSRestController 继承)才能使用类似这样的东西,也许它也可以帮助任何人: $view = $this->view($facility); $view->getSerializationContext()->enableMaxDepthChecks();返回 $this->handleView($view);
      • 你可以使用这个语法:$this->container->get('serializer')->serialize($entity, 'array') 你获得了一个 jsonencode/jsondecode 通行证
      【解决方案5】:

      我需要一个 toArray() 方法,它可以在水合后工作,但 get_object_vars() 技巧不起作用,因为教义 2.x 中的延迟加载/代理内容

      这是我的dropin方法

      use Doctrine\Common\Inflector\Inflector;
      ...
      public function toArray() {
          $methods = get_class_methods($this);
          $array = [];
          foreach ($methods as $methodName) {
              // remove methods with arguments
              $method = new \ReflectionMethod(static::class, $methodName);
              if ($method->getNumberOfParameters() > 0) continue;
              $matches = null;
              if (preg_match('/^get(.+)$/', $methodName, $matches)) {
                  // beautify array keys
                  $key = Inflector::tableize($matches[1]);
                  // filter unwanted data
                  if (in_array($key, ['object1', 'object2'])) continue;
                  $array[$key] = call_user_func([$this, $methodName]);
              }
          }
          return $array;
      }
      

      欢迎改进

      【讨论】:

      • 我通过在 preg_match 检查中添加 property_exists() 检查来改进它:if (!property_exists($this, $inflector->camelize($matches[1]))) continue;
      【解决方案6】:

      几个月前我在我的存储库中创建了一个递归函数,它并不完美(比如,如果你有一个字段 createdBy 和 updatedBy,它只会检索一个用户的值,因为使用 $ 来防止递归的相当简单aClassNamesDone),但它可能会有所帮助:

          public function entityToArray($entity, &$aClassNamesDone=array(), $latestClassName="") {
      
          $result = array();
      
          if(is_null($entity)) {
              return $result;
          }
      
          $className = get_class($entity);
      
          // init with calling entity
          if(empty($aClassNamesDone)) {
              $aClassNamesDone[] =$className;
          }
      
          $uow = $this->getEntityManager()->getUnitOfWork();
      
          $entityPersister = $uow->getEntityPersister($className);
          $classMetadata = $entityPersister->getClassMetadata();
      
          //DEPENDS ON DOCTRINE VERSION
          //if(strstr($className, 'DoctrineProxies\\__CG__\\')){
          if(strstr($className, 'Proxies\\__CG__\\')){
              $uow->initializeObject($entity);
          }
      
          foreach ($uow->getOriginalEntityData($entity) as $field => $value) {
      
              if (isset($classMetadata->associationMappings[$field])) {
      
                  $assoc = $classMetadata->associationMappings[$field];
      
                  if (isset($classMetadata->columnNames[$field])) {
                      $columnName = $classMetadata->columnNames[$field];
                      $result[$columnName] = $value;
                  }
      
                  // to avoid recursivity we can look for the owning side (gives similar results as Query::HYDRATE_ARRAY):
                  // elseif($assoc['isOwningSide']) { ...
                  // or we can track entities explored and avoid any duplicates (this will however ignore some fields pointing to the same entity class)
                  // for example: only one of createdBy, updatedBy will be kept
      
                  else if(!in_array($assoc['targetEntity'], $aClassNamesDone) || $assoc['targetEntity'] == $latestClassName) {
      
                      try {
      
                          if ($assoc['targetEntity'] != 'Timestamp') {
      
                              $aClassNamesDone[] = $assoc['targetEntity'];
      
                              $targetClass = $this->getEntityManager()->getClassMetadata($assoc['targetEntity']);
      
                              if (($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY) || ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY)) {
      
                                  $getterName = 'get' . ucfirst($assoc['fieldName']);
                                  $entityChildren = $entity->$getterName();
                                  foreach ($entityChildren as $oneChild) {
                                      $result[$assoc['fieldName']][] = $this->getEntityManager()->getRepository($assoc['targetEntity'])->entityToArray($oneChild, $aClassNamesDone, $assoc['targetEntity']);
                                  }
      
                              } else if (($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_ONE) || ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_ONE)) {
      
                                  $getterName = 'get' . ucfirst($assoc['fieldName']);
                                  $entityChild = $entity->$getterName();
                                  $result[$assoc['fieldName']] = $this->getEntityManager()->getRepository($assoc['targetEntity'])->entityToArray($entityChild, $aClassNamesDone, $assoc['targetEntity']);
      
                              }
                          }
      
                      } catch (\Exception $e) {
                          //var_dump('No entityToArray for ' . $assoc['targetEntity']);
                          throw ($e);
                      }
                  }
      
              }
          }
      
          return $result;
      }
      

      【讨论】:

        【解决方案7】:

        如果您只需要访问单个值,您也可以这样做...

        如果 'personType' 是一个对象,并且您想要关系的值...

        $personTypeId = $form->get('personType')->getViewData();
        

        【讨论】:

          【解决方案8】:

          如果有人想使用 Doctrine 2 来实现,请使用 UnitOfWork API 来实现。这是使用学说公共 API 的唯一方法。

          例子:-

          $em = $this->getEntityManager();
          $uow = $em->getUnitOfWork();
          
          $entity = $this->find($id);
          
          // Returning the fetched data as an array
          $uow->getOriginalEntityData($entity); // ['name' => 'Old Name', 'username'=> 'oldone']
          
          // But it will not be synchronized with the entity
          $entity->setName('New Name');
          $uow->getOriginalEntityData($entity); // ['name' => 'Old Name', 'username'=> 'oldone']
          
          // Luckily, there is a way to get changed data after called persist
          $em->persist($entity);
          $uow->getOriginalEntityData($entity); // ['name' => 'Old Name', 'username'=> 'oldone']
          $uow->getEntityChangeSet($entity); // ['name' => ['Old Name', 'New Name']]
          
          // Original data was syncronized after called flush method
          $em->flush();
          $uow->getOriginalEntityData($entity); // ['name' => 'New Name', 'username'=> 'oldone']
          

          阅读我的博文了解更多信息。 https://whizsid.github.io/blog/25/converting-a-doctrine-2-entity-to-an-array.html

          【讨论】:

            【解决方案9】:

            这对我有用

                   $sql="
                        SELECT * FROM users
                    ";
                    $stmt = $this->em->getConnection()->prepare($sql);
                    $users =  $stmt->executeQuery()->fetchAllAssociative();
            

            【讨论】:

              【解决方案10】:

              你可以用这个

              $demo=array($demo);
              

              【讨论】:

              • 您能否解释一下,这是如何解决问题的。如果我正确理解您的代码,您只需 put $demo 在一个数组中。但问题是,如何将实体转换为数组。
              • 通常它需要这样的演员表:$demo = (array)$demo;但它是否在教义对象中起作用,我不知道。
              猜你喜欢
              • 1970-01-01
              • 2017-06-16
              • 1970-01-01
              • 1970-01-01
              • 2018-09-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-01
              相关资源
              最近更新 更多