Add subscription status helpers

status() returns draft, trial, active, paused, cancelling, expired or
cancelled (SubscriptionStatus constants), derived from the fields the
same way Anikeen ID derives its status, so it also works with older
responses. isActive() is true while the subscription runs and is paid.
Both Subscription and AppSubscription have them. Document the states.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Maurice PreußandClaude Opus 5.5 committed 2026-11-04 16:15:48 +01:00
1 parent 2faccac0f4
commit ce820cd198
7 files changed
+348 -117

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
<?php
namespace Anikeen\Id\Concerns;
use Anikeen\Id\Enums\SubscriptionStatus;
/**
* The state of a subscription, derived from its fields the same way Anikeen ID derives `status`
* (so it also works with responses that only carry the fields).
*/
trait HasSubscriptionStatus
{
/**
* One of the SubscriptionStatus constants: draft, trial, active, paused, cancelling, expired
* or cancelled.
*/
public function status(): string
{
$active = (bool) $this->active;
$started = !empty($this->starts_at);
return match (true) {
(bool) $this->cancelled => SubscriptionStatus::CANCELLED,
!$active && !$started => SubscriptionStatus::DRAFT,
$active && !empty($this->cancels_at) => SubscriptionStatus::CANCELLING,
$active && !$this->autorenew => SubscriptionStatus::PAUSED,
$active && !empty($this->trial_ends_at) && strtotime($this->trial_ends_at) > time() => SubscriptionStatus::TRIAL,
$active => SubscriptionStatus::ACTIVE,
!$this->autorenew && $started => SubscriptionStatus::EXPIRED,
default => SubscriptionStatus::INACTIVE,
};
}
/**
* Not checked out or confirmed yet (third-party apps: send the user to confirmationUrl()).
*/
public function isDraft(): bool
{
return $this->status() === SubscriptionStatus::DRAFT;
}
/**
* Running and paid: active, in trial, paused or with a scheduled cancellation. Grant access
* while this is true.
*/
public function isActive(): bool
{
return in_array($this->status(), [SubscriptionStatus::TRIAL, SubscriptionStatus::ACTIVE, SubscriptionStatus::PAUSED, SubscriptionStatus::CANCELLING], true);
}
/**
* Paused: runs until the paid period ends, then expires (resume() to continue).
*/
public function isPaused(): bool
{
return $this->status() === SubscriptionStatus::PAUSED;
}
/**
* Running until a scheduled cancellation takes effect.
*/
public function isCancelling(): bool
{
return $this->status() === SubscriptionStatus::CANCELLING;
}
/**
* Paused and ran out: resume() starts a new period.
*/
public function isExpired(): bool
{
return $this->status() === SubscriptionStatus::EXPIRED;
}
/**
* Cancelled for good.
*/
public function isCancelled(): bool
{
return $this->status() === SubscriptionStatus::CANCELLED;
}
}