021-88881776

آموزش توسعه پیشرفته (Advanced) در Filament

آموزش Filament یکی از سریع‌ترین راه‌ها برای ساختن رابط‌های کاربری ادمین (Admin Panel) و فرم‌های پیچیده در سیستم مدیریت محتوای لاراول است. اگر تاکنون با مباحث اولیه آشنا شده‌اید و مایلید از سطح مبتدی فراتر بروید، این مقاله برای شماست. در اینجا قصد داریم به مبحث توسعه پیشرفته (Advanced) در Filament بپردازیم و تمامی جنبه‌های مهم آن را گام به گام بررسی کنیم. با مطالعه این مقاله، شما قادر خواهید بود تا پروژه‌های خود را حرفه‌ای‌تر سازماندهی کرده و از امکانات پیشرفته Filament به شکل بهینه استفاده کنید.

توسعه پیشرفته (Advanced) در Filament

در این بخش، به سه حوزه اصلی در توسعه پیشرفته (Advanced) در Filament خواهیم پرداخت: Events و Hooks، تست واحد (Unit Testing)، و یکپارچه‌سازی با سرویس‌ها. هر کدام از این موضوعات می‌توانند سطح توسعه شما را به شکل قابل توجهی ارتقا دهند.

Events و Hooks

در مباحث توسعه پیشرفته (Advanced) در Filament، آشنایی عمیق با Events و Hooks می‌تواند نقش کلیدی در طراحی ساختار ماژولار و انعطاف‌پذیر برای پنل مدیریتی شما داشته باشد. در ادامه، به صورت جامع به این دو مفهوم و نحوه استفاده از آن‌ها در Filament خواهیم پرداخت.

چیستی Events و Hooks

Event در لاراول:

لاراول به صورت پیش‌فرض مکانیزمی دارد که به کمک آن می‌توانید در صورت وقوع رخدادی خاص (مثل ایجاد، به‌روزرسانی یا حذف داده در دیتابیس) تکه کد مشخصی را اجرا کنید. این رخدادها معمولاً در مدل‌ها یا سرویس‌های مختلف تعریف می‌شوند. Filament نیز از همین ساختار بهره می‌برد تا زمانی که در بخش‌های مختلف یک عملیات انجام شد، بتوانید به آن واکنش نشان دهید.

Hook (قلاب) در Filament:

گاهی می‌خواهید پیش یا پس از انجام یک عملیات خاص در Filament—مثلاً هنگام مونت شدن (Mount) یک فرم یا پس از Submit شدن آن—منطق سفارشی‌سازی خود را اعمال کنید. اینجا مفهوم Hook وارد می‌شود. با تعریف یک Hook، شما در چرخه حیات (Lifecycle) کامپوننت‌های Filament (نظیر فرم‌ها، جداول، ویرایشگرها و غیره) نقطه‌ای را مشخص می‌کنید که در آن لحظه، کد دلخواهتان اجرا شود. به عبارت دیگر، Hookها برای زمانی مناسب هستند که نیاز دارید به صورت موضعی و دقیق، به یک رفتار داخلی Filament دسترسی داشته باشید.

تفاوت اصلی بین Events و Hooks

حوزه اجرا:

رویدادهای (Events) لاراول یا Filament معمولاً گسترده‌تر عمل می‌کنند و می‌توانند در سطح مدل (Model)، کنترلر (Controller)، یا سرویس‌های پایه‌ای فعال شوند. به عنوان مثال، ایجاد یک رکورد جدید در دیتابیس، ارسال اطلاعات به سرویس‌های خارجی یا ثبت لاگ (Log) می‌تواند نمونه‌ای از یک Event باشد.
قلاب‌ها (Hooks) بیشتر در سطح یک کامپوننت یا جزئیات داخلی آن (مثل فرم یا جدول) قرار می‌گیرند و گاهی اوقات حتی قبل از رویدادهای عمومی لاراول فعال می‌شوند. این ویژگی باعث می‌شود بتوانید در مرحله خاصی از چرخه حیات، مداخله کرده و تغییراتی را اعمال کنید.

زمان‌بندی اجرا:

Eventها اغلب بعد از وقوع یک عمل اصلی (نظیر ایجاد رکورد) فعال می‌شوند. برای مثال، متدهایی مانند created، updated یا deleted دقیقاً پس از عملیات مربوطه اجرا می‌شوند.
Hookها می‌توانند قبل و بعد از اعمال مختلفی مانند render یا mount شدن فرم اجرا شوند. برای مثال، با استفاده از Hookهای Filament، می‌توانید پیش از بارگذاری فرم بخشی از داده‌ها را آماده یا تغییر دهید.

محل تعریف:

در لاراول، Eventهای مرتبط با مدل‌ها معمولاً در فایل مدل یا در Service Providerهای جداگانه تعریف می‌شوند. در Filament نیز می‌توانید رویدادها را در Resource مربوط به هر مدل قرار دهید.
Hookها عموماً در همان کلاسی تعریف می‌شوند که مربوط به یک فرم (Form) یا جدول (Table) خاص است. به این ترتیب، این قلاب‌ها همواره به یک بخش مشخص از پنل مدیریتی شما متصل خواهند بود.

مزایای استفاده از Events و Hooks در توسعه پیشرفته (Advanced) در Filament

سفارشی‌سازی قدرتمند:

شما می‌توانید هر نوع منطق تجاری (Business Logic) یا پردازش داده را در نقاط زمانی مختلف انجام دهید. این موضوع باعث می‌شود پنل مدیریت خود را کاملاً مطابق نیازمندی‌های پروژه طراحی کنید.

کپسوله‌سازی (Encapsulation) منطق:

وقتی می‌خواهید تغییرات کوچکی در رفتار یک بخش ایجاد کنید، نیازی به تغییر کل ساختار کد نخواهید داشت. با افزودن یا تغییر یک Event یا Hook می‌توانید رفتار را هدفمند و در همان سطح موردنظر اعمال کنید.

سهولت نگهداری:

اگر روال شما پیچیده باشد و شامل مراحل زیادی برای کنترل داده‌ها شود، بهتر است این منطق را در Eventها یا Hookها تقسیم‌بندی کنید. بدین ترتیب، هنگام نگهداری و ارتقای پروژه، به راحتی متوجه می‌شوید که کدام بخش چه کاری انجام می‌دهد.

