Symfony2和Doctrine - 在控制器中将数据库结果作为数组的数组返回

4
在Symfony2控制器中执行此操作会得到一个数组,其中每个单独的结果都是一个对象。但我也需要它成为一个数组,这样我就可以很容易地对整个列表进行json_encode。
$em->getRepository('MyBundle:Report')->findByEvaluation($evaluation_id, \Doctrine\ORM\Query::HYDRATE_ARRAY)

那么,我如何获得一个数组的数组而不是使用 HYDRATE_ARRAY 时得到的对象数组?

2个回答

4

我最终安装了JMSSerializerBundle,这个包提供了我所需的方法。由于我有一个链接实体,但我不需要链接对象,在我的实体类中现在有以下代码:

...
use JMS\SerializerBundle\Annotation\ExclusionPolicy;
use JMS\SerializerBundle\Annotation\Exclude;
/**
 * Iddp\RorBundle\Entity\Report
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Iddp\RorBundle\Entity\ReportRepository")
 * @ExclusionPolicy("None")
 */
class Report

通过添加@ExclusionPolicy("None"),所有属性都应该被序列化,除了那些带有排除标记的属性。然后,在同一类中的链接实体中只需添加排除注释即可。
/**
 * @ORM\ManyToOne(targetEntity="Client", inversedBy="reports")
 * @ORM\JoinColumn(name="client_id", referencedColumnName="id")
 * @Exclude
 */
protected $client;

现在我可以在控制器中进行如下操作(在添加了use Symfony\Component\HttpFoundation\Response;之后):

$serializer = $this->container->get('serializer');
$reports = $serializer->serialize($reports, 'json');
return new Response($reports);

Symfony和Doctrine可以把一些简单的事情变得复杂。

2
“没有办法直接告诉Doctrine将一个对象视为数组。但是,通过一些微调和一些有争议的设计决策,你可以实现这一点。
首先,你需要创建一个基类(供你的类继承),该基类实现了ArrayAccess接口。可以在Doctrine cookbook中找到描述此过程的文章。它看起来像这样:”
abstract class DomainObject implements ArrayAccess
{

    public function offsetExists($offset)
    {
        return isset($this->$offset);
    }

    public function offsetSet($offset, $value)
    {
        throw new BadMethodCallException(
            "Array access of class " . get_class($this) . " is read-only!"
        );
    }

    public function offsetGet($offset)
    {
        return $this->$offset;
    }

    public function offsetUnset($offset)
    {
        throw new BadMethodCallException(
            "Array access of class " . get_class($this) . " is read-only!"
        );
    }

}

然后,当您创建模型类(或至少要将其视为数组的类)时,您需要扩展此DomainObject类。拼图的最后一块是将您的类属性设置为public,以便让json_encode函数能够检查您的类属性并将它们用作json对象的键。

NB:在类中使用公共属性可能会导致很多难以跟踪的错误,并且通常被认为是可疑的做法。这只是一个我快速想出来的示例,以说明如何实现。我相信有一种更优雅的方法可以实现这一点,而不需要公共属性。这个解决方案只是为了让事情开始运转。

一个示例域类可能如下所示:

class Tester extends DomainObject
{

    public $foo;

    public $bar;

    public function __construct($foo, $bar)
    {

        $this->foo = $foo;
        $this->bar = $bar;

    }

}

现在,您将能够将 Tester 类的实例转换为数组,并将该数组传递给 json_encode 函数。
$test = new Tester('Hello', 'World');
echo json_encode((array)$test);

这将产生以下输出:
{"foo":"Hello","bar":"World"}

编辑:为了让你的代码片段回到上下文中,你不再需要使用HYDRATE_ARRAY,它应该像这样:
$results = $em->getRepository('MyBundle:Report')->findByEvaluation($evaluation_id);
foreach ($results as $result) {
    echo json_encode((array)$result);
}

假设你的Report类扩展了上面定义的DomainObject类。

谢谢你的帮助,但正如你指出的那样,暴露实体属性并不是最好的解决方案,所以我选择了下面发布的解决方案。 - scc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接