Installation
composer require cmrweb/stripe-bundle
Add to config/bundles.php:
return [
// ...
Cmrweb\StripeBundle\StripeBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console cmrweb:stripe:install
Update .env with your Stripe keys:
STRIPE_SECRET_KEY=your_secret_key
STRIPE_PUBLISHABLE_KEY=your_publishable_key
First Use Case
Inject the StripeService in a controller/service:
use Cmrweb\StripeBundle\Service\StripeService;
class PaymentController extends AbstractController
{
public function __construct(private StripeService $stripe)
{
}
public function createCustomer(Request $request)
{
$customer = $this->stripe->customers()->create([
'email' => $request->request->get('email'),
'name' => $request->request->get('name'),
]);
return new JsonResponse($customer);
}
}
Customer Management
// Create
$customer = $stripe->customers()->create(['email' => 'user@example.com']);
// Retrieve
$customer = $stripe->customers()->retrieve('cus_123');
// Update
$stripe->customers()->update('cus_123', ['email' => 'new@example.com']);
Payment Intents
$intent = $stripe->paymentIntents()->create([
'amount' => 1000,
'currency' => 'usd',
'customer' => 'cus_123',
'payment_method' => 'pm_123',
]);
Webhooks
Configure routes in config/routes.yaml:
stripe_webhook:
path: /stripe/webhook
controller: Cmrweb\StripeBundle\Controller\WebhookController::handle
Handle events in a custom service:
use Cmrweb\StripeBundle\Event\StripeEvent;
public function onStripeEvent(StripeEvent $event)
{
$data = $event->getData();
// Handle logic (e.g., subscription updates)
}
Subscription Management
$subscription = $stripe->subscriptions()->create([
'customer' => 'cus_123',
'items' => [['price' => 'price_123']],
]);
Cmrweb\StripeBundle\Form\Type\StripeElementType for Stripe Elements integration.{{ app.stripe.publicKey }}
StripeService in PHPUnit:
$this->mockStripeService()->shouldReceive('customers()->create')->andReturn($mockCustomer);
Configuration Overrides
The bundle uses stripe.yaml for configuration. Overrides in config/packages/cmrweb_stripe.yaml take precedence, but ensure you don’t accidentally override required keys (e.g., secret_key).
Webhook Signing
By default, the webhook endpoint expects STRIPE_SIGNING_SECRET in .env. If missing, webhook verification fails silently. Verify with:
$this->stripe->webhooks()->constructEvent(
$request->getContent(),
$request->headers->get('stripe-signature'),
'your_signing_secret'
);
Deprecation Warnings The bundle wraps Stripe’s PHP library. If you upgrade Stripe’s SDK, test thoroughly—some methods may behave differently. Check the Stripe PHP changelog.
Idempotency Keys The bundle doesn’t enforce idempotency keys by default. For critical operations (e.g., charges), add them manually:
$stripe->charges()->create([
'amount' => 1000,
'currency' => 'usd',
'idempotency_key' => uniqid(),
]);
Enable Logging
Add to config/packages/monolog.yaml:
handlers:
stripe:
type: stream
path: "%kernel.logs_dir%/stripe.log"
level: debug
channels: ["stripe"]
Then configure the bundle to use the stripe channel in stripe.yaml:
logging: true
Common Errors
InvalidRequestError: Validate input data against Stripe’s API specs. Use $stripe->customers()->retrieve('cus_123', ['expand' => ['sources']]) to debug nested objects.AuthenticationError: Double-check .env keys and ensure they’re not URL-encoded.Custom Services Extend the base service to add domain-specific logic:
use Cmrweb\StripeBundle\Service\StripeService;
class CustomStripeService extends StripeService
{
public function createProPlanCustomer(array $data)
{
$data['metadata']['plan'] = 'pro';
return $this->customers()->create($data);
}
}
Bind it in services.yaml:
services:
App\Service\CustomStripeService:
decorates: 'cmrweb_stripe.service'
arguments: ['@.inner']
Event Subscribers Listen to Stripe events globally:
use Cmrweb\StripeBundle\Event\StripeEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class StripeSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
StripeEvent::STRIPE_EVENT => 'onStripeEvent',
];
}
public function onStripeEvent(StripeEvent $event)
{
if ($event->getType() === 'invoice.payment_succeeded') {
// Handle logic
}
}
}
Twig Extensions Add custom filters/functions:
use Twig\TwigFunction;
class StripeTwigExtension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new TwigFunction('stripe_currency_format', [$this, 'formatCurrency']),
];
}
public function formatCurrency(float $amount, string $currency = 'usd')
{
return '$' . number_format($amount / 100, 2);
}
}
Register in services.yaml:
services:
App\Twig\StripeTwigExtension:
tags: ['twig.extension']
How can I help you explore Laravel packages today?