مثال عملی از رویداد (Event)

فرض کنید در پروژه شما، پس از ایجاد یک سفارش جدید (Order)، لازم است یک اعلان ایمیلی به کاربر ارسال شود. می‌توانید از رویداد created در Resource مربوط به سفارش استفاده کنید:

class OrderResource extends Resource
{
    public static function boot()
    {
        parent::boot();

        static::created(function ($order) {
            // ارسال ایمیل به کاربر
            Mail::to($order->user->email)->send(new OrderCreatedMail($order));
        });
    }

    // سایر متدها و خصوصیات
}

در این مثال:

پس از ایجاد رکورد جدید در جدول سفارش‌ها، Event created فعال می‌شود.
یک ایمیل حاوی جزییات سفارش به کاربر ارسال می‌شود.

مثال عملی از قلاب (Hook)

گاهی می‌خواهید پیش از ایجاد یا به‌روزرسانی رکورد، فرمی را به شکل خاصی پیش‌پردازش کنید. برای مثال، اگر در پروژه شما فرمی وجود دارد که نیاز دارید قبل از نمایش به کاربر، فیلدهای آن بسته به نقش (Role) کاربر فعال یا غیرفعال شوند، می‌توانید از یک Hook در کلاس فرم استفاده کنید:

class OrderForm extends Form
{
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                // تعریف فیلدها
            ])
            ->mountUsing(function (Component $component) {
                // دسترسی به جزئیات کاربر جاری
                $user = auth()->user();

                // اگر کاربر نقش خاصی دارد، تغییراتی در فرم اعمال کنید
                if ($user->hasRole('manager')) {
                    // مثلا یک فیلد را فقط برای مدیران نمایش دهید
                    $component->schema([
                        TextInput::make('manager_notes')->label('یادداشت مدیر')
                    ]);
                }
            });
    }
}

در این مثال، Hook mountUsing هر بار که فرم OrderForm بارگذاری (Mount) می‌شود، اجرا خواهد شد و بسته به شرایط کاربر یا موقعیت دیگر، تغییرات لازم را در فرم اعمال می‌کند.

نکات کلیدی در استفاده از Events و Hooks

مستندسازی و نام‌گذاری دقیق:

برای جلوگیری از سردرگمی آینده، بهتر است نام Eventها و Hookها را متناسب با وظیفه آن‌ها انتخاب کرده و در جایی مانند ویکی پروژه یا مستندات داخلی ذکر کنید.

تفکیک مسئولیت‌ها:

سعی کنید منطق خود را در کلاس‌ها یا متدهای مجزا بنویسید و فقط در Event یا Hook آن کلاس‌ها را فراخوانی کنید. این کار باعث می‌شود از تکرار کد جلوگیری کرده و تست واحد (Unit Testing) را راحت‌تر انجام دهید.

هماهنگی با سایر قابلیت‌ها:

اگر از پکیج‌ها یا سرویس‌های دیگر استفاده می‌کنید (مانند پکیج‌های Auth یا سرویس‌های پرداخت)، اطمینان حاصل کنید که زمان و مکان اجرای Event یا Hook با آن سرویس‌ها همخوانی داشته باشد. برای مثال، اگر پس از پرداخت موفق می‌خواهید داده‌ای را در جدول سفارش‌ها ذخیره کنید، Hook خود را در مرحله مناسبی از چرخه حیات تعریف کنید.

به طور خلاصه، Events زمانی مفید هستند که می‌خواهید در سطح بالاتر و پس از رخداد یک واقعه اصلی (مثل ایجاد، به‌روزرسانی یا حذف رکورد) واکنش نشان دهید. اما Hooks برای زمانی مناسب‌اند که می‌خواهید در سطح جزئی‌تری از کامپوننت‌ها و قبل یا بعد از رخدادهای داخلی (مثل بارگذاری فرم یا ثبت مقادیر) مداخله داشته باشید. در هر دو روش، مزیت اصلی در این است که می‌توانید ضمن حفظ ساختار اصلی کد، فرآیند سفارشی‌سازی را با انعطاف بالا انجام دهید و به یکی از مهم‌ترین اهداف توسعه پیشرفته (Advanced) در Filament دست یابید.

چرا استفاده از Events و Hooks؟

یکی از ستون‌های اصلی در توسعه پیشرفته (Advanced) در Filament این است که بتوانید به شکل مؤثری منطق کسب‌وکار (Business Logic) خود را مدیریت کنید و هم‌زمان انعطاف‌پذیری بالایی در تغییر رفتار بخش‌های مختلف پنل مدیریت داشته باشید. در این راستا، Events و Hooks امکاناتی ایده‌آل برای سازمان‌دهی کدها و بهینه‌سازی فرآیند توسعه هستند. در ادامه، به دلایل مهم استفاده از این سازوکارها اشاره می‌کنیم:

جدا کردن منطق کسب‌وکار (Business Logic)

اغلب در پروژه‌های نرم‌افزاری، منطق مربوط به عملیات خاص (مثلاً زمان ایجاد یا به‌روزرسانی یک رکورد) در میان کدهای بخش‌های دیگر گم می‌شود یا به شکلی درهم‌ریخته نوشته می‌شود. با استفاده از Events و Hooks، می‌توانید این منطق را از سایر قسمت‌های کد جدا کنید و در نقاط دقیقی که رخدادها اتفاق می‌افتند، واکنش نشان دهید.

این روش باعث کپسوله‌سازی (Encapsulation) بهتر منطق کسب‌وکار می‌شود.
در نتیجه، توسعه‌دهندگان مختلف (یا حتی خود شما در آینده) به راحتی می‌توانند از طریق رویدادها به رفتار موردنظر پی ببرند و تغییرات لازم را اعمال کنند.

گسترش آسان

در توسعه پیشرفته (Advanced) در Filament ممکن است نیاز باشد در آینده قابلیت‌های جدیدی به پروژه اضافه کنید یا رفتارهای متفاوتی برای برخی کامپوننت‌ها تعریف نمایید. با طراحی ساختار کد حول محور Events و Hooks:

می‌توانید بدون تغییر در هسته اصلی Filament یا دستکاری عمیق کدهای قبلی، ویژگی‌های جدید را اضافه کنید.
سفارشی‌سازی هر بخش راحت‌تر می‌شود؛ به جای ویرایش مستقیم در کلاس‌های اصلی، صرفاً Event یا Hook دلخواه را به پروژه می‌افزایید و رفتار موردنیاز را تعریف می‌کنید.

