Initial baseline: LaraBlog core with plugin commerce surface.

Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
ak
2026-08-12 01:15:38 +08:00
commit 263b98b218
337 changed files with 31393 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace App\Domain\Blog;
final class AccessDecision
{
public const ALLOW = 'allow';
public const NEED_LOGIN = 'need_login';
public const NEED_PURCHASE = 'need_purchase';
public const NEED_PASSWORD = 'need_password';
/** @var array<string, int> */
private const SEVERITY = [
self::ALLOW => 0,
self::NEED_LOGIN => 1,
self::NEED_PURCHASE => 2,
self::NEED_PASSWORD => 3,
];
public function __construct(
public string $status,
public ?string $teaserHtml = null,
public ?string $checkoutUrl = null,
public ?string $message = null,
) {}
public static function allow(): self
{
return new self(self::ALLOW);
}
public static function needPassword(?string $message = null): self
{
return new self(self::NEED_PASSWORD, message: $message);
}
public static function needPurchase(?string $teaserHtml = null, ?string $checkoutUrl = null, ?string $message = null): self
{
return new self(self::NEED_PURCHASE, $teaserHtml, $checkoutUrl, $message);
}
public function isAllow(): bool
{
return $this->status === self::ALLOW;
}
public function severity(): int
{
return self::SEVERITY[$this->status] ?? 0;
}
/**
* Only allow tightening (higher severity). Metadata from the stricter side wins when status changes;
* otherwise fill empty meta from $other.
*/
public function tightenWith(self $other): self
{
if ($other->severity() < $this->severity()) {
return new self(
$this->status,
$this->teaserHtml ?? $other->teaserHtml,
$this->checkoutUrl ?? $other->checkoutUrl,
$this->message ?? $other->message,
);
}
if ($other->severity() > $this->severity()) {
return new self(
$other->status,
$other->teaserHtml ?? $this->teaserHtml,
$other->checkoutUrl ?? $this->checkoutUrl,
$other->message ?? $this->message,
);
}
return new self(
$this->status,
$other->teaserHtml ?? $this->teaserHtml,
$other->checkoutUrl ?? $this->checkoutUrl,
$other->message ?? $this->message,
);
}
/**
* @return array{status: string, teaser_html: ?string, checkout_url: ?string, message: ?string}
*/
public function toArray(): array
{
return [
'status' => $this->status,
'teaser_html' => $this->teaserHtml,
'checkout_url' => $this->checkoutUrl,
'message' => $this->message,
];
}
}