Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Subscriptions Laravel Package

kazistm/subscriptions

Flexible Laravel subscription and plan management for SaaS apps. Create plans with features and usage limits, manage subscription lifecycles, track consumption via subscription usage, and extend/override models as needed. Built on laravelcm/laravel-subscriptions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require kazistm/subscriptions
    php artisan vendor:publish --provider="KaziSTM\Subscriptions\SubscriptionsServiceProvider" --tag="migrations"
    php artisan migrate
    
  2. Publish Config

    php artisan vendor:publish --provider="KaziSTM\Subscriptions\SubscriptionsServiceProvider" --tag="config"
    
    • Edit config/subscriptions.php to define your payment gateways (Stripe, PayPal, etc.) and default settings.
  3. First Use Case: Create a Plan

    use KaziSTM\Subscriptions\Models\Plan;
    
    $plan = Plan::create([
        'name' => 'Premium',
        'description' => 'Access to all features',
        'price' => 29.99,
        'interval' => 'month',
        'interval_count' => 1,
        'currency' => 'USD',
        'trial_period_days' => 7,
    ]);
    
  4. Make a Model Subscribable

    use KaziSTM\Subscriptions\Traits\Subscribable;
    
    class User extends Authenticatable
    {
        use Subscribable;
    }
    
  5. Subscribe a User

    $user->subscribe($plan, $gateway = 'stripe', $card = null);
    

Implementation Patterns

Core Workflows

1. Plan Management

  • Create/Update Plans Use the Plan model to define subscription tiers. Leverage the hasMany relationship for limitations (e.g., API calls, storage).

    $plan->limitations()->create([
        'name' => 'api_calls',
        'max' => 1000,
        'period' => 'month',
    ]);
    
  • Dynamic Pricing Use the price field for static pricing or extend the Plan model to support dynamic calculations (e.g., tiered pricing).

    // Example: Override price logic in a custom Plan model
    public function getPriceAttribute()
    {
        return $this->base_price + ($this->base_price * $this->user_count_discount / 100);
    }
    

2. Subscription Lifecycle

  • Webhook Handling Configure your payment gateway (e.g., Stripe) to send webhooks to POST /subscriptions/webhook. The package includes a WebhookController to handle events like invoice.paid or customer.subscription.deleted.

    // Example: Extend webhook logic in a service
    public function handleWebhook($payload)
    {
        if ($payload->type === 'invoice.paid') {
            $subscription = Subscription::find($payload->data->object->subscription);
            $subscription->markAsActive();
        }
    }
    
  • Cancellation & Renewals Use the cancel() and resume() methods on the Subscription model.

    $user->subscription()->cancel(); // Soft cancel
    $user->subscription()->cancelNow(); // Immediate cancellation
    

3. Usage Tracking & Limitations

  • Track Usage Use the Usage model to log consumption (e.g., API calls).
    $user->trackUsage('api_calls', 1);
    
  • Check Limits
    if ($user->hasExceededLimit('api_calls')) {
        abort(429, 'Limit exceeded');
    }
    

4. Integration with Auth & Frontend

  • Middleware for Subscription Checks
    public function handle($request, Closure $next)
    {
        if (!$request->user()->isSubscribed()) {
            abort(403, 'Subscription required');
        }
        return $next($request);
    }
    
  • Blade Directives
    @subscribed
        <p>You are subscribed!</p>
    @else
        <p>Please subscribe to access this feature.</p>
    @endsubscribed
    

Advanced Patterns

1. Custom Gateways

Extend the Gateway class to support non-Stripe/PayPal providers.

namespace App\Subscriptions\Gateways;

use KaziSTM\Subscriptions\Contracts\Gateway as GatewayContract;

class CustomGateway implements GatewayContract
{
    public function createSubscription($user, $plan, $token)
    {
        // Custom logic
    }
}

Register in config/subscriptions.php:

'gateways' => [
    'custom' => \App\Subscriptions\Gateways\CustomGateway::class,
],

2. Multi-Tenant Subscriptions

Use the tenant() method on the Subscription model to scope subscriptions to tenants.

$tenantSubscriptions = Subscription::where('tenant_id', $tenant->id)->get();

3. Bulk Operations

Use query builders to manage subscriptions at scale.

// Cancel all subscriptions for a plan
Subscription::where('plan_id', $plan->id)->update(['ends_at' => now()]);

4. Testing

Use the SubscriptionTestCase trait for seamless testing.

use KaziSTM\Subscriptions\Tests\SubscriptionTestCase;

class SubscriptionTest extends SubscriptionTestCase
{
    public function test_subscription_creation()
    {
        $user = User::factory()->create();
        $plan = Plan::factory()->create();

        $this->assertTrue($user->subscribe($plan));
    }
}

Gotchas and Tips

Pitfalls

  1. Webhook Verification

    • Always verify webhook signatures to avoid malicious requests. The package includes middleware for Stripe/PayPal, but custom gateways require manual verification.
    • Example for Stripe:
      use KaziSTM\Subscriptions\Http\Middleware\VerifyStripeWebhook;
      
      Route::post('/subscriptions/webhook', [WebhookController::class, 'handle'])
           ->middleware(VerifyStripeWebhook::class);
      
  2. Database Transactions

    • Subscription creation/update should wrap database operations in transactions to avoid partial failures.
      DB::transaction(function () use ($user, $plan) {
          $user->subscribe($plan);
          // Additional logic (e.g., send welcome email)
      });
      
  3. Plan Updates

    • Changing a plan’s price or features mid-subscription can lead to unexpected billing. Use the proration_behavior field in the Plan model to control proration (e.g., none, create_prorations, none).
    • Test thoroughly with your payment gateway’s sandbox to ensure proration works as expected.
  4. Time Zones

    • Subscription dates (e.g., starts_at, ends_at) are stored in UTC. Convert to user time zones when displaying to users.
      $user->subscription->ends_at->tz($user->timezone)->format('F j, Y');
      
  5. Soft Deletes

    • The Subscription model uses soft deletes. Use withTrashed() if querying for canceled subscriptions.
      $canceled = Subscription::withTrashed()->whereNotNull('canceled_at')->get();
      

Debugging Tips

  1. Log Webhook Payloads Add logging to the WebhookController to debug payloads:

    \Log::debug('Webhook payload', ['payload' => $payload]);
    
  2. Check Gateway Responses Inspect the gateway_response field on the Subscription model for errors from payment providers.

  3. Use Tinker for Quick Checks

    php artisan tinker
    
    $user = App\User::find(1);
    $user->subscription; // Inspect current subscription
    $user->subscription->plan; // Inspect plan details
    

Extension Points

  1. Custom Events Publish and listen to subscription events (e.g., SubscriptionCreated, SubscriptionCanceled).

    // In a service provider
    event(new SubscriptionCreated($subscription));
    
    // In an event listener
    public function handle(SubscriptionCreated $event)
    {
        // Send notification, update analytics, etc.
    }
    
  2. Override Models Extend the core models (Plan, Subscription, Usage) to add custom fields or logic.

    namespace App\Models;
    
    use KaziSTM\Subscriptions\Models\Plan as BasePlan;
    
    class Plan extends BasePlan
    {
        protected $casts = [
            'is_active' => 'boolean',
        ];
    }
    
  3. Custom Validation Override the validateForSubscription method in your subscribable model to add custom rules.

    public function validateForSubscription(array $attributes)
    {
        $validator = Validator::make($attributes, [
            'plan_id'
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin