Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Cashier: Trouble Updating Card (Fatal Error)

I've installed Laravel Cashier (v3.0.4) in my project and am at the point of allowing users to update their credit cards, but am running into issues when I attempt to do so. Here's the relevant pieces from my controller that handles it:

public function __construct() {
    $this->user = Auth::user();
}

/**
 * Update credit card
 * @return \Illuminate\Http\RedirectResponse
 */
public function updateCardPost() {
    $this->user->updateCard(Input::get('stripe-token'));

    session()->flash('flash_message', 'You have updated your credit card');
    return redirect()->route('dashboard.index');
}

I've verified the sanity-check items:

  1. Actually posts to this controller
  2. Successfully passing in token

But every time I try submit it, I'm getting an error in Cashier itself:

FatalErrorException in StripeGateway.php line 454:
Call to a member function create() on null

I've looked into this and it looks like it's passing the $token to the following: $card = $customer->cards->create(['card' => $token]);

So, I then did another sanity check by dd($token) in that method and that returns exactly what my form is supplying. It doesn't look like this block has changed much recently -- but there were some PSR-2 and one-off purchase updates; neither of which appear to have anything to do with what's going on here. So I'm at my whits-end on what's up here, but any clues would be a huge help. Thanks!

Update

Have verified running dd($customer->cards) inside of the updateCard() method returns null -- probably because it's not ever saving the last four to the database when creating the subscription. Struggling to see how I can create a subscription (verified on Stripe), cancel and resume, yet my card details are not being updated locally, nor can I swap cards.

I used https://www.youtube.com/watch?v=iPaKX7aPczQ as inspiration for how simple it "should be" to do this, with success on that end, but not mine.

Update 2

Here's my entire User controller and Coffee implementation if it helps:

<?php namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Laravel\Cashier\Billable;
use Laravel\Cashier\Contracts\Billable as BillableContract;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract, BillableContract {

    use Authenticatable, CanResetPassword, Billable;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * Laravel Cashier
     *
     * @var array
     */
    protected $dates = ['trial_ends_at', 'subscription_ends_at'];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'email',
        'password',
        'first_name',
        'last_name',
        'phone',
        'biography',
        'twitter',
        'facebook',
        'linkedin'
    ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];

    /**
     * A user can have many listings
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function listings() {
        return $this->hasMany('App\Models\Dashboard\Listing');
    }
}

Stripe.coffee

(($) ->
  'use strict'

  StripeBilling =
    init: ->
      @form = $('.js-subscription__create')
      @submitButton = @form.find '.js-subscription__create__submit'
      @submitButtonText = @submitButton.text()

      stripeKey = $('meta[name="publishable_key"]').attr 'content'
      Stripe.setPublishableKey stripeKey

      @bindEvents()
      return

    bindEvents: ->
      @form.on('submit', $.proxy(@sendToken, @))
      return

    sendToken: (event) ->
      event.preventDefault()
      @submitButton.attr("disabled", true).text 'One Moment'

      Stripe.createToken(@form, $.proxy(@stripeResponseHandler, @))
      return

    stripeResponseHandler: (status, response) ->
      if response.error
        @form.find('.js-form__errors').removeClass("uk-hidden").text response.error.message
        return @submitButton.text(@submitButtonText).attr('disabled', false)

      $('<input>'
        type: 'hidden'
        name: 'stripe-token'
        value: response.id
      ).appendTo @form

      @form[0].submit()
      return

  StripeBilling.init()

  return
) jQuery
like image 337
Zach Avatar asked Feb 26 '15 05:02

Zach


1 Answers

I think it's due to an API change on Stripe's end. If you look at their changelog you'll notice that the "cards" attribute was changed to "sources" fairly recently.

UPDATE

You can choose the API Version that Stripe's own PHP framework is using with the following static method:

Stripe::setApiVersion("2015-02-10");

(That version number worked for me, but it could be that we need an older version.)

like image 92
Tom Barrett Avatar answered Sep 28 '22 19:09

Tom Barrett