0

I'm looking to override Cashier's SubscriptionBuilder::buildPayload(). Which looks like:

    protected function buildPayload()
    {
        return array_filter([
            'billing_cycle_anchor' => $this->billingCycleAnchor,
            'coupon' => $this->coupon,
            'expand' => ['latest_invoice.payment_intent'],
            'metadata' => $this->metadata,
            'plan' => $this->plan,
            'quantity' => $this->quantity,
            'tax_percent' => $this->getTaxPercentageForPayload(),
            'trial_end' => $this->getTrialEndForPayload(),
            'off_session' => true,
        ]);
    }

I'm looking to add 1 param to this which is 'collection_method': 'invoice'

So I'm trying to override this function so I can modify it.

I tried a few things, namely following some of the below answers:

Strategy to override a class in a library installed with Composer

Laravel 5.7 Override vendor class and extend old one

I have added my CustomSubscriptionBuilder in App\SparkOverrides\

<?php

namespace Laravel\Cashier;

class CustomSubscriptionBuilder extends SubscriptionBuilder
{
    protected function buildPayload()
    {
        dd('here');
    }
}

Then in composer.json I have added:

"autoload": {
        ...
        "files": [
            "app/SparkOverrides/CustomSubscriptionBuilder.php"
        ]
    },

I have then run composer dump-autoload. But then when I try and create a subscription the dd() never gets hit. To make matters more confusing, I have added a dump and die to the vendor buildPayload() and that isn't getting hit either.

I feel like I'm close but am missing something. Thanks for any help.

brandonbanks
  • 1,125
  • 1
  • 14
  • 21
  • just because you made a class that extends another class doesn't mean that anything knows your new class exists ... where this SubscriptionBuilder is needed it is hard coded into the `Billable` trait `@newSubscription` – lagbox Nov 09 '19 at 19:45
  • That makes sense but it doesn't get me any closer to figuring out how to solve this problem. – brandonbanks Nov 09 '19 at 20:03
  • 1
    well its hardcocded in a trait, so extend the trait and override the method and use your new extended trait in your model or in the model override the method – lagbox Nov 09 '19 at 20:09
  • 1
    Thanks for the tips @lagbox! I was able to get it. – brandonbanks Nov 09 '19 at 21:00
  • nice, glad you got it :) – lagbox Nov 09 '19 at 21:00

2 Answers2

1

Figured it out! Thank you to @lagbox for pointing me in the right direction.

I created a CustomBillable class and a CustomSubscriptionBuilder class.

Both of these classes are in app/SparkOverrides/

<?php

namespace App\SparkOverrides;

use Laravel\Spark\Billable;

trait CustomBillable
{
    use Billable;

    /**
     * Overriding Cashier's newSubscription to use
     * my CustomSubscriptionBuilder
     */
    public function newSubscription($subscription, $plan)
    {
        return new CustomSubscriptionBuilder($this, $subscription, $plan);
    }
}
<?php

namespace App\SparkOverrides;

use Laravel\Cashier\SubscriptionBuilder;

class CustomSubscriptionBuilder extends SubscriptionBuilder
{
    protected function buildPayload()
    {
        return array_filter([
            'billing_cycle_anchor' => $this->billingCycleAnchor,
            'coupon' => $this->coupon,
            'expand' => ['latest_invoice.payment_intent'],
            'metadata' => $this->metadata,
            'plan' => $this->plan,
            'quantity' => $this->quantity,
            'tax_percent' => $this->getTaxPercentageForPayload(),
            'trial_end' => $this->getTrialEndForPayload(),
            'off_session' => true,
            'collection_method' => 'send_invoice',
            'days_until_due' => 30,
        ]);
    }
}

Then I replaced the Billable trait with my CustomBillable trait on the Spark\User.

<?php

namespace Laravel\Spark;

use App\SparkOverrides\CustomBillable;
use Illuminate\Support\Str;
use Illuminate\Notifications\RoutesNotifications;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use CustomBillable, HasApiTokens, RoutesNotifications;
    ...
}

The App's User extends Spark\User. So now when newSubscription() is called it uses CustomBillable's newSubscription() which in turn uses the CustomSubscriptionBuilder.

I hope this helps someone out. Been tinkering for a while on this one.

brandonbanks
  • 1,125
  • 1
  • 14
  • 21
  • 1
    The right way to do this is to write a class that implements `Laravel\Spark\Contracts\Interactions\Subscribe` interface and inject it in the container via the `register` method of `SparkServiceProvider` class. Take a look at `Laravel\Spark\Providers\SparkServiceProvider::registerServices()` – impeto Aug 19 '20 at 18:33
0

I'm late, but you could just override the newSubscription method in the App\User class which inherits it from the Laravel\Spark\User class. Just a thought...

impeto
  • 350
  • 6
  • 14