افزایش قابلیت نگهداری

از مهم‌ترین اهداف در هر پروژه نرم‌افزاری، سهولت نگهداری در آینده است. وقتی منطق شما در فایل‌ها یا کلاس‌های مجزا و در قالب Event یا Hook تعریف می‌شود:

تغییر در یک بخش، ریسک آسیب‌رسانی به سایر قسمت‌های پروژه را به شدت کاهش می‌دهد.
می‌توانید فایل یا کلاس مربوط به رویداد یا قلاب موردنظر را به شکل ماژولار به‌روزرسانی کنید، بدون آن‌که درگیر پیچیدگی‌های اضافی شوید.
مستندسازی و عیب‌یابی سریع‌تر صورت می‌گیرد؛ چرا که به سرعت می‌دانید در کدام Event یا Hook باید دنبال مشکل بگردید.

مثال عملی

فرض کنید می‌خواهید پس از ایجاد یک کاربر جدید در پنل مدیریتی، یک پیام خوشامد به ایمیل او ارسال شود. در توسعه پیشرفته (Advanced) در Filament، می‌توانید از رویداد created در Resource مربوط به کاربر استفاده کنید:

class UserResource extends Resource
{
    public static function boot()
    {
        parent::boot();

        static::created(function ($user) {
            // ارسال ایمیل خوشامد
            Mail::to($user->email)->send(new WelcomeMail($user));
        });
    }
}

آنچه رخ می‌دهد: هنگامی که کاربر جدیدی از طریق رابط Filament ایجاد می‌شود، این رویداد فعال شده و متد Mail::to برای ارسال ایمیل خوشامد فراخوانی می‌گردد.
مزیت اصلی: به جای قرار دادن کد ارسال ایمیل در مکان‌های مختلف—مثل کنترلر یا مدل—تنها در یک نقطه مشخص (Event created) آن را مدیریت می‌کنید. این روش منجر به کدی تمیزتر و سازمان‌یافته‌تر می‌شود.
به طور کلی، تکیه بر Events و Hooks در بخش‌های حساس، علاوه بر اینکه کد شما را ساختارمند می‌کند، فرایند توسعه و نگهداری را نیز سرعت می‌بخشد و انعطاف موردنیاز برای توسعه پیشرفته (Advanced) در Filament را فراهم می‌آورد.

تست واحد (Unit Testing)

تست واحد در هر پروژه نرم‌افزاری، یکی از بنیان‌های اصلی تضمین کیفیت و پایداری کد محسوب می‌شود. در توسعه پیشرفته (Advanced) در Filament نیز تست واحد نقش مهمی ایفا می‌کند؛ چرا که با پیچیده‌تر شدن پروژه و افزایش تعداد کامپوننت‌ها، نیاز به اطمینان از صحت عملکرد بخش‌های مختلف بیشتر احساس می‌شود. در ادامه، به دلایل مهم استفاده از تست واحد می‌پردازیم.

چرا تست واحد؟

اطمینان از سلامت کد

یکی از مهم‌ترین دلایل اجرای تست واحد این است که می‌توانیم با خاطری آسوده در کد تغییر ایجاد کنیم یا قابلیت تازه‌ای بیفزاییم. اگر تست‌های واحد را به‌صورت جامع نوشته باشیم، در صورت بروز مشکل یا شکست یکی از سناریوها، پیام هشداردهنده‌ای دریافت می‌کنیم که نشان می‌دهد تغییرات اخیر، رفتار قبلی کد را مختل کرده است.

سازگاری در طول زمان

هنگامی که پروژه شما به‌صورت مداوم در حال توسعه و افزودن قابلیت‌های جدید است، ممکن است ناخواسته بخشی از کدهای موجود تحت تأثیر این تغییرات قرار گیرند. تست واحد مانع از آن می‌شود که یک تغییر کوچک در گوشه‌ای از پروژه، عملکرد ماژول‌های کلیدی را با اختلال مواجه سازد. به عبارتی، تست واحد به شما اطمینان می‌دهد که رفتار بخش‌های حیاتی پروژه در طول زمان ثابت و قابل اتکا باقی بماند.

مزایای تکمیلی تست واحد در توسعه پیشرفته (Advanced) در Filament

قابلیت اعتماد در فرآیند دیپلوی (Deployment)

وقتی پروژه خود را در محیط‌های مختلف (Local, Staging, Production) مستقر می‌کنید، وجود تست واحد به شما اطمینان می‌دهد که اختلافات نسخه لاراول، نسخه PHP یا پکیج‌های جانبی منجر به شکستن بخشی از کد نخواهد شد. پیش از دیپلوی، کافی است تست‌ها را اجرا کنید تا اگر مشکلی وجود داشت، همان جا متوجه شوید.

سهولت در اضافه کردن تست‌های جدید برای قابلیت‌های نو

در توسعه پیشرفته (Advanced) در Filament ممکن است بخش‌های جدیدی مانند کامپوننت‌های سفارشی، Hookها و رویدادهای (Events) اختصاصی به پروژه اضافه شوند. زمانی که ساختار تست واحد به خوبی پایه‌ریزی شده باشد، تعریف تست‌های جدید برای این بخش‌ها کاری آسان و در عین حال سریع خواهد بود. این امر باعث می‌شود کیفیت کل پروژه در سطح بالایی حفظ شود.

کاهش هزینه‌های نگهداری

در پروژه‌های طولانی‌مدت، یافتن خطاهای پنهان (Bugs) ممکن است مستلزم صرف وقت و هزینه زیادی باشد. هرچه تست‌های واحد جامع‌تری بنویسید، مشکلات را در همان مراحل ابتدایی توسعه پیدا می‌کنید. در نتیجه، هزینه‌های عیب‌یابی و رفع باگ کاهش می‌یابد و تیم توسعه می‌تواند روی بهبود قابلیت‌ها تمرکز کند.

تحقق رویکرد TDD (Test-Driven Development)

