Stripe:处理 charge/customer 错误,然后将数据插入 PHP 中的数据库

Stripe : handling charge/customer errors then insert data into DB in PHP

我正在使用 Silex 中的 Stripe。在这里,在我的路线中,我从表单获取数据,然后我想创建一个 $customer 和一个 $charge 对象,然后我想将客户和订单信息保存到我的数据库中。

我还想按照 Stripe 文档中的建议使用 try/catch 捕获所有可能的错误,但我觉得我的 try/catch 太长了。如果尝试成功,我想将数据插入我的数据库,但我不知道什么是最佳实践。

这是我的代码:

$app->post('/{category}/{id}', function ($id) use ($app) {

$message = null;

$book = $app['dao.book']->findById($id);

$minAmount = $book->getPrice();
$paidAmount = floatval($_POST['amount']);

// check if value matches
$convMinAmount = ($book->getPrice()) * 100;
$convPaidAmount = (floatval($_POST['amount'])) * 100;

if (($convMinAmount > $convPaidAmount)) {
    $message = 'Veuillez saisir un montant plus élevé que le montant minimum s\'il vous plait.';
} else {
    $item_bought = $book->getTitle();
    $token = $_POST['stripeToken'];
    $stripeinfo = \Stripe\Token::retrieve($token);
    $email = $stripeinfo->email;

    $customer = \Stripe\Customer::create(array(
        'email' => $email,
        'source' => $token
    ));

    try {
        $charge = \Stripe\Charge::create(array(
            'customer' => $customer->id,
            'amount' => $paidAmount * 100,
            'currency' => "eur",
            'description' => 'Achat d\'un livre',
            'receipt_email' => $customer->email
        ));

        // Prepare values for insert into DB
        $full_name = $charge->source->name;
        $address = $charge->source->address_line1 . ', ' . $charge->source->address_city .
            ' ' . $charge->source->address_zip . ', ' . $charge->source->address_country;

        // Save order to DB
        $commande = new Commande();

        $commande->setName($full_name);
        $commande->setAdress($address);
        $commande->setItemBought($item_bought);
        $commande->setPricePaid($paidAmount);
        $commande->setEmail($email);

        $app['dao.commande']->save($commande);

        $message = 'Merci pour votre achat. Votre commande d\'un montant de ' . (floatval($charge->amount)) / 100 . '€ est validée. Un mail récapitulatif vous a été envoyé.';

     } catch (\Stripe\Error\Card $e) {
        echo($e->getMessage());
        // Since it's a decline, \Stripe\Error\Card will be caught
        $body = $e->getJsonBody();
        $err = $body['error'];
        $message = $err;
    } catch (\Stripe\Error\RateLimit $e) {
        // Too many requests made to the API too quickly
        $message = 'Too many requests, veuillez réessayer plus tard s\'il vous plait.';
    } catch (\Stripe\Error\InvalidRequest $e) {
        // Invalid parameters were supplied to Stripe's API
        print('Status is: ' . $e->getHttpStatus() . "\n");
        $message = 'Les paramètres sont invalides, veuillez s\'il vous plait contacter le webmaster du site.';
    } catch (\Stripe\Error\Authentication $e) {
        // Authentication with Stripe's API failed
        // (maybe you changed API keys recently)
        $message = 'L\'authentication à l\'API Stripe a échoué, veuillez s\'il vous plait contacter le webmaster du site.';
    } catch (\Stripe\Error\ApiConnection $e) {
        // Network communication with Stripe failed
        $message = 'La communication a échoué, veuillez réessayer plus tard s\'il vous plait.';
    } catch (\Stripe\Error\Base $e) {
        // Display a very generic error to the user, and maybe send
        // yourself an email
        $message = 'Il semblerait que la requête ait échoué, veuillez réessayer plus tard s\'il vous plait';
    } catch (Exception $e) {
        // Something else happened, completely unrelated to Stripe
        $message = 'Il semblerait que la requête ait échoué, veuillez réessayer plus tard s\'il vous plait';
    }
}

return $app['twig']->render('book.html.twig', array(
    'book' => $book,
    'message' => $message,
    'minAmount' => $minAmount
));

最后,我 return $message 处理任何情况,并将用户重定向到书页。 抱歉这个菜鸟问题,我在这里迷路了。该代码正在运行,但我不确定它是最好的方法。感谢您的帮助。

我没用过silex,不过应该和Symfony有很多共同点。在 symfony 中你可以使用事件监听器。 Here 您可以查看一些有关如何实现事件侦听器的示例。

想法是监听异常事件。检查异常是否来自 Stripe,并根据需要设置消息。基本上,您只需将此代码移至事件侦听器,这样您就可以重用它而无需重复代码。然后你可以像这样修改你的例子:

} catch (\Stripe\ErrorInterface $e) {
    $message = $e->getMessage();
} catch (SomeDbException $dbException){
    ...
}

假设所有 Stripe Errors 异常都实现相同的接口。 (从未使用过条纹)。

我不知道这是否是最佳实践,但它可以减少和清除您的代码。

编辑 对不起,我误解了你的问题。就你的观点。您应该保留它,因为它预计会有一些额外的数据库异常。如果你把它放在 try/catch 块之后,即使有异常,它也会将数据插入数据库。

但最佳做法是将您的代码(持久保存到数据库)提取到不同的服务中。此方法应该只负责获取请求并返回响应。

因此关于事件的第一点可能如下所示:

if (($convMinAmount > $convPaidAmount)) {
    $message = 'Veuillez saisir un montant plus élevé que le montant minimum s\'il vous plait.';
} else {
    $item_bought = $book->getTitle();
    try{
        $stripeService->makeRequest($_POST['stripeToken'],...)
        $databaseService->insertCommande($charge, $fulname, $address,...)


        $message = 'Merci pour votre achat. Votre commande d\'un montant de ' . (floatval($charge->amount)) / 100 . '€ est validée. Un mail récapitulatif vous a été envoyé.';

    } catch (\Stripe\ErrorInterface $e) {
        $message = $e->getMessage();
    } 
}

return $app['twig']->render('book.html.twig', array(
    'book' => $book,
    'message' => $message,
    'minAmount' => $minAmount
));