我正在尝试使用API Platform捆绑软件在使用Symfony 4.4的嵌入式MongoDB文档上运行反规范化器(数据输入)。对于标准化(数据输出),这可以按预期工作,但是对于非标准化过程,嵌入式数据仅对父数据没有触发。
如果这是它的工作方式,那么我可能需要将非规范化逻辑转移到父级中。也许我只是做错了什么。我要完成的工作是在包含已弃用字段的入站请求上引发异常。解析注释和扫描属性的类按预期工作,只是确定插入位置,而我希望嵌入式文档的反规范化过程能够工作。
这是我的services.yaml:
'App\Serializer\InvestmentNormalizer':
arguments: [ '@security.authorization_checker' ]
tags:
- { name: 'serializer.normalizer', priority: 64 }
'App\Serializer\InvestmentDenormalizer':
tags:
- { name: 'serializer.denormalizer', priority: 64 }
'App\Serializer\ProjectNormalizer':
tags:
- { name: 'serializer.normalizer', priority: 64 }
'App\Serializer\ProjectDenormalizer':
tags:
- { name: 'serializer.denormalizer', priority: 64 }
然后我的反规范化器类永远不会执行:
class ProjectDenormalizer implements DenormalizerInterface
{
private const ALREADY_CALLED = 'PROJECT_DENORMALIZER_ALREADY_CALLED';
public function denormalize($data, $class, $format = null, array $context = [])
{
$context[self::ALREADY_CALLED] = true;
return $this->removeDeprecatedFields($data);
}
public function supportsDenormalization($data, $type, $format = null)
{
if (isset($context[self::ALREADY_CALLED])) {
return false;
}
return $type == get_class(new Project());
}
private function removeDeprecatedFields(array $normalizedData) : array
{
$apiPropertyReader = new AnnotationReader(Project::class, ApiProperty::class);
$deprecatedProperties = $apiPropertyReader->readAllHavingAttribute('deprecationReason');
$errors = [];
foreach (array_keys($deprecatedProperties) as $deprecatedPropertyName) {
if (!isset($normalizedData[$deprecatedPropertyName])) {
continue;
}
$errors[] = $deprecatedPropertyName . ' has been deprecated';
}
if (!empty($errors)) {
throw new DeprecatedFieldException(implode('. ', $errors));
}
return $normalizedData;
}
}
答案 0 :(得分:2)
如果您查看文档,会发现序列化程序组件没有任何serializer.denormalizer
服务,
因此,自动发现不会检测到您的班级。 Symfony Service Tags
您需要遵循并实现规范化程序,该规范化程序在单个类中同时实现规范化程序和去规范化程序逻辑,并将其注册为规范化程序Normalizer & Encoder usages
这听起来听起来有点令人困惑,但是您的规范化器会通过将序列化逻辑标记为适当的方法,来对是否具有DenormalizerInterface
进行规范化和是否具有NormalizerInfterface
进行规范化处理。
它自己的API平台提供了有关两者如何工作的示例:decorating-a-serializer-and-adding-extra-data 这是您在api平台上装饰Normalizer的方法:
services:
'App\Serializer\ApiNormalizer':
decorates: 'api_platform.jsonld.normalizer.item'
arguments: [ '@App\Serializer\ApiNormalizer.inner' ]
或者您可以按照symfony方式注册此规范化器:
services:
get_set_method_normalizer:
class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
tags: [serializer.normalizer]
实施:
namespace App\Serializer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;
final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
private $decorated;
public function __construct(NormalizerInterface $decorated)
{
if (!$decorated instanceof DenormalizerInterface) {
throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
}
$this->decorated = $decorated;
}
public function supportsNormalization($data, $format = null)
{
return $this->decorated->supportsNormalization($data, $format);
}
public function normalize($object, $format = null, array $context = [])
{
$data = $this->decorated->normalize($object, $format, $context);
if (is_array($data)) {
$data['date'] = date(\DateTime::RFC3339);
}
return $data;
}
public function supportsDenormalization($data, $type, $format = null)
{
return $this->decorated->supportsDenormalization($data, $type, $format);
}
public function denormalize($data, $class, $format = null, array $context = [])
{
return $this->decorated->denormalize($data, $class, $format, $context);
}
public function setSerializer(SerializerInterface $serializer)
{
if($this->decorated instanceof SerializerAwareInterface) {
$this->decorated->setSerializer($serializer);
}
}
}
您可以修改逻辑并为每个实体创建Normalizer类。无论您使用哪种数据库,对于PHP和Symfony来说,都是对象。
在此处查看完整的文档以了解其实现方式:Serializer Docs