فصل ۶- کامپوننت‌ های فرانت‌ اند

کامپوننت‌ های فرانت‌ اند

لاراول عمدتاً به عنوان یک فریم‌ورک PHP شناخته می‌شود، اما در واقع یک فریم‌ورک فول‌استک است، به این معنا که مجموعه‌ای از کامپوننت‌ها و قراردادها برای تولید کدهای فرانت‌اند دارد. برخی از این موارد، مانند صفحه‌بندی (pagination) و Message Bagها، هلپرهایی در PHP هستند که برای فرانت‌اند طراحی شده‌اند؛ اما لاراول همچنین یک سیستم ساخت فرانت‌اند مبتنی بر Vite، چند قرارداد در مورد فایل‌های غیر PHP و چند Starter Kit آماده نیز ارائه می‌دهد.

کیت‌ های آغازین (Starter Kits) لاراول

لاراول به‌صورت پیش‌فرض یک سیستم کامل ساخت (build system) ارائه می‌دهد که به‌زودی بررسی خواهیم کرد، اما همچنین شامل کیت‌های شروع (starter kits) قابل نصب آسانی است که قالب‌ها، احراز هویت (auth)، استایل‌ها، جاوااسکریپت و فرآیندهای ثبت‌نام و مدیریت کاربر را در بر می‌گیرند.دو کیت شروع لاراول Breeze و Jetstream نام دارند.Breeze گزینه ساده‌تر است؛ این کیت تمام روت‌ها، ویوها و استایل‌های مورد نیاز برای سیستم احراز هویت لاراول را فراهم می‌کند، از جمله ثبت‌نام، ورود، بازیابی رمز عبور، تایید رمز عبور، تأیید ایمیل و صفحه‌ای برای ویرایش پروفایل. Breeze از استایل‌های Tailwind استفاده می‌کند و می‌توانید بین قالب‌های Blade...

برای دیدن ادامه محتوا وارد شوید

Laravel Breeze

Laravel Breeze یک کیت آغازین ساده است که همه چیزهایی را که برای یک اپلیکیشن معمولی لاراول نیاز دارید فراهم می‌کند تا کاربران بتوانند ثبت‌نام، ورود و مدیریت پروفایل خود را انجام دهند.

نصب Breeze

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

laravel new myProject
cd myProject
composer require laravel/breeze --dev

پس از اضافه کردن Breeze به پروژه، نصب‌کننده آن را اجرا می‌کنید:

php artisan breeze:install

پس از اجرای نصب، از شما خواسته می‌شود که یک استک انتخاب کنید: Blade، Inertia با React یا Inertia با Vue، یا API که برای فرانت‌اندهای غیر Inertia مثل Next.js طراحی شده است.
پس از نصب Breeze، حتماً مایگریشن‌ها را اجرا و فرانت‌اند را build کنید:

php artisan migrate
npm install
npm run dev

 

Breeze شامل چه چیزهایی است؟

Breeze به‌صورت خودکار مسیرهایی را برای ثبت‌نام، ورود، خروج، ریست رمز عبور، تأیید ایمیل، و تأیید رمز عبور ثبت می‌کند. این مسیرها در فایل جدید routes/auth.php قرار دارند.

نسخه‌های غیر API از Breeze همچنین مسیرهایی برای داشبورد و صفحه "ویرایش پروفایل" ثبت می‌کنند که مستقیماً به routes/web.php اضافه می‌شوند.

همچنین، کنترلرهایی برای صفحه ویرایش پروفایل، تأیید ایمیل، ریست رمز عبور و سایر امکانات مربوط به احراز هویت نیز منتشر می‌شوند. همچنین، بسته‌های Tailwind، Alpine.js، و PostCSS نیز (برای Tailwind) به پروژه افزوده می‌شوند.

Breeze Blade

نسخه‌ی Blade از Breeze شامل مجموعه‌ای از قالب‌های Blade برای تمام ویژگی‌های ذکرشده در بالا است که می‌توانید آن‌ها را در مسیرهای resources/views/auth، resources/views/components، resources/views/profile و چند مسیر پراکنده‌ی دیگر پیدا کنید.

Breeze Inertia

