


لاراول 8 - آشنایی با ویژگی ها و تغییرات Laravel8
لاراول 8 در ٨ سپتامبر ٢٠٢٠ منتشر شد و مثل تمامی آپدیت ها سروصدای زیادی به پا کرد. ما در این مقاله تمام تغییرات نسخه آخر LARAVEL را بررسی میکنیم.
از انتشار ورژن ٨ لاراول خیلی نگذشته، برای همین بهتر است در مورد تغییرات جذاب و کاربردی این ورژن از فریمورک لاراول صحبت کنیم. با توجه به اعلام آقای تیلور آتول، از ورژن هفت به بعد لاراول از روش ورژنینگ (versioning) جدیدی به نام semantic versioning استفاه میکند و قرار است هر شش ماه یک بار تغییرات عمدهای بر روی لاراول منتشر شوند. نسخه ٨ لاراول در ٨ سپتامبر ٢٠٢٠ منتشر شد. برای یادگیری آخرین نسخه این فریورک محبوب آموزش لاراول 8 را مشاهده کنید.
برای upgrade از نسخه ٧ به ٨ لاراول پکیج های زیر در composer.json باید آپدیت شوند:
- guzzlehttp/guzzle to ^7.0.1
- facade/ignition to ^2.3.6
- laravel/framework to ^8.0
- laravel/ui to ^3.0
- nunomaduro/collision to ^5.0
- phpunit/phpunit to ^9.0
در laravel8 ساختار کلی لاراول چندان تفاوتی نکرده اما چند تغییر بسیار مهم در لاراول وجود دارد. از جمله این که seeder ها و factory ها دارای namespace خواهند بود. و این که seeder ها به جای دایرکتوری seeds در دیرکتوری seeders قرار خواهند گرفت:
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
...
}
}
اگر از پکیج laravel/legacy-factories استفاده میکنید، لازم نیست هیچ تغیری بر factory های خود اعمال کنید. به هر حال، اگر factory های خود را upgrade میکنید، لازم است این namespace را به این کلاس ها اضافه نمایید:
Database\Factories
در قدم بعدی در فایل composer.json بلاک classmap را از autoload حذف کنید و قطعهی زیر را اضافه نمایید:
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
در ادامه به بررسی سایر تغییرات می پردازیم:
پکیج Laravel JetStream در لاراول 8
این پکیج توسط آقای تیلور آتول توسعه داده شده است. این پکیج شامل امکاناتی برای لاگین، ثبت نام، اعتبار سنجی ایمیل، احراز هویت دو مرحله ای (two factor authentication)، مدیریت session ها، امکان پیاده سازی API و امکان مدیریت تیم ها را با Role/Permission (مدیریت دسترسی ها و نقش ها) را فراهم میکند.
این پکیج از livewire و همچنین inertia استفاده میکنند. Livewire فریمورکی است برای ایجاد ui که ساختن صفحات داینامیک با لاراول را ساده میکند. همچنین inertia ابزای برای ساختن اپ های تک صفحهای با استفاده از روتینگ لاراول است.
دوره های پیشنهادی: کامل ترین پکیج آموزش Laravel 8 ✅ + آموزش لاراول پروژه محور
دایرکتوری Models
از لاراول ٤ به بعد، مدل های لاراول در مسیر app قرار میگرفتند. برای بسیاری از برنامه نویس ها این مسیر حس شلختگی و بی نظمی را ایجاد میکرد، برای همین بعضی از توسعه دهندگان خودشان وارد عمل میشدند و مدل های خود را در مسیر app/Models قرار میدادند.
اما در لاراول 8 دوباره فولدر Models به دایرکتوری های اصلی لاراول اضافه شد. تمام دستورات مربوط هم با این تغییر هماهنگ شدهاند. درصورتی که مسیر Models در پروژه موجود نباشد(توسط توسعه دهنده حذف شود) فرض لاراول بر این است که مدل ها در مسیر app قرار بگیرند.
مقاله مرتبط: آشنایی با middleware ها در لاراول
کلاس های Model Factory در لاراول 8
در ورژن آخر لاراول Factory ها به طور کلی بازنویسی شدهاند و استفاده از آن ها به شیوەای متفاوت و بسیار خوانا تر از قبل امکان پذیر است. با اجرای دستور UserFactory php artisan make:factory در لاراول ٨ کلاسی مشابه کلاس زیر ایجاد خواهد شد(البته کلاس 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),
];
}
}
همانطور که در کد مشخص است باید در تابع definition فیلد های مدل خود را مقدار دهی کنیم. برای استفاده از این کلاس کافیست تا یک trait به نام HasFactory را در مدل User فرخوانی کنید. برای ایجاد رکوردهای فیک خود از این به بعد از کد زیر میتوانید استفاده کنید:
\App\Models\User::factory()->count(50)->create();
اما برای تعریف state ها هم میتوان از همین کلاس ها استفاده کرد. برای افزودن و استفاده از حالت ها کافیست تابعی را هم نام با حالت مد نظر تعریف کنیم.
public function suspended()
{
return $this->state([
'account_status' => 'suspended',
]);
}
برای افزودن حالت به داده های تولید شده توسط Factory باید تابع حالت (در اینجا suspended) پس از تابع count فراخوانی کنیم:
\App\Models\User::factory()->count(50)->suspended()->create();
از دیگر ویژگی های جذاب Factory در لاراول ٨ امکان استفاده از روابط روی Factory هاست. به عنوان مثال اگر در مدل User رابطهی زیر برقرار باشد:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Models\Post;
class User extends Authenticatable
{
use HasFactory, Notifiable;
public function posts()
{
return $this->hasMany(Post::class);
}
}
در این صورت قطعه کد زیر یک آبجکت از User همراه با سه پست به ما خواهد داد:
$users = User::factory()
->hasPosts(3, [
'published' => false,
])
->create();
Migration Squash
ممکن است در پروژهی شما، مایگریشن ها بسیار پر تعداد شوند. و به تبع آن مدیریت میگریشن ها سخت شود. در لاراول ٨ برای دیتابیس های MySql و PostgreSql این امکان را فراهم کرده که از مایگریشن های خود خروجی با فرمت sql بگیرید. با وارد کردن دستور artisan زیر :
php artisan schema:dump
درصورتی که فایل sql در مراحل قبلی ایجاد شده باشد، ابتدا این فایل اجرا خواهد شد، و درصورتی که میگریشن جدیدی اضافه کرده باشید، این میگریشن با دستور فوق به فایل sql اضافه خواهد شد.
در صورتی که بخواهیم فایل sql از ابتدا ساخته شود باید به صورت زیر عمل کنیم:
php artisan schema:dump –prune
اجرای دستهایی job ها در لاراول
این ویژگی لاراول به شما کمک میکند تا گروهی از job ها را به سادگی فراخوانی و اجرا کنید. بر روی فساد (Facade) Bus تابع جدیدی به نام batch اضافه شده که این امکان را برای ما فراهم میکند.
use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
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 ها درست و بدون مشکل انجام شوند، اجرا خواهد شد، درصورتی که اولین job دچار مشکل شود قطعهی catch اجرا خواهد شد. در صورتی که اجرای batch به اتمام برسد قطعهی finaly به اجرا در خواهد آمد.
بهبود RateLimiting در Laravel8
احتمالا از میان افزار (middleware) throttle قبلا استفاده کردەاید. در نسخه ٨ لاراول امکان استفاده از Rate Limiting به صورت خواناتر و البته با پرفورمنس بیشتر فراهم شده.
قبلا با استفاده از throttle میتوانستیم یک rate limit به شکل زیر برای route هایمان در لاراول تعریف کنیم:
Route::middleware('throttle:60,1')->get('/user', function () {
//
});
همانطور که میدانید این کد به این معنی است که در یک دقیقه میتوان به این route به صورت متوالی ٦٠ درخواست فرستاد. در نسخه جدید لاراول میتوان در RouteServiceProvide همراه با اسم مد نظر و به صورت خوانا rate limit تعریف کرد:
RateLimiter::for('testing', function (Request $request) {
return Limit::perMinute(1000);
});
و حالا ما میتوانیم به جای 60,1 بیایم و اسم testing رو به مسیر مد نظرمان اختصاص بدهیم. به این شکل:
Route::middleware('throttle:testing')->get('/user', function(){
//
});
شما میتوانید برای rate limit خود رسپانس مد نظر خود را تعریف کنید:
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000)->response(function () {
return response('Custom response...', 429);
});
});
حتی میتوانید بر اساس نقش کاربر درخواس دهنده rate limit را تعیین کنید:
RateLimiter::for('uploads', function (Request $request) {
return $request->user()->vipCustomer()
? Limit::none()
: Limit::perMinute(100);
});
بهبود حالت نگهداری (Maintenance Mode)
در نسخه های قبلی لاراول، دستور php artisan down یک امکان داشت و آن هم این بود که ip هایی که در حالت نگهداری در لیست “allow list” قرار داشتند، اجازە داشتند که به سایت یا اپلیکیشن دسترسی داشته باشند. این ویژگی در نسخه جدید لاراول برداشته شده و ویژگی جایگزین آن که از توکن استفاده می کند بسیار ساده تر است.
هنگامی که از حالت نگهداری استفاده میکنید، میتوانید یک توکن را به شکل زیر به برنامه خود اختصاص دهید:
php artisan down --secret="1630542a-246b-4b66-afa1-dd72a4c43515"
پس از اختصاص توکن، برنامه از طریق توکن اختصاص داده شده در دسترس خواهد بود.
https://example.com/1630542a-246b-4b66-afa1-dd72a4c43515
پس از دسترسی به این مسیر پنهان، شما به مسیر اصلی پروژه انتقال خواهید یافت. پس از این که کوکی برای شما ست شد، شما به این پروژه مانند هنگامی که در حالت نگهداری نیست دسترسی خواهید داشت.
نکتهای دیگر
شما ممکن است در هنگام دپلوی پروژه خود از حالت نگهداری استفاه کنید اما همچنان بخاطر آپدیت شدن پکیج های کامپوزر و اتفاقاتی از این دست، کاربر شما در زمان دپلوی به سایت شما درخواستی ارسال کند و خطایی را دریافت کند.
برای جلوگیری از این اتفاق، امکان جدیدی فراهم شده تا در هنگام درخواست کاربر، پیش از هر پردازش دیگری، یک فایل view خاص اجرا شود. شما میتوانید فایل مد نظر خود را به صورت یک فلگ در هنگام اجرای دستور حالت نگهداری مشخص کنید.
php artisan down --render="errors::503" php artisan down --render="errors::503"
بهبود دستور serve
در نسخه های قبلی لاراول در صورتی که در فایل .env تغیری ایجاد میشد، شما میبایست یک بار پروژه را متوقف و از ابتدا serve میکردید، که در ورژن ٨ لاراول ایم مسئله بهبود یافته و تغییرات .env در حین اجرای پروژه اعمال میشوند.
بهبود Event Listener
در نسخه جدید لاراول، با یک تابع callback میتوانید event ها را فراخوانی کنید:
use App\Events\PodcastProcessed;
use Illuminate\Support\Facades\Event;
Event::listen(function (PodcastProcessed $event) {
//
});
به علاوە، میتوان event ها را بە شکل queueable هم فراخوانی نمود:
use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
Event::listen(queueable(function (PodcastProcessed $event) {
//
}));
همانند queued job امکان تعریف connection, onQueue و delay روی event ها هم فراهم شده است تا اجرای event ها بصورت customize ممکن شود:
Event::listen(queueable(function (PodcastProcessed $event) {
//
})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));
اگر event ها بصورت صف فراخوانی شوند، در صورتی که اجرای یکی از صف ها fail شود و بخواهید fail شدن بصورت نا محسوس انجام شود، میتوانید از تابع catch استفاده کنید:
use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
use Throwable;
Event::listen(queueable(function (PodcastProcessed $event) {
//
})->catch(function (PodcastProcessed $event, Throwable $e) {
// The queued listener failed...
}));
به روز آوری Routing NameSpace در لاراول8
این تغییر که کمتر در جاهای مختلف به آن اشاره شده نحوه فراخوانی توابع action در کنترلر هاست. در نسخه های قبل تر لاراول فراخوانی توابع action به شکل زیر انجام میشد:
Route::get(‘/users’, ‘UserController@index’);
اما در نسخه ٨ فراخوانی توابع action به شکل زیر انجام میشود:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
اگر روش قبلی موجود در ورژن های قبلی لاراول را ترجیح میدهید، میتوانید $nameSpace را به عنوان یک متغیر کلاسی در RouteServiceProvider اضافه کنید:
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/home';
/**
* If specified, this namespace is automatically applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60);
});
}
}
کامپوننت های داینامیک (پویا) در blade
اگر به نسبت شرایط قرار است از بین چند کامپوننت، یکی را انتخاب کنید، لاراول این امکان را برای شما فراهم کرده است. در این صورت شما میتوانید نام کامپوننت مد نظر را بە صورت متغیر ارسال کنید.
<x-dynamic-component :component="$componentName" class="mt-4" />
سفر در زمان با لاراول
در هنگام تست، ممکن است لازم شود زمان را تغییر دهید. اکنون در کلاس های تست لاراول این امکان فراهم شده تا بتوانید زمان را تغییر دهید.
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();
}
صفحه بندی با استفاده از TailWind
لاراول٨ برای pagination خود اکنون از tailwind استفاده میکند. TailWind یک فریمورک سطح بالای css است که اخیرا به لاراول اضافه شده. این فریمورک تمام اجزای مورد نیاز شما در یک صفحه وب را در اختیارتان قرار میدهد. البته همچنان Bootstrap3, 4 همچنان در لاراول قابل استفاده هستند.
اگر میخواهید همچنان از Bootstrap استفاده کنید در داخل متد boot از AppServiceProvider میتوانید کد زیر را اضافه کنید:
use Illuminate\Pagination\Paginator;
Paginator::useBootstrap();