Symfony 2.8 にアプリケーションがあり、payum 経由で支払いを取得するときにエラーが発生します - omnipay-bridge および omnipay/targetpay です。
prepareAction を呼び出すと、targetpay Web サイトの外部支払いフォームにリダイレクトされます。キャンセルすると (キャンセル = テストモードで支払う)、次の例外を除いて自分のサイトにリダイレクトされます。
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 を作成しました:
エンティティ 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);
}
}
コントローラ 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);
}
}
あなたの専門知識をありがとう!