یکی از روش‌های مدرن توسعه نرم‌افزار، رویکرد TDD است که در آن قبل از پیاده‌سازی ویژگی جدید، ابتدا تست‌های آن ویژگی نوشته می‌شوند. با داشتن ساختار تست واحد قوی در Filament، می‌توانید این رویکرد را به آسانی پیاده‌سازی کنید. این کار نه تنها به بهبود کیفیت کد منجر می‌شود، بلکه به روشن‌تر شدن نیازمندی‌ها و انتظارات از ابتدا نیز کمک می‌کند.

نکات تکمیلی و پیشنهادات عملی

تفکیک تست‌های Unit از Integration

گاهی اوقات تست‌های شما تنها عملکرد یک ماژول یا متد را به شکل ایزوله بررسی می‌کنند (Unit Test) و گاهی نیاز به بررسی تعامل بین چندین ماژول یا سرویس دارید (Integration Test). توصیه می‌شود ساختار پوشه‌بندی پروژه تست‌ها را به گونه‌ای تعریف کنید که این دو نوع تست به وضوح جدا شوند.

استفاده از ابزارهای Mock و Stub

زمانی که می‌خواهید وابستگی‌های خارجی (مثلاً فراخوانی یک API یا سرویس پیامک) را تست کنید، توصیه می‌شود از Mock کردن این سرویس‌ها در تست واحد استفاده کنید. به این ترتیب، تست‌های شما سریع‌تر اجرا شده و کمتر مستعد خطاهای شبکه یا مشکلات بیرونی خواهند بود.

پوشش کامل سناریوهای بحرانی

در توسعه پیشرفته (Advanced) در Filament ممکن است بخش‌هایی حساس مثل فرایند لاگین ادمین، ثبت سفارش یا پرداخت آنلاین وجود داشته باشد. برای این بخش‌ها تست‌های متنوع‌تری بنویسید تا اطمینان حاصل کنید تمامی سناریوهای ممکن از جمله سناریوهای خطا پوشش داده شده‌اند.

افزایش تدریجی تست‌پذیری (Testability) کد

اگر در ابتدای پروژه تست‌نویسی را شروع نکرده‌اید، ممکن است بخشی از کد شما تست‌پذیری پایینی داشته باشد. سعی کنید در هر مرحله از توسعه، با استفاده از اصول طراحی شی‌گرایی (SOLID) و وابستگی معکوس (Dependency Injection)، کد را اصلاح و تست‌پذیری آن را افزایش دهید.

روش پیاده‌سازی تست واحد در Filament

در چارچوب توسعه پیشرفته (Advanced) در Filament، تست واحد از مهم‌ترین عوامل تضمین کیفیت و پایداری کد محسوب می‌شود. از آنجا که Filament بر بستر لاراول توسعه یافته، می‌توانید به سادگی از تمام ابزارها و قابلیت‌های تست لاراول برای تست واحد بهره ببرید. در ادامه، روش پیاده‌سازی تست واحد در Filament و نکات مهم آن را بررسی خواهیم کرد.

۱. استفاده از Laravel Test

لاراول به صورت پیش‌فرض ابزار تست PHPUnit را در خود دارد که برای اجرای تست‌های واحد مناسب است. علاوه بر آن، می‌توانید از کتابخانه‌های اضافی نظیر:

laravel/browser-kit-testing: برای شبیه‌سازی تعامل کاربر با برنامه از طریق مرورگر (بر پایه‌ی ابزار BrowserKit).
laravel/dusk: برای انجام تست‌های End-to-End (E2E) با استفاده از شبیه‌سازی مرورگر واقعی.
با توجه به اینکه Filament هم مبتنی بر لاراول است، تمام ساختار تست‌نویسی مشابه پروژه‌های لاراول خواهد بود. کافی است در پروژه خود، تست‌های واحد را در پوشه tests/Unit و تست‌های یکپارچه (Integration) یا عملکردی (Functional) را در پوشه tests/Feature قرار دهید. سپس با دستور زیر می‌توانید تست‌ها را اجرا کنید:

php artisan test

یا مستقیماً با PHPUnit:

vendor/bin/phpunit

۲. آماده‌سازی محیط تست

تنظیمات فایل phpunit.xml:

در اکثر پروژه‌های لاراول، فایل phpunit.xml در ریشه‌ی پروژه قرار دارد و شامل تنظیماتی مانند مسیر پوشه تست‌ها، پوشش کد (Coverage) و غیره است. اطمینان حاصل کنید که این فایل متناسب با ساختار پروژه شما و نیازهای توسعه پیشرفته (Advanced) در Filament پیکربندی شده باشد.

تراکنش‌های دیتابیس و ریست (Refresh) دیتابیس:

برای جلوگیری از باقی ماندن داده‌های تست در دیتابیس اصلی، می‌توانید از تریت (Trait) RefreshDatabase در لاراول استفاده کنید. این تریت باعث می‌شود دیتابیس تست شما در هر تست، ریست و مجدداً مقداردهی اولیه شود.
اگر مایل باشید از Memory Database (دیتابیس در حافظه) استفاده کنید، می‌توانید در فایل phpunit.xml یا در فایل .env.testing تنظیمات مربوط به SQLite in-memory را انجام دهید. این روش عموماً سرعت تست‌ها را افزایش می‌دهد.

تعریف Factories:

در صورت لزوم برای ساخت رکوردهای تست، از Factoryهای لاراول استفاده کنید. به عنوان مثال، اگر می‌خواهید کاربر تستی ایجاد کنید، می‌توانید User::factory()->create() را فراخوانی کنید تا یک کاربر تصادفی بر اساس مشخصات از پیش تعیین‌شده تولید شود.

تنظیم Auth در تست‌ها:

اگر فیلامنت شما از احراز هویت (Auth) خاصی استفاده می‌کند یا با نقش‌های کاربری (Roles) سروکار دارد، لازم است در تست‌های مربوطه از متد actingAs($user) لاراول استفاده کنید تا شبیه‌سازی لاگین کاربر انجام شود. برای نمونه:

$this->actingAs(User::factory()->create());

۳. مثال ساخت تست فرم ایجاد کاربر در Filament

به عنوان نمونه، برای بررسی عملکرد یک فرم در Filament می‌توانید از کد زیر استفاده کنید:

