Doctrine - 如何将结果及其关系提取为数组

时间:2014-12-19 18:47:35

标签: doctrine-orm zend-framework2

我有一个实体,称之为Stones and Stones与Attributes有ManyToMany关系。

所以我查询实体以获取石头,然后我将其水合以将其转换为数组。

    $result =  $this->stoneRepository->find($stone_id);

    if ( ! $result )
    {
        return false;
    }

    $resultArray =  $this->doctrineHydrator->extract($result);

这适用于Stone实体但是我注意到连接(属性)仍然是对象。

array (size=12)
  'id' => int 1
  'name' => string 'Agate' (length=5)
  'title' => string 'Title' (length=5)
'attribute' => 
    array (size=5)
      0 => 
        object(Stone\Entity\StAttribute)[1935]
          private 'id' => int 2
          private 'name' => string 'Hay fevor' (length=9)
          private 'state' => boolean true
          private 'created' => null
          private 'modified' => null
      1 => 
        object(Stone\Entity\StAttribute)[1936]
          private 'id' => int 15
          private 'name' => string 'Libra' (length=5)
          private 'state' => boolean true
          private 'created' => null
          private 'modified' => null
      2 => 

水合属性对象的过程是什么?

2 个答案:

答案 0 :(得分:4)

水合作用是使用与提取相反的数组填充对象(实体)。

由于您希望结果集采用数组格式,因此应该防止在ORM级别内已经发生的不必要的水合和提取过程。

尝试使用Query Builder Api而不是实体存储库的内置find()方法。这不是一个单行,而是非常直接和快速的解决方案,它应该有效:

$qb = $this->stoneRepository->createQueryBuilder('S');
$query = $qb->addSelect('A')
            ->leftJoin('S.attribute', 'A')
            ->where('S.id = :sid')
            ->setParameter('sid', (int) $stone_id)
            ->getQuery();

$resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

这样,您还可以防止针对数据库运行其他SQL查询以获取关联实体。 (在你的情况下StAttribute)

答案 1 :(得分:0)

我想我会对此进行跟进,以展示如何使用CustomStrategy解决这个问题。

到目前为止,foozy提出了最简单,最快速的方法。我喜欢的解决方案是,当我在ApiGility中使用水合作用时,我可以构建自定义查询,这将在极少数代码行中产生所需的结果。

我正在研究的另一个解决方案是添加自定义策略:

<?php
namespace Api\V1\Rest\Stone;

use DoctrineModule\Stdlib\Hydrator\Strategy\AbstractCollectionStrategy;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

class CustomStrategy extends AbstractCollectionStrategy
{

    public function __construct($hydrator)
    {
        $this->hydrator = $hydrator;
    }

    /**
     * @param mixed $values
     * @return array|mixed
     */
    public function extract($values)
    {
        $returnArray = [];

        foreach ($values AS $value)
        {

            $returnArray[] =  $this->hydrator->extract($value);
        }

        return $returnArray;

    }

    /**
     * @param mixed $values
     * @return mixed
     */
    public function hydrate($values)
    {
        $returnArray = [];

        foreach ($values AS $value )
        {
            $returnArray[] = $this->hydrator->hydrate($value);
        }

        return $returnArray;
    }
}

然后从服务方面我向水槽中加入各种策略:

$result =  $this->stoneRepository->find($stone_id);

$this->doctrineHydrator->addStrategy("product", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("attribute", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("image", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("related", new CustomStrategy( $this->doctrineHydrator ) );

$resultArray =  $this->doctrineHydrator->extract($result);

之后我创建了一个自定义实体:

<?php
namespace Api\V1\Rest\Stone;

class StoneEntity
{
    public $id;
    public $name;
    public $description;
    public $code;
    public $attribute;
    public $product;
    public $image;

    public function getArrayCopy()
    {
        return array(
            'id'          => $this->id,
            'name'        => $this->name,
            'description' => $this->description,
            'code'        => $this->code,
            'attribute'   => $this->attribute,
            'product'     => $this->product,
            'image'       => $this->image
        );
    }

    public function exchangeArray(array $array)
    {
        $this->id           = $array['id'];
        $this->name         = $array['name'];
        $this->description  = $array['description'];
        $this->code         = $array['code'];
        $this->attribute    = $array['attribute'];
        $this->product      = $array['product'];
        $this->image        = $array['image'];
    }
}

最后一部分是与自定义实体交换返回的数据:

    $entity = new StoneEntity();
    $entity->exchangeArray($resultArray);

最后返回结果:

    return $entity;

老实说,上面的内容太长了,根据foozy的建议,我的最终解决方案就是:

public function fetchOne($stone_id)
    {
        $qb = $this->stoneRepository->createQueryBuilder('S');
        $query = $qb->addSelect('A','P','I','C')
            ->leftJoin('S.attribute', 'A')
            ->innerJoin('A.category', 'C')
            ->innerJoin('S.product' , 'P')
            ->innerJoin('S.image' , 'I')
            ->where('S.id = :sid')
            ->setParameter('sid', (int) $stone_id)
            ->getQuery();

        $resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

        if ( ! $resultArray )
        {
            return false;
        }

        return $resultArray;
    }