تخفیف ویژه

بررسی تغییرات لاراول 8

دسته بندی: لاراول
زمان مطالعه: 12 دقیقه
۲۲ آبان ۱۳۹۹

لاراول 8 در تاریخ 8 سپتامبر 2020، به طور رسمی، منتشر شد. تیم لاراول هر 6 ماه یک‌بار یک نسخه‌ی جدید از لاراول را با تغییرات عمده‌ای منتشر می‌کند. لاراول 8، Non-LTS است، یعنی مثل نسخه‌ی 6 که LTS یا Long Term Support است، پشتیبانی بلند مدت ندارد. رفع باگ‌های لاراول 8 به مدت 6 ماه، به صورت هفتگی، تا 8 مارس 2021 ادامه دارد و رفع باگ‌های امنیتی نیز به مدت یک سال، تا 8 سپتامبر 2021 پشتیبانی خواهد شد. در لاراول 8، ویژگی‌های  جدید بسیاری افزوده شده و اصلاحاتی نیز انجام شده است. در ادامه‌ی این مقاله با ما همراه باشید تا این ویژگی‌ها را با هم بررسی کنیم.

فهرست محتوای این مقاله

پوشه‌ی Models

تا قبل از لاراول 5، در پوشه app، پوشه‌ی دیگری با نام Models وجود داشت که مدل‌های ایجاد شده در آنجا قرار می‌گرفتند. این پوشه از لاراول 5 به بعد، حذف شد و مدل‌ها به طور مستقیم در پوشه‌ی app ایجاد می‌شدند. این کار در اپلیکیشن‌هایی که شامل تعداد زیادی مدل بودند، باعث ایجاد بی‌نظمی زیادی می‌شد.

اما بنا به درخواست‌های متعدد توسعه‌دهندگان لاراول، مسیر app/Models دوباره به عنوان مسیر پیش‌فرض مدل‌های لاراول انتخاب شده است.

Model Factories

ویژگی Model Factory لاراول در نسخه‌ی 8 به طور کامل بازسازی و Class Based شده و کار کردن با آن‌ها را بسیار ساده‌تر کرده است. با اجرای دستور زیر می‌توانید برای مدل Post یک کلاس Factory ایجاد کنید:

php artisan make:factory PostFactory

فایل PostFactory به شکل زیر در مسیر database/factories ایجاد می‌شود:

namespace Database\Factories;

use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Post::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'title' => $this->faker->unique()->sentence,
            'text' => $this->faker->text,
            'status' => $this->faker->numberBetween(0, 3),
            'date' => $this->faker->date('Y-m-d', 'now'),

        ];
    }
}

می‌بینید که خصوصیت model، حاوی کلاس مدل مورد نظر است. برای استفاده از کلاس Factory فوق می‌توانید به روش زیر عمل کنید:

use App\Models\Post;

$fakePosts = Post::factory()->count(10)->create();

در این حالت، کلاس مدل باید از Trait با نام HasFactory استفاده کند که متد ()factory را به کلاس مدل اضافه می‌کند. این متد، یک نمونه از کلاس Factory را برمی‌گرداند که می‌توان متدهای مختلف را با استفاده از آن صدا زد. اگر نخواهید از Trait فوق استفاده کنید، می‌توانید به روش زیر عمل کنید و مستقیما از کلاس Factory نمونه بسازید:

use Database\Factories\PostFactory;

$fakePosts = PostFactory::new()->count(10)->create();

وضعیت در Factory

وضعیت Factory در یک متد مجزا می‌تواند نوشته شود:

namespace Database\Factories;

use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;

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

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'title' => $this->faker->unique()->sentence,
            'text' => $this->faker->text,
            'status' => $this->faker->numberBetween(0, 3),
            'date' => $this->faker->date('Y-m-d', 'now'),

        ];
    }

    public function published()
    {
        return $this->state(function (array $attributes) {
            return [
                'status' => 2,
            ];
        });
    }
}

روابط در Factory

روابط در Factory Model‌ها به خوبی بهبود یافته‌اند. برای مثال ما در قطعه کد زیر، یک کاربر ایجاد می‌کنیم که این کاربر، 5 پست را ایجاد کرده است:

$writer = User::factory()
    ->has(
        Post::factory()
            ->count(5)
            -> published()
    )
    ->create();

