【发布时间】:2016-05-15 15:04:43
【问题描述】:
我想知道 Payum(或 PayumBundle)是否在捕获付款时发送事件? 目的是向客户发送确认电子邮件。
我发现什么都不是文档,我在代码源中只发现了三个事件:
- payum.gateway.pre_execute
- payum.gateway.execute
- payum.gateway.post_execute
但我猜它与付款本身无关。顺便说一句,它似乎从未与 Stripe 付款一起发送。
谢谢。
【问题讨论】:
我想知道 Payum(或 PayumBundle)是否在捕获付款时发送事件? 目的是向客户发送确认电子邮件。
我发现什么都不是文档,我在代码源中只发现了三个事件:
但我猜它与付款本身无关。顺便说一句,它似乎从未与 Stripe 付款一起发送。
谢谢。
【问题讨论】:
Payum 默认不调度任何事件。它旨在通过扩展进行扩展。例如,如果您想在实例推送通知 (Paypal IPN) 上做一些事情,您可以添加如下所述的扩展:http://payum.org/doc/1.0/Core/instant-payment-notification
还有一个扩展名为dispatch events。您必须手动创建它并添加到 payum。
【讨论】:
我遇到了同样的问题:针对某些支付操作发送自定义事件。就我而言,我想处理 Authorize 和 Capture 动作。
我注意到Payum 请求可能会为 1 次付款操作处理多次,这就是为什么我需要将我的付款标记为已处理,以便只发送一次我的自定义事件(Payment::$customPaymentEventDispatched 的目的属性)。
这是我的付款实体:
<?php
namespace MyApp\PaymentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Payment as BasePayment;
class Payment extends BasePayment
{
// ...
// Not persisted
protected $payable;
protected $customPaymentEventDispatched = false;
// ...
public function setPayable($payable)
{
$this->payable = $payable;
return $this;
}
public function getPayable()
{
return $this->payable;
}
public function markAsCustomPaymentEventDispatched()
{
$this->customPaymentEventDispatched = true;
return $this;
}
public function isCustomPaymentEventDispatched()
{
return $this->customPaymentEventDispatched;
}
}
然后注册 Payum eventDispatcherExtension 和我的自定义监听器
services:
payum.extension.event_dispatcher:
class: Payum\Core\Bridge\Symfony\Extension\EventDispatcherExtension
arguments: ["@event_dispatcher"]
tags:
- { name: payum.extension, all: true, prepend: false }
my_app_payment.payum.listener.payment_listener:
class: MyApp\PaymentBundle\EventListener\PaymentListener
arguments:
- "@monolog.logger.payment"
tags:
- { name: kernel.event_listener, event: payum.gateway.post_execute }
以及监听器的代码:
<?php
namespace MyApp\PaymentBundle\EventListener;
use Payum\Core\Bridge\Symfony\Event\ExecuteEvent;
use Payum\Core\Request\Authorize;
use Payum\Core\Request\BaseGetStatus;
use Payum\Core\Request\Capture;
use Payum\Core\Model\PaymentInterface;
use Payum\Core\Request\GetHumanStatus;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use MyApp\PaymentBundle\Entity\Payment;
use MyApp\PaymentBundle\Event\PayablePaymentStatusChangeEvent;
use MyApp\PaymentBundle\PaymentEvents;
class PaymentListener
{
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onPayumGatewayPostexecute(ExecuteEvent $event, $eventName, EventDispatcherInterface $eventDispatcher)
{
$request = $event->getContext()->getRequest();
// Exclude Payum GetStatus request
// => protect from infinite loop as following code execute one GetStatus request
if ($request instanceof BaseGetStatus) {
return;
}
// Request types requiring dispatching an event
if (!($request instanceof Authorize || $request instanceof Capture)) {
return;
}
$payment = $request->getFirstModel();
if (!$payment instanceof PaymentInterface) {
return;
}
$event->getContext()->getGateway()->execute($status = new GetHumanStatus($payment));
if (!$payment->isCustomPaymentEventDispatched()) {
if ($request instanceof Capture && $status->isCaptured())
{
$payable = $payment->getPayable();
$this->logger->info('Dispatching PAYMENT_SUCCESS for '.$payable->__toString());
$tmEvent = new PayablePaymentStatusChangeEvent($payment->getPayable());
$eventDispatcher->dispatch(PaymentEvents::PAYMENT_PENDING, $tmEvent);
$payment->markAsCustomPaymentEventDispatched();
}
elseif ($request instanceof Authorize && $status->isAuthorized())
{
$payable = $payment->getPayable();
$this->logger->info('Dispatching PAYMENT_PENDING for '.$payable->__toString());
$tmEvent = new PayablePaymentStatusChangeEvent($payment->getPayable());
$eventDispatcher->dispatch(PaymentEvents::PAYMENT_PENDING, $tmEvent);
$payment->markAsCustomPaymentEventDispatched();
}
}
}
}
我对这个实现并不完全满意,但我没有找到更好的方法来实现它。如有任何反馈,我将不胜感激!
【讨论】:
这就是您可以检查付款是否被捕获的方法:
use Payum\Core\Action\CapturePaymentAction;
use Payum\Core\Bridge\Symfony\Event\ExecuteEvent;
use Payum\Core\Request\Capture;
use Payum\Core\Request\GetHumanStatus;
class SuccessPaymentListener
{
public function onPostExecute(ExecuteEvent $event) {
$context = $event->getContext();
$action = $context->getAction();
$request = $context->getRequest();
if ($action instanceof CapturePaymentAction && $request instanceof Capture) {
$status = new GetHumanStatus($request->getToken());
$gateway = $context->getGateway();
$gateway->execute($status);
if ($status->isCaptured()) {
$payment = $status->getFirstModel();
//here is your stuff
}
}
}
}
services.yml:
app.payum.extension.event_dispatcher:
class: Payum\Core\Bridge\Symfony\Extension\EventDispatcherExtension
arguments: ["@event_dispatcher"]
tags:
- { name: payum.extension, all: true, prepend: false }
app.success_payment_listener:
class: AppBundle\Listener\SuccessPaymentListener
tags:
- { name: kernel.event_listener, event: payum.gateway.post_execute, method: onPostExecute }
【讨论】: