Symfony2将实体对象序列化到会话中

9
我希望将我的一个实体对象保存到会话中,但在保存时,我遇到了以下两个错误:
异常: Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector::serialize() 必须返回一个字符串或 NULL

ErrorException: 注意:serialize():从__sleep()返回的成员变量“id”不存在于 /var/www/clients/client71/web256/web/_dev_fd/kkupon/vendor/symfony/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php 第 29 行
我的代码如下:
$offer = $this->getEntityManager()->getRepository('KkuponMainBundle:Offer')->find($offer_id);
$request->getSession()->set('offer', $offer);

我应该如何做才能做对呢?

谢谢。

更新 在Rowgm的帮助下,我通过将属性设置为protected而不是private来解决了这个问题。唯一的问题是,在从会话中读取实体后,EntityManager并不知道它,如果我将对象(从会话中)添加到另一个对象中(它们之间存在OneToMany关系),它将无法正常工作。

<?php
$offer = $this->get('session')->get('offer');
$coupon = new Coupon();
$coupon->setOffer($offer);
$this->em->persist($coupon);
$this->em->flush();

这会引发错误,因为按照EntityManager的说法,coupon具有一个对象属性,而该属性不在数据库中(实际上该属性是从数据库中放入会话中的)。

<?php
$offer = $this->get('session')->get('offer');
echo $this->em->getUnitOfWork()->isInIdentityMap($offer) ? "yes":"no"; //result: no

一种解决方案是:

$offer = $this->em->merge($offer);

但这似乎不是最好的方法。我希望我的EntityManager能够感知存储在会话中的实体对象,而不需要每次都告诉它。

有什么想法吗?

3个回答

15

您可以通过将实体的所有属性和关系从私有更改为受保护来序列化任何实体。

即使您已将所有属性设置为受保护,您在symfony2中可能会遇到常见问题:您必须重新生成您更改的那些实体的代理。要这样做,只需清除缓存。对于dev环境

app/console cache:clear

正如您所说,“它包含许多外部对象甚至是外部实体的ArrayCollections”,此方法仍然适用。


想一想:如果您存储所有实体,那么您将在会话数据中存储一个大对象。对于您的开发环境,这不是问题。但是如果您有很多用户,这将浪费资源。解决方案非常简单:存储对象的ID并使用存储库的find()方法检索对象。最终,这是相同的事情。 - Rowinson Gallego
我认为,框架应该为我提供这个功能。这样我就不必每次想使用实体时都调用查找函数。 - David Frank

6
序列化实体并不推荐,你可以在Doctrine文档中看到。你应该实现Serializable接口,手动序列化/反序列化实体数据。请注意不要删除HTML标签。

序列化我的实体会有问题,因为它包含许多外部对象,甚至是外部实体的ArrayCollections。除了仅存储ID并在每次需要时从数据库检索对象之外,还有更好的想法吗? - David Frank
从你的异常信息可以看出,当将其放入会话中时,它将被序列化,这就是导致错误的原因。但正如你所说,由于对象的复杂性,你应该考虑存储ID并再次从数据库中检索对象。可能使用某种对象缓存也可以,但我不确定。 - dbrumann
1
谢谢,我只会存储ID。 - David Frank

2
您可以通过覆盖 __sleep 方法来排除不必要的字段:
public function __sleep() {

    // these are field names to be serialized, others will be excluded
    // but note that you have to fill other field values by your own
    return array('id', 'username', 'password', 'salt');
}

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