آشنایی با امکانات جدید لاراول ۸

در این مقاله از سری مقاله های آموزش لاراول، به آموزش ویژگی های لاراول 8 می پردازیم. laravel 8 در 8 سپتامبر سال 2020 منتشر شد. این نسخه همچنان به پیشرفت های انجام شده در نسخه قبلی (نسخه 7) ادامه داده و همچنین شامل ویژگی های جدیدی مانند پشتیبانی از Jetstream و dynamic blade component, model factory classes, job batching,خدمات improved artisan و خیلی های دیگر است.

در طی این مقاله آموزش لاراول، ما به 13 ویژگی جدید معرفی شده در این نسخه جدید نگاه خواهیم کرد که در زیر ذکر شده است:

  • Laravel Jetstream
  • Models directory
  • Model factory classes
  • Migration squashing
  • Job batching
  • Improved rate limiting
  • Improved maintenance mode
  • Closure dispatch / chain
  • Dynamic blade components
  • Time testing helpers
  • Artisan serve improvements
  • Tailwind pagination views
  • Routing namespace updates

Laravel Jetstream

Laravel Jetstream یک برنامه برای برنامه های scaffolding لاراول است. Jetstream که با استفاده از Tailwind CSS طراحی شده است، نقطه شروع خوبی برای پروژه های جدید با فیچرهایی مانند احراز هویت ، مدیریت پروفایل ، امنیت و پشتیبانی API با استفاده از Laravel Sanctum است.

Laravel Jetstream page

همچنین، Jetstream دو گزینه برای frontend scaffolding با Livewire و Inertia ارائه می دهد.

Laravel Livewire - کتابخانه ای است که ساخت برنامه های full-stack بر روی Laravel را بدون نیاز به pull کردن سایر کتابخانه ها و فریمورک های frontend مانند React و Vue.js امکان پذیر می کند. از آنجا که Livewire از blend templating engine استفاده می كند، توسعه دهندگان لاراول می توانند به راحتی اینترفیس های داینامیک را ایجاد كنند.

Inertia.js - پکیجی است که همراه با Laravel Jetstream ارائه می شود و به شما امکان می دهد با Vue.js تمپلیت های client-side را بسازید. چیزی که این موضوع را جالب می کند این است که می توانید از قدرت کامل Vue بدون پیچیدگی frontend routing لذت ببرید زیرا می توانید از روتر استاندارد لاراول که با آن آشنا هستید استفاده کنید.

Jetstream installation - اگر Laravel installer را نصب کرده اید، به راحتی  Jetstream را با Laravel installation با اضافه کردن فلگ --jet نصب کنید.مانند:

$ laravel new project-name --jet

با اجرای migration ها، تنظیمات را کامل کنید:

$ php artisan migrate

می توانید از composer برای نصب Jetstream در یک برنامه جدید Laravel استفاده کنید. نصب Jetstream از طریق composer نیاز به اجرای دستور jetstream:install artisan  دارد که نام frontend stack مورد نظر شما را به عنوان مثال livewire یا Inertia.js می پذیرد. این کار را می توان با اجرای دستورات زیر انجام داد:

$ php artisan jetstream:install livewire

$ php artisan migrate

$ npm install && npm run dev

Model directory

همیشه پیشنهاداتی وجود داشته است که لاراول باید Model directory را به عنوان پیش فرض برای ذخیره model ها داشته باشد. در سال 2016، Taylor Otwell در این باره نظرسنجی کرد و نتایج نشان داد که درصد بالاتری از مردم خواهان model directory پیش فرض هستند.

در نسخه های قبلی لاراول ، اگر هنگام تولید model مسیری را مشخص نکرده باشید، همه فایل های model به طور پیش فرض در دایرکتوری /app ذخیره می شدند. با این حال، از زمان آپدیت جدید، لاراول اکنون به طور پیش فرض شامل دایرکتوری app/Models است.

