I'm using the following to override the default handleCustomerSubscriptionDeleted
method by placing the following in app/Http/Controllers/WebHookController.php
:
<?php namespace App\Http\Controllers;
use Laravel\Cashier\WebhookController;
use Symfony\Component\HttpFoundation\Response;
class StripeWebhooks extends WebhookController {
/**
* Handle stripe subscription webhook
*
* @param array $payload
* @return Response
*/
public function handleCustomerSubscriptionDeleted($payload)
{
$billable = $this->getBillable($payload['data']['object']['customer']);
if ($billable && $billable->subscribed()) {
$billable->subscription()->cancel();
}
return new Response('Webhook Handled', 200);
}
}
In order for this to actually override the default, should I be updating my route to my extended controller, or still reference the default? I don't think that leaving it at the defaults would even let Laravel know my controller exists, but wanted to confirm as well.
Current:
Route::post('stripe/webhook', '\Laravel\Cashier\WebhookController@handleWebhook');
The other part of this is within handleCustomerSubscriptionDeleted
I'd also like to be able to grab the current user this is referencing and perform other actions; in this case, automatically setting records to unpublished. What would be the best way to go about retrieving the user? It looks like $payload['data']['object']['customer']
could potentially hold and relate to the stripe_id
column in the users table, but would like to confirm. Thanks for any help!
Update
I believe (based on the docs), it should be more like this:
<?php namespace App\Http\Controllers;
use App\Models\Dashboard\Listing;
use App\User;
use Symfony\Component\HttpFoundation\Response;
use Laravel\Cashier\WebhookController as BaseController;
class WebhookController extends BaseController
{
/**
* Handle stripe subscription webhook
*
* @param array $payload
* @return Response
*/
public function handleCustomerSubscriptionDeleted($payload)
{
$billable = $this->getBillable($payload['data']['object']['customer']);
if ($billable && $billable->subscribed()) {
$billable->subscription()->cancel();
// Get current user
$user = User::find($billable);
// Set each listing to draft
foreach ($user->listings as $listing) {
$current_listing = Listing::find($listing->id);
if ($current_listing->status == 'published') {
$current_listing->status = 'draft';
$current_listing->save();
}
}
}
return new Response('Webhook Handled', 200);
}
}
I then updated my route to the following:
Route::post('stripe/webhook', 'WebhookController@handleWebhook');
But it's still not firing. BUT, what I'm also wondering is if handleCustomerSubscriptionDeleted
is called "when they cancel" or after their grace period is over and the actual subscription is cancelled. Is there a more reliable way for me to test this than to play the waiting game locally?
Update #2
I have updated my override class to the following:
<?php namespace App\Http\Controllers;
use App\Models\Dashboard\Listing;
use App\User;
use Symfony\Component\HttpFoundation\Response;
use Laravel\Cashier\WebhookController as BaseController;
class WebhookController extends BaseController
{
/**
* Handle stripe subscription webhook
*
* @param array $payload
* @return Response
*/
public function handleCustomerSubscriptionDeleted(array $payload)
{
$billable = $this->getBillable($payload['data']['object']['customer']);
if ($billable && $billable->subscribed()) {
$billable->subscription()->cancel();
// Get current user
$user = User::where('stripe_id', $billable)->firstOrFail();
// Set each listing to draft
foreach ($user->listings as $listing) {
$current_listing = Listing::find($listing->id);
if ($current_listing->status == 'published') {
$current_listing->status = 'draft';
$current_listing->save();
}
}
}
return new Response('Webhook Handled', 200);
}
}
The part I changed was changing $billable
to search for the user by, as that's what the response returns -- not the user ID as I once thought. I did end up trying localtunnel.me as @Shaz mentioned which did allow me to send a request to it, BUT without being able to pass in the customer ID I'd like impact, I'm not sure how I can verify everything is actually working. I may try to dig in to see if I can manually run an event through Cashier, but still seems a bit odd.
Update #3
Tried doing something a little simpler as far as listening to customer.subscription.created
(since that fires immediately):
<?php namespace App\Http\Controllers;
use App\Models\Dashboard\Listing;
use App\User;
use Symfony\Component\HttpFoundation\Response;
use Laravel\Cashier\WebhookController as BaseController;
class WebhookController extends BaseController
{
/**
* @param array $payload
*/
public function handleCustomerSubscriptionCreated(array $payload) {
$billable = $this->getBillable($payload['data']['object']['customer']);
if ($billable) {
// Get current user
$user = User::where('stripe_id', $billable)->firstOrFail();
$user->first_name = 'Helloooooo';
$user->save();
}
}
/**
* Handle stripe subscription webhook
*
* @param array $payload
* @return Response
*/
public function handleCustomerSubscriptionDeleted(array $payload)
{
$billable = $this->getBillable($payload['data']['object']['customer']);
if ($billable && $billable->subscribed()) {
$billable->subscription()->cancel();
// Get current user
$user = User::where('stripe_id', $billable)->firstOrFail();
// Set each listing to draft
foreach ($user->listings as $listing) {
$current_listing = Listing::find($listing->id);
if ($current_listing->status == 'published') {
$current_listing->status = 'draft';
$current_listing->save();
}
}
}
return new Response('Webhook Handled', 200);
}
}
I used localtunnel.me to setup the webhook, but it doesn't appear that it is correctly responding to the webhook, as I see 500 errors in the Stripe response logs even though my "Test Webhooks" event fired from the Stripe dashboard (with no customer ID set obviously) is fine. The response I'm getting about the 500 error is unfortunately lost/cut-off in the jumbled mess of source code that Laravel is spitting out:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="robots" content="noindex,nofollow" />
<style>
/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html */
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
html { backgr...