رفتن به متن راهنما
همه‌ی راهنماها

قانون‌های اعتبارسنجی و cast در Eloquent

قانون‌های اعتبارسنجی ایرانی را در فرم‌های Laravel به کار ببرید، تاریخ جلالی را با JalaliCast در مدل‌های Eloquent ذخیره کنید و در Blade نشان بدهید.

برنامه RTLY-Kit 0.2.0آخرین بررسی زمان خواندن 7 دقیقه

در این صفحه

قانون‌های اعتبارسنجی

بعد از نصب بسته (راه‌اندازی Laravel)، شش قانون در دسترس است (با هفت نام، چون mobile نام کوتاه iran_mobile است). آن‌ها را در هر validator، form request یا $request->validate() می‌توانید بنویسید. هر قانون یکی از اعتبارسنج‌های توضیح‌داده‌شده در صفحه‌های اعتبارسنجی است.

قانونچه چیزی را قبول می‌کندجزئیات
national_codeکد ملی ایرانکد ملی
shebaشبا / IBAN، با IR یا بدون آنشبا و کارت بانکی
bank_cardشمارهٔ کارت بانکی ۱۶ رقمی (بررسی Luhn)شبا و کارت بانکی
iran_mobileشمارهٔ موبایل ایرانموبایل، کدپستی، پلاک
mobileنام کوتاه iran_mobileرفتار یکسان
postal_codeکدپستی ۱۰ رقمی ایرانموبایل، کدپستی، پلاک
vehicle_plateپلاک خودروی ایران، مثلاً 12ب345-67موبایل، کدپستی، پلاک

نام تکراری. mobile اسم عمومی است. اگر بستهٔ دیگری یا کد خودتان قانونی با همین نام ثبت کند، همه‌جا iran_mobile را بنویسید تا اشتباه نشود.

استفاده

PHP
use Illuminate\Http\Request;

public function store(Request $request)
{
    $data = $request->validate([
        'national_code' => 'required|national_code',
        'mobile'        => 'required|iran_mobile',
        'card'          => 'nullable|bank_card',
        'iban'          => 'nullable|sheba',
        'postal'        => 'required|postal_code',
        'plate'         => 'nullable|vehicle_plate',
    ]);
}

اجرای واقعی با داده‌های نادرست و زبان fa این نتیجه را داد:

PHP
// national_code = '1234567890'، mobile = '0912'، iban = 'IR000000000000000000000000'
// card و postal و plate درست‌اند و رد نمی‌شوند.
//
// national_code: national code کد ملی معتبر نیست.
// mobile: mobile شماره موبایل معتبر نیست.
// iban: iban شماره شبا معتبر نیست.

متن انگلیسی «The national code is not a valid Iranian national code.» است و متن عربی هم هست. ترجمه‌ها و عوض کردن پیام‌ها را ببینید.

چه ورودی‌ای قبول می‌شود

  • رشته. رقم‌های فارسی و عربی قبول می‌شوند. ۰۰۱۳۵۴۲۴۱۹ قانون national_code را رد می‌کند و می‌گذراند.
  • عدد صحیح و اعشاری اول به رشته تبدیل می‌شود. مراقب عددهایی باشید که با صفر شروع می‌شوند. عدد JSON با مقدار 13542419 صفرهای اول 0013542419 را از دست داده و رد می‌شود . کد ملی، موبایل و کدپستی را رشته بفرستید.
  • آرایه، شیء و بولی به اعتبارسنج نمی‌رسند و قانون را رد می‌کنند.
  • مقدار خالی. مثل قانون‌های خود Laravel، رشتهٔ خالی و کلید غایب نادیده گرفته می‌شود، مگر فیلد required باشد. مقدار صریح null رد می‌شود، مگر فیلد nullable باشد. با required یا nullable منظورتان را روشن کنید.
PHP
$f->make(['n' => '۰۰۱۳۵۴۲۴۱۹'], ['n' => 'national_code'])->passes();          // true
$f->make(['n' => 13542419],      ['n' => 'national_code'])->passes();          // false (صفرهای اول از دست رفته)
$f->make(['n' => null],          ['n' => 'nullable|national_code'])->passes(); // true
$f->make(['n' => null],          ['n' => 'national_code'])->passes();          // false
$f->make(['n' => ''],            ['n' => 'national_code'])->passes();          // true  (نادیده گرفته می‌شود)
$f->make(['n' => ''],            ['n' => 'required|national_code'])->passes(); // false
$f->make([],                     ['n' => 'national_code'])->passes();          // true  (کلید غایب)

اگر دلیل رد شدن را هم می‌خواهید (طول نادرست، رقم کنترل غلط، نوع نادرست)، خود اعتبارسنج را صدا بزنید که Result کامل می‌دهد. مرور اعتبارسنج‌ها را ببینید.

cast در Eloquent با JalaliCast

کلاس RtlyKit\Laravel\Casts\JalaliCast ستون پایگاه داده را میلادی (Y-m-d H:i:s) نگه می‌دارد، همان‌طور که همهٔ ابزارها انتظار دارند. در مدل، مقدار را به شکل یک شیء تغییرناپذیر RtlyKit\Calendar\Jalali نشان می‌دهد.

PHP
use Illuminate\Database\Eloquent\Model;
use RtlyKit\Laravel\Casts\JalaliCast;

class Post extends Model
{
    protected $guarded = [];

    protected $casts = [
        'published_at' => JalaliCast::class,
    ];
}

