ipunkt / subscriptions

该软件包已被废弃且不再维护。没有建议的替代软件包。

laravel应用的订阅处理软件包

1.0.2 2020-07-11 15:36 UTC

This package is auto-updated.

Last update: 2023-09-11 22:21:18 UTC


README

Latest Stable Version Latest Unstable Version License Total Downloads

安装

将以下行添加到您的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)
    }
}