public function testCreateUserForm()
{
    // شبیه‌سازی درخواست به فرم ایجاد کاربر
    // توجه: در صورت نیاز به شبیه‌سازی ورود به سیستم (Auth)، قبل از ارسال درخواست، از actingAs() استفاده کنید.
    
    $response = $this->post(route('filament.resources.users.create'), [
        'name' => 'Test User',
        'email' => 'test@example.com',
        'password' => '12345678'
    ]);
    
    // بررسی اینکه کاربر در دیتابیس ثبت شده است
    $this->assertDatabaseHas('users', [
        'email' => 'test@example.com',
    ]);

    // بررسی بازگشت پاسخ موفق
    $response->assertRedirect(route('filament.resources.users.index'));
}

شبیه‌سازی درخواست: در این تست، متد post() را فراخوانی می‌کنیم تا عملکرد فرم ایجاد کاربر را در Filament ارزیابی کنیم.
کنترل ثبت داده در دیتابیس: با استفاده از متد assertDatabaseHas اطمینان می‌یابیم که رکورد کاربر جدید در دیتابیس واقعاً ذخیره شده است.
بررسی نوع پاسخ: در انتها، با استفاده از assertRedirect بررسی می‌کنیم که پس از ایجاد موفق کاربر، کاربر (یا ادمین) به مسیر موردنظر (users.index) هدایت می‌شود.

۴. نکات تکمیلی برای تست واحد در Filament

تست کامپوننت‌های پیچیده:

اگر در پروژه خود کامپوننت‌های سفارشی یا رفتارهای پیچیده‌ای (نظیر رویدادها و قلاب‌ها) تعریف کرده‌اید، توصیه می‌شود تست‌های ویژه‌ای برای آن‌ها بنویسید. این تست‌ها، تا حد امکان باید رفتارهای گوناگون را پوشش دهند تا در آینده، هر تغییری موجب شکست کل سیستم نشود.

تست سیاست‌های دسترسی (Policies):

بسیاری از پروژه‌های فیلامنت از سیاست‌های دسترسی لاراول (Laravel Policies) برای کنترل سطوح دسترسی مختلف (مثل کاربر عادی یا مدیر) استفاده می‌کنند. اطمینان پیدا کنید که این سیاست‌ها در تست پوشش داده می‌شوند. مثلاً می‌توانید شرایطی را بررسی کنید که در آن کاربر عادی اجازه ایجاد رکورد جدید ندارد و باید خطای 403 دریافت کند.

تست اعتبارسنجی (Validation):

فرم‌های Filament معمولاً همراه با قوانین اعتبارسنجی (Validation Rules) تعریف می‌شوند. با ایجاد تست‌های منفی (Negative Test) می‌توانید اطمینان پیدا کنید که فرم در صورت ورودی‌های نامعتبر، پیام خطا یا رفتار صحیح را نشان می‌دهد:

public function testCreateUserFormWithInvalidData()
{
    $response = $this->post(route('filament.resources.users.create'), [
        'name' => '',
        'email' => 'not-a-valid-email',
        'password' => ''
    ]);

    $response->assertSessionHasErrors(['name', 'email', 'password']);
}

استفاده از Test Classes اختصاصی:

برای حفظ نظم، می‌توانید برای هر Resource یا ماژول در Filament، فایل تست جداگانه‌ای بسازید؛ مثلاً UserResourceTest, OrderResourceTest و غیره. این امر به تفکیک وظایف و نگهداری بهتر کمک می‌کند.

استفاده از متدهای کمکی (Helper Methods):

اگر چندین تست مشابه دارید که حاوی منطق تکراری هستند (مثلاً ایجاد پیش‌شرط‌ها یا تنظیم کاربر تستی خاص)، می‌توانید این منطق را در متدهای کمکی قرار داده و در تست‌های مختلف فراخوانی کنید. این کار باعث تمیزتر شدن کدها و کاهش تکرار می‌شود.

یکپارچه‌سازی با سرویس‌ها

در توسعه پیشرفته (Advanced) در Filament اغلب نیاز دارید تا پروژه خود را با سرویس‌های خارجی (Third-Party Services) یا دیگر میکروسرویس‌های داخلی سازمان یکپارچه کنید.

دلایل اصلی یکپارچه‌سازی با سرویس‌ها

در توسعه پیشرفته (Advanced) در Filament، یکپارچه‌سازی با سرویس‌های خارجی نقش بسیار مهمی در ارتقاء عملکرد و افزایش انعطاف‌پذیری پروژه‌ها دارد. این یکپارچه‌سازی‌ها نه تنها امکانات جدیدی را به پروژه اضافه می‌کنند، بلکه باعث بهبود فرآیندهای داخلی و افزایش بهره‌وری تیم توسعه می‌شوند. در ادامه به تفصیل به دو دلیل اصلی یکپارچه‌سازی با سرویس‌ها می‌پردازیم:

۱. گسترش امکانات پروژه

یکپارچه‌سازی با سرویس‌های خارجی می‌تواند قابلیت‌های پروژه‌ی شما را به طور قابل توجهی افزایش دهد. این سرویس‌ها معمولاً تخصصی و بهینه‌سازی شده‌اند و استفاده از آن‌ها به جای توسعه مجدد امکانات مشابه می‌تواند زمان و منابع شما را صرفه‌جویی کند. برخی از جنبه‌های گسترش امکانات پروژه شامل موارد زیر می‌شوند:

درگاه‌های پرداخت: با اتصال به سرویس‌های پرداخت مانند Stripe، PayPal، یا زرین‌پال، می‌توانید به راحتی امکان پرداخت آنلاین را به کاربران خود ارائه دهید. این امر نه تنها تجربه کاربری را بهبود می‌بخشد بلکه اطمینان از امنیت تراکنش‌ها را نیز فراهم می‌کند.

مثال عملی: فرض کنید می‌خواهید یک فروشگاه آنلاین با Filament ایجاد کنید. با یکپارچه‌سازی با Stripe، کاربران می‌توانند به سادگی و با اطمینان خرید خود را انجام دهند و شما می‌توانید فرآیند مدیریت سفارشات و پرداخت‌ها را به طور خودکار پیگیری کنید.

سرویس‌های پیامکی: استفاده از سرویس‌های پیامکی مانند Twilio یا Kavenegar به شما امکان می‌دهد تا به صورت خودکار پیام‌های تأییدیه، اعلان‌ها و یادآوری‌ها را به کاربران ارسال کنید. این قابلیت به بهبود ارتباط با کاربران و افزایش تعامل آن‌ها با سیستم کمک می‌کند.

