Codoloper

Laravel 13.20: پردازش تصویر بدون package شخص ثالث

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.

اطلاعات نویسنده
عرفان دهقانی
نوشته ها در PHP
تبلیغات
کامنت جدید

برای ثبت کامنت وارد شوید

برای اینکه بتوانید زیر این پست کامنت بگذارید، باید وارد حساب کاربری خود شوید.

برای ادامه، وارد حساب خود شوید

بعد از ورود، دوباره به همین پست برمی‌گردید و می‌توانید کامنتتان را ثبت کنید.

ورود به حساب
کامنت‌ها

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

دیدگاه‌هایی که برای این نوشته ثبت شده‌اند.

هنوز کامنتی برای این پست ثبت نشده است.