Tashil (تسهيل) is a comprehensive subscription management package for Laravel with built-in Redis caching, feature-gated access, usage tracking, billing, and analytics.
- Installation
- Configuration
- Quick Start
- Subscriptions
- Usage Tracking
- Billing & Invoices
- Console Commands
- Analytics & Reporting
- HasSubscriptions Trait
- Events
- Caching Architecture
- API Reference
- Examples
- PHP 8.2+
- Laravel 10.x, 11.x, or 12.x
- Redis (for caching layer)
composer require foysal50x/tashilphp artisan vendor:publish --tag=tashil-config
php artisan vendor:publish --tag=tashil-migrations
php artisan migrateAfter publishing, update config/tashil.php as needed:
return [
/*
|--------------------------------------------------------------------------
| Database Configuration
|--------------------------------------------------------------------------
*/
'database' => [
// The database connection to use for Tashil tables.
// If null, the default application connection will be used.
'connection' => env('TASHIL_DB_CONNECTION', null),
// Table prefix for all Tashil tables.
'prefix' => 'tashil_',
// Customise table names used by the package.
'tables' => [
'packages' => 'packages',
'features' => 'features',
'package_feature' => 'package_feature',
'subscriptions' => 'subscriptions',
'subscription_items' => 'subscription_items',
'usage_logs' => 'usage_logs',
'invoices' => 'invoices',
'transactions' => 'transactions',
],
],
/*
|--------------------------------------------------------------------------
| Invoice Configuration
|--------------------------------------------------------------------------
*/
'invoice' => [
'prefix' => 'INV',
'format' => '#-YYMMDD-NNNNNN', // #=Prefix, YY/MM/DD=Date, N=Digit, S=Letter, A=AlphaNumeric
'generator' => Foysal50x\Tashil\Services\Generators\InvoiceNumberGenerator::class,
],
/*
|--------------------------------------------------------------------------
| Default Currency
|--------------------------------------------------------------------------
*/
'currency' => env('TASHIL_CURRENCY', 'USD'),
/*
|--------------------------------------------------------------------------
| Redis Configuration
|--------------------------------------------------------------------------
*/
'redis' => [
'host' => env('TASHIL_REDIS_HOST', env('REDIS_HOST', '127.0.0.1')),
'password' => env('TASHIL_REDIS_PASSWORD', env('REDIS_PASSWORD', null)),
'port' => env('TASHIL_REDIS_PORT', env('REDIS_PORT', 6379)),
'database' => env('TASHIL_REDIS_DB', 5),
],
/*
|--------------------------------------------------------------------------
| Cache Configuration
|--------------------------------------------------------------------------
*/
'cache' => [
// Prefix for all cache keys generated by Tashil.
'prefix' => env('TASHIL_CACHE_PREFIX', 'tashil_cache:'),
// Default Time To Live (TTL) in seconds for cached items.
'ttl' => 3600,
// Whether to enable the caching layer globally.
'enabled' => env('TASHIL_CACHE_ENABLED', true),
],
];use Foysal50x\Tashil\Facades\Tashil;
// 1. Create features
$apiCalls = Tashil::feature('api-calls')
->name('API Calls')
->limit()
->create();
$darkMode = Tashil::feature('dark-mode')
->name('Dark Mode')
->boolean()
->create();
// 2. Create a package with features
$proPlan = Tashil::package('pro')
->name('Pro Plan')
->price(29.99)
->monthly()
->trialDays(14)
->feature($apiCalls, value: '10000')
->feature($darkMode, value: 'true')
->create();
// 3. Subscribe a user
$subscription = Tashil::subscription()->subscribe($user, $proPlan, withTrial: true);
// 4. Check feature access & track usage
if ($user->canUseFeature('api-calls')) {
$user->incrementUsage('api-calls');
}
// 5. Get analytics
$summary = Tashil::analytics()->dashboardSummary();- Flexible Plans: Create unlimited packages with custom billing intervals (daily, weekly, monthly, yearly) or lifetime access.
- Trial Periods: Configurable trial days per package.
- Lifecycle Management: Subscribe, cancel (gracefully or immediately), resume, and switch plans with prorated handling.
- State Management: Robust status handling (Active, OnTrial, Cancelled, Expired) using Enums.
- Automated Invoicing: Generates invoices for subscriptions and renewals.
- Custom Currencies: Support for package-specific currencies.
- Proration: Handles plan switching calculations.
- Grace Periods: Configurable due dates and overdue handling.
- Granular Permissions:
- Boolean: Simple on/off access (e.g., "Pro Dashboard").
- Limit: Numerical quotas (e.g., "10 Projects").
- Consumable: One-time use tokens (e.g., "5 AI Credits").
- Usage Tracking: Real-time tracking of feature usage.
- Limit Enforcement: Automatically blocks actions when limits are exceeded.
- Usage Warnings: Dispatches events when usage hits thresholds (e.g., 80%).
- Resets: Reset limits manually or automatically on renewal.
- Dashboard Summary: All-in-one KPI method for quick admin dashboards (uses batch queries — only 2 DB queries).
- Revenue Metrics:
- MRR (Monthly Recurring Revenue) & ARPU (Average Revenue Per User).
- Total Revenue & Revenue by Package.
- Revenue trends over time.
- Growth Metrics:
- New Subscriptions trend.
- Trial Conversion Rates.
- Churn Rate & Churn Trends (batch-optimized — 2 queries instead of 24).
- Operational Metrics:
- Pending & Overdue Invoice counts.
- Active vs. Inactive Subscriber breakdowns.
- Cross-Database Compatibility: All analytics queries use
tpetry/laravel-query-expressions— no raw SQL.
- Trait-based Integration: Add
use HasSubscriptionsto any model (User, Team, etc.). - Fluent API:
$user->subscribe($package)$user->onPlan('pro')$user->canUseFeature('api-calls')
- Events: Rich event system (
SubscriptionCreated,SubscriptionRenewed,UsageLimitWarning) for custom hook integration. - Repository Pattern: Swappable repositories for caching and database abstraction.
- High Performance: In-memory subscription caching, batch queries, and Redis caching support.
Tashil supports four feature types:
| Type | Enum | Description |
|---|---|---|
| Boolean | FeatureType::Boolean |
On/off toggle (e.g. dark mode) |
| Limit | FeatureType::Limit |
Numeric limit with enforcement (e.g. 10,000 API calls) |
| Consumable | FeatureType::Consumable |
Trackable usage without hard limit |
| Enum | FeatureType::Enum |
Named option value |
use Foysal50x\Tashil\Facades\Tashil;
// Boolean feature
$feature = Tashil::feature('priority-support')
->name('Priority Support')
->description('Access to priority support channels')
->boolean()
->create();
// Limit feature
$feature = Tashil::feature('api-calls')
->name('API Calls')
->limit()
->metadata(['reset_period' => 'monthly'])
->create();
// Consumable feature
$feature = Tashil::feature('storage')
->name('Storage (GB)')
->consumable()
->create();
// Create or update (idempotent by slug)
$feature = Tashil::feature('api-calls')
->name('API Calls (Updated)')
->limit()
->createOrUpdate();use Foysal50x\Tashil\Facades\Tashil;
$package = Tashil::package('pro')
->name('Pro Plan')
->description('For growing teams')
->price(29.99)
->originalPrice(49.99) // strike-through price
->monthly() // or ->yearly(), ->quarterly(), ->lifetime()
->trialDays(14)
->featured() // mark as featured plan
->sortOrder(2)
->feature($apiCalls, value: '10000')
->feature($darkMode, value: 'true')
->feature($storage, value: '50')
->create();
// Attach multiple features at once
$package = Tashil::package('enterprise')
->name('Enterprise')
->price(99.99)
->yearly()
->features([
$apiCalls => ['value' => '100000'],
$darkMode => ['value' => 'true'],
$storage => ['value' => '500'],
])
->create();| Period | Enum | Example |
|---|---|---|
| Daily | Period::Day |
->billingPeriod(Period::Day, 1) |
| Weekly | Period::Week |
->billingPeriod(Period::Week, 1) |
| Monthly | Period::Month |
->monthly() |
| Quarterly | – | ->quarterly() |
| Yearly | Period::Year |
->yearly() |
| Lifetime | Period::Lifetime |
->lifetime() |
subscribe() ──▶ OnTrial ──▶ Active ──▶ cancel() ──▶ Cancelled
│ │
└─ (trial ends) ─────────┘ resume()
│
◀──────┘
| Status | Enum | Meaning |
|---|---|---|
| Pending | SubscriptionStatus::Pending |
Awaiting activation |
| Active | SubscriptionStatus::Active |
Currently active |
| On Trial | SubscriptionStatus::OnTrial |
In free trial period |
| Past Due | SubscriptionStatus::PastDue |
Payment overdue |
| Cancelled | SubscriptionStatus::Cancelled |
User cancelled |
| Expired | SubscriptionStatus::Expired |
Subscription period ended |
| Suspended | SubscriptionStatus::Suspended |
Admin-suspended |
use Foysal50x\Tashil\Facades\Tashil;
// Subscribe without trial
$subscription = Tashil::subscription()->subscribe($user, $package);
// Subscribe with trial (uses package's trial_days)
$subscription = Tashil::subscription()->subscribe($user, $package, withTrial: true);When a subscription is created:
- The subscription record is persisted with calculated
ends_at - Feature items from the package are synced to the subscription
- A
SubscriptionCreatedevent is dispatched
// Cancel at end of billing period (grace period)
Tashil::subscription()->cancel($subscription, reason: 'Too expensive');
// Cancel immediately
Tashil::subscription()->cancel($subscription, immediate: true);// Resume a cancelled subscription (only if ends_at is in the future)
Tashil::subscription()->resume($subscription);// Switch to a different package (cancels old, creates new)
$newSubscription = Tashil::subscription()->switchPlan($subscription, $newPackage);$subscription->isActive(); // true if status is Active
$subscription->isOnTrial(); // true if status is OnTrial
$subscription->isCancelled(); // true if status is Cancelled
$subscription->isExpired(); // true if status is Expired
$subscription->isPastDue(); // true if status is PastDue
$subscription->isValid(); // true if Active or OnTrialuse Foysal50x\Tashil\Facades\Tashil;
// Increment by 1
Tashil::usage()->increment($subscription, 'api-calls');
// Increment by custom amount
Tashil::usage()->increment($subscription, 'storage', amount: 2.5);Returns false if:
- The feature doesn't exist on the subscription
- The usage would exceed the feature's limit
// Can the feature be consumed?
$canUse = Tashil::usage()->check($subscription, 'api-calls');
// Check a specific amount
$canUse = Tashil::usage()->check($subscription, 'storage', amount: 10);// Reset a single feature
Tashil::usage()->resetUsage($subscription, 'api-calls');
// Reset all features
Tashil::usage()->resetAllUsage($subscription);When a feature reaches 80% usage, a UsageLimitWarning event is dispatched automatically. Listen for this in your EventServiceProvider:
use Foysal50x\Tashil\Events\UsageLimitWarning;
protected $listen = [
UsageLimitWarning::class => [
SendUsageWarningNotification::class,
],
];use Foysal50x\Tashil\Facades\Tashil;
// Generate invoice using the package price
$invoice = Tashil::billing()->generateInvoice($subscription);
// Generate with custom amount
$invoice = Tashil::billing()->generateInvoice($subscription, amount: 39.99);Each invoice gets a unique number in the format INV-YYYYMMDD-XXXXXX.
| Status | Enum |
|---|---|
| Draft | InvoiceStatus::Draft |
| Pending | InvoiceStatus::Pending |
| Paid | InvoiceStatus::Paid |
| Void | InvoiceStatus::Void |
| Refunded | InvoiceStatus::Refunded |
// Mark invoice as paid
$invoice->markAsPaid();
// Void an invoice
$invoice->markAsVoid();Automates subscription renewals and expirations. Suggested to run daily.
php artisan tahsil:process-subscriptions- Renewals: Creates invoices for auto-renewing subscriptions expiring today.
- Expirations: Marks non-renewing subscriptions as expired.
// app/Console/Kernel.php or routes/console.php
$schedule->command('tashil:process-subscriptions')->daily();The AnalyticsService provides comprehensive subscription, revenue, and usage analytics. Access it via the facade:
$analytics = Tashil::analytics();// Total subscriptions (all statuses)
$analytics->totalSubscriptionCount(); // 1,250
// Active subscriptions only (active + on_trial)
$analytics->activeSubscriptionCount(); // 980
// Breakdown by status
$analytics->subscriptionCountByStatus();
// ['active' => 800, 'on_trial' => 180, 'cancelled' => 150, 'expired' => 120]
// Subscribers per package
$analytics->subscribersByPackage();
// [['package_id' => 1, 'package_name' => 'Pro', 'count' => 600], ...]
// Trial conversion rate (% of trials that became active)
$analytics->trialConversionRate(); // 72.50
// Subscription growth over time (chart data)
$analytics->subscriptionGrowth(months: 12);
// [['month' => '2025-01', 'count' => 85], ['month' => '2025-02', 'count' => 92], ...]// Monthly Recurring Revenue
$analytics->calculateMRR(); // 28,560.00
// Average Revenue Per User
$analytics->averageRevenuePerUser(); // 29.14
// Lifetime total revenue
$analytics->totalRevenue(); // 342,720.00
// Monthly revenue trend (chart data)
$analytics->revenueByPeriod(months: 12);
// [['month' => '2025-01', 'revenue' => 25430.00], ...]
// Revenue per package
$analytics->revenueByPackage();
// [['package_id' => 1, 'package_name' => 'Pro', 'revenue' => 180000.00], ...]// Pending invoices
$analytics->pendingInvoiceCount(); // 45
// Overdue invoices (pending + past due date)
$analytics->overdueInvoiceCount(); // 12// Churn rate for last 30 days
$analytics->churnRate(days: 30); // 4.25
// Churn trend over 12 months (chart data)
$analytics->churnTrend(months: 12, windowDays: 30);
// [['month' => '2025-01', 'churn_rate' => 3.80], ...]// Daily usage for a feature over the last 30 days
$analytics->getDailyUsage($subscription, featureId: 1, days: 30);
// [['date' => '2025-02-01', 'total' => 245], ...]Get all KPIs in a single call:
$summary = Tashil::analytics()->dashboardSummary();
// Returns:
// [
// 'total_subscriptions' => 1250,
// 'active_subscriptions' => 980,
// 'subscriptions_by_status' => ['active' => 800, 'on_trial' => 180, ...],
// 'mrr' => 28560.00,
// 'arpu' => 29.14,
// 'total_revenue' => 342720.00,
// 'churn_rate' => 4.25,
// 'trial_conversion_rate' => 72.50,
// 'pending_invoices' => 45,
// 'overdue_invoices' => 12,
// 'pending_invoices' => 45,
// 'overdue_invoices' => 12,
// ]Get a detailed breakdown of metrics for each package:
$packageStats = Tashil::analytics()->packageAnalytics();
// Returns array of packages with stats:
// [
// [
// 'package_id' => 1,
// 'package_name' => 'Pro Plan',
// 'total_subscribers' => 150,
// 'active_subscribers' => 120,
// 'mrr' => 3599.80,
// 'average_mrr' => 29.99,
// 'trial_conversion_rate' => 75.00,
// 'cancelled_count' => 10,
// 'pending_invoices' => 5,
// 'overdue_invoices' => 2,
// 'total_revenue' => 45000.00,
// ],
// ...
// ]Add subscription capabilities to any Eloquent model:
use Foysal50x\Tashil\Traits\HasSubscriptions;
class User extends Authenticatable
{
use HasSubscriptions;
}// Subscription management
$user->subscribe($package);
$user->subscribe($package, withTrial: true);
$user->cancelSubscription(immediate: false);
$user->resumeSubscription();
$user->switchPlan($newPackage);
// Status checks
$user->isSubscribed(); // has any valid subscription
$user->isSubscribedTo($package); // subscribed to specific package (model or slug)
$user->onPlan('pro'); // alias for subscribedTo by slug
$user->isOnTrial(); // currently on trial
$user->subscription(); // get current valid subscription (always queries DB)
$user->loadSubscription(); // get cached subscription (avoids redundant queries)
// Feature access
$user->hasFeature('dark-mode'); // boolean feature check
$user->canUseFeature('api-calls'); // has access + within limits
$user->featureValue('api-calls'); // get raw feature value
$user->featureUsage('api-calls'); // current usage count
$user->featureRemaining('api-calls'); // remaining allowance
$user->useFeature('api-calls'); // increment and log usage
$user->dailyUsageFor('api-calls', 30); // daily usage breakdown for last N days
// Invoices
$user->invoices(); // invoices relationship
$user->allInvoices(); // flattened collection of all invoices
// Cache management
$user->clearSubscriptionCache(); // force re-fetch on next accessNote
Performance: Methods like hasFeature(), featureValue(), featureUsage(), featureRemaining(), dailyUsageFor(), and useFeature() all use loadSubscription() internally, which caches the active subscription for the model's lifetime. This eliminates redundant queries when multiple methods are called on the same model instance. The cache is automatically cleared after subscribe(), cancelSubscription(), resumeSubscription(), and switchPlan().
Tashil dispatches events that you can listen to in your application:
Fired when a new subscription is created.
use Foysal50x\Tashil\Events\SubscriptionCreated;
class HandleNewSubscription
{
public function handle(SubscriptionCreated $event): void
{
$subscription = $event->subscription;
// Send welcome email, provision resources, etc.
}
}Fired when feature usage crosses the 80% threshold.
use Foysal50x\Tashil\Events\UsageLimitWarning;
class HandleUsageWarning
{
public function handle(UsageLimitWarning $event): void
{
$subscription = $event->subscription;
$feature = $event->feature;
$usage = $event->usage; // current usage
$limit = $event->limit; // maximum allowed
// Notify user they're approaching their limit
}
}Tashil implements a decorator-based caching layer using the Repository pattern:
Service Layer
└── CacheRepository (decorator)
└── EloquentRepository (implementation)
└── Database
- Read operations are cached with configurable TTL
- Write operations automatically invalidate related cache entries
- The cache layer can be disabled entirely via config
- Aggregate values (active count, MRR, etc.) are selectively cached
| Key Pattern | Data |
|---|---|
subscription:{id} |
Single subscription |
subscription:{Model}:{id}:valid |
Subscriber's valid subscription |
subscription:aggregate:active_count |
Active subscription count |
subscription:aggregate:mrr |
Monthly Recurring Revenue |
subscription:aggregate:total_count |
Total subscription count |
subscription:aggregate:count_by_status |
Status breakdown |
subscription:aggregate:by_package |
Subscribers per package |
subscription:aggregate:revenue_by_package |
Revenue per package |
subscription:aggregate:dashboard_stats |
Batched dashboard KPIs |
invoice:aggregate:pending_count |
Pending invoice count |
invoice:aggregate:total_revenue |
Total revenue |
Set in config/tashil.php:
'cache' => [
'enabled' => false,
],Or in .env:
TASHIL_CACHE_ENABLED=false
Tashil::subscription() // → SubscriptionService
Tashil::usage() // → UsageService
Tashil::analytics() // → AnalyticsService
Tashil::billing() // → BillingService
Tashil::feature($slug) // → FeatureBuilder
Tashil::package($slug) // → PackageBuilder| Method | Return | Description |
|---|---|---|
subscribe(Model $subscriber, Package $package, bool $withTrial = false) |
Subscription |
Create subscription |
cancel(Subscription $sub, bool $immediate = false, ?string $reason = null) |
Subscription |
Cancel subscription |
resume(Subscription $sub) |
Subscription |
Resume cancelled subscription |
switchPlan(Subscription $sub, Package $newPackage) |
Subscription |
Switch to different package |
| Method | Return | Description |
|---|---|---|
increment(Subscription $sub, string $featureSlug, float $amount = 1) |
bool |
Increment feature usage |
check(Subscription $sub, string $featureSlug, float $amount = 1) |
bool |
Check if feature can be used |
resetUsage(Subscription $sub, string $featureSlug) |
bool |
Reset single feature usage |
resetAllUsage(Subscription $sub) |
void |
Reset all feature usage |
| Method | Return | Description |
|---|---|---|
generateInvoice(Subscription $sub, ?float $amount = null) |
Invoice |
Generate invoice |
| Method | Return | Description |
|---|---|---|
dashboardSummary() |
array |
All-in-one KPI summary |
packageAnalytics() |
array |
Detailed stats per package |
calculateMRR() |
float |
Monthly Recurring Revenue |
churnRate(int $days) |
float |
Churn percentage |
trialConversionRate() |
float |
Trial conversion percentage |
totalSubscriptionCount() |
int |
All subscriptions |
activeSubscriptionCount() |
int |
Active + on-trial |
subscriptionCountByStatus() |
array |
Count per status |
subscribersByPackage() |
array |
Distribution per package |
trialConversionRate() |
float |
Trial→active % |
subscriptionGrowth(int $months = 12) |
array |
Monthly growth data |
calculateMRR() |
float |
Monthly Recurring Revenue |
averageRevenuePerUser() |
float |
ARPU |
totalRevenue() |
float |
Lifetime revenue |
revenueByPeriod(int $months = 12) |
array |
Monthly revenue trend |
revenueByPackage() |
array |
Revenue per package |
pendingInvoiceCount() |
int |
Pending invoices |
overdueInvoiceCount() |
int |
Overdue invoices |
churnRate(int $days = 30) |
float |
Churn % |
churnTrend(int $months = 12, int $windowDays = 30) |
array |
Churn over time |
getDailyUsage(Subscription $sub, int $featureId, int $days = 30) |
array |
Daily usage data |
getDailyUsage(Subscription $sub, int $featureId, int $days = 30) |
array |
Daily usage data |
dashboardSummary() |
array |
All KPIs in one call |
packageAnalytics() |
array |
Detailed stats per package |
| Method | Return | Description |
|---|---|---|
name(string $name) |
self |
Set display name |
description(string $desc) |
self |
Set description |
boolean() |
self |
Set type to boolean |
limit() |
self |
Set type to limit |
consumable() |
self |
Set type to consumable |
type(FeatureType $type) |
self |
Set type explicitly |
active(bool $active = true) |
self |
Set active status |
inactive() |
self |
Mark as inactive |
sortOrder(int $order) |
self |
Set display order |
metadata(array $data) |
self |
Attach metadata |
create() |
Feature |
Persist to database |
createOrUpdate() |
Feature |
Upsert by slug |
| Method | Return | Description |
|---|---|---|
name(string $name) |
self |
Set display name |
description(string $desc) |
self |
Set description |
price(float $price) |
self |
Set price |
originalPrice(float $price) |
self |
Set original/strike-through price |
currency(string $currency) |
self |
Set currency |
monthly() |
self |
Bill monthly |
quarterly() |
self |
Bill quarterly |
yearly() |
self |
Bill yearly |
lifetime() |
self |
One-time payment |
billingPeriod(Period $period, int $interval = 1) |
self |
Custom billing cycle |
trialDays(int $days) |
self |
Set trial duration |
featured(bool $featured = true) |
self |
Mark as featured |
sortOrder(int $order) |
self |
Set display order |
metadata(array $data) |
self |
Attach metadata |
feature(Feature|int $feature, ...) |
self |
Attach single feature |
features(array $features) |
self |
Attach multiple features |
create() |
Package |
Persist to database |
createOrUpdate() |
Package |
Upsert by slug |
| Relationship | Type | Target |
|---|---|---|
package() |
BelongsTo | Package |
items() |
HasMany | SubscriptionItem |
usageLogs() |
HasMany | UsageLog |
invoices() |
HasMany | Invoice |
| Method | Return | Description |
|---|---|---|
isActive() |
bool |
Status is Active |
isOnTrial() |
bool |
Status is OnTrial |
isCancelled() |
bool |
Status is Cancelled |
isExpired() |
bool |
Status is Expired |
isPastDue() |
bool |
Status is PastDue |
isValid() |
bool |
Active or OnTrial |
| Relationship | Type | Target |
|---|---|---|
features() |
BelongsToMany | Feature |
subscriptions() |
HasMany | Subscription |
| Scope | Description |
|---|---|
active() |
Only active packages |
featured() |
Only featured packages |
ordered() |
Ordered by sort_order |
| Relationship | Type | Target |
|---|---|---|
subscription() |
BelongsTo | Subscription |
transactions() |
HasMany | Transaction |
| Method | Description |
|---|---|
markAsPaid() |
Set status to Paid |
markAsVoid() |
Set status to Void |
| Method | Return | Description |
|---|---|---|
isOverLimit() |
bool |
Usage exceeds value |
remainingUsage() |
float |
Value minus usage |
usagePercentage() |
float |
Usage as % of value |
| Variable | Default | Description |
|---|---|---|
TASHIL_DB_CONNECTION |
null |
Database connection |
TASHIL_CURRENCY |
USD |
Default currency |
TASHIL_REDIS_HOST |
REDIS_HOST / 127.0.0.1 |
Redis host |
TASHIL_REDIS_PASSWORD |
REDIS_PASSWORD / null |
Redis password |
TASHIL_REDIS_PORT |
REDIS_PORT / 6379 |
Redis port |
TASHIL_REDIS_DB |
5 |
Redis database index |
TASHIL_CACHE_PREFIX |
tashil_cache: |
Cache key prefix |
TASHIL_CACHE_ENABLED |
true |
Enable/disable caching |
Tashil creates the following tables (all names are configurable):
tashil_packages
tashil_features
tashil_package_feature (pivot)
tashil_subscriptions
tashil_subscription_items
tashil_usage_logs
tashil_invoices
tashil_transactions
The subscriptions table uses a polymorphic subscriber_type / subscriber_id pattern, so any Eloquent model can be a subscriber.
For more detailed examples and usage scenarios, check the examples/ directory:
MIT