هر دو استک Inertia ابزارهایی مانند Inertia، Ziggy (ابزاری برای ساخت URL برای مسیرهای لاراول در جاوااسکریپت)، کامپوننت فرم‌های Tailwind، و پکیج‌های جاوااسکریپت موردنیاز برای اجرای فریم‌ورک‌های فرانت‌اند مربوطه را اضافه می‌کنند.
همچنین، یک قالب ابتدایی Blade که Inertia را لود می‌کند و مجموعه‌ای از کامپوننت‌های React/Vue برای صفحات منتشرشده در مسیر resources/js منتشر می‌شود.

Breeze API

استک API از Breeze کدها و پکیج‌های بسیار کمتری نسبت به سایر استک‌ها نصب می‌کند، اما فایل‌های بوت‌استرپ پیش‌فرض که همراه اپ‌های جدید لاراول هستند را حذف می‌کند. این استک برای ساخت اپ‌هایی طراحی شده که فقط به عنوان بک‌اند API برای اپ‌های جداگانه مثل Next.js استفاده می‌شوند؛ بنابراین فایل‌های package.json، تمام فایل‌های جاوااسکریپت و CSS و همه قالب‌های فرانت‌اند حذف می‌شوند.

Laravel Jetstream

Jetstream بر پایه‌ی قابلیت‌های Breeze ساخته شده و ابزارهای بیشتری برای شروع یک اپلیکیشن جدید فراهم می‌کند؛ با این حال، تنظیمات آن پیچیده‌تر است و گزینه‌های پیکربندی کمتری دارد، بنابراین باید مطمئن باشید که به آن نیاز دارید پیش از آن‌که Jetstream را به‌جای Breeze انتخاب کنید. Jetstream مانند Breeze، روت‌ها، کنترلرها، ویوها و فایل‌های پیکربندی را منتشر می‌کند. مشابه Breeze، از Tailwind استفاده می‌کند و در قالب تکنولوژی‌های مختلف (tech stacks) عرضه می‌شود. اما برخلاف Breeze، Jetstream به تعامل‌پذیری (interactivity) نیاز دارد، بنابراین نسخه‌ی فقط-Blade ندارد. در عوض، دو انتخاب دارید: Livewire (که Blade است به‌همراه تعامل‌پذیری با استفاده...

برای دیدن ادامه محتوا وارد شوید

پیکربندی Vite در لاراول

Vite یک محیط توسعه فرانت‌اند برای لوکال است که شامل یک سرور توسعه و زنجیره ابزارهای ساخت مبتنی بر Rollup می‌باشد. ممکن است این توضیح پیچیده به نظر برسد، اما در لاراول، کاربرد اصلی آن بسته‌بندی (bundle کردن) فایل‌های CSS و JavaScript با یکدیگر است.
لاراول یک پلاگین NPM و یک دایرکتیو Blade برای کار راحت‌تر با Vite ارائه می‌دهد. هر دوی این ابزارها به صورت پیش‌فرض در اپلیکیشن‌های لاراول وجود دارند، همراه با یک فایل پیکربندی به نام vite.config.js.
برای مشاهده محتوای فایل پیش‌فرض vite.config.js، به مثال 6-1 نگاه کنید.

مثال 6-1. فایل پیش‌فرض vite.config.js

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
});

ما داریم فایل‌هایی را که پلاگین باید از آن‌ها شروع به ساختن کند ("input") تعریف می‌کنیم، و همچنین مشخص می‌کنیم که می‌خواهیم قابلیت "رفرش کردن صفحه هر بار که یک فایل view ذخیره شد" فعال باشد ("refresh").

به‌صورت پیش‌فرض، Vite از دو فایلی که در مثال 6-1 آمده‌اند استفاده می‌کند و به‌طور خودکار هر بار که فایلی در پوشه‌های زیر تغییر کند، صفحه را رفرش می‌کند:

  • app/View/Components/

  • lang/

  • resources/lang/

  • resources/views/

  • routes/

حالا که پیکربندی Vite ما به فایل‌های ورودی CSS و JavaScript اشاره می‌کند، باید از این فایل‌ها با دایرکتیو @vite در Blade استفاده کنیم، همان‌طور که در مثال 6-2 می‌بینید.

 

مثال 6-2. استفاده از دایرکتیو @vite در Blade

<html>
<head>
    @vite(['resources/css/app.css', 'resources/js/app.js'])

