我正在使用 API 平台 3.1。我需要在创建后生成某些实体的缩略图。我想使用Symfony Messenger触发此操作并异步执行,因为可能需要一些时间来处理,但我希望立即保存实体。
当资源同时使用信使和自定义处理器(以保存实体)时,如果使用 messenger=true
则不会创建消息,或者如果使用 则不会调用处理器>messenger='输入'
。
如何重现
#[ORM\Entity]
#[ApiResource(
operations: [
new Post(
processor: MyEntityProcessor::class,
messenger: 'input',
deserialize: false,
)
]
)]
class MyEntity
{
}
final class MyEntityProcessor implements ProcessorInterface
{
public function __construct(private ProcessorInterface $persistProcessor)
{
}
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
{
$result = $this->persistProcessor->process($data, $operation, $uriVariables, $context);
return $result;
}
}
final class MyEntityHandler implements MessageHandlerInterface
{
public function __construct(private EntityManagerInterface $entityManager)
{
}
public function __invoke(MyEntity $myEntity)
{
// my long running function
$this->entityManager->persist($myEntity);
$this->entityManager->flush();
}
}
services.yaml
services:
App\State\MyEntityProcessor:
bind:
$persistProcessor: '@api_platform.doctrine.orm.state.item_provider'
messenger.yaml
framework:
messenger:
transports:
async: 'doctrine://default'
routing:
'App\Entity\MyEntity': async
Symfony Messenger Integration 中提到的 API 平台文档:
Note: when using
messenger=true
ApiResource attribute in a Doctrine entity, the Doctrine Processor is not called. If you want the Doctrine Processor to be called, you should decorate a built-in state processor and implement your own logic.
这是 suggested on a GitHub issue我应该装饰消息处理程序以保存实体。但是,我需要立即保存我的实体,而不是等待它被 messenger:consume
工作线程消耗。
最佳答案
一个可能的解决方案是在第一次持久化实体
后在您的处理器
中分派(dispatch)消息
。也许不是那么干净,因为它需要更多代码,但是您可以更好地控制 Message
的处理方式和时间。此外,您还可以使用 DelayStamp
来发送它。 .
在你的处理器中我会 dispatch the Message
像这样:
final class MyEntityProcessor implements ProcessorInterface
{
public function __construct(
private ProcessorInterface $persistProcessor,
private MessageBusInterface $bus,
) {
}
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
{
$result = $this->persistProcessor->process($data, $operation, $uriVariables, $context);
// $data should be your MyEntity Entity.
$this->bus->dispatch(new GenerateThumbMessage($data), [
// wait 5 seconds before processing
new DelayStamp(5000),
]);
return $result;
}
}
Create the Message
App\Message\GenerateThumbMessage.php
:
class GenerateThumbMessage
{
public function __construct(private readonly MyEntity $myEntity) {}
public function getMyEntity(): MyEntity
{
return $this->myEntity;
}
}
然后create your MessageHandler
App\Message\GenerateThumbMessageHandler.php
:
final class GenerateThumbMessageHandler implements MessageHandlerInterface
{
public function __construct(private EntityManagerInterface $em) {}
public function __invoke(GenerateThumbMessage $generateThumbMessage)
{
$myEntity = $generateThumbMessage->getMyEntity();
// your long running function to generate a thumbnail
$this->em->persist($myEntity);
$this->em->flush();
}
}
您的 messenger.yaml
配置应如下所示:
framework:
messenger:
transports:
async: 'doctrine://default'
routing:
'App\Message\GenerateThumbMessage': async
在配置中,您没有使用实体
,而是将消息
配置为异步处理。
类似的解决方案可以在 API Platform documentation 中找到
关于php - 如果在 APIPlatform 3.1 中的同一资源上使用处理器,Messenger 将无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76972957/