We love Laravel! It is our go to framework for php development projects. At times though we run into trouble using it.
This time we wanted to change the way Laravel\Cashier was working. We wanted to extend the Subscription
model. and have Laravel/Cashier use that model.
Why Extend the Subscription Model of Cashier?
Because we wanted to know on our platform which period the subscriptions covers. When did it start? When does it end?
That was not enough though, we had to also override the create()
method from SubscriptionBuilder
to save Stripe’s response to our new Model without calling Stipe again.
Because Cashier is a vendor package, it is not advisable to hack the vendor files. The reason is because next time there is an update the package all your changes will be lost.
Where to begin? Let’s make a migration
Let’s start with the migration. Create a migration in the terminal
php artisan make:migration alter_subscriptions_table_add_subscription_period
Now edit the migration to add the two columns for the start and end period.
/database/migrations/2017_11_27_130110_alter_subscriptions_table_add_subscription_period.php
We trust you know how to drop the columns. We have included only the up()
method in our code.
public function up()
{
Schema::table('subscriptions', function ($table) {
$table->timestamp('current_period_start')->nullable();
$table->timestamp('current_period_end')->nullable();
});
}
Create Subscription Model
Now we can create our CustomSubscription
model to replace Casier’s Subscription model. Head to the terminal and type:
php artisan make:model CustomSubscription
Amend the CustomSubscription
class to suite your needs. Such as the namespace. We are using our own name spacing and we also have composer to autoload our folder (app\Underthecocotree\Cashier
.
We are extending the Laravel\Cashier\Subscription
model that way all the functions will work without changing anything.
We are trying to keep changes to a minimum in order to not break the functionality in case of an update. We extend and only update what we need.
<?php
namespace Underthecocotree\Cashier;
use Laravel\Cashier\Subscription;
class CustomSubscription extends Subscription
{
/**
* The subscription class already includes the $dates variable, so we are reusing it and adding our custom columns
*/
protected $dates = [
'trial_ends_at', 'ends_at',
'created_at', 'updated_at',
'current_period_start', 'current_period_end',
];
/**
* Set the subscription table otherwise it will point to another table
*/
protected $table = 'subscriptions';
}
How to swap the Subscription class for CustomSubscription
To update the referenced class of Subscription
we need to replace the \Laravel\Cashier\Bilalble
class as well. To do that we need to create a trait.
Under the same directory as the CustomSubscription
create a CustomBillable.php
file. In our case it is under app/Underthecocotree\Cashier\CustomBillable.php
Our CustomBillable
trait uses Billable
. A trait function can be redefined by just creating that method. We redefine subscriptions()
method and pass in the CustomSubscription
class that we created earlier.
<?php
namespace Underthecocotree\Cashier;
use Laravel\Cashier\Billable;
use Underthecocotree\Cashier\CustomSubscription;
trait CustomBillable
{
use Billable;
/**
* Override the subscriptions() from Larave\Cashier\Billable
* to inject CustomSubscription model
*/
public function subscriptions()
{
return $this->hasMany(CustomSubscription::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
}
We know this tutorial is getting long but bear with us. It is all worth it if you want to change Cashier’s Subscription model.
Update User.php to reference CustomBillable
As part of the Cashier installation, the User.php
class needs to use the Billable
trait. Well, guess what? We now need to change that to point to our own CustomBillable
trait.
Open up User.php
and amend it to use the CustomBillable trait
use Underthecocotree\Cashier\CustomBillable;
class User extends Authenticatable
{
use Notifiable, CustomBillable;
Cool, we hope you are still with us. Now our User
uses the CustomBillable
trait which loads the CustomSubscription
model.
Add the subscription duration to our Subscription table
Like we said earlier, we did not get into all this trouble just for fun. We want to save the start and end date to the database.
We got to make one last class. Create a CustomSubscriptionBuilder
that extends Larvel\Cashier\SubscriptionBuilder
under the same folder (app/Underthecocotree\Cashier\CustomBillable.php
). We now override the create()
method.
We have omitted most of the code that comes in that function to make this tutorial easier to follow. You should copy the whole function and amend it for your needs.
<?php
namespace Underthecocotree\Cashier;
use Laravel\Cashier\SubscriptionBuilder;
class CustomSubscriptionBuilder extends SubscriptionBuilder
{
public function create($token = null, array $options = [])
{
// ...
return $this->owner->subscriptions()->create([
// ...
'current_period_start' => $subscription->current_period_start,
'current_period_end' => $subscription->current_period_end,
]);
}
}
Conclusion
So, when we first started looking into this we were frustrated. We thought there must be a way to do this. We don’t think that it is that difficult but with all the code you might feel a bit lost.
Let’s simplify it for you. You need two classes (CustomSubscription
, CustomSubscriptionBuilder
) and one trait (CustomBillable
). Then you need to update the User to use CustomBillable
instead of Cashier’s Billable
This will work for every new subscription but when there is a new charge for the next subscription period the start and end date will remain to the original value.
We go under our tree now and go work it out. Stay tuned to figure out how to update the start and end date of the subscription. We are thinking web hooks but we might need to look more at the Cashier’s code.
Want to read more? Follow these links.
Laravel Cashier - Laravel - The PHP Framework For Web Artisans
Kudos @david-navarro for opening our eyes