همین بود! حالا بگذارید ببینیم چطور می‌توان فایل‌ها را با Vite بسته‌بندی کرد.

 

نکته

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

// ...
export default defineConfig({
    plugins: [
        laravel({
            // ...
            valetTls: 'name-of_my-app-here.test',
        }),
    ],
});

 

بسته‌بندی فایل‌ها با Vite

در نهایت، وقت بسته&zwnj;بندی (bundle) دارایی&zwnj;هایمان رسیده است. دو روش برای این کار با Vite وجود دارد: "build" و "dev". اگر فقط می&zwnj;خواهید فایل&zwnj;هایتان یک&zwnj;بار ساخته شوند، چه برای ارائه در محیط production یا تست محلی، دستور npm run dev را اجرا کنید و Vite دارایی&zwnj;های شما را بسته&zwnj;بندی خواهد کرد. اما اگر در حال توسعه&zwnj;ی محلی هستید، احتمالاً ترجیح می&zwnj;دهید که Vite یک پردازش را راه&zwnj;اندازی کند که تغییرات در فایل&zwnj;های view را زیر نظر بگیرد، و هر بار که تغییری تشخیص داده شد، ساخت مجدد را انجام داده و صفحه&zwnj;ی مرورگر را رفرش کند. این همان کاری است...

برای دیدن ادامه محتوا وارد شوید

سرور توسعه‌ ی Vite

وقتی npm run dev را اجرا می‌کنید، یک سرور HTTP واقعی راه‌اندازی می‌شود که توسط Vite قدرت می‌گیرد. کمک‌کننده‌ی Blade مربوط به Vite، آدرس فایل‌های دارایی را بازنویسی می‌کند تا به جای دامنه‌ی محلی شما، به همان مسیرها روی سرور dev اشاره کند، که این کار باعث می‌شود Vite بتواند سریع‌تر وابستگی‌های شما را به‌روزرسانی و رفرش کند.
یعنی اگر کد Blade شما به این صورت باشد:

@vite(['resources/css/app.css', 'resources/js/app.js'])

در محیط production به شکل زیر خواهد بود:

<link rel="preload" as="style"
    href="http://my-app.test/build/assets/app-1c09da7e.css" />
<link rel="modulepreload"
    href="http://my-app.test/build/assets/app-ea0e9592.js" />
<link rel="stylesheet
    href="http://my-app.test/build/assets/app-1c09da7e.css" />
<script type="module" src="http://my-app.test/build/assets/app-ea0e9592.js"></script>

اما اگر سرور Vite شما در حال اجرا باشد، در محیط لوکال چیزی شبیه به این خواهد بود:
 

<script type="module" src="http://127.0.0.1:5173/@vite/client"></script>
<link rel="stylesheet" href="http://127.0.0.1:5173/resources/css/app.css" />
<script type="module" src="http://127.0.0.1:5173/resources/js/app.js"></script>

 

کار با دارایی‌ های ایستا (Static Assets) و Vite

تا اینجا فقط در مورد بارگذاری JavaScript و CSS با Vite صحبت کردیم. اما پیکربندی Vite در لاراول می&zwnj;تواند دارایی&zwnj;های ایستا (مثل تصاویر) را هم پردازش و ورژن&zwnj;بندی کند.اگر در قالب&zwnj;های JavaScript کار می&zwnj;کنید، Vite لینک&zwnj;های نسبی به دارایی&zwnj;های ایستا را پردازش و ورژن&zwnj;بندی می&zwnj;کند. اما دارایی&zwnj;های ایستای مطلق توسط Vite نادیده گرفته می&zwnj;شوند.یعنی تصاویر زیر (اگر در قالب جاوااسکریپت باشند) رفتار متفاوتی خواهند داشت: &lt;!-- نادیده گرفته می&zwnj;شود توسط Vite --&gt; &lt;img src="/resources/images/soccer.jpg"&gt; &lt;!-- پردازش می&zwnj;شود توسط Vite &rarr; &lt;img src="../resources/images/soccer.jpg"&gt; اگر در قالب&zwnj;های Blade کار می&zwnj;کنید، برای اینکه Vite دارایی&zwnj;های ایستای شما را مدیریت کند، باید دو مرحله...

برای دیدن ادامه محتوا وارد شوید

کار با فریم‌ ورک‌ های جاوااسکریپت و Vite

