Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
This tutorial uses an older version of Symfony of the stripe-php SDK. The majority of the concepts are still valid, though there *are* differences. We've done our best to add notes & comments that describe these changes.

Pretty Card Formatting

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $9.00

The old, embedded form had a couple of nice formatting behaviors - like automatically adding a space between every 4 card numbers. Fortunately, Stripe has us covered once again here. Go back to the documentation and scroll down - they eventually reference something called jQuery.payment: a neat little JavaScript library for formatting checkout fields nicely.

It even provides validation, in case you want to make sure the numbers are sane before sending them off to Stripe.

I've already downloaded this library into the web/js directory, so all we need to do is include it on the page and point it at our form.

At the top, add a new script tag and set its src="js/jQuery.payment.min.js":

... lines 1 - 3
{% block javascripts %}
... lines 5 - 6
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script src="{{ asset('js/jquery.payment.min.js') }}"></script>
... lines 9 - 57
{% endblock %}
... lines 59 - 98

The asset function is an optional helper function from Symfony - nothing magic going on there.

Then, down below... try to ignore the ugly indentation that I should have fixed earlier, and say $form.find(). We need to find the credit card number input. But don't worry! I planned ahead and gave it a special js-cc-number class. I also added js-cc-exp and js-cc-cvc:

<form action="" method="POST" class="js-checkout-form checkout-form">
... lines 2 - 12
<div class="row">
<div class="col-xs-8 col-sm-6 col-sm-offset-2 form-group">
<div class="input-group">
... lines 16 - 18
<input data-stripe="number" type="text" autocomplete="off" class="form-control js-cc-number" id="card-number" required placeholder="Card Number"/>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-4 col-sm-3 col-sm-offset-2 form-group">
<div class="input-group">
... lines 27 - 29
<input data-stripe="exp" type="text" size="4" autocomplete="off" class="form-control js-cc-exp" id="card-expiration" required="required" placeholder="mm/yy"/>
</div>
</div>
<div class="col-xs-4 col-sm-3 form-group">
<div class="input-group">
... lines 35 - 37
<input data-stripe="cvc" type="text" size="4" autocomplete="off" class="form-control js-cc-cvc" id="card-cvc" required="required" placeholder="CVC"/>
</div>
</div>
</div>
... lines 42 - 66
</form>

Fill in .js-cc-number and then call .payment('formatCardNumber'):

... lines 1 - 3
{% block javascripts %}
... lines 5 - 9
<script type="text/javascript">
... lines 11 - 12
$(function () {
var $form = $('.js-checkout-form');
$form.find('.js-cc-number').payment('formatCardNumber');
... lines 17 - 28
});
... lines 30 - 56
</script>
{% endblock %}
... lines 59 - 98

Repeat this two more times for js-cc-exp with formatCardExpiry and formatCardCVC. Don't forget to update that class name too:

... lines 1 - 15
$form.find('.js-cc-number').payment('formatCardNumber');
$form.find('.js-cc-exp').payment('formatCardExpiry');
$form.find('.js-cc-cvc').payment('formatCardCVC');
... lines 19 - 98

Try it out! So sweet! The card field gets pretty auto-spacing and even more importantly, the library adds the slash automatically for the expiration field. It also limits the CVC field to a maximum of 4 numbers.

So custom forms are a little bit more work. But they fundamentally work the same.

Before we finish, there's one big hole left in our setup: failing gracefully when someone's card is declined.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses an older version of Symfony of the stripe-php SDK. The majority of the concepts are still valid, though there *are* differences. We've done our best to add notes & comments that describe these changes.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9, <7.4",
        "symfony/symfony": "3.1.*", // v3.1.10
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "friendsofsymfony/user-bundle": "~2.0.1", // v2.0.1
        "stof/doctrine-extensions-bundle": "^1.2", // v1.2.2
        "stripe/stripe-php": "^3.15", // v3.23.0
        "doctrine/doctrine-migrations-bundle": "^1.1", // 1.1.1
        "twig/twig": "^1.24.1", // v1.35.2
        "composer/package-versions-deprecated": "^1.11" // 1.11.99
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.2
        "hautelook/alice-bundle": "^1.3", // v1.3.1
        "doctrine/data-fixtures": "^1.2" // v1.2.1
    }
}
userVoice