مثال عملی: در یک سامانه مدیریت پروژه، می‌توانید با ارسال پیامک‌های یادآوری به اعضا، اطمینان حاصل کنید که وظایف خود را به موقع انجام می‌دهند.

سیستم‌های CRM: یکپارچه‌سازی با سیستم‌های مدیریت ارتباط با مشتری (CRM) مانند Salesforce یا HubSpot به شما این امکان را می‌دهد که اطلاعات مشتریان را به صورت متمرکز مدیریت کرده و فرآیندهای فروش و بازاریابی را بهینه کنید.

مثال عملی: در یک پروژه فروشگاهی، با اتصال Filament به Salesforce، می‌توانید اطلاعات مشتریان، تاریخچه خریدها و تعاملات آن‌ها را به راحتی مدیریت و تحلیل کنید.

سرویس‌های ابری: استفاده از سرویس‌های ابری مانند AWS، Google Cloud یا Azure می‌تواند امکانات ذخیره‌سازی، محاسباتی و امنیتی پروژه شما را بهبود بخشد. این سرویس‌ها امکانات مقیاس‌پذیری و دسترسی بالا را فراهم می‌کنند که برای پروژه‌های بزرگ و پویا بسیار حیاتی است.

مثال عملی: با استفاده از AWS S3 برای ذخیره‌سازی فایل‌ها، می‌توانید به راحتی فضای ذخیره‌سازی مقیاس‌پذیر و امنی را به پروژه خود اضافه کنید.

۲. بهبود گردش کار (Workflow)

یکپارچه‌سازی با سرویس‌های خارجی می‌تواند فرآیندهای داخلی پروژه را ساده‌تر و کارآمدتر کند. این امر منجر به بهبود جریان کاری، کاهش خطاها و افزایش سرعت توسعه می‌شود. برخی از جنبه‌های بهبود گردش کار شامل موارد زیر هستند:

اتوماتیک‌سازی فرآیندها: با اتصال Filament به سرویس‌هایی مانند Zapier یا Integromat، می‌توانید بسیاری از فرآیندهای تکراری و زمان‌بر را اتوماتیک کنید. این امر باعث می‌شود تا تیم توسعه و دیگر اعضای تیم بتوانند بر روی وظایف مهم‌تر تمرکز کنند.

مثال عملی: هر بار که یک سفارش جدید در سیستم ثبت می‌شود، می‌توانید با استفاده از Zapier به طور خودکار یک تسک جدید در Trello ایجاد کنید و اعضای تیم را مطلع سازید.

مانیتورینگ و لاگ‌گیری پیشرفته: اتصال به سرویس‌های مانیتورینگ مانند Sentry یا New Relic به شما این امکان را می‌دهد که به صورت لحظه‌ای از وضعیت سیستم مطلع شوید و به سرعت به مشکلات واکنش نشان دهید.

مثال عملی: با یکپارچه‌سازی Filament با Sentry، می‌توانید خطاها و استثناهای سیستم را به صورت خودکار گزارش کنید و از آن‌ها باخبر شوید تا به سرعت اقدامات لازم را انجام دهید.

مدیریت پروژه و همکاری تیمی: استفاده از ابزارهای مدیریت پروژه مانند Jira یا Asana در کنار Filament به شما کمک می‌کند تا وظایف، مهلت‌ها و پیشرفت پروژه را به صورت متمرکز مدیریت کنید.

مثال عملی: با اتصال Filament به Jira، می‌توانید هر تغییر در پنل مدیریت را به طور خودکار به عنوان یک تسک جدید در Jira ثبت کنید و فرآیند پیگیری آن را تسهیل کنید.

بهبود ارتباطات داخلی: یکپارچه‌سازی با ابزارهای ارتباطی مانند Slack یا Microsoft Teams می‌تواند ارتباطات داخلی تیم را بهبود بخشد و اطلاعات مهم را به سرعت به اشتراک بگذارد.

مثال عملی: با اتصال Filament به Slack، می‌توانید هر بار که یک کاربر جدید ثبت می‌شود، یک پیام اطلاع‌رسانی در کانال مربوطه ارسال کنید تا تیم مربوطه از این تغییر باخبر شود.

مثال یکپارچه‌سازی با سرویس پیامکی

در توسعه پیشرفته (Advanced) در Filament، یکپارچه‌سازی با سرویس‌های پیامکی می‌تواند ارتباط مؤثرتری با کاربران برقرار کرده و تجربه کاربری بهتری ارائه دهد. به عنوان مثال، ارسال پیام‌های تأییدیه پس از ثبت سفارش، یادآوری‌ها، یا اعلان‌های خاص به کاربران از طریق پیامک می‌تواند ارزش افزوده قابل توجهی به پروژه شما ببخشد. در این بخش، به صورت جامع و گام‌به‌گام به یکپارچه‌سازی Filament با یک سرویس پیامکی مانند Kavenegar می‌پردازیم.

مراحل یکپارچه‌سازی با سرویس پیامکی

۱. انتخاب سرویس پیامکی و نصب پکیج مربوطه

ابتدا باید یک سرویس پیامکی معتبر انتخاب کنید. در این مثال از Kavenegar استفاده خواهیم کرد، اما می‌توانید از سرویس‌های دیگری مانند Twilio نیز بهره ببرید.

گام‌های انجام‌شده:

ایجاد حساب کاربری در Kavenegar: به وب‌سایت Kavenegar مراجعه کرده و یک حساب کاربری ایجاد کنید.

دریافت کلید API: پس از ثبت‌نام و ورود به حساب کاربری، به بخش API Keys رفته و یک کلید API جدید تولید کنید.

نصب پکیج Kavenegar در پروژه لاراول: با استفاده از Composer پکیج Kavenegar را به پروژه خود اضافه کنید.

composer require kavenegar/php

۲. پیکربندی کلید API در فایل .env

برای حفظ امنیت کلید API، باید آن را در فایل .env پروژه لاراول خود قرار دهید. این فایل به شما امکان می‌دهد تا تنظیمات حساس را از کد منبع جدا نگه دارید.

گام‌های انجام‌شده:

افزودن کلید API به فایل .env:

KAVENEGAR_API_KEY=your_api_key_here
SENDER_NUMBER=your_sender_number_here