اگر می‌خواهید با Vue، React، Inertia یا یک اپلیکیشن تک‌صفحه‌ای (SPA) کار کنید، ممکن است نیاز به نصب پلاگین‌های خاص یا انجام پیکربندی‌های خاصی داشته باشید. در ادامه خلاصه‌ای از نیازهای رایج‌ترین سناریوها آمده است.

Vite و Vue

برای کار با Vue و Vite، ابتدا پلاگین Vue برای Vite را نصب کنید:

npm install --save-dev @vitejs/plugin-vue

سپس باید فایل vite.config.js خود را طوری تغییر دهید که افزونه Vue را فراخوانی کند و دو تنظیم پیکربندی را به آن منتقل کند. اولین مورد، `template.transformAssetUrls.base = null`، به افزونه Laravel اجازه می‌دهد تا به‌جای افزونه Vue، بازنویسی URLها را انجام دهد. دومین مورد، `template.transformAssetUrls.includeAbsolute = false`، این امکان را می‌دهد که URLها در قالب‌های Vue به فایل‌های موجود در پوشه public ارجاع دهند.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [
    laravel(['resources/js/app.js']),
    vue({
      template: {
        transformAssetUrls: {
          base: null,
          includeAbsolute: false,
        },
      },
    }),
  ],
});

 

Vite و React

برای کار با React و Vite، ابتدا پلاگین React برای Vite را نصب کنید:

npm install --save-dev @vitejs/plugin-react

سپس فایل vite.config.js را طوری تغییر دهید که پلاگین React را فراخوانی کند.

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [
    laravel(['resources/js/app.js']),
    react(),
  ],
});

در نهایت، دایرکتیو @viteReactRefresh را قبل از وارد کردن فایل‌های جاوااسکریپت با @vite در قالب Blade خود اضافه کنید.

@viteReactRefresh
@vite('resources/js/app.jsx')

 

Vite و Inertia

اگر خودتان Inertia را تنظیم می‌کنید، باید کاری کنید که Inertia بتواند کامپوننت‌های صفحه را resolve کند.
در اینجا نمونه‌ای از کدی که احتمالاً در فایل resources/js/app.js خواهید نوشت آمده، اما بهترین روش این است که Inertia را با استفاده از Breeze، Jetstream یا مستندات رسمی Inertia نصب کنید.

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
  resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
    return pages[`./Pages/${name}.vue`]
  },
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

 

Vite و SPA ها

اگر در حال ساخت یک اپلیکیشن تک‌صفحه‌ای (SPA) هستید، فایل resources/css/app.css را از vite.config.js حذف کنید تا به عنوان نقطه‌ی ورود (entry point) شناخته نشود.
در عوض، CSS خود را در فایل جاوااسکریپت وارد کنید. برای این کار، این خط را دقیقاً زیر خط وارد کردن bootstrap به فایل resources/js/app.js اضافه کنید:

import './bootstrap';
import '../css/app.css';

استفاده از متغیرهای محیطی در Vite

&nbsp;اگر می&zwnj;خواهید در فایل&zwnj;های جاوااسکریپت خود از متغیرهای محیطی استفاده کنید، باید نام متغیر را با پیشوند VITE_ بنویسید، همان&zwnj;طور که در مثال 6-3 می&zwnj;بینید. مثال 6-3: ارجاع به متغیرهای محیطی در vite.config.js // .env VITE_BASE_URL=http://local-development-url.test // resources/js/app.js const baseUrl = import.meta.env.VITE_BASE_URL; هر بار که npm run dev یا npm run build را اجرا می&zwnj;کنید، این متغیر محیطی از فایل .env بارگذاری و در اسکریپت شما تزریق می&zwnj;شود.

برای دیدن ادامه محتوا وارد شوید

صفحه‌ بندی (Pagination)

برای چیزی که در بیشتر برنامه‌های وب رایج است، پیاده‌سازی صفحه‌بندی همچنان می‌تواند بسیار پیچیده باشد. خوشبختانه، لاراول یک مفهوم داخلی از صفحه‌بندی دارد، و این قابلیت به‌صورت پیش‌فرض به نتایج Eloquent و روتینگ متصل شده است.

صفحه‌ بندی نتایج دیتابیس

