If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
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.
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.
"Houston: no signs of life"
Start the conversation!
// 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
}
}