KAVENEGAR_API_KEY: کلید API دریافتی از سرویس Kavenegar.
SENDER_NUMBER: شماره فرستنده‌ای که از سرویس Kavenegar دریافت کرده‌اید.
ایجاد فایل پیکربندی برای Kavenegar (اختیاری): می‌توانید یک فایل پیکربندی جداگانه برای تنظیمات Kavenegar ایجاد کنید تا دسترسی و مدیریت آن آسان‌تر شود.

ایجاد فایل config/kavenegar.php:

<?php

return [
    'api_key' => env('KAVENEGAR_API_KEY'),
    'sender' => env('SENDER_NUMBER'),
];

۳. ایجاد متد ارسال پیامک در Resource سفارش (OrderResource)

اکنون که سرویس پیامکی پیکربندی شده است، باید در Resource مربوط به سفارش‌ها، پس از ذخیره سفارش جدید، متد ارسال پیامک فراخوانی شود.

گام‌های انجام‌شده:

ویرایش کلاس OrderResource:

<?php

namespace App\Filament\Resources;

use App\Models\Order;
use Filament\Resources\Resource;
use Filament\Resources\Form;
use Filament\Resources\Table;
use Kavenegar\KavenegarApi;
use Illuminate\Support\Facades\Mail;

class OrderResource extends Resource
{
    protected static ?string $model = Order::class;

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                // تعریف فیلدهای فرم
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                // تعریف ستون‌های جدول
            ]);
    }

    public static function boot()
    {
        parent::boot();

        static::created(function ($order) {
            // ارسال پیامک به کاربر
            $api = new KavenegarApi(config('kavenegar.api_key'));
            try {
                $api->Send(config('kavenegar.sender'), $order->user->phone, "سفارش شما با موفقیت ثبت شد. شماره سفارش: {$order->id}");
            } catch (\Kavenegar\Exceptions\ApiException $e) {
                // مدیریت خطاهای API
                \Log::error("Kavenegar API Error: " . $e->getMessage());
            } catch (\Kavenegar\Exceptions\HttpException $e) {
                // مدیریت خطاهای HTTP
                \Log::error("Kavenegar HTTP Error: " . $e->getMessage());
            }
        });
    }
}

توضیحات:

وارد کردن کلاس‌های مورد نیاز: برای استفاده از Kavenegar API، باید کلاس‌های مربوطه را وارد کنید.
تعریف متد boot: این متد زمانی فراخوانی می‌شود که Resource بارگذاری می‌شود. با استفاده از static::created، یک رویداد تعریف می‌کنیم که پس از ایجاد یک رکورد جدید در مدل Order اجرا می‌شود.
ارسال پیامک: با استفاده از API Kavenegar، پیامک مورد نظر به شماره کاربر ارسال می‌شود.
مدیریت خطاها: برای جلوگیری از بروز خطاهای ناخواسته در پروژه، خطاهای احتمالی در هنگام ارسال پیامک را با استفاده از بلاک‌های try-catch مدیریت می‌کنیم و آنها را در لاگ‌ها ثبت می‌کنیم.

۴. آزمایش یکپارچه‌سازی

پس از انجام مراحل بالا، باید یکپارچه‌سازی را آزمایش کنید تا از عملکرد صحیح آن اطمینان حاصل کنید.

گام‌های انجام‌شده:

ایجاد یک سفارش جدید از طریق پنل مدیریت Filament:

به بخش سفارش‌ها (Orders) در پنل مدیریت بروید و یک سفارش جدید ایجاد کنید.
مطمئن شوید که اطلاعات کاربر شامل شماره تلفن صحیح وارد شده است.
بررسی دریافت پیامک:

پس از ایجاد سفارش، بررسی کنید که پیامک مورد نظر به شماره تلفن کاربر ارسال شده است.
در صورت عدم دریافت پیامک، لاگ‌های سیستم را بررسی کنید تا علت احتمالی خطا را بیابید.
مدیریت خطاها:

برای اطمینان از اینکه سیستم در صورت بروز خطاها به درستی عمل می‌کند، می‌توانید موقتا کلید API را اشتباه وارد کرده و سپس تلاش کنید یک سفارش جدید ایجاد کنید تا ببینید آیا خطاها به درستی لاگ می‌شوند یا خیر.

۵. نکات تکمیلی برای یکپارچه‌سازی با سرویس پیامکی

اعتبارسنجی شماره تلفن‌ها:

قبل از ارسال پیامک، اطمینان حاصل کنید که شماره تلفن کاربران معتبر و در فرمت صحیح ذخیره شده‌اند. می‌توانید از کتابخانه‌هایی مانند libphonenumber برای اعتبارسنجی شماره‌ها استفاده کنید.

استفاده از صف‌ها (Queues):

ارسال پیامک ممکن است زمان‌بر باشد و می‌تواند باعث کندی فرآیند ایجاد سفارش شود. برای بهبود عملکرد، پیشنهاد می‌شود از صف‌های لاراول استفاده کنید تا ارسال پیامک‌ها به صورت پس‌زمینه انجام شوند.
مثال:

ایجاد Job برای ارسال پیامک:

php artisan make:job SendOrderConfirmationSms

ویرایش کلاس Job:

<?php

namespace App\Jobs;

use App\Models\Order;
use Kavenegar\KavenegarApi;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class SendOrderConfirmationSms implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $order;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $api = new KavenegarApi(config('kavenegar.api_key'));
        try {
            $api->Send(config('kavenegar.sender'), $this->order->user->phone, "سفارش شما با موفقیت ثبت شد. شماره سفارش: {$this->order->id}");
        } catch (\Kavenegar\Exceptions\ApiException $e) {
            \Log::error("Kavenegar API Error: " . $e->getMessage());
        } catch (\Kavenegar\Exceptions\HttpException $e) {
            \Log::error("Kavenegar HTTP Error: " . $e->getMessage());
        }
    }
}

ویرایش OrderResource برای استفاده از Job:

use App\Jobs\SendOrderConfirmationSms;

class OrderResource extends Resource
{
    // ...

    public static function boot()
    {
        parent::boot();

        static::created(function ($order) {
            // ارسال پیامک به صورت صف
            SendOrderConfirmationSms::dispatch($order);
        });
    }

    // ...
}

تنظیمات صف‌ها:

در فایل .env، نوع اتصال صف‌ها را تنظیم کنید (مثلاً database):