رایج‌ترین موقعیتی که صفحه‌بندی را می‌بینید، زمانی است که در حال نمایش نتایج یک کوئری دیتابیس هستید و این نتایج برای نمایش در یک صفحه زیاد هستند. هم Eloquent و هم query builder، پارامتر page از درخواست فعلی را می‌خوانند و از آن برای فراهم کردن متد paginate() روی هر مجموعه‌ای از نتایج استفاده می‌کنند؛ تنها پارامتری که باید به paginate() بدهید، تعداد نتایجی است که می‌خواهید در هر صفحه نمایش داده شوند. برای درک بهتر، به مثال 6-4 توجه کنید.

مثال 6-4: صفحه‌بندی پاسخ query builder

// PostController
public function index()
{
   return view('posts.index', ['posts' => DB::table('posts')->paginate(20)]);
}

مثال 6-4 مشخص می‌کند که این مسیر باید ۲۰ پست در هر صفحه بازگرداند، و بر اساس پارامتر page در URL کاربر، تعیین می‌کند که کدام "صفحه" از نتایج باید نمایش داده شود (اگر این پارامتر وجود داشته باشد). مدل‌های Eloquent نیز همین متد paginate() را دارند.
زمانی که نتایج را در view خود نمایش می‌دهید، مجموعه شما حالا دارای متد links() خواهد بود که کنترل‌های صفحه‌بندی را تولید می‌کند. (مثال 6-5 که برای استفاده در کتاب ساده شده است را ببینید).

مثال 6-5: رندر کردن لینک‌های صفحه‌بندی در قالب

// posts/index.blade.php
<table>
@foreach ($posts as $post)
    <tr><td>{{ $post->title }}</td></tr>
@endforeach
</table>

{{ $posts->links() }}

//به‌طور پیش‌فرض، $posts->links() خروجی‌ای مانند این تولید می‌کند:
<div class="...">
    <div>
        <p class="...">
            Showing
            <span class="...">1</span>
            to
            <span class="...">2</span>
            of
            <span class="...">5</span>
            results
        </p>
    </div>
    <div>
        <span class="...">
            <span aria-disabled="true" aria-label="&amp;laquo; Previous">
                <!-- SVG here for the ... ellipsis -->
            </span>
            <span class="...">1</span>
            <a href="http://myapp.com/posts?page=2" class="..." aria-label="Go to page 2">
                2
            </a>
            <a href="http://myapp.com/posts?page=3" class="..." aria-label="Go to page 3">
                3
            </a>
            <a href="http://myapp.com/posts?page=2" class="..."
                rel="next" aria-label="Next &amp;raquo;">
                <!-- SVG here for the ... ellipsis -->
            </a>
        </span>
    </div>
</div>

استایل پیش‌فرض صفحه‌بند در لاراول از TailwindCSS استفاده می‌کند. اگر می‌خواهید از استایل‌های Bootstrap استفاده کنید، در فایل AppServiceProvider خود متد Paginator::useBootstrap() را فراخوانی کنید:

use Illuminate\Pagination\Paginator;

public function boot()
{
    Paginator::useBootstrap();
}

 

سفارشی‌سازی تعداد لینک‌های صفحه‌بندی

اگر می‌خواهید کنترل کنید که چند لینک در دو طرف صفحه فعلی نمایش داده شود، می‌توانید به راحتی با متد onEachSide() این مقدار را تنظیم کنید:

DB::table('posts')->paginate(10)->onEachSide(3);

// خروجی:
// 5 6 7 [8] 9 10 11

 

ایجاد دستی صفحه‌ بند

اگر با Eloquent یا query builder کار نمی‌کنید، یا اگر با کوئری پیچیده‌ای کار می‌کنید (مثلاً کوئری‌ای که از groupBy استفاده می‌کند)، ممکن است نیاز پیدا کنید که به صورت دستی یک paginator بسازید. خوشبختانه، می‌توانید این کار را با کلاس‌های Illuminate\Pagination\Paginator یا Illuminate\Pagination\LengthAwarePaginator انجام دهید.
تفاوت این دو کلاس در این است که Paginator فقط دکمه‌های قبلی و بعدی را فراهم می‌کند، ولی لینک‌هایی به هر صفحه نمی‌دهد؛ LengthAwarePaginator نیاز دارد تا طول کل نتایج را بداند تا بتواند لینک‌هایی برای هر صفحه ایجاد کند. ممکن است بخواهید از Paginator برای مجموعه‌نتایج بزرگ استفاده کنید، تا صفحه‌بند شما از شمارش سنگین نتایج بی‌نیاز باشد.
هر دو کلاس Paginator و LengthAwarePaginator نیاز دارند که شما به صورت دستی بخش موردنظر از محتوا را استخراج و به view ارسال کنید. به مثال 6-6 توجه کنید.

مثال 6-6: ساخت دستی یک صفحه‌بند

use Illuminate\Http\Request;
use Illuminate\Pagination\Paginator;

Route::get('people', function (Request $request) {
    $people = [...]; // لیست بزرگی از افراد

    $perPage = 15;
    $offsetPages = $request->input('page', 1) - 1;

    // Paginator به صورت خودکار آرایه را برش نمی‌دهد
    $people = array_slice(
        $people,
        $offsetPages * $perPage,
        $perPage
    );

    return new Paginator(
        $people,
        $perPage
    );
});

 

کیسه‌ های پیام (Message Bags)

یکی دیگر از ویژگی‌های رایج ولی دردناک در برنامه‌های وب، ارسال پیام بین بخش‌های مختلف برنامه است، زمانی که هدف نهایی نمایش آن‌ها به کاربر است. برای مثال، کنترلر شما ممکن است بخواهد یک پیام اعتبارسنجی ارسال کند: «فیلد ایمیل باید یک آدرس ایمیل معتبر باشد.» با این حال، این پیام فقط نباید به view برسد؛ بلکه باید از یک redirect عبور کند و در view صفحه‌ای دیگر نمایش داده شود. چگونه باید این منطق پیام‌رسانی را ساختار دهید؟
Illuminate\Support\MessageBag کلاسی است که مسئول ذخیره، دسته‌بندی و بازگرداندن پیام‌هایی است که برای کاربر نهایی در نظر گرفته شده‌اند. این کلاس همه پیام‌ها را بر اساس کلید گروه‌بندی می‌کند، جایی که کلیدها معمولاً چیزی مثل errors و messages هستند، و متدهای کمکی برای دریافت همه پیام‌ها یا فقط پیام‌های یک کلید خاص و خروجی گرفتن از آن‌ها در فرمت‌های مختلف ارائه می‌دهد.
می‌توانید یک نمونه جدید از MessageBag به صورت دستی بسازید، همان‌طور که در مثال 6-7 نشان داده شده است. البته صادقانه بگوییم، احتمالاً هرگز این کار را به صورت دستی انجام نخواهید داد—این فقط یک تمرین ذهنی است برای اینکه نشان دهد این کلاس چگونه کار می‌کند.

مثال 6-7: ساخت و استفاده دستی از یک message bag

$messages = [
    'errors' => [
        'Something went wrong with edit 1!',
    ],
    'messages' => [
        'Edit 2 was successful.',
    ],
];
$messagebag = new \Illuminate\Support\MessageBag($messages);

// بررسی وجود ارورها؛ در صورت وجود، آن‌ها را تزئین و چاپ کن
if ($messagebag->has('errors')) {
    echo '<ul id="errors">';
    foreach ($messagebag->get('errors', '<li><b>:message</b></li>') as $error) {
        echo $error;
    }
    echo '</ul>';
}

 

message bagها همچنین به‌شدت با اعتبارسنجی‌های لاراول مرتبط هستند (در بخش «اعتبارسنجی» بیشتر در مورد آن یاد می‌گیرید): زمانی که اعتبارسنج‌ها اروری بازمی‌گردانند، در واقع یک نمونه از MessageBag بازمی‌گردانند، که می‌توانید آن را به view ارسال یا با redirect('route')->withErrors($messagebag) به redirect متصل کنید.
لاراول یک نمونه خالی از MessageBag را به هر view ارسال می‌کند، که در متغیر $errors ذخیره شده است؛ اگر با استفاده از withErrors() یک message bag را فلش کرده باشید، به جای نمونه خالی، همان bag به متغیر $errors تخصیص داده می‌شود. این یعنی هر view می‌تواند فرض کند که یک MessageBag با نام $errors دارد که می‌توان در هر جایی که اعتبارسنجی انجام می‌شود از آن استفاده کرد. این موضوع منجر به مثال 6-8 می‌شود که یک قطعه کد رایج است که توسعه‌دهندگان در هر صفحه قرار می‌دهند.

