ipunkt / subscriptions
laravel应用的订阅处理软件包
Requires
- php: >=7.4.0
- illuminate/config: 7.*
- illuminate/contracts: 7.*
- illuminate/database: 7.*
- illuminate/events: 7.*
- illuminate/support: 7.*
README
安装
将以下行添加到您的composer.json文件中
"require": {
"ipunkt/subscriptions": "^1.0"
}
运行php artisan vendor:publish ipunkt/subscriptions
然后编辑config/plans.php
中的plans.php
以满足您的需求。所有已知计划仍然在其中。
您可以使用Subscription
外观。
运行php artisan migrate
以迁移必要的数据库表。
配置
计划配置
// @see src/config/plans.php
return [
'PLAN-ID' => [
'name' => 'TRIAL',
'description' => 'Trial subscription.',
'subscription_break' => 0, // optional for preventing a subscription for X days after last subscription ends
],
];
可选属性'subscription_break'
可以用来防止订阅者在配置的天数过去之前订阅此计划。例如,为了有一个只能每年订阅一次的TRIAL计划。
计划的好处配置
// @see src/config/plans.php
return [
'PLAN-ID' => [
// [..]
'benefits' => [
'feature-1' => [], // feature is present
'feature-2-countable' => [
'min' => 10, // feature is present and has margins/countable range
],
'feature-3-countable' => [
'min' => 10,
'max' => 50,
],
'feature-4-countable' => [
'max' => 50, // min is automatically 0 (zero)
],
],
],
];
计划的支付选项
// @see src/config/plans.php
return [
'PLAN-ID' => [
// [..]
'payments' => [
[
'price' => 1, // for 1.00
'quantity' => 12, // in 12-times
'days' => 30, // of 30-days
'methods' => ['paypal'], // allowed payment methods
],
[
'price' => 2, // for 2.00
'quantity' => 12, // in 12-times
'days' => 30, // of 30-days
'methods' => ['paypal', 'invoice'],
],
],
],
];
为所有订阅者选择默认计划
要为所有订阅者设置默认计划,您可以使用src/config/defaults.php
并设置默认计划的ID。因此,当订阅者还没有计划时,每次基于计划的特性检查都会解析此默认计划。
用法
获取所有计划
/** @var Plan[] $plans */
$plans = Subscription::plans();
如果您的计划配置中使用了订阅中断,请使用selectablePlans
方法获取所有计划。这将检查每个中断计划的最后一个订阅。
/** @var Plan[] $plans */
$plans = Subscription::selectablePlans($this->user);
获取订阅者的当前计划
/** @var Plan|null $plan */
$plan = Subscription::plan($subscriber);
订阅者是否已经存在订阅
Subscription::exists($subscriber); // returns true when a subscription exists
每个计划都可以有好处(特性)
$plan->can('feature'); // returns true or false
$plan->can('countable-feature', 14); // returns true or false
或使用Subscription
外观来检查订阅者的当前订阅计划。这是推荐的
Subscription::can($subscriber, 'feature'); // returns true or false
Subscription::can($subscriber, 'countable-feature', 14); // returns true or false
获取计划的所有可能的支付选项
/** @var PaymentOption[] $paymentOptions */
$paymentOptions = $plan->paymentOptions();
创建新的订阅
/** creating a subscription for a subscriber, maybe the current authenticated user */
$subscription = Subscription::create($plan, $paymentOption, SubscriptionSubscriber $subscriber);
要创建订阅,您必须提供Plan
或计划的ID以及选定的PaymentOption
或支付选项的标识符。$subscriber
是订阅所属的实体。这可以是任何可变形态的eloquent对象。
成功创建订阅后,会触发类型为Ipunkt\Subscriptions\Subscription\Events\SubscriptionWasCreated
的事件。
底层仓库本身控制重复项。因此对于现有订阅,它将更新当前订阅并触发类型为 Ipunkt\Subscriptions\Subscription\Events\SubscriptionWasUpdated
的事件。
您可以升级订阅到任何其他计划。相同的 Subscription::create()
方法处理此升级。
触发的事件都具有当前订阅、所选计划和支付选项作为属性。因此,您可以在这些事件上监听并执行自己的操作。
获取订阅者的当前订阅
/** @var Subscription|null $subscription */
$subscription = Subscription::current($subscriber);
检查试用订阅者
/** be careful because current() can return null when no subscription existing */
$onTrial = Subscription::current($subscriber)->onTrial();
检查订阅是否已付款
$subscription = Subscription::current($subscriber);
$isPaid = $subscription->paid(); // or Subscription::paid($subscriber);
获取订阅的所有周期
/** @var Period[] $periods */
$periods = $subscription->periods;
用户代码
适配您的控制器
我们使用 laracasts/commander
包来处理业务命令和事件。
class SubscriptionsController extends \Controller
{
/**
* use commandbus to execute commands
*/
use Laracasts\Commander\CommanderTrait;
// display an overview of all subscriptions
public function index()
{
$subscribed = Subscription::exists($this->user);// $this->user represents a SubscriptionSubscriber interface
if ( ! $subscribed) {
$plans = Subscription::selectablePlans($this->user); // unselectable plans filtered out already
$defaultPlan = Subscription::plan($this->user);
return View::make('subscriptions.create', compact('plans', 'defaultPlan'));
}
$plan = Subscription::plan($this->user);
$subscription = Subscription::current($this->user);
$paid = $subscription->paid();
$subscriptions = Subscription::all($this->user);
return View::make('subscriptions.index', compact('subscribed', 'plan', 'subscription', 'subscriptions', 'paid'));
}
// create a plan (form)
public function create($plan)
{
$plan = Subscription::findPlan($plan);
$subscription = Subscription::all($this->user)->last();
if (null !== $subscription && $subscription->subscription_ends_at->isPast())
$subscription = null;
$startDate = (null === $subscription) ? Carbon::now() : $subscription->subscription_ends_at->addSeconds(1);
return View::make('subscriptions.create_plan', compact('plan', 'startDate'));
}
// store the plan as subscription for user
public function store()
{
try {
$this->validate(Input::all());
} catch (FormValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->getErrors());
}
$plan = Subscription::findPlan(Input::get('plan'));
if (null === $plan)
throw (new ModelNotFoundException('No plan ' . Input::get('plan') . ' found.'))->setModel(Plan::class);
$this->execute(CreateSubscriptionCommand::class, Input::all());
Flash::success('subscriptions.subscription_created');
return Redirect::route('subscriptions.index');
}
}
相应的命令 CreateSubscriptionCommandHandler
就在这里(CreateSubscriptionCommand
只是一个输入值的 DTO)
class CreateSubscriptionCommandHandler implements Laracasts\Commander\CommandHandler
{
use Laracasts\Commander\Events\DispatchableTrait;
/**
* authenticated user
*
* @var \Illuminate\Auth\Guard
*/
private $auth;
/**
* @param AuthManager $auth
*/
public function __construct(\Illuminate\Auth\AuthManager $auth)
{
$this->auth = $auth;
}
/**
* Handle the command
*
* @param CreateSubscriptionCommand $command
* @return mixed
*/
public function handle($command)
{
/** @var User|SubscriptionSubscriber $user */
$user = $this->auth->user();
// store invoice data
// create subscription
$subscription = Subscription::create($command->plan, $command->payment_option, $user);
// fire event for "subscription created" or "subscription updated"
$this->dispatchEventsFor($subscription);
}
}
几乎与扩展或升级计划时需要做的相同。您可以使用相同的命令、处理程序和控制器操作。订阅仓库会自动处理订阅计划的更新或创建。
注册监听器
# in your app/listeners.php for example
Event::listen('Ipunkt.Subscriptions.Subscription.Events.*', 'App\Subscriptions\Listeners\EmailNotifier');
// we use the laracasts/commander package, so you can inform you about a listener too
class EmailNotifier extends Laracasts\Commander\Events\EventListener
{
/**
* will be called when event SubscriptionWasCreated was fired
*
* @param SubscriptionWasCreated $event
*/
public function whenSubscriptionWasCreated(SubscriptionWasCreated $event)
{
// do something when a subscription was created (a new plan was set up and no plan exists before
// or every plan subscription before was in the past)
}
/**
* will be called when event SubscriptionWasUpdated was fired
*
* @param SubscriptionWasUpdated $event
*/
public function whenSubscriptionWasUpdated(SubscriptionWasUpdated $event)
{
// do something when a subscription was updated (e.g. smaller plan before gets upgraded to a more-featured
// plan or a subscription was extended to get longer running)
}
}