QUEUE_CONNECTION=database

اجرای مایگریشن برای جدول صف‌ها:

php artisan queue:table
php artisan migrate

اجرای Worker صف‌ها:

php artisan queue:work

استفاده از صف‌ها باعث می‌شود که ارسال پیامک‌ها بدون تأثیرگذاری بر عملکرد اصلی ایجاد سفارش انجام شوند و تجربه کاربری بهتری ارائه شود.

مدیریت تعداد پیامک‌های ارسالی:

برخی سرویس‌های پیامکی محدودیت‌هایی در تعداد پیامک‌های ارسالی در یک بازه زمانی دارند. برای جلوگیری از ارسال بیش از حد پیامک‌ها، می‌توانید از مکانیزم‌هایی مانند Rate Limiting یا Caching استفاده کنید.
تنظیمات چندزبانه:

اگر پروژه شما از چندین زبان پشتیبانی می‌کند، می‌توانید متن پیامک‌ها را به صورت داینامیک و بر اساس زبان کاربر تنظیم کنید. برای این کار از فایل‌های ترجمه لاراول استفاده کنید.
مثال:

$message = __('messages.order_confirmation', ['order_id' => $order->id]);
$api->Send(config('kavenegar.sender'), $order->user->phone, $message);

در فایل‌های ترجمه resources/lang/{locale}/messages.php:

<?php

return [
    'order_confirmation' => 'سفارش شما با موفقیت ثبت شد. شماره سفارش: :order_id',
];

پیگیری وضعیت پیامک‌ها:

برخی سرویس‌های پیامکی امکان پیگیری وضعیت ارسال پیامک‌ها را فراهم می‌کنند. می‌توانید با استفاده از این امکانات، وضعیت هر پیامک را ثبت و مدیریت کنید.
مثال:

$result = $api->Send(config('kavenegar.sender'), $order->user->phone, $message);
if ($result[0]->status == 200) {
    // پیامک با موفقیت ارسال شد
    $order->update(['sms_sent' => true]);
} else {
    // مدیریت خطا
    \Log::error("Failed to send SMS: " . $result[0]->message);
}

مزایای اصلی یکپارچه‌سازی با سرویس‌ها در توسعه پیشرفته (Advanced) در Filament

افزایش بهره‌وری و کاهش زمان توسعه: با استفاده از سرویس‌های آماده، نیازی به توسعه مجدد امکانات مشابه نیست و می‌توانید بر روی ویژگی‌های منحصر به فرد پروژه خود تمرکز کنید.

بهبود کیفیت و اطمینان از عملکرد: سرویس‌های معتبر معمولاً به صورت مداوم به‌روزرسانی و بهینه‌سازی می‌شوند، بنابراین با استفاده از آن‌ها می‌توانید از کیفیت و پایداری بالاتری برخوردار شوید.

مقیاس‌پذیری آسان‌تر: سرویس‌های ابری و مبتنی بر API به شما امکان می‌دهند تا به راحتی با افزایش تعداد کاربران و نیازهای پروژه، منابع خود را افزایش دهید.

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

بهبود تجربه کاربری: با اضافه کردن امکانات جدید و بهبود فرآیندهای داخلی، تجربه کاربری نهایی پروژه شما بهبود می‌یابد که این امر می‌تواند منجر به افزایش رضایت و وفاداری کاربران شود.

یکپارچه‌سازی با سرویس‌های خارجی یکی از اصول کلیدی در توسعه پیشرفته (Advanced) در Filament است که به شما امکان می‌دهد پروژه‌های خود را با امکانات بیشتر، عملکرد بهتر و انعطاف‌پذیری بالاتر توسعه دهید. با بهره‌گیری از روش‌های متداول یکپارچه‌سازی مانند API-based Integration، استفاده از SDKها و پکیج‌های آماده، و بهره‌گیری از وب‌هوک‌ها، می‌توانید به راحتی سرویس‌های مختلف را به پروژه خود اضافه کنید و از مزایای آن‌ها بهره‌مند شوید. این اقدامات نه تنها فرآیند توسعه را تسهیل می‌کنند، بلکه به بهبود کیفیت و پایداری پروژه نیز کمک شایانی می‌کنند.

نتیجه‌گیری

در این مقاله به بررسی جامع و کامل توسعه پیشرفته (Advanced) در Filament پرداختیم و مفاهیم کلیدی آن را از سطح مبتدی تا پیشرفته مورد بررسی قرار دادیم. با استفاده از Events و Hooks، توانستیم منطق کسب‌وکار را به شکلی مدولار و سازمان‌یافته مدیریت کنیم که این امر انعطاف‌پذیری و قابلیت نگهداری کد را به طرز چشمگیری افزایش می‌دهد.

همچنین، اهمیت تست واحد (Unit Testing) را در توسعه پیشرفته (Advanced) در Filament برجسته کردیم. با نوشتن تست‌های جامع، اطمینان حاصل می‌کنیم که تغییرات و افزودن قابلیت‌های جدید بدون ایجاد اختلال در عملکرد پروژه انجام می‌شود. این امر به حفظ کیفیت و پایداری کدها کمک شایانی می‌کند.

در بخش یکپارچه‌سازی با سرویس‌ها، نشان دادیم که چگونه اتصال به سرویس‌های خارجی مانند درگاه‌های پرداخت، سرویس‌های پیامکی و سیستم‌های CRM می‌تواند امکانات پروژه را گسترش داده و گردش کار را بهبود بخشد. مثال عملی یکپارچه‌سازی با سرویس پیامکی Kavenegar، فرآیند ارسال پیامک‌های خودکار پس از ثبت سفارش را به طور کامل توضیح داد که این امر ارتباط مؤثرتری با کاربران ایجاد می‌کند.

توسعه پیشرفته (Advanced) در Filament ابزارهایی قدرتمند برای ساختن پروژه‌های پیچیده و مقیاس‌پذیر فراهم می‌کند. با بهره‌گیری از رویدادها، قلاب‌ها، تست‌های واحد و یکپارچه‌سازی‌های متنوع، می‌توانید پروژه‌هایی با کیفیت بالا، عملکرد بهینه و قابلیت نگهداری آسان ایجاد کنید.

آموزش توسعه پیشرفته (Advanced) در Filament

دیدگاه های شما

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *