Laravel 13.20: پردازش تصویر بدون package شخص ثالث
یه کار که تقریباً هر پروژهی Laravel ای در یه نقطهای بهش نیاز داره اینه که تصویر آپلودشده رو resize کنه، فرمتش رو عوض کنه، یا یه thumbnail ازش بسازه. تا الان برای این کار حتماً باید یه package جداگانه نصب میکردی — معمولاً intervention/image — و بعد خودت wrapper مینوشتی. Laravel 13.20 که ۱۴ جولای ۲۰۲۶ منتشر شد، این کار رو داخل خود فریمورک آورده.
Image facade: پردازش تصویر first-party
یه Image facade جدید اضافه شده که یه API immutable برای تبدیل تصاویر داره. immutable یعنی هر transformation یه instance جدید برمیگردونه — یعنی میتونی از یه تصویر چند variant مختلف بسازی بدون اینکه مشکل side effect داشته باشی.
رایجترین حالت استفاده اینه که مستقیم از request بگیری:
$request->image('avatar')
->cover(200, 200)
->toWebp()
->store('avatars');
ولی میتونی از هر جایی image بسازی:
Image::fromPath('/path/to/photo.jpg');
Image::fromUrl('https://example.com/photo.jpg');
Image::fromBytes($bytes);
Image::fromStorage('photos/avatar.jpg', 's3');
Storage::disk('s3')->image('photos/avatar.jpg');
transformationهایی که در دسترسن:
$image->cover(200, 200); // crop و resize با هم
$image->contain(800, 600); // resize بدون crop
$image->crop(200, 200);
$image->resize(1024, 768);
$image->scale(1200, 800);
$image->rotate(90);
$image->blur(10);
$image->sharpen(10);
$image->grayscale();
$image->flip();
$image->flop();
$image->orient(); // EXIF rotation رو اعمال میکنه
برای output هم:
$image->toWebp();
$image->toJpg()->quality(80);
$image->optimize(); // WebP با quality 70
$image->optimize('jpg', 85);
چون immutable هست، ساختن چند variant از یه عکس تمیزه:
$image = $request->image('photo');
$image->cover(200, 200)->toWebp()->store('thumbnails');
$image->grayscale()->toWebp()->store('grayscale');
دو driver داره — GD و Imagick — و میتونی per-image هم انتخاب کنی:
$image->usingGd();
$image->usingImagick();
یه نکتهی مهم: خود intervention/image بهعنوان suggested dependency اضافه شده، نه required. یعنی باید خودت نصبش کنی:
composer require intervention/image
ویژگی WithoutMiddleware
یه attribute جدید اضافه شده که counterpart ویژگی #[Middleware] هست. تا الان میتونستی روی کل controller یه middleware بذاری و برای بعضی method ها استثنا بدی. حالا این کار رو میتونی با attribute بکنی:
#[Middleware(EnsureTokenIsValid::class)]
class UserController
{
public function index()
{
// middleware اینجا اعمال میشه
}
#[WithoutMiddleware(EnsureTokenIsValid::class)]
public function profile()
{
// اینجا اعمال نمیشه
}
}
یه نکتهی ظریف: از ReflectionAttribute::IS_INSTANCEOF استفاده میکنه، یعنی subclass های اون middleware هم automatically exclude میشن.
پیشوند جداگانه برای Session در Redis
اگه هم SESSION_DRIVER و هم CACHE_STORE هر دو به Redis اشاره میکنن، تا الان session ها از همون prefix که برای cache تنظیم کردی استفاده میکردن. این debug کردن Redis keyspace رو مشکل میکرد.
حالا میتونی توی config/session.php یه prefix جداگانه بذاری:
'prefix' => env('SESSION_PREFIX', Str::slug(env('APP_NAME', 'laravel')).'-session-'),
cache store قبل از اعمال session prefix کلون میشه، پس این تغییر روی cache key ها تاثیر نمیذاره.
incrementEachQuietly و decrementEachQuietly
Eloquent قبلاً incrementQuietly() و decrementQuietly() داشت که یه column رو بدون trigger کردن model event تغییر میدادن. این نسخه نسخهی multi-column اینا رو اضافه کرده:
$user->incrementEachQuietly(['posts_count' => 1, 'points' => 10]);
$user->decrementEachQuietly(['credits' => 3, 'tokens' => 2]);
وقتی داری یه batch operation انجام میدی و نمیخوای event هایی مثل saved یا updated fire بشن، این دقیقاً چیزیه که میخوای.
Enum بهعنوان کلید WithoutOverlapping
WithoutOverlapping middleware برای queue jobs الان مستقیم enum قبول میکنه:
public function middleware(): array
{
return [new WithoutOverlapping($this->category)];
}
قبلاً باید enum رو به string تبدیل میکردی. این تغییر backward compatible هست.
بقیه چیزهای کوچیک ولی مفید
چند چیز دیگه که کمتر headline میگیرن ولی در عمل کاربرد دارن:
make:migration حالا timestamp prefix هایی میسازه که collision-free و مرتب هستن — مشکل قدیمی که دو migration همزمان ساختهشده اسم تکراری میگرفتن.
#[SensitiveParameter] به parameter هایی که secret حمل میکنن اضافه شده، یعنی password ها و token ها دیگه توی stack trace نمایش داده نمیشن.
Storage::assertEmpty() اضافه شده که توی test ها مفیده.
Str::containsAll() دیگه برای آرایهی خالی true برنمیگردونه — یه bug قدیمی که رفتار غیرمنطقی داشت.
Number::forHumans() دیگه برای عددهای خیلی کوچیک منفی، -0 برنمیگردونه.
upgrade کردن
تغییر breaking ای وجود نداره. اگه میخوای از Image facade استفاده کنی، فقط intervention/image رو نصب کن. بقیهی تغییرات opt-in هستن یا bug fix.