یا می‌توان از متدهای جادویی، برای تعریف روابط استفاده کرد. برای مثال، قطعه کد زیر، براساس رابطه‌ی posts بین مدل User و Post به صورت یک به چند، اجرا می‌شود:

$writer = User::factory()
    ->hasPosts(3,[
	'status' => 2
	])
    ->create();

Jetstream

Jetstream لاراول، یک پکیج Scaffolding است که به منظور انجام کارهای مربوط به احراز هویت، جایگزین پکیج Laravel/ui شده است. این پکیج رایگان و منبع باز (Open-Source) است. این پکیج ویژگی‌های زیادی از قبیل مدیریت پروفایل کاربر، احراز هویت دو مرحله‌ای، مدیریت توکن‌های Api، مدیریت تیم، حذف اکانت، مدیریت نشست‌های متعدد (Multi-Session Management) را در خود دارد. دیزاین قالب فرانت اند آن به‌وسیله‌ی کتابخانه‌ی Tailwind CSS انجام گرفته است و برای اجرای ویژگی‌های فوق، بنا به انتخاب خود، می‌توانید از پیکج Laravel Livewire یا Inertiajs استفاده کنید.

تغییرات و ویژگی‌های لاراول 8

Namespace پیش‌فرض برای کنترلرها

در لاراول 7 و نسخه‌های پیش از آن، در فایل RouteServiceProvider در مسیر app/Providers، یک خصوصیت protected با نام namespace وجود دارد که در متدهای ()mapWebRoutes و ()mapApiRoutes از آن استفاده می‌شود و مسیر کنترلرهای استفاده شده در پوشه‌ی routes را مشخص می‌کند.

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

use App\Http\Controllers\UserProfileController;

Route::get('user/profile', [UserProfileController::class, 'show']);

در اینجا درخواست Get به مسیر user/profile را به متد show در کنترلر UserProfileController متصل کرده‌ایم.

دستور schema:dump

با توسعه‌ی اپلیکیشن لاراولی و بزرگتر شدن دیتابیس، یکی از مسائلی که توسعه‌دهنده‌ها با آن مواجه می‌شوند، تعداد زیاد فایل‌های Migration موجود در مسیر database/migrations است که به مرور با توسعه‌ی هرچه بیشتر پروژه، تعدادشان افزایش می‌یابد. راه حلی که برای این مساله در لاراول 8 در نظر گرفته شده است، دستور Artisan جدیدی به شکل زیر است:

php artisan schema:dump

با اجرای این دستور، یک فایل Sql از Schema مربوط به دیتابیس mysql اپلیکیشن، در مسیر database/schema، ایجاد می‌شود. این فایل حاوی تمام اطلاعات مورد نیاز برای ایجاد جداول موجود در دیتابیس است.

با افزودن Flag با نام prune، فایل‌های Migration اپلیکیشن نیز با ایجاد فایل Sql، حذف می‌شوند:

php artian schema:dump –prune

با اجرای دستور php artisan migrate، ابتدا فایل Sql موجود در پوشه‌ی schema اجرا می‌شود و پس از آن، فایل‌های Migration موجود در پوشه‌ی migrations اجرا می‌شوند.

Rate Limiter

در نسخه‌های پیشین لاراول، برای مبحث Rate Limiting یا محدود کردن تعداد درخواست‌ها به Resourceها، یک Middleware Group با نام api داریم که در فایل kernel.php موجود در مسیر app/Http تعریف شده است. در این Middleware Group، یک Middleware با نام throttle تعریف شده است. در این Middleware، به طور پیش‌فرض، هر مسیر، با تعداد 60 درخواست در یک دقیقه محدود شده و در فایل RouteServiceProvider هم بر تمام Apiها اعمال شده است.

اما در لاراول 8، می‌توانیم با استفاده از Facade RateLimiter، به تعداد دلخواه Rate Limiter ایجاد کنیم. این کار را باید در متد ()ConfigureRateLimiting که در انتهای فایل RouteServiceProvider است، انجام دهیم. برای مثال:

RateLimiter::for('writer', function (Request $request) {
    return Limit::perMinute(50);
});

در قطعه کد فوق، نام Rate Limiter را که در این‌جا writer است، به عنوان پارامتر اول و یک Closure را به عنوان پارامتر دوم، به متد ()for پاس داده‌ایم. یک نمونه از کلاس Request را به Closure پاس می‌دهیم تا محدودیت‌های لازم را با استفاده از متدهای مختلف کلاس Limit، بر روی درخواست Http، ایجاد کنیم. پس از تعریف Rate Limiter، می‌توانیم با استفاده از throttle Middleware، به شیوه‌ی زیر از آن استفاده کنیم:

Route::get('/download, [DownloadController::class, 'getFile'])->middleware(['throttle:writer']);

و یا به شکل زیر برای گروهی از مسیرها:

Route::middleware(['throttle:writer'])->group(function () {
    //
});

لازم به ذکر است که Rate Limiter‌ها به همین شکل برای مسیرهای تعریف شده در فایل web.php هم قابل استفاده هستند.

Events and Listeners

در نسخه‌های قبلی لاراول، اگر بخواهیم Listener را به صورت یک Closure در متد ()boot موجود در فایل EventServiceProvider، ایجاد کنیم، به صورت زیر عمل می‌کنیم:

Event::listen(RegisterEvent::class, function(RegisterEvent $event) { 
    // Do something
});

‌اما در نسخه‌ی جدید لاراول یعنی لاراول 8، فقط Closure را در همان پارامتر اول به متد ()listen پاس می‌دهیم:

Event::listen(function(RegisterEvent $event) { 
    // Do something
});

اما نکته مهم‌تر آن است که در لاراول 8، می‌توان Listener تعریف شده به شکل فوق را در صف یا به اصطلاح Queue قرار داد که در نسخه‌های پیشین لاراول، این امکان میسر نبود. می‌توان برای Listenerهایی که اجرایشان طول می‌کشد، با استفاده از تابع ()queueable، از این قابلیت به شکل زیر استفاده کرد:

use function Illuminate\Events\queueable;

Event::listen(queueable(function(RegisterEvent $event) { 
    // Do something
})->onQueue(‘high’)->delay(now()->addMinutes(5)));

همان طور که می‌بینید مثل جاب‌هایی که در Queue قرار می‌دهیم، می‌توان متدهای ()onQueue() ،onConnection و ()delay را به صورت زنجیره‌ای در ادامه‌ی تابع ()queueable تعریف کرد.

Job Batching

Job Batching قابلیت جدید و قدرتمندی است که در نسخه‌ی 8 لاراول وجود دارد. با استفاده از این ویژگی، می‌توانیم چند Job را به صورت همزمان یا در قالب یک Batch، به صف یا Queue ارسال کنیم. می‌توانیم تمام Jobهای خود را در قالب یک آرایه، به متد ()batch تعریف شده در Bus Facade پاس دهیم. این ویژگی زمانی مفید است که بتوانیم از Callback Completion‌ها استفاده کنیم تا بعد از اجرای دسته‌ای از جاب‌ها اجرا شوند. متدهای ()then() ،catch و ()finally را می‌توانیم برای تعریف Callback برای یک Batch مورد استفاده قرار دهیم. هر کدام از این Callback ها، یک نمونه از کلاس Illuminate\Bus\Batch را به عنوان پارامتر ورودی دریافت می‌کنند:

use App\Jobs\SendEmailJob;
use App\Models\User;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
use Throwable;

$batch = Bus::batch([
    new SendEmailJob(User::find(1)),
    new SendEmailJob(User::find(2)),
    new SendEmailJob(User::find(3)),
    new SendEmailJob(User::find(4)),
    new SendEmailJob(User::find(5)),
])->then(function (Batch $batch) {
    //
})->catch(function (Batch $batch, Throwable $e) {
    //
})->finally(function (Batch $batch) {
    //
})->dispatch();

متد ()then هنگامی اجرا می‌شود که همه‌ی Jobهای ارسال شده در Batch، با موفقیت اجرا شوند. متد ()catch، پس از آن ‌که اولین اخطار در اجرای Jobها شناسایی شد، اجرا می‌شود. متد ()finally نیز زمانی اجرا می‌شوند که اجرای همه‌ی Jobهای یک Batch به پایان برسد، خواه همه‌ی Jobها با موفقیت اجرا شده باشند، خواه تعدادی به خطا برخورد کرده باشند.

حالت تعمیر و نگهداری (Maintenance Mode)

پیش از این، برای Down کردن موقتی وب سایت به منظور تعمیر و نگهداری، از دستور php artisan down استفاده می‌کردیم. در حالت تعمیر و نگهداری، با اجرای دستورات Composer، وابستگی‌ها به‌روز می‌شوند. در نتیجه محتویات پوشه‌ی vendor به‌روز و فایل autoload جدید ایجاد می‌شود. اپلیکیشن در این حالت، به جای صفحه‌ی مربوط به حالت تعمیر و نگهداری، اخطارهای دیگری را به کاربران نمایش می‌دهد. چرا که برای نمایش صفحه‌ی فوق، نیاز است تا کل اپلیکیشن Boot شود.

اما در لاراول 8، یک Flag جدید با نام render تعریف شده است که می‌توانید نام View موردنظرتان را به آن پاس دهید. لاراول در این حالت، ابتدا صفحه موردنظر را رندر می‌کند و سپس عملیات مربوط به تعمیر و نگهداری را انجام می‌دهد.

Flag دیگر، secret است که شما یک رشته‌ی دلخواه را به آن پاس می‌دهید. توسعه‌دهنده‌ای که از این رشته در آدرس URL استفاده می‌کند، می‌تواند در حالتی که اپلیکیشن به منظور تعمیر و نگهداری، Down است و کاربران به آن دسترسی ندارند، به صفحات مختلف اپلیکیشن دسترسی داشته باشد. در این حالت، برای توسعه‌دهنده یک کوکی ایجاد و ذخیره می‌شود.

با استفاده از Flag دیگری با نام redirect می‌توان تمام درخواست‌ها را به یک URL مشخص هدایت کرد. همچنین می‌توان با استفاده از Flag با نام status، کد وضعیت Http را ست کرد. برای مثال می‌توان از دستور زیر استفاده کرد:

php artisan down --status=200 --secret="1630542a-246b-4b66-afa1-dd72a4c43515" --render="errors.custom-error"

تغییرات و ویژگی‌های لاراول 8

برای دسترسی توسعه‌دهنده به صفحات، secret باید به شکل زیر در آدرس URL استفاده شود:

https://example.com/1630542a-246b-4b66-afa1-dd72a4c43515

Pagination Views

Paginator در لاراول 8 به صورت پیش‌فرض از فریم‌ورک Tailwind Css، به جای Bootstrap استفاده می‌کند. اگر نیاز دارید که از همان فریم ورک Bootstrap استفاده کنید، می‌توانید در متد ()boot در فایل AppServiceProvider، از متد ()useBootstrap مربوط به Paginator استفاده کنید:

use Illuminate\Pagination\Paginator;

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

دستور serve

در نسخه‌های پیشین لاراول، در صورت استفاده از سرور داخلی PHP با دستور php artisan serve، اگر تغییری در فایل env. صورت بگیرد، ناچاریم سرور را Restart کنیم. در لاراول 8، با تغییر فایل env.، عمل Restart به صورت خودکار انجام می‌گیرد.

منابع تکمیلی

برای مشاهده لیست کامل تغییرات انجام شده در نسخه‌ی 8 لاراول، به مستندات مربوطه در وبسایت لاراول مراجعه کنید.

جمع‌بندی:

در مقاله‌ی فوق از سری مقالات آموزش لاراول، سعی کردیم مهم‌ترین تغییرات لاراول 8 نسبت به نسخه‌ی 7 را برای شما بیان کنیم. واکنش‌ها نسبت به این تغییرات، متفاوت بوده است. بعضی از توسعه دهندگان، اجبار به استفاده از Livewire یا Inertiajs را در پکیج Jetstream، یک مساله‌ی منفی تلقی می‌کنند و برخی‌ها نیز ویژگی‌های جدیدی که این پکیج برای بحث احراز هویت در اختیار توسعه‌دهندگان قرار می‌دهد را ستوده‌اند. در مجموع ویژگی‌های جدیدی که در لاراول 8 قابل مشاهده است و اصلاحاتی که انجام شده، مثبت ارزیابی می‌شوند. هر چند باید دید که این ویژگی‌ها و اصلاحات، در دراز مدت جای خود را در میان توسعه‌دهندگان باز می‌کنند یا این که از نسخه‌های آتی لاراول حذف خواهند شد.

اگر نظر یا سوالی دارید، خوشحال می‌شویم آن را در قسمت نظرات با ما و سایر کاربران سون لرن به اشتراک بگذارید.

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

چه امتیازی به این مقاله می دید؟
نویسنده رضا زیدی
از یادگیری ، عمل‌گرایی و چالش‌های مربوطه ، لذت می‌برم ...

نظرات کاربران

اولین دیدگاه این پست رو تو بنویس !

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :