Override Name Collision in Laravel Cashier Models and Migration
Why you might need to do this
If your application already has a subscriptions
, subscription_items
, customers
table, or models with the same name
as Laravel Cashier, you will run into a naming collision where Laravel Cashier will try to use its own models and
migrations, but your models might already have a relation called "subscriptions" or "subscription_items" which
interferes with Laravel Cashier and breaks your billing functionality.
Solution: Override Laravel Cashier models and migrations
Publish the Cashier config and migrations:
php artisan vendor:publish --tag="cashier-config"
php artisan vendor:publish --tag="cashier-config"
Modify the cashier migrations, add a prefix (like stripe_
or cashier_
) to the table names:
// File database/migrations/2019_05_03_000002_create_subscriptions_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('stripe_subscriptions', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id');
$table->string('name');
$table->string('stripe_id')->unique();
$table->string('stripe_status');
$table->string('stripe_price')->nullable();
$table->integer('quantity')->nullable();
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('ends_at')->nullable();
$table->timestamps();
$table->index(['user_id', 'stripe_status']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('stripe_subscriptions');
}
};
// File database/migrations/2019_05_03_000003_create_subscription_items_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('stripe_subscription_items', function (Blueprint $table) {
$table->id();
$table->foreignId('stripe_subscription_id');
$table->string('stripe_id')->unique();
$table->string('stripe_product');
$table->string('stripe_price');
$table->integer('quantity')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('stripe_subscription_items');
}
};
Then create new models that extend the Cashier models.
php artisan make:model StripeSubscription
php artisan make:model StripeSubscriptionItem
Extend the Cashier models, setting the $table
property and using an alias for the class is optional, I just like to do
it when I deal with third-party packages.
// File: app/Models/StripeSubscription.php
<?php
namespace App\Models;
use Laravel\Cashier\Subscription as CashierSubscription;
class StripeSubscription extends CashierSubscription
{
protected $table = 'stripe_subscriptions';
}
// File: app/Models/StripeSubscriptionItem.php
<?php
namespace App\Models;
use Laravel\Cashier\SubscriptionItem as CashierSubscriptionItem;
class StripeSubscriptionItem extends CashierSubscriptionItem
{
protected $table = 'stripe_subscription_items';
}
Finally, add this to your AppServiceProvider
(or any other service provider that is loaded when your application
starts):
// File: app/Providers/AppServiceProvider.php
use App\Models\StripeSubscription;
use App\Models\StripeSubscriptionItem;
class AppServiceProvider extends ServiceProvider
{
public function register() { /* no changes in this method */ }
public function boot()
{
Cashier::useSubscriptionModel(App\Models\StripeSubscription::class);
Cashier::useSubscriptionItemModel(App\Models\StripeSubscriptionItem::class);
}
}