بنابراین، وقتی دستور $ php artisan make:model ModelName را اجرا کردید: ModelName.php در app/Models ذخیره می شود. با این حال، اگر دایرکتوری وجود نداشته باشد، لاراول تصور می کند که model های برنامه از قبل در دایرکتوری app/ هستند.

کلاس های Model factory

Eloquent model factory ها به ما اجازه می دهند pattern های مورد استفاده در تولید داده های فیک را هنگام تست برنامه خود تعریف کنیم. در نسخه های قبلی، لاراول یک آبجکت $factory ارائه می داد که می توانستیم آن را تعریف کنیم و factory های خود را تعریف کنیم. در لاراول 8، factory ها class-based هستند و از روابط بین factory ها پشتیبانی می کنند (به عنوان مثال کاربر پست های زیادی دارد).

تعریف factory قبلاً شبیه این بود:

// database/factories/UserFactory.php

use Faker\Generator as Faker;
use Illuminate\Support\Str;

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
    ];
});

سپس می توانیم از factory تعریف شده مانند این استفاده کنیم:

public function testDatabase()
{
    $user = factory(App\User::class)->make();

    // Use model in tests...
}

در نسخه جدید، factory اکنون به عنوان یک کلاس تعریف می شود، مانند این:

// database/factories/UserFactory.php

namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
    {
        /**
         * The name of the factory's corresponding model.
         *
         * @var string
         */
        protected $model = User::class;

        /**
         * Define the model's default state.
         *
         * @return array
         */
        public function definition()
        {
            return [
                'name' => $this->faker->name,
                'email' => $this->faker->unique()->safeEmail,
                'email_verified_at' => now(),
                'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
                'remember_token' => Str::random(10),
            ];
        }
    }

با ویژگی جدید HasFactory که در مدل های تولید شده موجود است، ممکن است از model factory مانند این استفاده شود:

use App\Models\User;
public function testDatabase()
{
    $user = User::factory()->make();
    // Use model in tests...
}

Migration squashing

 ویژگی جدید migration squashing می تواند فایل های بزرگ migration را در یک فایل SQL اسکواش کنید. هنگامی که migration ها را اجرا می کنید، فایل تولید شده ابتدا اجرا می شود، سپس لاراول هر فایل migration دیگری را که بخشی از فایل squashed schema نیستند، اجرا می کند. با استفاده از دستور artisan زیر می توانید فایل های migration خود را squash کنید:

$ php artisan schema:dump

// Dump the current database schema and prune all existing migrations...
$ php artisan schema:dump --prune

هنگامی که دستور را اجرا می کنید، لاراول یک فایل schema را در دایرکتوری database/schema شما می نویسد.

Job batching

نسخه جدید لاراول همچنین دارای یک ویژگی عالی است که به شما امکان می دهد گروهی از job ها را به طور موازی اجرا کنید. برای نظارت بر فرآیند grouped/batched job، می توانید از متدهای catch، then و finally برای تعریف فراخوانی های تکمیل شده مانند این استفاده کنید:

use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Batch;
use Throwable;

$batch = Bus::batch([
    new ProcessPodcast(Podcast::find(1)),
    new ProcessPodcast(Podcast::find(2)),
    new ProcessPodcast(Podcast::find(3)),
    new ProcessPodcast(Podcast::find(4)),
    new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();

return $batch->id;

برای کسب اطلاعات بیشتر در مورد job batching feature، می توانید داکیومنت های لاراول را مطالعه کنید.

rate limiting

با rate limiting جدید، اکنون می توانید با استفاده از RateLimiter facade کارهای بیشتری انجام دهید، به عنوان مثال محدود کردن درخواست ها به صورت داینامیک. ابتدا، نگاهی به نحوه رسیدگی به درخواست در نسخه قبلی میندازیم.

در Laravel 7، برای محدود کردن درخواست API، باید فایل Kernel.php را در فولدر app/Http ویرایش می کردید:

// app/Http/Kernel.php
...

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
    'api' => [
        'throttle:60,1', // Here the API request limit is set to 60 request per minute
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

...

در Laravel 8، پیکربندی فوق اکنون به این شکل است:

// app/Http/Kernel.php
...
protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            'throttle:api', // Request limit is now defined in RouteServiceProvider
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
...

محدودیت درخواست API اکنون در RouteServiceProvider.php  در دایرکتوری app/Providers/ تعریف شده است:

// app/Providers/RouteServiceProvider.php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
...
public function boot()
{
    $this->configureRateLimiting();
    ...
}
// Configure the rate limiters for the application.
protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60); // 60 Request per minute
    });
}

