串行器Symfony上的回调

时间:2015-10-15 12:36:15

标签: php symfony serialization

我正在运行Symfony 2.7,我正在尝试输出一个对象(Doctrine实体)作为JSON。

当我对对象进行规范化时,我想转换它的一些值。要做到这一点,我在the documentation中找到了“setCallbacks”方法,但我对如何将它应用于我的案例感到有点困惑。

有没有办法在调用Symfonys序列化程序服务时设置的规范化程序上调用“setCallbacks”方法?

以下是我想要实现的一个简短示例:

//ExampleController.php

public function getJSONOrderByIdAction($id) {
    $serializer = $this->get('serializer');
    $normalizer = $serializer->getNormalizer(); // <- This is what I'm unable to do

    $dateTimeToString = function ($dateTime) {
        return $dateTime instanceof \DateTime ? $dateTime->format(\DateTime::ISO8601) : '';
    };

    $normalizer->setCallbacks(['time' => $dateTimeToString]);


    $order = $this->getDoctrine()->find("AppBundle:Order", $id);

    return new JsonResponse(["order" => $serializer->normalize($order, null, ["groups" => ["public"]])]);
}

我知道大多数人都已切换到JMS序列化程序。看起来好像内置的序列化程序应该能够处理我想要实现的目标。

4 个答案:

答案 0 :(得分:4)

默认的Serializer服务是在依赖注入阶段创建的,而Serializer接口不允许编辑(完全)检索规范化器。

我认为你(至少)有三个选择:

  1. 将自定义规范化程序添加到默认的Serializer服务
  2. 将NormalizableInterface添加到您的实体
  3. 按照您的尝试创建新的Serializer服务(或文档建议的本地对象)。
  4. 我认为在你的场景中,案例1是首选(因为2变得很无聊)。

    我会做这样的事情;首先创建一个自定义规范化器

    <?php
    namespace AppBundle; 
    
    class DateTimeNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface
    {
        /**
         * {@inheritdoc}
         */
        public function normalize($object, $format = null, array $context = array())
        {
            return $object->format(\DateTime::ISO8601);
        }
    
        /**
         * {@inheritdoc}
         */
        public function denormalize($data, $class, $format = null, array $context = array())
        {
            return new $class($data);
        }
    
        /**
         * Checks if the given class is a DateTime.
         *
         * @param mixed  $data   Data to normalize.
         * @param string $format The format being (de-)serialized from or into.
         *
         * @return bool
         */
        public function supportsNormalization($data, $format = null)
        {
            return $data instanceof \DateTime;
        }
    
        /**
         * Checks if the given class is a DateTime.
         *
         * @param mixed  $data   Data to denormalize from.
         * @param string $type   The class to which the data should be denormalized.
         * @param string $format The format being deserialized from.
         *
         * @return bool
         */
        public function supportsDenormalization($data, $type, $format = null)
        {
            $class = new \ReflectionClass($type);
    
            return $class->isSubclassOf('\DateTime');
        }
    }
    

    然后将其注册到您的服务:

    # app/config/services.yml
    services:
        datetime_normalizer:
            class: AppBundle\DateTimeNormalizer
            tags:
                - { name: serializer.normalizer }
    

答案 1 :(得分:3)

我自己的解决方案

根据giosh94mhz的建议,我尝试切换到JMS Serializer但最终回到了Symfonys序列化程序。

JMS Serializer提出了它自己的问题,在搜索那些偶然发现blog post by Thomas Jarrand的人的答案时,他们做了很好的工作,解释了如何让实现你自己的规范化程序在Symfony。

答案 2 :(得分:1)

您可以使用K.Dunglas组件的回调规范化器。

您可以在ObjectNormalizer中看到它(在normalize方法中)

if (isset($this->callbacks[$attribute])) {
    $attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
 }

这意味着您必须在回调数组键中使用您不想标准化的属性名称。

例如,在我的实体中,我有一个名为“名称”的字段,其类型为“ pgarray”(类似于postgresql的数组)。我不想将这些数据标准化。相反,我需要一个字符串。

/**
     * $object represent the property "name" because callback is attached to name property (setCallback)
     */
    $nameCallback = function ($object, $outerObject = null) {
        return $object[0];      
    };
    $this->normalizer->setCallbacks(['name' => $dateCallback]);

请记住,自Symfony 4.2起,您必须在DI中使用$ context才能使用回调。

答案 3 :(得分:0)

在我看来,你似乎试图让事情过于复杂。这是我在需要将实体序列化为JSON时所采用的方法:

PHP 2.5及更高版本允许您在对象上实现jsonSerialize方法,并直接在对象上调用json_encode

如果您仍在使用PHP 2.4,则只需在对象上手动调用jsonSerialize()

例如:

/**
 * @ORM\Entity
 */
class MyEntity {
    ...
    public function jsonSerialize() {
        $data = array("foo" => $this->bar());
        // add other data here ...
        return $data
    }
}

然后在调用代码时:

// for PHP 2.5 and up:
$normalized = json_encode($myEntityInstance);

// for PHP 2.4 and below
$normalized = json_encode($myEntityInstance->jsonSerialize());