带有参数和自定义侦听器

带有参数和自定义侦听器

本文介绍了带有参数和自定义侦听器/订阅者的 JMS VirtualProperty的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试序列化作为 Doctrine Criteria 的属性:

I am trying to serialize a property which is a Doctrine Criteria:

public function getUserResults(User $user)
{
    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('user', $user))
    ;

    return $this->getResults()->matching($criteria);
}

我不能使用 @VirtualProperty 因为它需要一个参数,所以我在这篇文章之后为我的一种类型实现了一个自定义订阅者:

I cannot use the @VirtualProperty because it needs an argument so I implemented a custom subscriber for one of my types following this post:

https://stackoverflow.com/a/44244747

<?php

namespace AppBundleSerializer;

use JMSSerializerEventDispatcherEventSubscriberInterface;
use JMSSerializerEventDispatcherPreSerializeEvent;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorage;
use JMSSerializerEventDispatcherObjectEvent;

class ExerciseSubscriber implements EventSubscriberInterface
{
    private $currentUser;

    public function __construct(TokenStorage $tokenStorage)
    {
        $this->currentUser = $tokenStorage->getToken()->getUser();
    }

    public static function getSubscribedEvents()
    {
        return array(
            array(
                'event' => 'serializer.post_serialize',
                'method' => 'onPostSerialize',
                'class' => Exercise::class, // if no class, subscribe to every serialization
                'format' => 'json', // optional format
            ),
        );
    }

    public function onPostSerialize(ObjectEvent $event)
    {
        if (!$this->currentUser) {
            return;
        }

        $exercise = $event->getObject();
        $visitor = $event->getVisitor();

        $results = $exercise->getUserResults($this->currentUser);
        dump($results); // <-- It is an ArrayCollection with many elements

        $visitor->setData(
            'my_user_results',
            $results // <-- when rendered is an empty {}
        );
    }
}

很遗憾,user_results 属性始终为空!
我查看了序列化程序的源代码,发现:

Unfortunately the user_results property is always empty!
I looked into the source code for the serializer and I found that:

/**
 * Allows you to add additional data to the current object/root element.
 * @deprecated use setData instead
 * @param string $key
 * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
 *                                                       It must not contain any objects anymore.
 */
public function addData($key, $value)
{
    if (isset($this->data[$key])) {
        throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key));
    }

    $this->data[$key] = $value;
}

请注意它不能再包含任何对象.

我该如何解决这个问题?

How can I solve this?

推荐答案

请尝试使用serializer.post_serialize 事件代替serializer.pre_serialize 事件.此外,您的虚拟属性名称 (user_results) 应该不同于任何现有的可序列化字段.

Please try to use serializer.post_serialize event instead of serializer.pre_serialize one. Also your virtual property name (user_results) should be different from any existing serializable fields.

setData 方法的第二个参数必须是常规标量或数组.它不能包含任何对象.我建议将 JMS 序列化程序注入到您的侦听器类中,以将您的对象数组序列化为标量数组.

The second argument of setData method must either be a regular scalar, or an array. It must not contain any objects. I suggest to inject JMS serializer into your listener class to serialize your objects array into array of scalars.

<?php

namespace AppBundleSerializer;

use JMSSerializerEventDispatcherEventSubscriberInterface;
use JMSSerializerEventDispatcherPreSerializeEvent;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorage;
use JMSSerializerEventDispatcherObjectEvent;
use JMSSerializerSerializer;

class ExerciseSubscriber implements EventSubscriberInterface
{
    private $currentUser;
    private $serializer;

    public function __construct(TokenStorage $tokenStorage, Serializer $serializer)
    {
        $this->currentUser = $tokenStorage->getToken()->getUser();
        $this->serializer  = $serializer;
    }

    public static function getSubscribedEvents()
    {
        return array(
            array(
                'event'  => 'serializer.post_serialize',
                'method' => 'onPostSerialize',
                'class'  => Exercise::class, // if no class, subscribe to every serialization
                'format' => 'json', // optional format
            ),
        );
    }

    public function onPostSerialize(ObjectEvent $event)
    {
        if (!$this->currentUser) {
            return;
        }

        $exercise = $event->getObject();
        $visitor = $event->getVisitor();

        $visitor->setData(
            'user_results',
            $this->serializer->toArray($exercise->getUserResults($this->currentUser))
        );
    }
}

这篇关于带有参数和自定义侦听器/订阅者的 JMS VirtualProperty的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 03:15