如何在写入数据之前使用 API-平台事件改变数据
How to mutate data with API-Platform events before writting it
我有一个用户和一个具有多对一关系的大学实体(一所大学可以有很多用户)。我在大学名称上添加了唯一性约束以避免重复。
因此,当我在 /users/$id 路由上使用包含存在的大学名称的有效负载执行 PUT HTTP 请求时,我得到以下信息:
Integrity constraint violation: 1062 Duplicate entry 'INSA' for key 'unique_university_name'
我想要的是在 doctrine 将条目写入数据库之前,如果它已经存在则对其进行变异。
为此,我尝试使用 API 平台的事件系统:https://api-platform.com/docs/core/events
通过 kernel.request 事件,我可以访问数据,但我没能改变它。我没有找到更改请求的 "content" 的方法。我也试过这个:Is there a way to modify request body in a Symfony kernel event_listener 最后我遇到了这个错误。
Serialization for the format html is not supported
我想用 kernel.view 事件来做,例如 PRE_VALIDATE、POST_VALIDATE 或 PRE_WRITE,但由于某种原因它们没有被触发。
我使用的方法正确吗?如果根据 "name"?
大学已经存在,我应该如何将大学添加到用户
如果我理解正确,您想修改嵌入在 user
实体中的 university
对象。
如果您正在按照文档进行操作,并且这样做,那么它将不起作用,因为主要对象是一个 User
实例。
$object = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$object instanceof University || Request::METHOD_POST !== $method) {
return;
}
一种方法是:
$object = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$object instanceof User || Request::METHOD_POST !== $method) {
return;
}
$university = $user->getUniversity();
// modify or replace your university here.
另一种方法是使用 doctrine event subscriber, keep in mind that this gets executed after entity validation。
为了解决您的问题,我看到了 3 种可能性:
- 添加一个自定义反规范化程序来验证名称并即时更改它(详见下文)
- 添加 custom listener for doctrine 预持久化事件
- 使用域事件参见 this lib 示例
以下是创建自定义反规范化器的方法:
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
final class UniversityDenormalizer implements DenormalizerInterface
{
private $decoratedDenormalizer;
private $repository;
public function __construct(DenormalizerInterface $decorated, UniversityRepository $repository) {
$this->repository = $repository;
$this->decoratedNormalizer = $decorated;
}
public function denormalize($data, $class, $format = null, array $context = array())
{
if ($count = $this->repository->countUniversitiesStartingBy($data['name'])) {
$data['name'] .= '_' . ($this->repository->countUniversities() + 1);
}
return $this->decoratedDenormalizer->denormalize($data, $class, $context);
}
public function supportsDenormalization($data, $type, $format = null)
{
return is_string($data) && University::class === $type;
}
}
您还需要将其注册为服务:
App\Serializer\UniversityDenormalizer:
arguments:
# Choose the denormalizer depending on your output.
# For example, for JSON+LD it's "api_platform.jsonld.normalizer.item"
- '@api_platform.json.normalizer.item'
- '@App\Repository\UniversityRepository'
tags:
# Priority is important but any value more than 8 should be ok
- { name: serializer.normalizer, priority: 17 }
我有一个用户和一个具有多对一关系的大学实体(一所大学可以有很多用户)。我在大学名称上添加了唯一性约束以避免重复。
因此,当我在 /users/$id 路由上使用包含存在的大学名称的有效负载执行 PUT HTTP 请求时,我得到以下信息:
Integrity constraint violation: 1062 Duplicate entry 'INSA' for key 'unique_university_name'
我想要的是在 doctrine 将条目写入数据库之前,如果它已经存在则对其进行变异。
为此,我尝试使用 API 平台的事件系统:https://api-platform.com/docs/core/events
通过 kernel.request 事件,我可以访问数据,但我没能改变它。我没有找到更改请求的 "content" 的方法。我也试过这个:Is there a way to modify request body in a Symfony kernel event_listener 最后我遇到了这个错误。
Serialization for the format html is not supported
我想用 kernel.view 事件来做,例如 PRE_VALIDATE、POST_VALIDATE 或 PRE_WRITE,但由于某种原因它们没有被触发。
我使用的方法正确吗?如果根据 "name"?
大学已经存在,我应该如何将大学添加到用户如果我理解正确,您想修改嵌入在 user
实体中的 university
对象。
如果您正在按照文档进行操作,并且这样做,那么它将不起作用,因为主要对象是一个 User
实例。
$object = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$object instanceof University || Request::METHOD_POST !== $method) {
return;
}
一种方法是:
$object = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$object instanceof User || Request::METHOD_POST !== $method) {
return;
}
$university = $user->getUniversity();
// modify or replace your university here.
另一种方法是使用 doctrine event subscriber, keep in mind that this gets executed after entity validation。
为了解决您的问题,我看到了 3 种可能性:
- 添加一个自定义反规范化程序来验证名称并即时更改它(详见下文)
- 添加 custom listener for doctrine 预持久化事件
- 使用域事件参见 this lib 示例
以下是创建自定义反规范化器的方法:
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
final class UniversityDenormalizer implements DenormalizerInterface
{
private $decoratedDenormalizer;
private $repository;
public function __construct(DenormalizerInterface $decorated, UniversityRepository $repository) {
$this->repository = $repository;
$this->decoratedNormalizer = $decorated;
}
public function denormalize($data, $class, $format = null, array $context = array())
{
if ($count = $this->repository->countUniversitiesStartingBy($data['name'])) {
$data['name'] .= '_' . ($this->repository->countUniversities() + 1);
}
return $this->decoratedDenormalizer->denormalize($data, $class, $context);
}
public function supportsDenormalization($data, $type, $format = null)
{
return is_string($data) && University::class === $type;
}
}
您还需要将其注册为服务:
App\Serializer\UniversityDenormalizer:
arguments:
# Choose the denormalizer depending on your output.
# For example, for JSON+LD it's "api_platform.jsonld.normalizer.item"
- '@api_platform.json.normalizer.item'
- '@App\Repository\UniversityRepository'
tags:
# Priority is important but any value more than 8 should be ok
- { name: serializer.normalizer, priority: 17 }