در متد boot، این configureRateLimiting()فراخوانی می شود. و همانطور که از نام آن پیداست، پیکربندی rate limiting را در خود دارد.

Rate limiter ها با استفاده از متد RateLimiter facade’s for تعریف می شوند. متد for دو پارامتر می گیرد، یک نام rate limiter (به عنوان مثال api) و یک closure که limit configuration را برمی گرداند که فقط باید در route هایی اعمال شود که به این rate limiter اختصاص داده شده اند.

همانطور که مشاهده می کنید، متد for نمونه درخواست HTTP را در اختیار شما قرار می دهد و امکان کنترل کامل محدود کردن درخواست ها را به صورت داینامیک می دهد.

می خواهیم برای کاربر فاقد تأیید اعتبار ده request در دقیقه و برای کاربران تایید شده  unlimited request تعیین کنیم. این کار را به صورت زیر انجام می دهیم:

// app/Providers/RouteServiceProvider.php

protected function configureRateLimiting()
{
    ...
    RateLimiter::for('guest', function (Request $request) {
    return $request->user()
                ? Limit:none()
                : Limit::perMinute(10); // 10 Request per minute
    });
}

configured rate را می توان به طور مستقیم در یک route با استفاده از middleware مانند این اعمال کرد:

// routes/api.php
...
Route::get('posts', 'PostController@store')->middleware('throttle:guest');
...

برای کسب اطلاعات بیشتر در مورد rate-limiting می توانید به این لینک مراجعه کنید.Laravel routing documentation

Improved maintenance mode

در نسخه های قبلی لاراول، می توان با تنظیم لیستی از آدرس های IP در لیست سفید که اجازه دسترسی به برنامه را دارند، حالت maintenance انجام می شود، این فیچر با توجه به secret/token حذف شده است. ببینیم که چگونه کار می کند:

هنگام تنظیم برنامه خود روی حالت maintenance، می توانید secret برای دسترسی به سایت را به این ترتیب تعیین کنید:

$ php artisan down --secret="my-secret"

تا زمانی که برنامه در حالت maintenance است، می توانید با مشخص کردن secret خود به آن دسترسی پیدا کنید:


yourdomain.com/YOUR_SECRET_HERE

لاراول با استفاده از کلید laravel_maintenance، کوکی را برای مرورگر شما تنظیم می کند برای بررسی کند بازدیدکننده به آن دسترسی دارد یا خیر.

Maintenance prerendering

یکی دیگر از پیشرفت های حالت maintenance، توانایی ارائه پیش رندرهای maintenance به انتخاب شما است. در نسخه های قبلی لاراول، زمانی که برنامه شما برای maintenance خاموش می شود، آپدیت وابستگی هایی که در حال اجرای composer install است، بازدیدکنندگان شما را با خطای واقعی سرور مواجه می کند.

برای بررسی اینکه آیا برنامه در حال maintenance است یا خیر، باید لاراول را بوت کرد. پیش رندرهای maintenance به شما امکان می دهد view یی را تعیین کنید که در ابتدای سیکل درخواست بازگردانده شود. این view قبل از لود وابستگی های برنامه شما رندر می شود.

می توانید یک view پیش فرض را با گزینه --render از دستور artisan down پیش رندر کنید مانند این:

$ php artisan serve
// Starting Laravel development server: http://127.0.0.1:8000
...

$ php artisan down --render="errors::503"
// Application is now in maintenance mode.

با اجرای دستور بالا صفحه زیر نمایش داده می شود:
503 service error

Closure dispatch / chain