$post = new Post();
$post->published_at = '1404/01/15 10:30';

echo $post->getAttributes()['published_at'];          // 2025-04-04 10:30:00   (مقدار ذخیره‌شده)
echo $post->published_at->format('Y/m/d H:i');        // 1404/01/15 10:30
echo get_class($post->published_at);                  // RtlyKit\Calendar\Jalali
echo $post->published_at->addDays(20)->format('Y/m/d'); // 1404/02/04

نوع ستون همان datetime یا timestamp می‌ماند و migration عوض نمی‌شود.

مقدارهایی که می‌شود نوشت

مقداری که می‌نویسیدمقدار ذخیره‌شده (میلادی)
رشتهٔ جلالی '1404/01/15 10:30'2025-04-04 10:30:00
فقط تاریخ جلالی با رقم فارسی و خط تیره '۱۴۰۴-۰۱-۱۵'2025-04-04 00:00:00
رشتهٔ میلادی '2025-04-04 08:00:00'2025-04-04 08:00:00
زمان یونیکس (عدد صحیح) 17437536002025-04-04 08:00:00 (با منطقهٔ زمانی پیش‌فرض UTC)
هر DateTimeInterface (از جمله Carbon)همان لحظه، به شکل Y-m-d H:i:s
شیء Jalaliمعادل میلادی آن
null یا ''null

رشته‌ای جلالی حساب می‌شود که سالش بین ۱۲۰۰ و ۱۵۹۹ باشد و جداکننده‌اش / یا -، با ساعت اختیاری HH:MM یا HH:MM:SS بعد از فاصله یا T. بقیهٔ رشته‌ها مثل تاریخ میلادی خوانده می‌شوند.

خطاها

ورودی نادرست موقع نوشتن RtlyKit\Exceptions\InvalidDateException می‌دهد، نه خطای خام PHP:

PHP
$post->published_at = '1404/13/01';   // Invalid Jalali date: 1404/13/1
$post->published_at = '1404/07/31';   // Invalid Jalali date: 1404/7/31   (مهر ۳۰ روز دارد)
$post->published_at = 'not a date';   // Unable to parse date: not a date
$post->published_at = 1.5;            // Cannot cast value for 'published_at' to a date.
$post->published_at = ['x'];          // Cannot cast value for 'published_at' to a date.

ورودی کاربر را قبل از رسیدن به مدل اعتبارسنجی کنید (مثال form request پایین‌تر است) تا اشتباه تایپی خطای فرم بدهد، نه استثنا. خواندن برای null و رشتهٔ خالی راحت‌گیر است (هر دو null می‌دهند). ولی اگر در پایگاه داده متنی باشد که خوانده نمی‌شود، خواندن ویژگی InvalidDateException می‌دهد.

تبدیل مدل به JSON

کلاس‌های Jalali و Hijri و Hebrew JsonSerializable هستند. در مدلی که JalaliCast دارد، toJson() همان (string) $date را می‌دهد، مثلاً {"published_at":"1404/01/01 10:00:00"}. toArray() خود شیء Jalali را نگه می‌دارد. اگر شکل دیگری می‌خواهید، خودتان قالب‌بندی کنید.

form request

قانون آماده‌ای برای فیلد تاریخ جلالی نیست. شکل را با قانون regex خود Laravel یا یک قانون کوچک دلخواه بررسی کنید و تبدیل را به cast بسپارید:

PHP
public function rules(): array
{
    return [
        'published_at' => ['required', 'regex:/^1[2-5]\d\d[\/-]\d{1,2}[\/-]\d{1,2}$/u'],
    ];
}

این الگو 1404/01/15 و 1404-1-5 را می‌گذراند و 2025/01/01 و abc را رد می‌کند. تاریخی که شکلش درست است ولی وجود ندارد، مثل 1404/07/31، به cast می‌رسد و همان‌جا خطا می‌دهد. اگر کاربر متن آزاد می‌نویسد، InvalidDateException را در یک قانون دلخواه یا در controller بگیرید.

Blade

cast یک شیء Jalali می‌دهد. پس در Blade به تابع کمکی نیازی نیست:

PHP
{{ $post->published_at?->format('Y/m/d') }}            {{-- 1404/01/15 --}}
{{ $post->published_at?->format('l j F Y') }}          {{-- جمعه 15 فروردین 1404 --}}
{{ \RtlyKit\to_persian_digits($post->published_at->format('Y/m/d')) }}  {{-- ۱۴۰۴/۰۱/۱۵ --}}

برای ستونی که cast ندارد، مثل created_at معمولی (یک Carbon)، از تابع فضای‌نام‌دار استفاده کنید. این توابع همیشه بارگذاری می‌شوند و ثبت‌نام نمی‌خواهند:

PHP
{{ \RtlyKit\jdate($post->created_at)->format('Y/m/d H:i') }}   {{-- 1404/01/15 08:00 --}}

اگر زیاد به کار می‌برید، بالای فایل Blade با @php use function RtlyKit\jdate; @endphp واردش کنید. با ماکروهای Carbon همین کار $post->created_at->jformat('Y/m/d') است. ماکروهای Carbon را ببینید.

نکته. ویژگی‌ای که null باشد خودکار قالب‌بندی نمی‌شود. مثل بالا از ?-> استفاده کنید، وگرنه Blade روی null خطا می‌دهد. فهرست کامل توکن‌های قالب در تقویم جلالی است.