我有一个Dashboard
实体被JMSSerializer正确序列化/反序列化(通过JMSSerializerBundle):
/**
* @ORM\Table(name="dashboard", schema="myappID")
* @ORM\Entity(repositoryClass="Belka\MyBundle\Entity\Repository\DashboardRepository")
*/
class Dashboard
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue("SEQUENCE")
*
* @Serializer\Groups({"o-all", "o-all-getCDashboard", "i-p2-editDashboard"})
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="Belka\MyBundle\Entity\User")
*
* @ORM\JoinTable(name="users_dashboards_associated",
* schema="myAppID",
* joinColumns={@ORM\JoinColumn(name="dashboard_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
* )
*
* @Serializer\groups({
* "o-p2-create",
* "i-p2-create",
* "o-p2-patch",
* "i-p2-editDashboard"
* })
*/
protected $users;
}
我正在使用JMSSerializer的jms_serializer.doctrine_object_constructor
作为对象构造函数。
一切都像魅力一样,但我有以下几个案例:有时我必须将Dashboard::$users
设置为一个字符串(即当客户端发送一个语义不正确的users
属性时,在我检查后我返回对象以及一个字符串,以便通知它。这对前端应用程序非常方便)。
JMSSerializer takes advantage of the Doctrine's annotation,但在这种情况下我真的想以编程方式覆盖它,因为这是一个非常大的问题。我想到了两个方法:
SerializationContext
设置为将Dashboard::$users
映射为字符串属性?任何建议都非常受欢迎
答案 0 :(得分:2)
我找到了一个解决方案,虽然它没有考虑嵌套实体的属性(has-a relations)。这意味着访问整个图表,但我没有时间研究优秀的JMSSSerializer的胆量。它非常适合强制实现第一级实体的属性:
首先,需要pre-serialize
订阅者。它将遍历受保护的属性并检查它们是否包含字符串。是这样,序列化的类型将被覆盖。
class SerializationSubscriber implements EventSubscriberInterface
{
/**
* @inheritdoc
*/
static public function getSubscribedEvents()
{
return array(
array('event' => 'serializer.pre_serialize', 'method' => 'onPreserialize'),
);
}
public function onPreSerialize(PreSerializeEvent $event)
{
$entity = $event->getObject();
$metadata = $event->getContext()->getMetadataFactory()->getMetadataForClass($event->getType()['name']);
$reflect = new \ReflectionClass($entity);
$props = $reflect->getProperties(\ReflectionProperty::IS_PROTECTED);
foreach ($props as $prop) {
$prop->setAccessible(true);
if (is_string($prop->getValue($entity))) {
// here is the magic
$metadata->propertyMetadata[$prop->name]->type = array('name' => 'string', 'params' => array());
}
}
}
}
接下来,每次我序列化某些内容时,我都不想听这个。这是我的一项服务中的一个极端案例。尽管JMS\Serializer\EventDispatcher\EventDispatcher::addSubscriber
服务已声明为EventDispatcher
,但我们可以利用private
。
因此,让我们通过编译器传递将该服务转换为public
,以便利用addSubscriber
:
class MyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new OverrideJmsSerializerEventDispatcherDefPass());
}
}
...让我们将该服务转换为public
个
class OverrideJmsSerializerEventDispatcherDefPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('jms_serializer.event_dispatcher');
$definition->setPublic(true);
}
}
因此,我们可以将其注入我们的服务中。即在我的services.yml
:
belka.mybundle.dashboardhandler:
class: Belka\MyBundle\Handlers\DashboardHandler
calls:
- [setEventDispatcher, ["@jms_serializer.event_dispatcher"]]
好的,现在我们可以在需要的时候轻松添加我们的用户,每次我的应用程序执行序列化时都没有其他监听器的负担:
$serializationSubscriber = new SerializationSubscriber();
$this->eventDispatcher->addSubscriber($serializationSubscriber);
随意使用访问整个实体的解决方案来完成答案。图形。那会很棒。