با استفاده از تابع catch، اکنون می توانید یک closure بنویسید که در صورت عدم موفقیت در اجرای صف پس از چند مرتبه تلاش، باید اجرا شود:

use Throwable;

dispatch(function () use ($podcast) {
    $podcast->publish();
})->catch(function (Throwable $e) {
    // This job has failed...
});

Dynamic blade components

مواردی وجود دارد که ممکن است بخواهید component یی را ارائه دهید که به اکشن های انجام شده view در زمان اجرا بستگی دارد. با استفاده از dynamic blade component ها، می توانید کامپوننت هایی را با وارد کردن component name به عنوان متغیر ارائه دهید.

Time testing helpers

با الهام از Ruby on Rails، تغییرات زمانی در carbon PHP library هنگام تست، یک گام فراتر رفته است.

هنگام نوشتن test case ها، ممکن است گاهی اوقات نیاز به تغییر زمان بازگشت helper هایی مانند now یا Illuminate\Support\Carbon::now()داشته باشید. فیچر test class لاراول اکنون شامل متدهای helper است که به شما امکان می دهد زمان فعلی را به این صورت دستکاری کنید:

public function testTimeCanBeManipulated()
{
    // Travel into the future...
    $this->travel(5)->milliseconds();
    $this->travel(5)->seconds();
    $this->travel(5)->minutes();
    $this->travel(5)->hours();
    $this->travel(5)->days();
    $this->travel(5)->weeks();
    $this->travel(5)->years();

    // Travel into the past...
    $this->travel(-5)->hours();

    // Travel to an explicit time...
    $this->travelTo(now()->subHours(6));

    // Return back to the present time...
    $this->travelBack();
}

Artisan serve improvements

در نسخه های قبلی لاراول، هنگامی که برنامه خود را با دستور php artisan serve استارت می کنید، با تغییر.env لازم است که برنامه را به صورت دستی ریست کنید. در نسخه جدید، تغییر .env به طور خودکار برنامه را reload می کند تا دیگر لازم نباشد برنامه را مجدداً راه اندازی کنید.

Tailwind pagination views

صفحه بندی لاراول برای استفاده از Tailwind CSS framework به طور پیش فرض آپدیت شده است. در حالی که هنوز از Bootstrap 3 و 4 پشتیبانی می کند.

برای پیکربندی pagination view خود برای استفاده از Bootstrap به جای Tailwind پیش فرض، می توانید متد paginator useBootstrap در  AppServiceProvider را فراخوانی کنید:

// app/Providers/AppServiceProvider.php

...
use Illuminate\Pagination\Paginator;
...
public function boot()
{
    Paginator::useBootstrap();
    ...
}

Routing namespace updates

 نسخه های قبلی لاراول، RouteServiceProvider شامل یک ویژگی $namespace بود که به طور خودکار پیشوند بر روی تعریف controller route و فراخوانی متد helper URL::action می شود.

// app/Providers/RouteServiceProvider.php

...

class RouteServiceProvider extends ServiceProvider
{
    protected $namespace = 'App\Http\Controllers';

    ...

}

این مقدار پیش فرض به شما اجازه می دهد تا یک route controller را به صورت زیر تعریف کنید:

// routes/web.php
...
Route::post('login', 'UserController@login')
...

در لاراول 8، خاصیت $namespace به طور پیش فرض null است، به این معنی که هیچ namespace prefix خودکار توسط لاراول انجام نمی شود. تعاریف Controller route باید با استفاده از syntax استاندارد قابل فراخوانی PHP تعریف شود:

// routes/web.php

use App\Http\Controllers\UserController;

Route::post('/login', [UserController::class, 'login']);

اگر نسخه قبلی را ترجیح می دهید، باید controller namespace خود را در RouteServiceProvider مشخص کنید.

نتیجه

در این مقاله، ما به فیچرهای جدید لاراول 8 پرداخته ایم. برای ارتقا برنامه فعلی خود به نسخه 8، می توانید upgrade guide و همچنین release notes را بررسی کنید.

× در حال پاسخ به: