问题描述
我正在使用 Symfony Serializer 3.3 包来将对象转换为 XML。
我希望布尔类型返回为 Y
或 N
,而不是 1
或 0
,而且我不想更改访问器方法。>
这是一个例子:
namespace Acme;
class Person
{
private $name;
private $enabled;
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function isEnabled()
{
return $this->enabled;
}
public function setEnabled($enabled)
{
$this->enabled = $enabled;
}
}
$person = new Acme\Person();
$person->setName('foo');
$person->setEnabled(true);
$serializer->serialize($person,'xml');
得到结果:
<?xml version="1.0"?>
<response>
<name>foo</name>
<enabled>1</enabled> <!-- bad value -->
</response>
预期结果:
<?xml version="1.0"?>
<response>
<name>foo</name>
<enabled>Y</enabled> <!-- goodvalue -->
</response>
解决方法
您可以通过事件订阅者执行此操作。它影响所有布尔属性
<?php
declare(strict_types=1);
namespace App\EventListener\Serializer\Entity;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use JMS\Serializer\Metadata\StaticPropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
class BoolSubscriber implements EventSubscriberInterface
{
/**
* @return array<array<string,mixed>>
*/
public static function getSubscribedEvents(): array
{
return [
[
'event' => Events::POST_SERIALIZE,'method' => 'onPostSerialize','format' => XmlEncoder::FORMAT,'priority' => 0,],];
}
public function onPostSerialize(ObjectEvent $event): void
{
$visitor = $event->getVisitor();
$class = get_class($event->getObject());
$reflectionExtractor = new ReflectionExtractor();
$properties = $reflectionExtractor->getProperties($class);
$propertyAccessor = new PropertyAccessor();
foreach ($properties as $property) {
$types = $reflectionExtractor->getTypes($class,$property);
$type = $types[0] ?? null;
if ($type instanceof Type && $type->getBuiltinType() == Type::BUILTIN_TYPE_BOOL) {
$metadata = new VirtualPropertyMetadata($class,$property);
if ($visitor->hasData($metadata->name)) {
$value = $propertyAccessor->getValue($event->getObject(),$property) ? 'Y' : 'N';
$visitor->visitProperty(
new StaticPropertyMetadata($class,$metadata->name,$value),$value
);
}
}
}
}
}
,
您可以注册一个新的 jms 类型 formatted_boolean
<?php
declare(strict_types=1);
namespace App\Util\Serializer\Normalizer;
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\XmlSerializationVisitor;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
class BoolHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods(): array
{
return [
[
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,'format' => XmlEncoder::FORMAT,'type' => 'formatted_boolean','method' => 'serializeToXml',];
}
public function serializeToXml(
XmlSerializationVisitor $visitor,$value,array $type,Context $context = null
) {
return $value ? 'Y' : 'N';
}
}
但在这种情况下,您必须为每个布尔属性添加 @JMS\Type(name="formatted_boolean")