Laravel Cashier Webhook:获取当前用户

时间:2015-06-20 15:30:10

标签: php laravel laravel-5 controllers laravel-cashier

我正在使用以下内容覆盖默认的handleCustomerSubscriptionDeleted方法,方法是将以下内容放入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);
  }

}

为了实际覆盖默认值,我应该更新到扩展控制器的路由,还是仍然引用默认值?我不认为将它保留为默认值甚至会让Laravel知道我的控制器存在,但也想确认。

电流:

Route::post('stripe/webhook', '\Laravel\Cashier\WebhookController@handleWebhook');

其他部分在handleCustomerSubscriptionDeleted之内我也希望能够抓住当前正在引用的用户并执行其他操作;在这种情况下,自动将记录设置为未发布。检索用户的最佳方法是什么?看起来$payload['data']['object']['customer']可能会保留并与users表中的stripe_id列相关联,但我们想要确认。谢谢你的帮助!

更新

我相信(基于文档),它应该更像是这样:

<?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);
  }
}

然后我将路线更新为以下内容:

Route::post('stripe/webhook', 'WebhookController@handleWebhook');

但它还没有解雇。但是,我还想知道,如果handleCustomerSubscriptionDeleted在他们取消时被调用,或者在他们的宽限期结束并且实际订阅被取消之后被调用。对我来说,测试这个比在本地玩等待游戏有更可靠的方法吗?

更新#2

我已将覆盖类更新为以下内容:

<?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);
  }
}

我更改的部分是更改$billable以搜索用户,因为这是响应返回的内容 - 而不是我曾经想过的用户ID。我最终尝试使用localtunnel.me作为@Shaz提到它允许我向它发送请求,但是我没有能够传递客户ID我想要影响,我不知道我怎么能验证一切都是实际工作。我可能会尝试深入了解是否可以通过Cashier手动运行事件,但仍然看起来有点奇怪。

更新#3

尝试做一些更简单的事情,只要听customer.subscription.created(因为它会立即触发):

<?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);
  }
}

我使用了localtunnel.me来设置webhook,但它似乎没有正确响应webhook,因为我看到Stripe响应日志中有500个错误,即使我的“测试Webhooks”事件是从Stripe发出的仪表板(显然没有设置客户ID)很好。遗憾的是,我对500错误的反应在Laravel吐出的混乱的源代码中丢失/切断了:

<!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...

3 个答案:

答案 0 :(得分:6)

阅读this question的答案 - 事件在订阅实际结束的日期/时间被触发,而非客户发起取消时。

基于Laravels Cashier Docs - 你的路线应该是:

Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook');

确保条带中的webhook设置实际指向yourapp.com/stripe/webhook

基于Laravel\Cashier代码中的handleWebhook方法 - ,任何适当命名的方法(以句柄开头,来自条带) event)将覆盖现有的。

如果您想在路线中使用扩展控制器;记得在类的开头添加一个构造函数:

public function __construct(){
  parent::__construct();
}

所以当您执行

时,handleWebhook方法可用
Route::post('stripe/webhook', 'WebhookController@handleWebhook');

而不是在路线中调用Laravel\Cashier\WebhookController

答案 1 :(得分:4)

我有这个工作,我指的是路由到我的控制器。

Route::post(
    'stripe/webhook',
    'WebhookController@handleWebhook'
);

由于我们正在扩展基本控制器,因此基本控制器中的任何方法都已可用。该控制器的要点是可以访问所有基本控制器方法。这样,您可以扩展任何新方法或覆盖现有方法。

我在获取捕获webhook事件的代码时遇到了问题。需要注意的是,如果您处于条带测试环境并触发webhook事件,请确保添加env变量。

CASHIER_ENV=testing

在基本webhook控制器中,它首先检查以确保事件存在,并且如果在测试环境中生成webhook,事件将不存在。

public function handleWebhook(Request $request)
{
    $payload = json_decode($request->getContent(), true);

    if (! $this->isInTestingEnvironment() && ! $this->eventExistsOnStripe($payload['id'])) {
        return;
    }

    $method = 'handle'.studly_case(str_replace('.', '_', $payload['type']));

    if (method_exists($this, $method)) {
        return $this->{$method}($payload);
    } else {
        return $this->missingMethod();
    }
}

答案 2 :(得分:1)

$billable = $this->getBillable($payload['data']['object']['customer']);
$user = $billable; // billable is User object