当我尝试
denormalize
具有 float
属性但具有 int
值的对象时,出现错误。
Symfony\Component\Serializer\Exception\NotNormalizableValueException
:
类的“solde”属性的类型 “钱包”必须是“float”之一(“int” 给出)。
我的序列化器配置:
class SerializerService implements SerializerInterface, NormalizerInterface, DenormalizerInterface
{
public const JSON_FORMAT = 'json';
/**
* @var Serializer
*/
private $serializer;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @param LoggerInterface $logger
*/
public function __construct(
LoggerInterface $logger
) {
$this->logger = $logger;
$this->serializer = new Serializer([
new DateTimeNormalizer(),
new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
new ArrayDenormalizer()
], [
new JsonEncoder(
new JsonEncode(),
new JsonDecode(),
)
]);
}
...
...
我在 Symfony Serializer 文档中没有找到任何相关内容。
你能帮我吗?
问题不在于序列化器,而在于您的数据。你可能有这样的想法:
{
“solde”: 1.0
}
但它应该是:
{“solde”: 1}
,即您的数据应该是 int 而不是 float。
如果你将 Wallet 对象中的
$solde
设置为 float,而不是 int,则不会出现此问题,因为从 int 转换为 float 通常是无损的,即 1 到 1.0。另外,您一开始就不应该接受此类数据的浮点数。假设“1.0”代表 1 美元或 1 欧元,那么通常将其保存为字符串或整数,即 100,我建议您的 JSON 也使用这种格式。这样,您就不需要浮点数,也不会遇到奇怪的浮点问题。我强烈建议走这条路。由于您以另一种方式进行转换(从 float 到 int),您将失去精度,即 1.5 将变为 1 或 2,这显然很糟糕,因为您的用户可能不知道这将是 2 个可能结果中的哪一个。
回到你的错误。在您的对象中,您可以在接收数据(即从 JSON 设置字段)时或在读取数据时解决此类型问题。对于前者,在该字段的对象设置器内进行有损转换(转换为 int、舍入等)。您可能需要调整您的 ObjectNormalizer 以使用 getter 和 setter 来实现此目的,但默认情况下它应该使用 PropertyAccess 组件,如果我没有记错的话,它应该在查找属性之前使用 setter。大概是这样的:
class Wallet
{
private int $solde;
// …
public function setSolde(float|int $solde): void
{
$this->solde = (int) $solde; // casting to int will just cut off anything after the “.” in floats
}
}
您还可以让字段为 float 或 int,然后在 getter 上进行转换,即当您使用该字段时,但当您想要将数据保留在数据库中时可能会遇到问题。
class Wallet
{
private int|float $solde;
// …
public function getSolde(): int
{
return (int) $this->solde; // casting to int will just cut off anything after the “.” in floats
}
}
如果你不想为此调整你的对象,那么你可以通过编写自定义反规范化器来教序列化器进行有损转换(Symfony 在其规范化器中结合了反规范化器和规范化器,即 ObjectNormalizer,如果你正在寻找参考如何写)。然后,该反规范化器将处理您的对象(即 Wallet),并手动将 JSON 中的每个字段映射到对象的字段,包括“solde”,其中存在类型错误。然后,您可以通过执行有损转换(转换为 int、舍入等)来解决 Denormalizer 中的类型错误。您必须小心,不要使反规范化器过于通用,因为即使在您不希望这样做的地方,您最终也可能会这样做。 Symfony 在自定义规范化器/反规范化器的文档中有一部分,所以它应该相当简单。如果你真的需要这个,我建议你走这条路,假设你只需要在从 JSON 读取数据时担心这个问题。
如果您传递“json”格式,Symfony Serialiser 无法更改值的类型。您应该严格遵循类型。
但是如果使用“xml”格式而不是 json,Symfony\Component\Serializer\NormalizerAbstractObjectNormalizer 中的“validateAndDenormalize”方法可以将类型从“string”更改为“int”或“float”。