Buy

We <3 Creating Stripe Customers

Head back to OrderController. Create a $user variable set to $this->getUser():

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 38
\Stripe\Stripe::setApiKey($this->getParameter('stripe_secret_key'));
/** @var User $user */
$user = $this->getUser();
... lines 43 - 70
}
... lines 72 - 78
}
}

This is the User object for who is currently logged in. I'll add some inline documentation to show that.

When the user submits the payment form, there are two different scenarios. First, if (!$user->getStripeCustomerId()), then this is a first-time buyer, and we need to create a new Stripe Customer for them:

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 40
/** @var User $user */
$user = $this->getUser();
if (!$user->getStripeCustomerId()) {
... lines 44 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

To do that, go back to their API documentation and find Create A Customer. Oh hey, it wrote the code for us again! Steal it! And paste it right inside the if statement:

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
$customer = \Stripe\Customer::create([
'email' => $user->getEmail(),
'source' => $token
]);
... lines 48 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

Customer has a lot of fields, but most are optional. Let's set email to $user->getEmail():

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
$customer = \Stripe\Customer::create([
'email' => $user->getEmail(),
... line 46
]);
... lines 48 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

So we can easily look up a user in Stripe's dashboard later.

The really important field is source. This refers to the payment source - so credit or debit card in our case - that you want to attach to the customer. Set this to the $token variable:

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
$customer = \Stripe\Customer::create([
... line 45
'source' => $token
]);
... lines 48 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

This is huge: it will attach that card to their account, and allow us - if we want to - to charge them using that same card in the future.

Set this call to a new $customer variable: the create() method returns a Stripe\Customer object:

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
$customer = \Stripe\Customer::create([
'email' => $user->getEmail(),
'source' => $token
]);
... lines 48 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

And we like that because this object has an id property.

To save that on our user record, say $user->setStripeCustomerId($customer->id):

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
$customer = \Stripe\Customer::create([
'email' => $user->getEmail(),
'source' => $token
]);
$user->setStripeCustomerId($customer->id);
... lines 49 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

Then, I'll use Doctrine to run the UPDATE query to the database:

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
... lines 44 - 47
$user->setStripeCustomerId($customer->id);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
... lines 53 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

If you're not using Doctrine, just make sure to update the user record in the database however you want.

Fetching the Existing Customer Object

Now, add the else: this means the user already has a Stripe customer object. Repeat customer! Instead of creating a new one, just fetch the customer with \Stripe\Customer::retrieve() and pass it $user->getStripeCustomerId():

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
... lines 44 - 52
} else {
$customer = \Stripe\Customer::retrieve($user->getStripeCustomerId());
... lines 55 - 57
}
... lines 59 - 70
}
... lines 72 - 78
}
}

Since this user is already in Stripe, we might eventually re-work our checkout page so that they don't need to re-enter their credit card. But, we haven't done that yet. And since they just submitted fresh card information, we should update their account with that. After all, this might be a different card than what they used the first time they ordered.

To do that, update the source field: set it to $token. To send that update to Stripe, call $customer->save():

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 42
if (!$user->getStripeCustomerId()) {
... lines 44 - 52
} else {
$customer = \Stripe\Customer::retrieve($user->getStripeCustomerId());
$customer->source = $token;
$customer->save();
}
... lines 59 - 70
}
... lines 72 - 78
}
}

So in both situations, the token will now be attached to the customer that's associated with our user. Phew!

Charging the User

The last thing we need to update is the Charge: instead of passing source, charge the customer instead. Set 'customer' => $user->getStripeCustomerId():

80 lines src/AppBundle/Controller/OrderController.php
... lines 1 - 11
class OrderController extends BaseController
{
... lines 14 - 31
public function checkoutAction(Request $request)
{
... lines 34 - 35
if ($request->isMethod('POST')) {
... lines 37 - 59
\Stripe\Charge::create(array(
... lines 61 - 62
"customer" => $user->getStripeCustomerId(),
... line 64
));
... lines 66 - 70
}
... lines 72 - 78
}
}

We're no long saying "Charge this credit card", we're saying "Charge this customer, using whatever credit card they have on file".

Ok, time to try it out! Go back and reload this page. Run through the checkout with our fake data and hit Pay. Hey, hey - no errors!

So go check your Stripe dashboard. Under Payments, you should see this new charge. And if you click into it, it is now associated with a customer. Success! The customer page shows even more information: the attached card, any past payments and eventually subscriptions. This is one big step forward.

Copy the customer's id and query for that on our fos_user table. Yes, it did update!

Since adding a customer went so well, let's talk about invoices.

Leave a comment!