Crear una suscripción con Symfony y Stripe

En este tutorial os quiero enseñar a crear una suscripción mediante Stripe y Symfony, ya que aunque está más o menos documentado en Stripe, es necesario rebuscar hasta encontrar con el proceso completo. Espero que os sirva de ayuda!

0. Requisitos

Los únicos requisitos para que podáis poner en práctica este tutorial son:

  • Tener instalada la librería stripe/stripe-php
  • Tener la una clave pública y una clave privada para comunicarnos con la API de Stripe. Esto es tan sencillo como registrarse en el portal.
  • No asustarse al ver objetos terminados en DTO (Data Transfer Object) en los parámetros de los métodos de los servicios. Tan solo es una especie de patrón de diseño con el propósito de encapsular la información que se pasa a los servicios.

1. Crear un Plan en Stripe

Lo primero que tenemos que hacer para crear una suscripción con Stripe será crear un Plan en Stripe, lo cual se compone de dos fases:

  • Crear un Product de tipo service , el cual representa el servicio al cual el usuario se está suscribiendo.
  • Crear un Plan , el cual representa las características de la suscripción.

Para crear un Product podemos generar el siguiente servicio:

Y para crear un Plan el siguiente:

Aquí lo único destacable es que estoy empleando una clase auxiliar llamada StripeUtils para convertir los números de formato aaaaa.xxxx en un string del tipo aaaaaxx ya que así nos lo pide Stripe:

Ahora ya podemos juntar todo en un servicio que concatene las llamadas a ambos servicios:

Nota. La clase StripeConsts es una clase que me he creado a mano para almacenar constantes útiles para llamar a la API de Stripe y tiene éste aspecto:

<?php
namespace App\Enum;
class StripeConsts {
  const CURRENCY_EUR = 'eur';
  const INTERVAL_YEARLY = 'year';
}

Por otra parte, la clase StripeCreatePlanDTO es también bastante sencilla:

Hecho esto, lo que haremos será crear un comando para poder crear nuestro primer plan en Stripe (también si queréis podéis incorporar este proceso al admin de vuestra plataforma), de modo que posteriormente los usuarios puedan crear la suscripción a ese plan.

Como veis, estoy persistiendo el plan en base de datos una vez que se crea correctamente en Stripe con el fin de podérselo mostrar luego al usuario en el momento en que quiera suscribirse a él.

La clase StripePlan no tiene mayor misterio:

Tras ejecutar el comando ya tendréis vuestro primer plan creado en Stripe:

2. Formulario para suscribirse a un plan

Ahora que ya tenemos un plan creado en Stripe lo siguiente será permitir a los usuarios que paguen por él. Es decir, la parte interesante.

Para ello, el flujo que propone Stripe es el siguiente:

  1. El usuario accede a la página donde se encuentra un formulario con el siguiente formato:
<form action="/create_subscription.php" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ publicKey }}"
data-image="/images/marketplace.png"
data-name="Emma's Farm CSA"
data-description="Subscription for 1 weekly box"
data-amount="2000"
data-label="Sign Me Up!">
</script>
</form>

Los campos son:

  • publicKey es la api pública que nos proporciona stripe asociada a nuestra cuenta
  • image es la imagen que se mostrará en la modal que lanza Stripe para introducir los datos de nuestra tarjeta
  • name , el nombre que se mostrara al usuario
  • description , la descripción de lo que está pagando
  • amount , el importe de la suscripción
  • label , el texto del botón que lanza el formulario

2. El usuario pulsa sobre el botón generado por el script de Stripe, lo cual lanza una modal similar a ésta:

3. El usuario introduce sus datos para el cobro y éstos son enviados a Stripe, el cual los procesa y devuelve un token asociado a la transacción. Tras ésto, nuestro formulario es automáticamente submitted a la url indicada en su action

4. En la url asociada a nuestro formulario recibimos un POST con los siguientes datos:

  • stripeToken
  • tokenType
  • stripeEmail

Con ese token crearemos una petición a Stripe para realizar el cobro de la suscripción.

5. Al enviar esa petición, Stripe crea un cliente e intenta realizar el cobro. Si todo va bien, creará una suscripción que será lo que nos devuelva.

Sabiendo todo esto, lo primero que tendremos que hacer será crear un controlador que pintará el formulario del paso 1 (uno para cada StripePlan que tengamos).

2.1. Creación de rutas

Añadiremos dos rutas. La primera será donde se mostrarán los planes entre los que el usuario puede escoger y la segunda será la encargada de recoger el formulario una vez que haya pasado por Stripe para ser validado y realizar el cobro de la suscripción.

2.2. Creación de ChooseSubscriptionController

A continuación, tendremos que crear los controladores asociados a dichas rutas.

Vamos primero con el ChooseSubscriptionController , el cual obtendrá todos los StripePlan y pintará un formulario para cada uno de ellos:

Y su plantilla asociada:

Como veis, estoy añadiendo al formulario un campo hidden con el id del plan, para así saber cuál escogió el usuario.

Con esto, ya podéis probar que el formulario se genera correctamente y se envía correctamente a la ruta stripe_process_subscription . Ahora solo falta procesar el token recibido desde Stripe y cobrar.

2.3. Creación de los servicios para procesar una suscripción.

Para procesar el retorno de checkout.js, el cual nos devuelve como os comentaba antes un POST con los siguientes datos:

  • stripeToken
  • tokenType
  • stripeEmail
  • los input hidden que hayáis añadido al formulario

son necesarias dos acciones:

  • Crear un Customer en Stripe
  • Crear una Subscription asociada a dicho Customer en Stripe

Para ello generaremos dos nuevos servicios encargados de realizar ambas acciones:

Y junto a estos dos servicios, un servicio encargado de invocarles en orden para llevar a cabo ambas acciones.

Notad que en este nuevo servicio estoy recogiendo el valor del input plan para recuperarlo de base de datos y obtener el planId de Stripe, de cara a pasárselo al servicio StripeCreateSubscription .

Con esto hecho, ya solo queda crear nuestro controlador asociado a la ruta: stripe_subscription_process , el cual tan solo crea un nuevo DTO a partir de los valores recibidos por POST y se los pasa al servicio StripeProcessSubscription :

Y con esto ya tenemos todo el proceso montado para crear una suscripción vía Stripe.

En otro artículo os explicaré algunas de las acciones más interesantes que podemos realizar con las suscripciones y el flujo que hay que seguir para ejecutarlas.

Espero que os haya servido!