لاراول رولبوک: قانونهایی که تاریخ انقضا دارن
خلاصهٔ کاملتر
نویسنده میگه Laravel Rulebook، پکیجی از Mathias Onea، برای اون دسته از قانونهای کسبوکاره که با گذشت زمان عوض میشن. مثالش روشنه: یه بازپرداخت که ماهها قبل با شرایط قدیمی حساب شده، یا فاکتوری که با نرخ کمیسیون سال گذشته صادر شده. اگه سیاست رو مستقیم توی کد ویرایش کرده باشی، تنها ردی که ازش مونده تاریخچهٔ git ـه و اونو که نمیتونی توی جواب مشتری کپی کنی.
هر قانون یه کلاس PHP سادهست که خودش میگه توی چه بازهای معتبر بوده: always()، from()، until() یا between(). بازهها نیمباز هستن، یعنی سالهای پشت سر هم هیچوقت روی هم نمیافتن. نتیجهش اینه که سیاست پارسال کنار سیاست امسال توی کدبیس میمونه و پاک نمیشه.
public function validity(): ValidityPeriod
{
return ValidityPeriod::between(
from: new DateTimeImmutable('2025-01-01T00:00:00-05:00'),
until: new DateTimeImmutable('2026-01-01T00:00:00-05:00'),
);
}توی مثال مقاله، یه بلیت انعطافپذیر تا آخر ۲۰۲۵ با ۷ روز اطلاع قبلی کامل برگشت میخورد، ولی از ژانویهٔ ۲۰۲۶ این مهلت شد ۱۴ روز بهعلاوهٔ ۳.۵ دلار کارمزد. وقتی تصمیم رو برای یه تاریخ مشخص میگیری، فقط یه قانون برنده میشه و برنده رو priority() تعیین میکنه، نه ترتیب قانونها توی آرایه.
$decision->outcome()->formatted(); // $89.00
class_basename($decision->winningRule()); // FlexibleFareRefund2025
$decision->winningResult()->reason(); // Refunded under the 2025 flexible fare policy.بقیهٔ قانونها هم گم نمیشن: هرکدوم با یه وضعیت و یه دلیل برمیگردن و دلیل میتونه یه reasonCode هم داشته باشه که روش فیلتر کنی. وضعیت outside_validity یعنی evaluate() اون قانون اصلاً اجرا نشده، و همین فرق «این سیاست هنوز وجود نداشت» با «این سیاست نگاه کرد و گفت نه» رو روشن میکنه. اگه هیچ قانونی جواب نده NoMatchingRule و اگه دوتا قانون مساوی بشن AmbiguousRuleMatch پرتاب میشه.
برای نگهداشتن همین رکورد، snapshot() کل تصمیم رو به یه ساختار JSON تبدیل میکنه که میتونی کنار خود رکورد ذخیرهش کنی. اسکالرها، آرایهها، enumهای backed و خروجیهای JsonSerializable همونطور رد میشن و بقیه یه callback میخوان. پکیج PHP 8.3 و لاراول ۱۲ یا ۱۳ لازم داره و به گفتهٔ نویسنده نه facade داره، نه رجیستری، نه فایل کانفیگ و نه migration.
نکات کلیدی:
- بازهٔ اعتبار هر قانون با always()، from()، until() یا between() تعریف میشه و نیمبازه، پس سالهای متوالی روی هم نمیافتن
- هر resolve دقیقاً یه برنده داره و انتخابش با priority() انجام میشه، نه با جای قانون توی آرایه
- هر قانون یه وضعیت و یه دلیل برمیگردونه؛ دلیل میتونه reasonCode داشته باشه که قابل فیلتره
- NoMatchingRule وقتی هیچ قانونی جواب نده و AmbiguousRuleMatch وقتی دوتا قانون مساوی بشن پرتاب میشه
- snapshot() تصمیم رو به JSON تبدیل میکنه تا کنار رکورد ذخیره بشه
- نیازمندیها: PHP 8.3 و Laravel 12 یا 13، بدون facade و config و migration




