使用JMSSerializerBundle在symfony2中序列化之前自动转换

时间:2013-12-12 13:25:07

标签: symfony doctrine jmsserializerbundle

我从数据库中获取实体后(通过findAll())并在将结果序列化为json之前应用了一些逻辑。

我想在某些字段上添加翻译。我知道我可以通过迭代每个实体并在控制器中应用我的逻辑来手动完成。但我需要一个更好的方法来做到这一点。

是否有建议将其自动化?

2 个答案:

答案 0 :(得分:4)

我遇到了类似的问题并试图使用自定义处理程序解决这个问题,但没有成功,所以我创建了编译器传递并覆盖了JsonSerializationVisitor,其中字符串值使用TranslatableJsonSerializationVisitor类进行序列化:

namespace tkuska\DemoBundle\Serialization;
use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\Context; 

class TranslatableJsonSerializationVisitor extends JsonSerializationVisitor
{
    /**
     * @var \Symfony\Component\Translation\Translator;
     */
    private $translator;

    public function visitString($data, array $type, Context $context)
    {
        if (in_array('translatable', $type['params'])) {
            return (string) $this->translator->trans($data);
        }
        return (string) $data;
    }

    public function setTranslator(\Symfony\Component\Translation\Translator $translator)
    {
        $this->translator = $translator;
    }
}

和编译器:

namespace tkuska\DemoBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class TranslatableJsonSerializationCompiler implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $jmsJsonSerializationVisitor = $container->getDefinition('jms_serializer.json_serialization_visitor');
        $jmsJsonSerializationVisitor->setClass('tkuska\DemoBundle\Serialization\TranslatableJsonSerializationVisitor');

        $jmsJsonSerializationVisitor->addMethodCall('setTranslator', array(new Reference('translator')));
    }
}
实体中的

我为类型'字符串'设置了注释。与param' translatable'

/**
 * @VirtualProperty
 * @Groups({"details"})
 * @Type("string<'translatable'>")
 * @return order status
 */
public function getOrderStatus(){
    return 'status.ordered';
}

当然&#39; status.ordered&#39;是我的翻译密钥。

答案 1 :(得分:1)

谢谢@zizoujab。非常有用的帖子。我对它做了一个小改进,调用父方法并取消设置我的参数,这样我就可以使用这种方式在更复杂的类型上更改数据,比如数组,已经有参数并使用了

/**
 * @VirtualProperty
 * @Groups({"details"})
 * @Type("string<translatable>")
 * @return order status
 */

而不是

/**
 * @VirtualProperty
 * @Groups({"details"})
 * @Type("string<'translatable'>")
 * @return order status
 */

转换字符串&#39; translatable&#39;参数名称而不是参数值,因此您可以传递更复杂的参数,并允许我在调用父方法之前取消设置此参数。

/**
 * @VirtualProperty
 * @Groups({"details"})
 * @Type("string<translatable<set of parameters>>")
 * @return order status
 */

代码:

<?php

namespace Mktp\DefaultBundle\Service\JmsSerializer;

use JMS\Serializer\Context;
use JMS\Serializer\JsonSerializationVisitor;
use Symfony\Component\Translation\Translator;

class TranslatableJsonSerializationVisitor extends JsonSerializationVisitor
{
    /**
     * @var Translator;
     */
    private $translator;

    /**
     * @param string $data
     * @param array $type
     * @param Context $context
     * @return string
     */
    public function visitString($data, array $type, Context $context)
    {
        $translatable = $this->getParameters('translatable', $type['params']);
        if (count($translatable)) {
            $data = (string)$this->translator->trans($data);
        }
        return parent::visitString($data, $type, $context);
    }

    /**
     * @param array $data
     * @param array $type
     * @param Context $context
     * @return array|\ArrayObject|mixed
     */
    public function visitArray($data, array $type, Context $context)
    {
        $translatable = $this->getParameters('translatable', $type['params']);

        if (count($translatable)) {
            foreach ($data as $key => $value) {
                if (is_string($value)) {
                    $data[$key] = (string)$this->translator->trans($value);
                }
            }

        }
        return parent::visitArray($data, $type, $context);
    }

    /**
     * @param Translator $translator
     */
    public function setTranslator(Translator $translator)
    {
        $this->translator = $translator;
    }

    /**
     * @param string $type
     * @param array $parameters
     * @param bool $unsetParameters
     * @return array
     */
    protected function getParameters($type, &$parameters, $unsetParameters = true)
    {
        $result = array();
        foreach ($parameters as $key => $parameter) {
            if ($parameter['name'] == $type) {
                $result[] = $parameter;
                if ($unsetParameters) {
                    unset($parameters[$key]);
                }
            }
        }
        $parameters = array_values($parameters);
        return $result;
    }
}