รับ UUID และ ULID จาก request เป็น object
เดิมเรามี $request->date() กับ $request->enum() ที่แปลงค่าให้เลย Pawel เพิ่ม uuid() กับ ulid() เข้าไปในชุดเดียวกัน (PR #62327, #62348)
$request->uuid('order_id'); // Ramsey\Uuid\UuidInterface|null
$request->ulid('order_id'); // Symfony\Component\Uid\Ulid|null
$request->safe()->uuid('order_id'); // จากค่าที่ validate แล้ว
- ถ้าไม่ได้ส่งค่ามาหรือส่งค่าว่าง จะได้
null - ถ้าส่งค่าที่ไม่ใช่ UUID จะโยน exception ทันที ไม่คืน string แปลก ๆ ไปถึง query
ulid()รับแค่ ULID จริง ส่ง UUID มาก็โยน exception ไม่แอบแปลงให้เป็น ULID อีกตัว
เมธอดอยู่ใน trait InteractsWithData จึงใช้ได้กับ Fluent, ค่าที่ validate แล้ว, query string ของ Uri, attribute ของ component และ input ของคำสั่ง artisan ด้วย
ระบบที่ใช้ UUID เป็นเลขอ้างอิงที่ส่งออกไปข้างนอก เช่นลิงก์ชำระเงินหรือ webhook จาก payment gateway จะได้ประโยชน์ตรงนี้ เพราะค่าที่ไม่ใช่ UUID หยุดตั้งแต่ตอนอ่าน แต่ถ้าอยากตอบผู้ใช้เป็นข้อความ validation ที่อ่านรู้เรื่อง ยังควรใส่กฎ uuid ไว้ก่อนเหมือนเดิม แนวคิดเดียวกับโหมด strict ที่มากับ 13.40
รู้ทันทีเมื่อ migration ล้มเหลว
Jack Bayliss เพิ่ม event MigrationFailed (PR #62342) ยิงเมื่อ migration โยน exception มี migration, method และ name เหมือน event อื่นของ migration และมี exception เพิ่มมา ส่วน exception ตัวจริงยังโยนต่อเหมือนเดิม คำสั่ง migrate จึงยังจบด้วย error
เรื่องนี้สำคัญกับคนใช้ MySQL หรือ MariaDB เพราะสองตัวนี้ commit คำสั่งเปลี่ยนโครงสร้างตาราง (DDL) อย่าง ALTER TABLE ทันทีที่รัน ถ้า migration หนึ่งไฟล์มีสามคำสั่ง แล้วคำสั่งที่สามพัง สองคำสั่งแรกจะค้างอยู่ในฐานข้อมูล กลายเป็นตารางที่เปลี่ยนไปครึ่งเดียว ในขณะที่โค้ดชุดใหม่อาจขึ้นไปแล้ว (PostgreSQL ไม่มีปัญหานี้ เพราะ DDL อยู่ใน transaction ได้)
use Illuminate\Database\Events\MigrationFailed;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
Event::listen(function (MigrationFailed $event) {
Artisan::call('down');
Log::channel('slack')->critical("Migration [{$event->name}] failed", [
'exception' => $event->exception->getMessage(),
]);
});
ใครที่ deploy ด้วยสคริปต์ที่รัน migrate --force ก่อนสลับโค้ด สคริปต์ส่วนใหญ่จะหยุดเองเมื่อ migrate จบด้วย error อยู่แล้ว event นี้ช่วยตรงที่เราได้ชื่อไฟล์กับข้อความ error ส่งเข้า LINE หรือ Telegram ทันที และเลือกได้ว่าจะปิดเว็บไว้ก่อนให้ผู้ใช้ไม่เจอหน้าพังจากตารางที่เปลี่ยนไปครึ่งเดียว
scheduler บอกเหตุผลที่ข้ามงาน
13.40 ให้ scheduler ยิง ScheduledTaskSkipped เมื่องาน onOneServer() รันไปแล้วบนเครื่องอื่น รุ่นนี้ Jack Bayliss เพิ่ม reason ให้ event (PR #62294) เป็น enum ScheduledTaskSkipReason สามค่า
| ค่า | ความหมาย |
|---|---|
ConditionNotMet |
เงื่อนไขใน when() หรือ skip() ไม่ผ่าน |
Paused |
งานโดนพักไว้ |
RanOnAnotherServer |
onOneServer() และเครื่องอื่นรันไปแล้ว |
Event::listen(function (ScheduledTaskSkipped $event) {
Log::info('Scheduled task skipped', [
'task' => $event->task->getSummaryForDisplay(),
'reason' => $event->reason?->value,
]);
});
เวลารายงานประจำวันไม่ออก log บรรทัดนี้บอกได้เลยว่าเงื่อนไขไม่ผ่านหรือเครื่องอื่นรับไปแล้ว ไม่ต้องเดา แต่ถ้า scheduler ไม่ได้รันเลยเพราะเซิร์ฟเวอร์ล่ม จะไม่มี event ไหนยิง เรื่องนั้นต้องแก้อีกทาง ซึ่งเขียนไว้ในโพสต์เรื่องงานที่ scheduler พลาดไปตอนเซิร์ฟเวอร์ล่ม
อีกเรื่องของ scheduler คือ schedule:list --json คืน cron expression และ timezone ของแต่ละงานตามที่ตั้งไว้จริง (PR #62352) เดิมแปลงเป็น timezone ของแอปทุกงาน ประเทศที่มี daylight saving จึงเพี้ยนไปหนึ่งชั่วโมง ไทยไม่มีปัญหานี้ แต่ถ้ามีสคริปต์ที่อ่าน JSON นี้อยู่ และมีงานที่ตั้ง timezone() แยกเอง ค่า expression, timezone และ next_due_date ของงานนั้นจะเปลี่ยน
เทียบ origin ของสอง URL ด้วย Uri::origin()
Naoya Miyagawa เพิ่ม Uri::origin() (PR #62326) คืน scheme, host และ port ที่ normalize แล้ว เช่น https://App.example.com:443 จะได้ https://app.example.com
use Illuminate\Support\Uri;
$sameOrigin = Uri::of($first)->origin() === Uri::of($second)->origin();
ใช้เช็ค URL ที่ผู้ใช้ส่งมาได้ เช่นพารามิเตอร์ redirect หลังล็อกอิน ว่าพากลับมาที่เว็บเราเอง ไม่ใช่เว็บอื่น ซึ่งเทียบด้วย string ตรง ๆ มักพลาดเรื่องตัวพิมพ์ใหญ่กับ port :443 รุ่นนี้ต้องใช้ league/uri 7.6 ขึ้นไป composer update จะดึงมาให้
ของที่เพิ่มอีกเล็กน้อย
LostConnectionDetector::detectUsing()(PR #62316) เพิ่มข้อความ error ที่ให้ Laravel ถือว่า connection หลุดแล้วต่อใหม่ได้เอง เหมาะกับฐานข้อมูลที่ข้อความ error ไม่อยู่ในรายการของ LaravelPendingProcessใส่ macro ได้ (PR #62351) เดิม macro บนProcessใช้ได้แค่เป็นตัวแรกของ chain ตอนนี้ต่อหลังtty()หรือเมธอดอื่นได้- Ably SDK เปลี่ยนชื่อ เป็น
ably/pubsub-server(PR #62315)install:broadcasting --ablyติดตั้งตัวใหม่ให้ แอปที่ใช้ably/ably-php1.x อยู่ยังทำงานได้
ของที่แก้ใน 13.42
TokenGuard::validate()hash token ก่อนเทียบ เมื่อเปิด hashing ไว้ (PR #62336) เดิม token ที่ถูกต้องก็ได้false- PostgreSQL ต่อใหม่ได้หลัง commit พังเพราะ connection หลุด (PR #62366) Laravel ทิ้ง PDO ตัวเก่า transaction ถัดไปจึงไม่พังตามทุกตัว ต่อเนื่องจากที่แก้ไว้ใน 13.40
foreignIdFor()สร้างคอลัมน์bigintสำหรับ model ที่ตั้ง$keyType = 'integer'(PR #62365) เดิมได้char(36)cursor()เคารพModel::preventLazyLoading()แล้ว (PR #62345)dispatch()->afterResponse()report exception แทนการพยายาม render (PR #62313) error จาก job หลังส่ง response จึงเข้า log หรือ error tracker ตามปกติ- JSON:API ไม่ใส่ resource ซ้ำ เมื่อ
BelongsToManyชี้ไปที่ตัวเดียวกัน (PR #62360)
รายละเอียดและตัวอย่างครบทุก PR อยู่ในโพสต์ต้นฉบับของ Laravel News ครับ






