我在Symfony 2.8中有一个应用程序,当我通过payum - omnipay-bridge和omnipay / targetpay捕获付款时出现错误。
当我致电prepareAction时,我会被重定向到targetpay网站上的外部付款表单。当我取消(取消=在testmode中付款)时,我被重定向回我的网站,但有以下例外:
Invalid input given. Should be an array or instance of \Traversable (500 Internal Server Error)
当我刷新页面时,我最终会在最终路线上结束' bsdb_payment_membership_status' (请参阅PaymentController),我的付款状态是' new'。我的付款流程出了什么问题?
我的composer.json看起来像这样:
"payum/payum-bundle": "~2.0",
"payum/omnipay-bridge": "~1.2",
"omnipay/targetpay": "~2.1",
我的config.yml看起来像这样:
payum:
security:
token_storage:
Bsdb\BsdbPaymentBundle\Entity\PaymentToken: { doctrine: orm }
storages:
Bsdb\BsdbPaymentBundle\Entity\PaymentDetails: { doctrine: orm }
gateways:
bsdb_membership_payment:
factory: omnipay
type: "TargetPay_Mrcash"
options:
subAccountId: 123456
testMode: true
我创建了一个自定义PaymentBundle: - 实体PaymentDetails - 实体PaymentToken - 带有prepareAction和captureDoneAction的Controller PaymentController
实体PaymentToken
namespace Bsdb\BsdbPaymentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Token;
/**
* @ORM\Table
* @ORM\Entity
*/
class PaymentToken extends Token
{
}
实体PaymentDetails
namespace Bsdb\BsdbPaymentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\ArrayObject;
use Application\Sonata\UserBundle\Entity\User;
/**
* @ORM\Table(name="PaymentDetails")
* @ORM\Entity
*/
class PaymentDetails extends ArrayObject
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*
* @var integer $id
*/
protected $id;
/**
* @var User $user
*
* @ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
* })
*/
protected $user;
/**
* @var \DateTime
*
* @ORM\Column(name="started_at", type="datetime", nullable=true)
*/
protected $startedAt;
/**
* @var \DateTime
*
* @ORM\Column(name="completed_at", type="datetime", nullable=true)
*/
protected $completedAt;
/**
* Set start date:
*/
public function __construct()
{
$this->setStartedAt(new \DateTime());
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param User $user
*/
public function setUser($user)
{
$this->user = $user;
}
/**
* @return \DateTime
*/
public function getStartedAt()
{
return $this->startedAt;
}
/**
* @param \DateTime $startedAt
*/
public function setStartedAt($startedAt)
{
$this->startedAt = $startedAt;
}
/**
* @return \DateTime
*/
public function getCompletedAt()
{
return $this->completedAt;
}
/**
* @param \DateTime $completedAt
*/
public function setCompletedAt($completedAt)
{
$this->completedAt = $completedAt;
}
public function getDetailsString()
{
return json_encode($this->details);
}
}
Controller PaymentController
namespace Bsdb\BsdbPaymentBundle\Controller;
use Application\Sonata\UserBundle\Entity\User;
use Application\Sonata\UserBundle\Event\UserEvent;
use Application\Sonata\UserBundle\Service\UserGroupAttacher;
use Application\Sonata\UserBundle\UserEvents;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Payum\Core\Request\GetHumanStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
class PaymentController extends Controller
{
/**
* @Route(name="bsdb_payment_membership_prepare", path="/membership/prepare")
*/
public function prepareAction()
{
$paymentName = 'bsdb_membership_payment';
$storage = $this->get('payum')->getStorage('Bsdb\BsdbPaymentBundle\Entity\PaymentDetails');
$currentUser = $this->get('security.context')->getToken()->getUser();
/** @var \Bsdb\BsdbPaymentBundle\Entity\PaymentDetails $paymentDetails */
$paymentDetails = $storage->create();
$paymentDetails['amount'] = $this->container->getParameter('premium.amount');
$paymentDetails['description'] = $this->container->getParameter('premium.description');
$paymentDetails['clientIp'] = $this->get('request')->getClientIp();
$paymentDetails->setUser($currentUser);
$storage->update($paymentDetails);
$captureToken = $this->get('payum')->getTokenFactory()->createCaptureToken(
$paymentName,
$paymentDetails,
'bsdb_payment_membership_captured' // the route to redirect after capture;
);
return $this->redirect($captureToken->getTargetUrl());
}
/**
* @Route(name="bsdb_payment_membership_captured", path="/membership/captured")
*/
public function captureDoneAction(Request $request)
{
$token = $this->get('payum')->getHttpRequestVerifier()->verify($request);
$gateway = $this->get('payum')->getGateway($token->getGatewayName());
$gateway->execute($status = new GetHumanStatus($token));
$payment = $status->getFirstModel();
if ($status->isCaptured()) {
/** @var User $user */
$user = $this->getUser();
$user->setLastPremiumUpgrade(new \DateTime());
$user->setPremiumExpiresAt(new \DateTime(sprintf('+%s days', $this->container->getParameter('premium.expiration.period'))));
// Set group
$entityManager = $this->getDoctrine()->getManager();
$groupAttachter = new UserGroupAttacher($entityManager);
$groupAttachter->attachUserGroup($user, $this->container->getParameter('premium.group'));
// Update payment data:
$payment->setCompletedAt(new \DateTime());
// Save:
$entityManager->persist($user);
$entityManager->flush();
// Trigger events for emails and stuff:
$event = new UserEvent($user);
$this->get('event_dispatcher')->dispatch(UserEvents::USER_PREMIUM_PURCHASED, $event);
}
return $this->redirect($this->generateUrl('bsdb_payment_membership_status', array('status' => $status->getValue())));
}
/**
* @Route(name="bsdb_payment_membership_status", path="/membership/status/{status}")
* @Template()
*/
public function paidAction($status)
{
return array('status' => $status);
}
}
感谢您的专业知识!