Abonnements
Créer un abonnement
use CashierBundle\Contract\BillableEntityInterface;
use CashierBundle\Service\SubscriptionService;
final readonly class SubscriptionController
{
public function __construct(
private SubscriptionService $subscriptionService,
) {
}
public function create(BillableEntityInterface $user): void
{
$subscription = $user->newSubscription('default', 'price_monthly')
->trialDays(14)
->create('pm_card_visa');
}
}Capacités du SubscriptionBuilder
$builder = $user->newSubscription('default');
$builder->price('price_monthly', quantity: 1);
$builder->meteredPrice('price_metered');
$builder->trialDays(14);
$builder->withCoupon('coupon_xxx');
$builder->withPromotionCode('promo_xxx');
$builder->withMetadata(['segment' => 'pro']);
$builder->withOptions(['collection_method' => 'charge_automatically']);
$builder->withBillingThresholds(['threshold_cycles' => 3]);
$builder->anchorBillingCycleOn(new \DateTime('2025-01-01'));
$builder->withPaymentBehavior('default_incomplete');
$builder->noProrate(); // ou prorate()Vérifier l’état
$user->subscribed('default');
$user->onTrial('default');
$subscription = $user->subscription('default');Cycle de vie complet
| Méthode | Description |
|---|---|
active() | Statut active ou trialing |
valid() | active OU onTrial OU onGracePeriod — cas d’usage courant pour « l’abonnement donne accès au service » |
onGracePeriod() | Abonnement annulé mais ends_at dans le futur — l’accès doit encore être accordé |
paused() | Abonnement Stripe paused |
notPaused() | Abonnement Stripe non paused |
onPausedGracePeriod() | Abonnement paused avec période de grâce |
ended() | Annulé ET ends_at dans le passé |
incomplete() | Statut d’échec de paiement (configurer Cashier::$deactivateIncomplete) |
pastDue() | Statut de paiement en attente (configurer Cashier::$deactivatePastDue) |
recurring() | Actif, pas en trial, pas en grace period |
$subscription->active();
$subscription->pastDue();
$subscription->paused();
$subscription->onGracePeriod();Faire évoluer l’abonnement
$subscriptionService->swap($subscription, 'price_yearly'); // swap sur place, proration par défaut
$subscriptionService->swapAndInvoice($subscription, 'price_yearly'); // + facture la proration immédiatement
$subscriptionService->updateQuantity($subscription, 5);
$subscriptionService->incrementQuantity($subscription, 2);
$subscriptionService->decrementQuantity($subscription, 1);
$subscriptionService->cancel($subscription); // fin de période
$subscriptionService->cancel($subscription, immediately: true); // immédiat
$subscriptionService->resume($subscription); // exige que onGracePeriod() soit trueMulti-prix
Pour un abonnement avec plusieurs prix (base + add-on):
$user->newSubscription('default')
->price('price_monthly_base')
->price('price_add_on', 1)
->create('pm_card_visa');Faire évoluer un abonnement multi-plan après création — ajouter/retirer un add-on, ou cibler un prix précis quand plusieurs items coexistent :
$subscriptionService->addPrice($subscription, 'price_add_on', quantity: 1);
$subscriptionService->removePrice($subscription, 'price_add_on'); // refuse le dernier item
// Ciblage déterministe sur un abonnement multi-items
$subscriptionService->swap($subscription, 'price_pro', fromPrice: 'price_basic');
$subscriptionService->updateQuantity($subscription, 10, price: 'price_seats');
$subscriptionService->incrementQuantity($subscription, 3, price: 'price_seats');Quand un abonnement a plusieurs items, les opérations de quantité et de swap exigent le
price (ou fromPrice) cible ; sinon elles lèvent une exception au lieu de deviner.
SubscriptionItem
Chaque prix d’un abonnement correspond à un SubscriptionItem:
$subscription->items; // Collection de SubscriptionItem
$item = $subscription->items()->first();
$item->stripePrice; // price_xxx
$item->quantity;
$item->meterId; // pour usage-based
$item->meterEventName;Facturation à l’usage (Meters API)
L’usage métré est reporté via la Meters API de Stripe, à travers MeterService. Chaque
SubscriptionItem métré stocke le nom d’événement meter auquel il reporte.
// Créer un meter une fois (agrégation "sum" par défaut)
$meterService->createMeter('API requests', 'api_requests');
// Reporter l'usage d'un item métré (utilise son meter_event_name + l'id Stripe du client)
$item = $subscription->items()->first();
$meterService->reportEventForItem($item, 100);
// Ou reporter un événement meter arbitraire directement
$meterService->reportEvent('api_requests', 100, $customer->getStripeId());En CLI : php bin/console cashier:report-usage <id-item-local> <quantité>.
Checkout subscription
Si vous préférez un abonnement créé via Stripe Checkout, utilisez CheckoutService::createSubscription().