PHP code example of vnuswilliams / laravel-subscription
1. Go to this page and download the library: Download vnuswilliams/laravel-subscription library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
vnuswilliams / laravel-subscription example snippets
// app/Enums/FeatureEnum.php
enum FeatureEnum: string
{
case MAX_EMPLOYEES = 'max-employees';
case EMPLOYEE_PORTAL = 'employee-portal';
case DOCUMENTS = 'documents';
case ADVANCED_REPORTS = 'advanced-reports';
case PRIORITY_SUPPORT = 'priority-support';
}
// app/Models/Company.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Vnuswilliams\Subscription\Traits\HasSubscriptions;
class Company extends Model
{
use HasSubscriptions;
}
use Vnuswilliams\Subscription\Facades\Subscription;
Subscription::subscribeTo($company, 'pro');
Subscription::cancel($company);
Subscription::canConsume($company, 'max-employees', 1);
Subscription::balance($company, 'max-employees');
use Vnuswilliams\Subscription\SubscriptionManager;
class SubscriptionService
{
public function __construct(
private readonly SubscriptionManager $subscription,
) {}
public function canAddEmployee(Company $company): bool
{
return $this->subscription->hasActiveSubscription($company)
&& $this->subscription->canConsume($company, FeatureEnum::MAX_EMPLOYEES->value, 1);
}
}
// By slug
$company->subscribeTo('pro');
// By instance
$plan = Plan::where('slug', 'pro')->firstOrFail();
$company->subscribeTo($plan);
// Via the Facade
use Vnuswilliams\Subscription\Facades\Subscription;
Subscription::subscribeTo($company, 'pro');
// Uses the plan price
$company->subscribeTo('pro');
// Stores 24.99 on the subscription, without changing the plan price
$company->subscribeTo('pro', price: 24.99);
// Integer-like prices are supported too
Subscription::subscribeTo($company, 'enterprise', price: 100);
// Free plan with a 15-day trial
$company->subscribeTo('free', expiration: now()->addDays(15));
// Promotional offer: 3 months free
$company->subscribeTo('pro', expiration: now()->addMonths(3));
// Immediate switch: the old subscription is removed, the new one starts
$company->switchTo('business');
// Deferred switch: the old subscription runs until its end date
$company->switchTo('starter', immediately: false);
// Via the Facade
Subscription::switchTo($company, 'business');
$company->subscription->cancel();
// Or via the Facade
Subscription::cancel($company);
if ($company->subscription->isCanceled()) {
// The user has cancelled, but still has access until ends_at
$expiresAt = $company->subscriptionExpiresAt();
}
$company->subscription->suppress();
// Or via the Facade
Subscription::suppress($company);
$company->renewSubscription();
// Or via the Facade
Subscription::renew($company);
// Is the subscription valid? (active, on trial, or in grace period)
$company->hasActiveSubscription(); // bool
// What is the current plan?
$plan = $company->currentPlan(); // Plan|null
echo $plan->name; // 'Pro'
echo $plan->slug; // 'pro'
// When does it expire?
$date = $company->subscriptionExpiresAt(); // Carbon|null
// Direct access to the Subscription model
$sub = $company->subscription;
$sub->isActive(); // bool
$sub->isOnTrial(); // bool
$sub->isOnGracePeriod(); // bool
$sub->isCanceled(); // bool
$sub->isExpired(); // bool
$sub->hasAccess(); // bool — aggregates all valid states
// Does the company have access to the employee portal?
if ($company->canConsume('employee-portal')) {
// access granted
}
// Via the Facade
if (Subscription::canConsume($company, 'employee-portal')) {
// access granted
}
// ✅ Recommended pattern
if ($company->canConsume('max-employees', 1)) {
// Business action first
$employee = Employee::create([...]);
// Consumption afterwards
$company->consume('max-employees', 1);
} else {
return back()->with('error', 'Employee quota reached. Please upgrade your plan.');
}
// Total slots allocated by the plan
$total = $company->totalCharges('max-employees'); // e.g. 25
// Slots consumed in the current period
$used = $company->usedCharges('max-employees'); // e.g. 17
// Remaining slots (PHP_INT_MAX if unlimited)
$remaining = $company->balance('max-employees'); // e.g. 8
Plan::create([
'slug' => 'pro',
'grace_days' => 7, // 7-day grace period after expiration
// ...
]);
Plan::create([
'slug' => 'free',
'grace_days' => 0, // No grace period on the free plan
// ...
]);
// routes/web.php
// Requires any valid subscription
Route::middleware(['auth', 'subscribed'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/employees', [EmployeeController::class, 'index']);
});
// Requires a specific plan (by slug)
Route::middleware(['auth', 'subscribed:business'])->group(function () {
Route::get('/analytics', [AnalyticsController::class, 'index']);
Route::get('/support', [SupportController::class, 'index']);
});
// app/Listeners/SendWelcomeEmail.php
use Vnuswilliams\Subscription\Events\SubscriptionCreated;
class SendWelcomeEmail
{
public function handle(SubscriptionCreated $event): void
{
$subscriber = $event->subscription->subscriber;
// $subscriber is the Company, User, etc. instance
Mail::to($subscriber->email)->send(new WelcomeMail($subscriber));
}
}
// app/Listeners/NotifyQuotaExhausted.php
use Vnuswilliams\Subscription\Events\FeatureQuotaReached;
class NotifyQuotaExhausted
{
public function handle(FeatureQuotaReached $event): void
{
$subscriber = $event->subscription->subscriber;
$featureSlug = $event->feature->slug; // e.g. 'max-employees'
// Send a notification suggesting an upgrade
$subscriber->notify(new QuotaReachedNotification($featureSlug));
}
}
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('subscription:check-lifecycle')->daily();
protected function schedule(Schedule $schedule): void
{
$schedule->command('subscription:check-lifecycle')->daily();
}
// app/Services/SubscriptionService.php
use Vnuswilliams\Subscription\SubscriptionManager;
final class SubscriptionService
{
public function __construct(
private readonly SubscriptionManager $subscription,
) {}
public function subscribeTo(Company $company, PlanEnum $planEnum): Subscription
{
$plan = $this->subscription->resolvePlan($planEnum->value);
// App-specific business logic:
// the FREE plan gets a manual 15-day trial
if ($planEnum === PlanEnum::FREE) {
return $this->subscription->subscribeTo($company, $plan, expiration: now()->addDays(15));
}
return $this->subscription->subscribeTo($company, $plan);
}
public function canAddEmployee(Company $company): bool
{
return $this->subscription->hasActiveSubscription($company)
&& $this->subscription->canConsume($company, FeatureEnum::MAX_EMPLOYEES->value, 1);
}
public function consumeEmployeeSlot(Company $company): void
{
$this->subscription->consume($company, FeatureEnum::MAX_EMPLOYEES->value, 1);
}
public function releaseEmployeeSlot(Company $company): void
{
$this->subscription->release($company, FeatureEnum::MAX_EMPLOYEES->value, 1);
}
public function remainingEmployeeSlots(Company $company): int
{
return $this->subscription->balance($company, FeatureEnum::MAX_EMPLOYEES->value);
}
public function currentPlan(Company $company): ?PlanEnum
{
$plan = $this->subscription->currentPlan($company);
return $plan !== null ? PlanEnum::tryFrom($plan->slug) : null;
}
}
// app/Http/Controllers/EmployeeController.php
class EmployeeController extends Controller
{
public function __construct(
private readonly SubscriptionService $subscriptionService,
) {}
public function store(StoreEmployeeRequest $request): RedirectResponse
{
$company = $request->user()->company;
if (! $this->subscriptionService->canAddEmployee($company)) {
return back()->with('error', 'Employee quota reached.');
}
$employee = Employee::create($request->validated());
$this->subscriptionService->consumeEmployeeSlot($company);
return redirect()->route('employees.index')
->with('success', 'Employee added successfully.');
}
public function destroy(Employee $employee): RedirectResponse
{
$company = auth()->user()->company;
$employee->delete();
// Release the slot so it can be reused
$this->subscriptionService->releaseEmployeeSlot($company);
return redirect()->route('employees.index')
->with('success', 'Employee deleted.');
}
}
use Vnuswilliams\Subscription\Exceptions\InvalidPlanException;
use Vnuswilliams\Subscription\Exceptions\SubscriptionNotFoundException;
use Vnuswilliams\Subscription\Exceptions\FeatureNotFoundException;
try {
Subscription::subscribeTo($company, 'non-existent-plan');
} catch (InvalidPlanException $e) {
// Plan not found or inactive
Log::warning($e->getMessage());
}