Stripe Customers + Our Users

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

As you can see, there are a lot of objects that you can interact with in Stripe's API. We've only talked about one: Charge. And it's enough to collect money.

But to create a really nice system, you need to talk about the Customer object. Customers give you three big super-powers.

First, if the same customer comes back over-and-over again, right now, they need to enter their credit card information every time. But with a Customer, you can store cards in Stripe and charge them using that. Second, all the charges for a customer will show up in one spot in Stripe's dashboard, instead of all over the place. And third, customers are needed to process subscription payments - something we'll talk about in the next Stripe course.

Storing stripeUserId on the User Table

So here's the goal: instead of creating random Charge objects, let's create a Customer object in Stripe and then charge that Customer. We also need to save the customer id to our user table so that when that user comes back in the future, we'll know that they are already a customer in Stripe.

In this project, the name of the user table is fos_user, and it contains just some basic fields, like email, username and few others related to things like resetting your password.

Let's add a new column called stripeUserId. To do that, open a class in AppBundle called User. Create a new private property called stripeCustomerId:

... lines 1 - 11
class User extends BaseUser
... lines 14 - 23
private $stripeCustomerId;
... lines 25 - 39

Above that, we're going to use annotations to say @ORM\Column(type="string") to create a varchar column. Let's even add a unique index on this field and add nullable=true to allow the field to be empty in the database:

... lines 1 - 11
class User extends BaseUser
... lines 14 - 20
* @ORM\Column(type="string", unique=true, nullable=true)
private $stripeCustomerId;
... lines 25 - 39

At the bottom of the class, I'll use the "Code"->"Generate" menu - or Command+N on a Mac - to generate the getters and setters for the new property:

... lines 1 - 11
class User extends BaseUser
... lines 14 - 30
public function getStripeCustomerId()
return $this->stripeCustomerId;
public function setStripeCustomerId($stripeCustomerId)
$this->stripeCustomerId = $stripeCustomerId;

Now that our PHP code is updated, we need to actually add the new column to our table. Since this project uses Doctrine migrations, open a new tab and run:

php bin/console doctrine:migrations:diff

All that did was create a new file that contains the raw SQL needed to add this new stripe_customer_id column:

... lines 1 - 10
class Version20160709170231 extends AbstractMigration
... lines 13 - 15
public function up(Schema $schema)
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('ALTER TABLE fos_user ADD stripe_customer_id VARCHAR(255) DEFAULT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_957A6479708DC647 ON fos_user (stripe_customer_id)');
... lines 24 - 27
public function down(Schema $schema)
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('DROP INDEX UNIQ_957A6479708DC647 ON fos_user');
$this->addSql('ALTER TABLE fos_user DROP stripe_customer_id');

To execute that, run another command:

php bin/console doctrine:migrations:migrate

Perfect! Back in SQL, you can see the fancy new column on the table.

We are ready to create Stripe customers.

Leave a comment!

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