مثال 6-8: قطعه کد بررسی خطا

// partials/errors.blade.php
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
        @foreach ($errors as $error)
            <li>{{ $error }}</li>
        @endforeach
        </ul>
    </div>
@endif

 

متغیر $errors موجود نیست

اگر هر مسیری دارید که تحت middleware گروه web نیست، آن‌ها middleware مربوط به session را نخواهند داشت، که به این معنی است که متغیر $errors در آن‌ها در دسترس نخواهد بود.

گاهی نیاز دارید message bagها را نه فقط با کلید (مثل notices و errors) بلکه با کامپوننت نیز تفکیک کنید. شاید یک فرم لاگین و یک فرم ثبت‌نام در یک صفحه داشته باشید؛ چگونه آن‌ها را از هم تفکیک می‌کنید؟
زمانی که ارورها را همراه با redirect ارسال می‌کنید با withErrors()، پارامتر دوم نام bag است:
redirect('dashboard')->withErrors($validator, 'login');

سپس، در صفحه dashboard می‌توانید از $errors->login استفاده کنید تا تمام متدهایی که قبلاً دیدید (مثل any(), count() و غیره) را صدا بزنید.

هلپرهای رشته‌ ای، جمع‌ بندی و بومی‌ سازی

به&zwnj;عنوان برنامه&zwnj;نویس، معمولاً به بلوک&zwnj;های متنی به&zwnj;عنوان divهای بزرگی نگاه می&zwnj;کنیم که منتظرند مشتری محتوای واقعی را در آن&zwnj;ها قرار دهد. به&zwnj;ندرت درگیر منطق داخل این بلوک&zwnj;ها می&zwnj;شویم. اما در برخی شرایط، از ابزارهایی که لاراول برای دستکاری رشته&zwnj;ها فراهم کرده سپاسگزار خواهید بود.

برای دیدن ادامه محتوا وارد شوید

هلپرهای رشته‌ ای و جمع‌ بندی

لاراول مجموعه‌ای از هلپرها برای دستکاری رشته‌ها دارد. این‌ها به‌صورت متدهایی روی کلاس Str در دسترس هستند (مثلاً: Str::plural()).

هلپرهای رشته‌ای و آرایه‌ای سراسری لاراول

نسخه‌های قدیمی‌تر لاراول شامل هلپرهای سراسری بودند که معادل‌هایی برای متدهای Str و Arr بودند. این هلپرهای سراسری با پیشوند str_ و array_ در نسخه‌ی ۶ لاراول حذف شده و به یک پکیج جداگانه منتقل شدند. اگر مایل باشید، می‌توانید پکیج laravel/helpers را از طریق Composer نصب کنید:

composer require laravel/helpers

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

e()
 میانبری برای html_entities()؛ تمام کاراکترهای HTML را برای امنیت کدگذاری می‌کند.

Str::startsWith()، Str::endsWith()، Str::contains()
 بررسی می‌کند که یک رشته (پارامتر اول) آیا با رشته‌ی دیگری (پارامتر دوم) شروع، پایان یا شامل آن است.


Str::is()
 بررسی می‌کند که آیا یک رشته (پارامتر دوم) با یک الگو (پارامتر اول) مطابقت دارد یا نه — برای مثال، foo* با foobar و foobaz مطابقت دارد.


Str::slug()
 یک رشته را به یک slug مناسب برای URL با خط تیره تبدیل می‌کند.


Str::plural(word, count)، Str::singular()
 یک کلمه را جمع یا مفرد می‌کند؛ فقط برای زبان انگلیسی (مثلاً Str::plural('dog') می‌شود dogs؛ و Str::plural('dog', 1) می‌شود dog).


Str::camel()، Str::kebab()، Str::snake()، Str::studly()، Str::title()
 رشته‌ی داده‌شده را به قالب‌های مختلف حروف‌چینی (case) تبدیل می‌کند.


Str::after()، Str::before()، Str::limit()
 یک رشته را برش می‌دهد و زیررشته‌ای برمی‌گرداند. Str::after() همه‌چیز بعد از یک رشته‌ی مشخص را برمی‌گرداند و Str::before() همه‌چیز قبل از آن را (هر دو، رشته‌ی کامل را به‌عنوان پارامتر اول و رشته‌ی جداکننده را به‌عنوان پارامتر دوم می‌پذیرند). Str::limit() یک رشته را تا تعداد مشخصی از کاراکترها کوتاه می‌کند (پارامتر دوم).


Str::markdown(string, options)
 مارک‌داون را به HTML تبدیل می‌کند. می‌توانید درباره گزینه‌هایی که می‌توان به آن داد در سایت PHP League بیشتر بخوانید.


Str::replace(search, replace, subject, caseSensitive)
 در رشته‌ی اصلی (subject) به‌دنبال رشته‌ی جستجو (search) می‌گردد و آن را با رشته‌ی جایگزین (replace) جایگزین می‌کند. اگر پارامتر حساس‌بودن به حروف (case sensitivity) true باشد، فقط در صورتی جایگزین می‌کند که تطابق دقیقاً با همان حروف باشد.
 (مثلاً: Str::replace(Running, Going, Laravel Up and Running, true) برمی‌گرداند: Laravel Up and Going)

بومی‌ سازی (Localization)

بومی&zwnj;سازی به شما اجازه می&zwnj;دهد چند زبان تعریف کرده و هر رشته&zwnj;ای را برای ترجمه علامت&zwnj;گذاری کنید. می&zwnj;توانید یک زبان پیش&zwnj;فرض (fallback) تعیین کرده و حتی حالت&zwnj;های مختلف جمع&zwnj;بندی را مدیریت کنید.در لاراول، باید در طول لود صفحه، "locale برنامه" را تنظیم کنید تا هلپرهای بومی&zwnj;سازی بدانند از کدام منبع ترجمه استفاده کنند. هر "locale" معمولاً به یک ترجمه متصل است و به شکل&zwnj;هایی مثل "en" (برای انگلیسی) خواهد بود. این کار را با App::setLocale($localeName) انجام می&zwnj;دهید، و معمولاً آن را در یک service provider قرار می&zwnj;دهید. فعلاً می&zwnj;توانید آن را در متد boot() از AppServiceProvider قرار دهید، اما اگر...

برای دیدن ادامه محتوا وارد شوید

تست‌ ها

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

تست پیام‌ ها و کیسه‌ های خطا

دو روش اصلی برای تست پیام‌هایی که همراه با کیسه‌های پیام و خطا ارسال می‌شوند وجود دارد. اول، شما می‌توانید یک رفتار در تست‌های برنامه‌تان انجام دهید که پیامی را تنظیم می‌کند که در نهایت در جایی نمایش داده می‌شود، سپس به آن صفحه ریدایرکت کنید و بررسی کنید که پیام مناسب نمایش داده شده باشد.
دوم، برای خطاها (که رایج‌ترین مورد استفاده است)، می‌توانید بررسی کنید که آیا جلسه خطاها دارد با assertSessionHasErrors($bindings = []). به مثال 6-17 نگاه کنید تا ببینید این چگونه می‌تواند باشد.
مثال 6-17. بررسی اینکه جلسه خطا دارد

public function test_missing_email_field_errors()
{
    $this->post('person/create', ['name' => 'Japheth']);
    $this->assertSessionHasErrors(['email']);
}

برای اینکه مثال 6-17 عبور کند، باید اعتبارسنجی ورودی را به آن مسیر اضافه کنید. این را در فصل 7 پوشش خواهیم داد.

ترجمه و بومی‌ سازی

ساده&zwnj;ترین روش برای تست بومی&zwnj;سازی، تست&zwnj;های برنامه است. زمینه مناسب را تنظیم کنید (چه از طریق URL یا جلسه)، صفحه را با get() بازدید کنید و بررسی کنید که محتوای مناسب را می&zwnj;بینید.

برای دیدن ادامه محتوا وارد شوید

غیرفعال کردن Vite در تست‌ ها

اگر بخواهید در هنگام تست‌ها، حل مسئله دارایی‌های Vite را غیرفعال کنید، می‌توانید با فراخوانی متد withoutVite() در بالای یک تست، Vite را به‌طور کامل غیرفعال کنید:

public function test_it_runs_without_vite()
{
    $this->withoutVite();

    // Test stuff
}

خلاصه

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