Subscriptionify: مدیریت اشتراک لاراول مستقل از درگاه پرداخت
خلاصهٔ کاملتر
به گفته نویسنده، Subscriptionify یه پکیج لاراوله که Rasel Islam Rafi ساخته و کارش مدلکردن پلنهای اشتراک و قابلیتهاییه که هر پلن باز میکنه. تفاوت اصلیش با Laravel Cashier اینه که Cashier دور API صورتحساب یه درگاه پرداخت میپیچه، ولی Subscriptionify مستقل از درگاه (gateway-agnostic) میمونه: پلنها، سهمیهی قابلیتها و مصرف رو تو دیتابیس خودت ردیابی میکنه و این که کی پولو جمع میکنه رو به عهده خودت میذاره. همین باعث میشه برای اپهایی مناسب باشه که از یه درگاه خارج از پوشش Cashier استفاده میکنن، از یه موجودی پیشپرداخت کم میکنن، یا اصلاً بدون دریافت پول دسترسی میدن. به PHP 8.2 نیاز داره و لاراول ۱۱ تا ۱۳ رو پشتیبانی میکنه.
هر مدلی میتونه قابل اشتراک بشه؛ کافیه قرارداد Subscribable رو پیادهسازی کنه و trait به اسم InteractsWithSubscriptions رو اضافه کنه. به این ترتیب میشه اشتراک رو به User، Organisation یا Workspace وصل کرد، بسته به ساختار اپلیکیشن.
ایدهی اصلی اینه که هر قابلیت رفتار یکسانی نداره، برای همین چهار نوع تعریف شده: Toggle یه دروازهی روشن/خاموش سادهست؛ Consumable یه سهمیهی مصرفیه که سر یه زمانبندی ریست میشه، مثل سهمیهی ماهانهی فراخوانی API؛ Limit یه سقف سفت روی یه مجموع جاریه که میشه دوباره آزادش کرد، مثل پروژههای فعال یا seatها که با حذف یکی جا آزاد میشه؛ و Metered مصرف pay-per-use رو بدون سقف ردیابی میکنه و به ازای هر واحد هزینه میگیره.
وقتی یه مدل اشتراک گرفت، متدهای مصرف مستقیم روی خودش قرار میگیرن و لازم نیست دستت بره تو رکوردهای subscription یا pivot. این متدها دسترسی رو چک میکنن، تست میکنن چندتا واحد موجوده و مصرفو ثبت میکنن:
$workspace->subscribe($plan);
$workspace->hasFeature('reports'); // اصلاً قابلیت در دسترسه؟
$workspace->canConsume('reports', 10); // الان ۱۰ واحد موجوده؟
$workspace->consume('reports', 10); // ثبت مصرف؛ اگه سهمیه پر شده باشه خطا میده
$workspace->tryConsume('reports', 10); // مثل بالا ولی بهجای خطا false برمیگردونه
$workspace->remainingUsage('reports'); // واحدهای باقیمونده تو دوره فعلیبرای قابلیتهای Limit متد release() واحدها رو پس میده و یه slot آزاد میکنه، و همینه که یه limit رو از یه consumable که فقط میشماره جدا میکنه. علاوه بر پلنها، با grantFeature() میشه یه قابلیتو مستقیم و جدا از پلن، روی هرچی پلن میده، اضافه کرد؛ مثلاً اگه پلن ۵۰۰ گزارش بده و تو ۱۰۰۰ تا grant کنی، سهمیه میشه ۱۵۰۰ تا. این برای شارژهای یکباره، پاداشهای تبلیغاتی و تنظیمات تکمشتری بدون ساختن پلن جداست.
صورتحساب opt-in هست. اگه قرارداد HasFunds رو کنار Subscribable پیاده کنی، پکیج شروع میکنه به کمکردن از یه موجودی که خودت کنترلش میکنی: قابلیتهای consumable و limit بعد از پرشدن سهمیه (در صورت تنظیم unit_price) هزینهی overage میگیرن و قابلیتهای metered از همون اولین استفاده به ازای هر واحد هزینه میگیرن. به گفته نویسنده، چون مبلغها بهصورت رشته پاس داده میشن و با bccomp مقایسه میشن، محاسبات با دقت دلخواه انجام میشه نه اعشار شناور. بدون HasFunds همون قابلیتها به سقفهای سفت برمیگردن، پس میتونی اول enforcement سهمیه رو بفرستی و بعداً صورتحسابو اضافه کنی بدون بازنویسی کد مصرف.
برای محافظت از مسیرها سه alias میدلور ثبت میشه (subscribed، plan: و feature:) که موقع شکست 403 برمیگردونن، و دایرکتیوهای Blade مثل @feature و @onTrial محتوا رو تو ویوها گیت میکنن، شامل حالتهای trial، پلن رایگان و دورهی grace بعد از لغو. اشتراکها هم متدهای چرخهی عمر معمول (changePlan()، renew()، cancel()، cancelNow() و resume()) رو دارن و هر گذار یه event مثل SubscriptionCreated یا FeatureConsumed منتشر میکنه. یه دستور artisan هم هست که اشتراکهای فعالِ گذشته از تاریخ پایان رو به expired منتقل میکنه.
نکات کلیدی:
- Subscriptionify مستقل از درگاه پرداخته و فقط پلنها، سهمیهی قابلیتها و مصرف رو تو دیتابیس خودت مدل میکنه
- هر مدلی با پیادهسازی قرارداد Subscribable و trait مربوطه قابل اشتراک میشه
- چهار نوع قابلیت: Toggle (روشن/خاموش)، Consumable (سهمیهی ریستشونده)، Limit (سقف قابلآزادسازی) و Metered (پرداخت به ازای مصرف)
- صورتحساب opt-in هست؛ با قرارداد HasFunds میشه از یه موجودی هزینه گرفت و محاسبات با bccomp دقیق انجام میشه
- محافظت از مسیر با سه میدلور و گیتکردن ویو با دایرکتیوهای Blade مثل @feature و @onTrial




