将单个字符串 属性 反序列化为 symfony JMS 中的对象 PHP
Deserialize single string property into object in symfony JMS PHP
具有 PHP、Symfony 4.4、JMS 序列化程序和 json 有效负载(请求正文):
{
"quantity": 1,
"product": {
"sku": "bla"
},
"myId": {
"id": "0010N00005GcOhhQAF"
}
}
此有效负载已发送到我的端点,并且所有内容都已正确反序列化为正确的结果 CustomRequest
对象 - 还正确创建了 Product
和 MyId
等嵌套对象。在 Product
对象的情况下没问题,因为 Product
具有具有多个属性的复杂结构。
但我想实现的是让 myId
的输入更容易。我想要它而不是:
"myId": {
"id": "0010N00005GcOhhQAF"
}
有简单的这个:
"myId": "0010N00005GcOhhQAF"
你可能会问为什么我有 class 作为简单的 id。它不是简单的 id,它内部有一些特殊的验证和业务逻辑,并在所有应用程序中使用,因此为了验证目的,最好有一个对象。
所以可以说,我希望我的反序列化器自动将那个简单的 id 字符串放入 class MyId 和 return 对象的构造函数中。 MyId class 很简单 class 比如:
class MyId
{
/**
* @AppAssert\MyId()
*/
private ?string $value = null;
public function __construct(string $value)
{
$this->value = $value;
}
public function __toString()
{
return $this->value;
}
}
仅供参考:我在生成的 CustomRequest
对象中尝试了此注释,但它不起作用
/**
* @Serializer\Type("App\Model\MyId")
*/
private ?MyId $myId = null;
编辑:另一个重要部分:这是端点自动将请求主体转换为 CustomRequest
对象的方式。在这里你可以看到,我正在使用 ParamConverter
。
/**
* @Rest\Post("/product")
* @ParamConverter("customRequest", options={
* "validator"={"groups"={"Default","product"="create"}},
* })
*/
public function postCreateProductAction(CustomRequest $customRequest) {
// ...
}
问题是:如何将 JMS 序列化程序与 Symfony 一起使用以使其工作。要采用简单的一个字符串,将其自动传递给构造函数并从中生成对象。这可能吗?谢谢
您需要编写自定义 (De)Normalizer。
这是什么:https://symfony.com/doc/current/components/serializer.html#normalizers
自定义方式:https://symfony.com/doc/current/serializer/custom_normalizer.html
我使用 JMS\Serializer\Handler\SubscribingHandlerInterface
让它工作。使用这种方法,您可以简单地添加在 serialization/deserialization 过程中启动的回调。请参阅下面显示 MyId
对象的精确解的代码。
在此处了解有关此技术的更多信息:https://jmsyst.com/libs/serializer/master/handlers
namespace App\Handlers;
use App\Model\MyId;
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
class MyIdHandler implements SubscribingHandlerInterface
{
/**
* @return array<int, array<string, int|string>>
*/
public static function getSubscribingMethods(): array
{
return [
[
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => MyId::class,
'method' => 'serializeMyIdToJson',
],
[
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => MyId::class,
'method' => 'deserializeMyIdFromJson',
],
];
}
/**
* @param array<mixed> $type
*/
public function serializeMyIdToJson(JsonSerializationVisitor $visitor, ?MyId $myId, array $type, Context $context): string
{
if ($myId === null) {
return '';
}
return (string)$myId;
}
/**
* @param array<mixed> $type
*/
public function deserializeMyIdFromJson(JsonDeserializationVisitor $visitor, string $myId, array $type, Context $context): ?MyId
{
if (empty($myId)) {
return null;
}
return new MyId($myId);
}
}
具有 PHP、Symfony 4.4、JMS 序列化程序和 json 有效负载(请求正文):
{
"quantity": 1,
"product": {
"sku": "bla"
},
"myId": {
"id": "0010N00005GcOhhQAF"
}
}
此有效负载已发送到我的端点,并且所有内容都已正确反序列化为正确的结果 CustomRequest
对象 - 还正确创建了 Product
和 MyId
等嵌套对象。在 Product
对象的情况下没问题,因为 Product
具有具有多个属性的复杂结构。
但我想实现的是让 myId
的输入更容易。我想要它而不是:
"myId": {
"id": "0010N00005GcOhhQAF"
}
有简单的这个:
"myId": "0010N00005GcOhhQAF"
你可能会问为什么我有 class 作为简单的 id。它不是简单的 id,它内部有一些特殊的验证和业务逻辑,并在所有应用程序中使用,因此为了验证目的,最好有一个对象。
所以可以说,我希望我的反序列化器自动将那个简单的 id 字符串放入 class MyId 和 return 对象的构造函数中。 MyId class 很简单 class 比如:
class MyId
{
/**
* @AppAssert\MyId()
*/
private ?string $value = null;
public function __construct(string $value)
{
$this->value = $value;
}
public function __toString()
{
return $this->value;
}
}
仅供参考:我在生成的 CustomRequest
对象中尝试了此注释,但它不起作用
/**
* @Serializer\Type("App\Model\MyId")
*/
private ?MyId $myId = null;
编辑:另一个重要部分:这是端点自动将请求主体转换为 CustomRequest
对象的方式。在这里你可以看到,我正在使用 ParamConverter
。
/**
* @Rest\Post("/product")
* @ParamConverter("customRequest", options={
* "validator"={"groups"={"Default","product"="create"}},
* })
*/
public function postCreateProductAction(CustomRequest $customRequest) {
// ...
}
问题是:如何将 JMS 序列化程序与 Symfony 一起使用以使其工作。要采用简单的一个字符串,将其自动传递给构造函数并从中生成对象。这可能吗?谢谢
您需要编写自定义 (De)Normalizer。
这是什么:https://symfony.com/doc/current/components/serializer.html#normalizers
自定义方式:https://symfony.com/doc/current/serializer/custom_normalizer.html
我使用 JMS\Serializer\Handler\SubscribingHandlerInterface
让它工作。使用这种方法,您可以简单地添加在 serialization/deserialization 过程中启动的回调。请参阅下面显示 MyId
对象的精确解的代码。
在此处了解有关此技术的更多信息:https://jmsyst.com/libs/serializer/master/handlers
namespace App\Handlers;
use App\Model\MyId;
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
class MyIdHandler implements SubscribingHandlerInterface
{
/**
* @return array<int, array<string, int|string>>
*/
public static function getSubscribingMethods(): array
{
return [
[
'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => MyId::class,
'method' => 'serializeMyIdToJson',
],
[
'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => MyId::class,
'method' => 'deserializeMyIdFromJson',
],
];
}
/**
* @param array<mixed> $type
*/
public function serializeMyIdToJson(JsonSerializationVisitor $visitor, ?MyId $myId, array $type, Context $context): string
{
if ($myId === null) {
return '';
}
return (string)$myId;
}
/**
* @param array<mixed> $type
*/
public function deserializeMyIdFromJson(JsonDeserializationVisitor $visitor, string $myId, array $type, Context $context): ?MyId
{
if (empty($myId)) {
return null;
}
return new MyId($myId);
}
}