<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2142305340755025784</id><updated>2026-07-02T22:58:54.150+07:00</updated><category term="PHP CI MANIA"/><category term="PHP"/><category term="CodeIgniter"/><category term="MySQL"/><category term="เขียนโปรแกรม"/><category term="JavaScript"/><category term="มือใหม่หัดเขียน PHP"/><category term="jQuery"/><category term="ฐานข้อมูล"/><category term="พื้นฐาน PHP"/><category term="PDF"/><category term="คอร์สสอนเขียนโปรแกรม"/><category term="DateTime"/><category term="Database"/><category term="PDF Generator"/><category term="PHP Array"/><category term="SQL"/><category term="Server"/><category term="Bootstrap"/><category term="CSS"/><category term="Laravel"/><category term="Security"/><category term="TCPDF"/><category term="PHP Excel"/><category term="PHP กับการคำนวณ"/><category term="PHP เบื้องต้น"/><category term="Shopping Cart"/><category term="XAMPP"/><category term="รวมคำสั่ง PHP"/><category term="แนวคิด"/><category term="Booking"/><category term="Chart"/><category term="CodeIgniter 4"/><category term="Coffee Shop"/><category term="FPDI"/><category term="MySQLi"/><category term="Template Engine"/><category term="Web Service"/><category term="บาสเกตบอล"/><category term="มุมกาแฟ"/><category term="เครื่องมือ"/><category term="แนะนำ PHP CI MANIA"/><category term="Debug"/><category term="Email"/><category term="String Functions"/><category term="ฝึกเขียน JavaScript กันเถอะ"/><category term="ระบบบริหารจัดการร้านกาแฟ"/><category term="หนังสือ"/><category term="เทคนิคการพัฒนาตนเอง"/><category term="โจทย์ปัญหา"/><category term="AI"/><category term="AJAX"/><category term="Apache"/><category term="App Review"/><category term="Autocomplete"/><category term="Bootstrap Template"/><category term="CSRF"/><category term="CSV"/><category term="Calendar"/><category term="Claude Code"/><category term="Code Generator"/><category term="Daily Report"/><category term="Deprecated"/><category term="Export"/><category term="Firewall"/><category term="Front-End"/><category term="GoLang"/><category term="HTML5 Canvas"/><category term="HeidiSQL"/><category term="Mail"/><category term="Microservices"/><category term="Notepad++"/><category term="PROJECT"/><category term="Project Management"/><category term="SOAP"/><category term="Select2"/><category term="Session"/><category term="Spring Boot API"/><category term="StackOverflow"/><category term="Trading Diary"/><category term="Validate"/><category term="Vibe Coding"/><category term="Website"/><category term="typeahead"/><category term="ตะกร้าสินค้า"/><category term="นิยาย"/><category term="ฟังก์ชั่นวันเวลา"/><category term="ระบบวัสดุคงเหลือ"/><category term="วันนี้วันพระ"/><category term="สมการ"/><category term="แจกโค้ดฟรี"/><category term="แนะนำวิดีโอ"/><category term="ไมโครคอนโทรลเลอร์"/><title type='text'>PHP Code Mania สร้างเว็บไซต์ด้วยตนเอง</title><subtitle type='html'>วิถีโปรแกรมเมอร์ PHP Code Mania ลดเวลาเขียนโค้ด เพิ่มเวลาพัฒนาระบบมากขึ้น สอนขียนโปรแกรม PHP สำหรับนักพัฒนาเว็บแอพพลิเคชั่น แบ่งปันเทคนิคการเขียนโปรแกรม</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default?start-index=26&amp;max-results=25'/><author><name>SONGCHAI SAETERN</name><uri>http://www.blogger.com/profile/08719799226044438861</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKQAnVYNcgIvg0GkVh6vE8Lb8Wcf6AWsWsLNjYLIp1ep-CHa0NO2X2X7uzRe452h8U_l5KbWwNxR6pR7JZI0vA7dElZBWyHGYwEJfJPQ-lyRFClnREJpvGntFjQUtpzA/s220/17264884_1773567132668281_8741538772126354523_n.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>378</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6473268034977600840</id><published>2026-07-02T22:58:54.150+07:00</published><updated>2026-07-02T22:58:54.150+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>PHP 8.2 ในปี 2026: ทำไมยังเป็นตัวเลือกที่ดีที่สุดสำหรับ CMS ข่าวและอีคอมเมิร์ซ</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEigOK_paiYCFC2K1HsTU6GODBkALehEj3ieq9SO4guSWJt_rGy1_0q9la7qTk6fPadx-02Pf7Hst1Kn7jKr18FA0JxRqLZw1ko_8KAinyBKDs8nxZP6vr7Ov2DfcV4u3x0Xb6VHf1Xij1ypeI7mGMfRpa-MvDvPFT8pjMrd5M7-JTqJaiZRRd0xfuAGhl4&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1536&quot; height=&quot;426&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEigOK_paiYCFC2K1HsTU6GODBkALehEj3ieq9SO4guSWJt_rGy1_0q9la7qTk6fPadx-02Pf7Hst1Kn7jKr18FA0JxRqLZw1ko_8KAinyBKDs8nxZP6vr7Ov2DfcV4u3x0Xb6VHf1Xij1ypeI7mGMfRpa-MvDvPFT8pjMrd5M7-JTqJaiZRRd0xfuAGhl4=w640-h426&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;h1 style=&quot;color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 30px; line-height: 1.4; margin: 10px 0px 20px; text-align: start;&quot;&gt;PHP 8.2 ในปี 2026: ทำไมยังเป็นตัวเลือกที่ดีที่สุดสำหรับ CMS ข่าวและอีคอมเมิร์ซ&lt;/h1&gt;&lt;p class=&quot;lead&quot; style=&quot;background: rgb(246, 243, 255); border-left: 4px solid rgb(124, 58, 237); border-radius: 6px; color: #444444; font-family: Sarabun, -apple-system, sans-serif; font-size: 18px; margin: 20px 0px 30px; padding: 16px 18px; text-align: start;&quot;&gt;ท่ามกลางกระแส PHP 8.4 และ 8.5 ที่ออกมาพร้อมฟีเจอร์ใหม่เพียบ หลายคนอาจสงสัยว่า PHP 8.2 ยัง &quot;ทันสมัย&quot; พอสำหรับการพัฒนาเว็บแอปในปี 2026 อยู่ไหม บทความนี้จะพาไปดูเหตุผลเชิงเทคนิคว่าทำไม PHP 8.2 ถึงยังเป็นจุดยืนที่มั่นคง โดยเฉพาะกับงานสาย CMS ข่าวและอีคอมเมิร์ซ พร้อมตัวอย่างโค้ดบน CodeIgniter 4 และ Laravel สำหรับมือใหม่&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(124, 58, 237); color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 23px; margin: 40px 0px 16px; padding-left: 14px; text-align: start;&quot;&gt;ทำไมต้องพูดถึง PHP 8.2 ในยุคที่ PHP 8.5 ออกมาแล้ว&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ถ้าเราดูตามประกาศเปิดตัวอย่างเป็นทางการ PHP 8.2 ถือเป็นการอัปเดตใหญ่ที่นำเสนอฟีเจอร์สำคัญหลายตัว ไม่ว่าจะเป็น readonly classes, การรองรับ null/false/true เป็น standalone type, DNF Types (Disjunctive Normal Form) รวมถึง extension &quot;random&quot; ตัวใหม่ที่ให้ API เชิงอ็อบเจ็กต์สำหรับสุ่มตัวเลขแบบปลอดภัยกว่าเดิม นอกจากนี้ยังมีการ deprecate dynamic properties เพื่อลดบั๊กที่เกิดจากการพิมพ์ผิดชื่อ property โดยไม่ตั้งใจ&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ประเด็นคือ ฟีเจอร์เหล่านี้ &quot;เพียงพอ&quot; สำหรับงานเว็บแอประดับ production ส่วนใหญ่แล้ว โดยเฉพาะระบบที่เน้นความเสถียรมากกว่าไล่ตามฟีเจอร์ล่าสุด เช่น ระบบ CMS ข่าว หรือแพลตฟอร์มอีคอมเมิร์ซที่ต้องรันตลอด 24 ชั่วโมง&lt;/p&gt;&lt;h3 style=&quot;color: #16213e; font-family: Sarabun, -apple-system, sans-serif; font-size: 19px; margin: 28px 0px 12px; text-align: start;&quot;&gt;เหตุผลเชิงระบบนิเวศ (Ecosystem)&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;หนึ่งในเหตุผลสำคัญคือความเข้ากันได้กับแพลตฟอร์มใหญ่ ๆ ที่ยังใช้งานกันอย่างแพร่หลาย ยกตัวอย่างเช่น Magento ซึ่งเป็นแพลตฟอร์มอีคอมเมิร์ซระดับองค์กรที่ยังคงยืนยันการรองรับ PHP 8.2 อยู่ในเวอร์ชัน 2.4.8 ทำให้ผู้ที่ดูแลระบบ Magento จำนวนมากยังต้อง &quot;ล็อก&quot; เวอร์ชัน PHP ไว้ที่ 8.2 เพื่อความเสถียรของระบบ ไม่สามารถกระโดดไปเวอร์ชันล่าสุดได้ทันที&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;เช่นเดียวกับปัญหาคลาสสิกที่นักพัฒนา Laravel มักเจอ คือ error ประเภท &lt;em&gt;&quot;Composer detected issues in your platform&quot;&lt;/em&gt; เมื่อเวอร์ชัน PHP บนเซิร์ฟเวอร์ไม่ตรงกับที่ dependency ต้องการ ปัญหานี้สะท้อนให้เห็นว่าการเลือกเวอร์ชัน PHP ที่ &quot;เสถียรและมีคนใช้เยอะ&quot; อย่าง 8.2 ช่วยลดความเสี่ยงเรื่อง compatibility ได้มากในระยะยาว เพราะ library ส่วนใหญ่ในตลาดยังทดสอบและซัพพอร์ตเวอร์ชันนี้อย่างต่อเนื่อง&lt;/p&gt;&lt;div class=&quot;pcm-callout&quot; style=&quot;background: rgb(255, 247, 230); border-radius: 8px; border: 1px solid rgb(255, 213, 128); color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 20px 0px; padding: 14px 18px; text-align: start;&quot;&gt;&lt;strong style=&quot;color: #b45309;&quot;&gt;ข้อควรระวัง:&lt;/strong&gt; อย่าใช้วิธีปิด platform check (&lt;code&gt;&quot;platform-check&quot;: false&lt;/code&gt;) เพื่อกลบปัญหาเวอร์ชันไม่ตรงกัน เพราะเป็นการซ่อนปัญหา ไม่ใช่แก้ที่ต้นเหตุ ควรตรวจสอบเวอร์ชัน PHP บนเซิร์ฟเวอร์จริงให้ตรงกับที่ระบบต้องการเสมอ&lt;/div&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(124, 58, 237); color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 23px; margin: 40px 0px 16px; padding-left: 14px; text-align: start;&quot;&gt;ตัวอย่างการใช้ฟีเจอร์ PHP 8.2 ใน CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ฟีเจอร์ readonly properties ของ PHP 8.2 เหมาะมากกับการสร้าง Entity หรือ Value Object ใน CodeIgniter 4 เพราะช่วยป้องกันไม่ให้ค่าถูกเปลี่ยนแปลงโดยไม่ตั้งใจหลังจากสร้างอ็อบเจ็กต์แล้ว ซึ่งมีประโยชน์มากในงาน CMS ข่าวที่ต้องการความชัวร์ว่าข้อมูลบทความจะไม่ถูกแก้ไขกลางทาง&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 18px; color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 18px 0px 26px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;border-radius: 50%; color: #9d9db8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; height: 11px; margin-left: 8px; width: 11px;&quot;&gt;app/Entities/ArticleEntity.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;color: #e4e4f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;ArticleEntity&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;int&lt;/span&gt; $id, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;string&lt;/span&gt; $title, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;string&lt;/span&gt; $slug, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; ?&lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;string&lt;/span&gt; $publishedAt = &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;null&lt;/span&gt; ) {} &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;isPublished&lt;/span&gt;(): &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;bool&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;return&lt;/span&gt; $this-&amp;gt;publishedAt !== &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;null&lt;/span&gt;; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ในตัวคอนโทรลเลอร์ เราสามารถใช้ DNF Types ร่วมกับ union type เพื่อให้โค้ดชัดเจนขึ้นเมื่อรับพารามิเตอร์ที่อาจเป็นได้หลายรูปแบบ:&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 18px; color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 18px 0px 26px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;border-radius: 50%; color: #9d9db8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; height: 11px; margin-left: 8px; width: 11px;&quot;&gt;app/Controllers/News.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;color: #e4e4f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;News&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;extends&lt;/span&gt; BaseController { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;string&lt;/span&gt; $slug) { $model = &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;new&lt;/span&gt; ArticleModel(); $row = $model-&amp;gt;where(&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;slug&#39;&lt;/span&gt;, $slug)-&amp;gt;first(); &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;if&lt;/span&gt; ($row === &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;null&lt;/span&gt;) { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;return&lt;/span&gt; $this-&amp;gt;response-&amp;gt;setStatusCode(404); } $article = &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;new&lt;/span&gt; ArticleEntity( id: $row[&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;id&#39;&lt;/span&gt;], title: $row[&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;title&#39;&lt;/span&gt;], slug: $row[&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;slug&#39;&lt;/span&gt;], publishedAt: $row[&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;] ); &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;return&lt;/span&gt; view(&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;news/show&#39;&lt;/span&gt;, [&lt;span class=&quot;str&quot; style=&quot;color: #c3e88d;&quot;&gt;&#39;article&#39;&lt;/span&gt; =&amp;gt; $article]); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(124, 58, 237); color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 23px; margin: 40px 0px 16px; padding-left: 14px; text-align: start;&quot;&gt;ตัวอย่างการใช้ฟีเจอร์ PHP 8.2 ใน Laravel&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ฝั่ง Laravel เองก็ใช้ประโยชน์จาก readonly classes ได้ดีเช่นกัน โดยเฉพาะการทำ DTO (Data Transfer Object) สำหรับส่งข้อมูลระหว่างชั้น Service กับ Controller ในระบบอีคอมเมิร์ซ เช่น ข้อมูลตะกร้าสินค้า:&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 18px; color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 18px 0px 26px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;border-radius: 50%; color: #9d9db8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; height: 11px; margin-left: 8px; width: 11px;&quot;&gt;app/DTO/CartItemDTO.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;color: #e4e4f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;final class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;CartItemDTO&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;int&lt;/span&gt; $productId, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;string&lt;/span&gt; $productName, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;float&lt;/span&gt; $price, &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public readonly&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;int&lt;/span&gt; $quantity ) {} &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #82aaff;&quot;&gt;subtotal&lt;/span&gt;(): &lt;span class=&quot;var&quot; style=&quot;color: #f78c6c;&quot;&gt;float&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #c792ea;&quot;&gt;return&lt;/span&gt; $this-&amp;gt;price * $this-&amp;gt;quantity; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;และในฝั่ง Blade template ก็สามารถเรียกใช้เมธอดจาก DTO ได้ตรง ๆ โดยไม่ต้องกังวลว่าค่าจะถูกแก้ไขโดยไม่ตั้งใจระหว่างการ render:&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 6px 18px; color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 18px 0px 26px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;border-radius: 50%; color: #9d9db8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; height: 11px; margin-left: 8px; width: 11px;&quot;&gt;resources/views/cart/summary.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;color: #e4e4f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #7c8ba1;&quot;&gt;&amp;lt;!-- resources/views/cart/summary.blade.php --&amp;gt;&lt;/span&gt; &amp;lt;ul&amp;gt; @foreach ($items as $item) &amp;lt;li&amp;gt; {{ $item-&amp;gt;productName }} x {{ $item-&amp;gt;quantity }} = {{ number_format($item-&amp;gt;subtotal(), 2) }} บาท &amp;lt;/li&amp;gt; @endforeach &amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(124, 58, 237); color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 23px; margin: 40px 0px 16px; padding-left: 14px; text-align: start;&quot;&gt;เปรียบเทียบภาพรวม: PHP 8.2 กับตัวเลือกอื่นในปี 2026&lt;/h2&gt;&lt;div class=&quot;pcm-table-wrap&quot; style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 20px 0px 30px; overflow-x: auto; text-align: start;&quot;&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; border-radius: 8px; font-size: 15px; overflow: hidden; width: 780px;&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: white; padding: 12px 14px; text-align: left;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: white; padding: 12px 14px; text-align: left;&quot;&gt;PHP 8.2&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: white; padding: 12px 14px; text-align: left;&quot;&gt;PHP 8.4 / 8.5&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ความเข้ากันได้กับ Magento / ระบบ Legacy&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;รองรับอย่างเป็นทางการ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ยังตามไม่ทันในหลายแพลตฟอร์ม&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(250, 249, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;เสถียรภาพของ Library ในตลาด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ทดสอบมานาน ครอบคลุมกว้าง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;บาง package ยังอัปเดตไม่ครบ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;Readonly classes / DNF Types&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;มีครบ ใช้งานได้จริง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;มีเช่นกัน พร้อมฟีเจอร์เสริมเพิ่ม&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(250, 249, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ความเร็วและการ Debug&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ดีในระดับที่เพียงพอ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ปรับปรุงเพิ่มเติมด้านความเร็ว/debug&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;เหมาะกับงานประเภทใด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;ระบบที่เน้นความเสถียรระยะยาว เช่น CMS ข่าว, อีคอมเมิร์ซที่ผูกกับแพลตฟอร์มเดิม&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(238, 238, 238); padding: 12px 14px;&quot;&gt;โปรเจกต์ใหม่ที่อยากใช้ฟีเจอร์ล่าสุด ไม่มีข้อจำกัดเรื่อง dependency&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;กล่าวโดยสรุปแล้ว PHP เวอร์ชันใหม่อย่าง 8.5 มาพร้อมการปรับปรุงเรื่องโค้ดที่กระชับขึ้น ความเร็ว และเครื่องมือ debug ที่ดีขึ้น ซึ่งเหมาะกับโปรเจกต์ใหม่ที่เริ่มจากศูนย์ แต่สำหรับระบบที่มีอยู่แล้วหรือผูกกับแพลตฟอร์มที่ยังไม่รองรับเวอร์ชันล่าสุด PHP 8.2 ก็ยังคงเป็นจุดที่สมดุลระหว่างฟีเจอร์ทันสมัยกับความเสถียรของระบบนิเวศโดยรวม&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(124, 58, 237); color: #1a1a2e; font-family: Sarabun, -apple-system, sans-serif; font-size: 23px; margin: 40px 0px 16px; padding-left: 14px; text-align: start;&quot;&gt;สรุป: เลือก PHP 8.2 เมื่อไหร่ดี&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;สำหรับมือใหม่ที่กำลังเริ่มต้นกับ CodeIgniter 4 หรือ Laravel คำแนะนำคือให้ดูที่ &quot;แพลตฟอร์มปลายทาง&quot; ที่จะ deploy เป็นหลัก หากทำงานร่วมกับระบบ legacy หรือแพลตฟอร์มอย่าง Magento การยึด PHP 8.2 เป็นมาตรฐานจะช่วยลดปัญหาเรื่อง dependency conflict ได้มาก แต่ถ้าเป็นโปรเจกต์ใหม่ล้วน ๆ ไม่มีข้อจำกัดด้านความเข้ากันได้ ก็สามารถพิจารณาขยับไปใช้ PHP เวอร์ชันใหม่กว่าเพื่อประโยชน์ด้านประสิทธิภาพในระยะยาวได้เช่นกัน&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, -apple-system, sans-serif; font-size: 17px; margin: 14px 0px; text-align: start;&quot;&gt;ไม่ว่าจะเลือกเวอร์ชันไหน สิ่งสำคัญที่สุดคือการตรวจสอบ compatibility ระหว่างเวอร์ชัน PHP กับ dependency ในไฟล์ composer.json ให้ตรงกันเสมอ เพื่อหลีกเลี่ยงปัญหาเวลา deploy ขึ้น production จริง&lt;/p&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6473268034977600840/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/07/php-82-2026-cms.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6473268034977600840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6473268034977600840'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/07/php-82-2026-cms.html' title='PHP 8.2 ในปี 2026: ทำไมยังเป็นตัวเลือกที่ดีที่สุดสำหรับ CMS ข่าวและอีคอมเมิร์ซ'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEigOK_paiYCFC2K1HsTU6GODBkALehEj3ieq9SO4guSWJt_rGy1_0q9la7qTk6fPadx-02Pf7Hst1Kn7jKr18FA0JxRqLZw1ko_8KAinyBKDs8nxZP6vr7Ov2DfcV4u3x0Xb6VHf1Xij1ypeI7mGMfRpa-MvDvPFT8pjMrd5M7-JTqJaiZRRd0xfuAGhl4=s72-w640-h426-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6328547831723880092</id><published>2026-06-30T07:37:45.737+07:00</published><updated>2026-06-30T07:37:45.737+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>เบื้องหลัง LLM API: เมื่อโค้ด PHP ของคุณคุยกับ AI</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEicTR9bNuvgHDJjS257xcO0QOPyoO9QTixN-NY3a6EGHuL7y3YzOskJ_0zgWFOgJChmZOuHHJGPEwv6hrdyEIFWmlY8MlYEXxFeU21Zv-pFcSHUV0FogkP-TlDzRqhu8pbB8FqNgtbpijQL0sNVFVrnGwIPur3icuW_QlN6saZSK-NdkPKNg5ze4kf6BEo&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1536&quot; height=&quot;453&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEicTR9bNuvgHDJjS257xcO0QOPyoO9QTixN-NY3a6EGHuL7y3YzOskJ_0zgWFOgJChmZOuHHJGPEwv6hrdyEIFWmlY8MlYEXxFeU21Zv-pFcSHUV0FogkP-TlDzRqhu8pbB8FqNgtbpijQL0sNVFVrnGwIPur3icuW_QlN6saZSK-NdkPKNg5ze4kf6BEo=w681-h453&quot; width=&quot;681&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;header class=&quot;post-header&quot; style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 40px; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;tag-row&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 8px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;&lt;span class=&quot;tag tag-blue&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(219, 234, 254); border-radius: 20px; box-sizing: border-box; color: #2563eb; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 10px;&quot;&gt;LLM API&lt;/span&gt;&lt;span class=&quot;tag tag-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 20px; box-sizing: border-box; color: #16a34a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 10px;&quot;&gt;PHP / Laravel / CI4&lt;/span&gt;&lt;span class=&quot;tag tag-purple&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 20px; box-sizing: border-box; color: #7c3aed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 10px;&quot;&gt;AI Integration&lt;/span&gt;&lt;/div&gt;&lt;h1 class=&quot;post-title&quot; style=&quot;box-sizing: border-box; font-size: clamp(26px, 5vw, 40px); line-height: 1.25; margin: 0px 0px 14px; padding: 0px;&quot;&gt;เบื้องหลัง LLM API:&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;span style=&quot;box-sizing: border-box; color: #2563eb; margin: 0px; padding: 0px;&quot;&gt;เมื่อโค้ด PHP ของคุณคุยกับ AI&lt;/span&gt;&lt;/h1&gt;&lt;p style=&quot;box-sizing: border-box; color: #64748b; font-size: 15px; margin: 12px 0px 16px; padding: 0px;&quot;&gt;เปิดฝากล่องดำ — ทำความเข้าใจว่าเกิดอะไรขึ้นจริงๆ ตั้งแต่กด &lt;code style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); border-radius: 4px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; margin: 0px; padding: 1px 6px;&quot;&gt;send&lt;/code&gt; ไปจนถึงได้รับคำตอบ&lt;/p&gt;&lt;div class=&quot;post-meta&quot; style=&quot;border-top: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #64748b; display: flex; flex-wrap: wrap; font-size: 13px; gap: 16px; margin: 12px 0px 0px; padding: 12px 0px 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;📅 มิถุนายน 2568&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;⏱ อ่าน ~8 นาที&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;✍️ PHP Code Mania&lt;/span&gt;&lt;/div&gt;&lt;/header&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;ทำไมต้องรู้เรื่องนี้?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;หลายคนเริ่มต้น integrate LLM เข้าโปรเจกต์ PHP ด้วยการ copy วาง &lt;code style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); border-radius: 4px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; margin: 0px; padding: 1px 5px;&quot;&gt;curl&lt;/code&gt; จาก docs แล้ว &quot;มันก็ทำงานได้&quot; — แต่พอ response แปลก, token หมด, หรือ latency พุ่งขึ้น ก็ไม่รู้จะ debug จากไหน&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;บทความนี้จะพาคุณเปิดฝากล่องดำนั้น ตั้งแต่ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;HTTP request ออกไปจนถึง token ไหลกลับมา&lt;/span&gt; พร้อม code ตัวอย่างจริงสำหรับ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/span&gt; และ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/span&gt; ที่นำไปใช้ได้เลย&lt;/p&gt;&lt;div class=&quot;callout info&quot; style=&quot;align-items: flex-start; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(219, 234, 254); border-left: 3px solid rgb(37, 99, 235); border-radius: 10px; box-sizing: border-box; color: #1a202c; display: flex; font-family: Sarabun, sans-serif; font-size: 15px; gap: 12px; margin: 24px 0px; padding: 16px 20px; text-align: start;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;💡&lt;/span&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;บทความนี้เหมาะสำหรับผู้ที่รู้จัก PHP พื้นฐานและเคยสร้าง REST API มาบ้างแล้ว ถ้ายังไม่คุ้นเรื่อง HTTP ลองอ่านซีรีส์ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;PHP RESTful Web Service&lt;/span&gt; ก่อนได้เลย&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;1. ภาพรวม: Request เดินทางอย่างไร?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;เมื่อคุณเรียก LLM API เช่น OpenAI, Claude, หรือ Gemini สิ่งที่เกิดขึ้นจริงๆ คือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;HTTP POST request&lt;/span&gt; ธรรมดาๆ ไปยัง endpoint ของ provider ไม่มีเวทมนตร์ซ่อนอยู่เลย&lt;/p&gt;&lt;div class=&quot;flow&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #1a202c; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 17px; gap: 0px; margin: 28px 0px; padding: 20px 24px; text-align: start;&quot;&gt;&lt;div class=&quot;flow-step&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 8px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; font-size: 14px; font-weight: 600; margin: 0px; min-width: 110px; padding: 10px 18px; text-align: center;&quot;&gt;PHP App&lt;small style=&quot;box-sizing: border-box; color: #64748b; display: block; font-size: 11px; font-weight: 400; margin: 2px 0px 0px; padding: 0px;&quot;&gt;สร้าง payload&lt;/small&gt;&lt;/div&gt;&lt;div class=&quot;flow-arrow&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-size: 20px; font-weight: 700; margin: 0px; padding: 0px 8px;&quot;&gt;→&lt;/div&gt;&lt;div class=&quot;flow-step&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 8px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; font-size: 14px; font-weight: 600; margin: 0px; min-width: 110px; padding: 10px 18px; text-align: center;&quot;&gt;HTTPS POST&lt;small style=&quot;box-sizing: border-box; color: #64748b; display: block; font-size: 11px; font-weight: 400; margin: 2px 0px 0px; padding: 0px;&quot;&gt;JSON body&lt;/small&gt;&lt;/div&gt;&lt;div class=&quot;flow-arrow&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-size: 20px; font-weight: 700; margin: 0px; padding: 0px 8px;&quot;&gt;→&lt;/div&gt;&lt;div class=&quot;flow-step&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 8px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; font-size: 14px; font-weight: 600; margin: 0px; min-width: 110px; padding: 10px 18px; text-align: center;&quot;&gt;LLM Server&lt;small style=&quot;box-sizing: border-box; color: #64748b; display: block; font-size: 11px; font-weight: 400; margin: 2px 0px 0px; padding: 0px;&quot;&gt;tokenize + infer&lt;/small&gt;&lt;/div&gt;&lt;div class=&quot;flow-arrow&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-size: 20px; font-weight: 700; margin: 0px; padding: 0px 8px;&quot;&gt;→&lt;/div&gt;&lt;div class=&quot;flow-step&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 8px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; font-size: 14px; font-weight: 600; margin: 0px; min-width: 110px; padding: 10px 18px; text-align: center;&quot;&gt;Response&lt;small style=&quot;box-sizing: border-box; color: #64748b; display: block; font-size: 11px; font-weight: 400; margin: 2px 0px 0px; padding: 0px;&quot;&gt;JSON / Stream&lt;/small&gt;&lt;/div&gt;&lt;div class=&quot;flow-arrow&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-size: 20px; font-weight: 700; margin: 0px; padding: 0px 8px;&quot;&gt;→&lt;/div&gt;&lt;div class=&quot;flow-step&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 8px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; font-size: 14px; font-weight: 600; margin: 0px; min-width: 110px; padding: 10px 18px; text-align: center;&quot;&gt;PHP App&lt;small style=&quot;box-sizing: border-box; color: #64748b; display: block; font-size: 11px; font-weight: 400; margin: 2px 0px 0px; padding: 0px;&quot;&gt;parse + แสดงผล&lt;/small&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;สิ่งที่ต่างจาก API ทั่วไปคือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;ฝั่ง server ใช้เวลาประมวลผลนานกว่าปกติมาก&lt;/span&gt; (ตั้งแต่ 1 วินาทีไปจนถึงหลายสิบวินาที) และ response อาจส่งกลับมาแบบ &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;streaming&lt;/em&gt; คือทยอยส่งทีละ chunk แทนที่จะรอให้ครบแล้วส่งพร้อมกัน&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;2. โครงสร้าง Request ที่ต้องรู้&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;ทุก LLM API มีโครงสร้าง JSON body คล้ายกัน ลองดู format ของ OpenAI-compatible API ซึ่งใช้ได้กับหลาย provider:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;code-titlebar&quot; style=&quot;align-items: center; background: rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;request-payload.json&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;gpt-4o-mini&quot;&lt;/span&gt;, &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// โมเดลที่ต้องการใช้&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;&quot;messages&quot;&lt;/span&gt;: [ { &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;system&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;You are a helpful assistant.&quot;&lt;/span&gt; }, { &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;user&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;สรุปบทความนี้ให้หน่อย...&quot;&lt;/span&gt; } ], &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;&quot;max_tokens&quot;&lt;/span&gt;: &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;500&lt;/span&gt;, &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// จำกัด output token&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;&quot;temperature&quot;&lt;/span&gt;: &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;0.7&lt;/span&gt;, &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 0 = deterministic, 2 = wild&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;&quot;stream&quot;&lt;/span&gt;: &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// true = ส่งแบบ chunk&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout warn&quot; style=&quot;align-items: flex-start; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 243, 199); border-left: 3px solid rgb(217, 119, 6); border-radius: 10px; box-sizing: border-box; color: #1a202c; display: flex; font-family: Sarabun, sans-serif; font-size: 15px; gap: 12px; margin: 24px 0px; padding: 16px 20px; text-align: start;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;⚠️&lt;/span&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;ระวัง context window!&lt;/span&gt; ทุก message ใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;messages[]&lt;/code&gt; นับ token ทั้งหมด ถ้าคุณส่ง conversation ยาวๆ หรือ document ใหญ่ๆ ค่าใช้จ่ายพุ่งขึ้นแน่นอน วางแผน context management ตั้งแต่ต้น&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;3. เรียก LLM API จาก CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;CI4 มี &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CURLRequest&lt;/code&gt; built-in ใน HTTP Client ทำให้ไม่ต้องพึ่ง library ภายนอก:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;code-titlebar&quot; style=&quot;align-items: center; background: rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;app/Services/LlmService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;App\Services&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter\HTTP\CURLRequest&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;LlmService&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CURLRequest&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$apiKey&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;apiKey&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;OPENAI_API_KEY&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;curlrequest&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;, [&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;baseURI&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;https://api.openai.com/v1/&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;timeout&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;chat&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$payload&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;= [&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;model&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;gpt-4o-mini&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;messages&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;system&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;ตอบเป็นภาษาไทย กระชับ และถูกต้อง&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;max_tokens&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;chat/completions&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;, [&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;headers&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Authorization&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Bearer &#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;application/json&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$payload&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;json_decode&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getBody&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ดึงคำตอบจาก response structure&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;choices&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2563eb; font-family: Sarabun, sans-serif; font-size: 18px; margin: 28px 0px 10px; padding: 0px; text-align: start;&quot;&gt;เรียกใช้จาก Controller&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;code-titlebar&quot; style=&quot;align-items: center; background: rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;app/Controllers/AiController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ask&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$question&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getPost&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;question&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$question&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setStatusCode&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;422&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setJSON&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;error&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;กรุณาระบุคำถาม&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$llm&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;LlmService&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$answer&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$llm&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;chat&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$question&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setJSON&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;([&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;answer&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$answer&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;4. เรียก LLM API จาก Laravel&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;Laravel มี HTTP Client ที่ wrap Guzzle ไว้ใช้งานง่ายมาก และรองรับ retry, timeout, และ async ได้ตั้งแต่ out-of-the-box:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;code-titlebar&quot; style=&quot;align-items: center; background: rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;app/Services/LlmService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;App\Services&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Illuminate\Support\Facades\Http&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Illuminate\Http\Client\RequestException&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;LlmService&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;chat&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$systemPrompt&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$messages&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;= [];&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$systemPrompt&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$messages&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[] =&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;system&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$systemPrompt&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$messages&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[] =&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$userMessage&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;Http&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;withToken&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;services.openai.key&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;retry&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// retry 2 ครั้ง รอ 1 วิ&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;https://api.openai.com/v1/chat/completions&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;, [&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;model&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;gpt-4o-mini&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;messages&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$messages&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;max_tokens&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// โยน exception ถ้า 4xx/5xx&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;choices.0.message.content&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout success&quot; style=&quot;align-items: flex-start; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-left: 3px solid rgb(22, 163, 74); border-radius: 10px; box-sizing: border-box; color: #1a202c; display: flex; font-family: Sarabun, sans-serif; font-size: 15px; gap: 12px; margin: 24px 0px; padding: 16px 20px; text-align: start;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;✅&lt;/span&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Laravel tip:&lt;/span&gt; ใส่ key ใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;config/services.php&lt;/code&gt; และอ่านจาก &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/code&gt; ผ่าน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;OPENAI_API_KEY=...&lt;/code&gt; อย่า hard-code API key ใน source code เด็ดขาด!&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;5. อ่าน Response ให้เป็น&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;Response ที่ได้กลับมามีโครงสร้างที่ควรรู้จัก:&lt;/p&gt;&lt;div class=&quot;anatomy&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); border-color: rgb(226, 232, 240); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #1a202c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.8; margin: 24px 0px; padding: 20px 24px; text-align: start;&quot;&gt;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;id&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;&quot;chatcmpl-abc123&quot;&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt; ← unique id ของ request นี้&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;choices&quot;&lt;/span&gt;: [{&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;message&quot;&lt;/span&gt;: {&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt; ← บทบาทของผู้ตอบ&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;&quot;คำตอบอยู่ตรงนี้...&quot;&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;finish_reason&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;&quot;stop&quot;&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt; ← stop/length/content_filter&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;}],&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;usage&quot;&lt;/span&gt;: {&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;prompt_tokens&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt; ← token ที่คุณส่งไป&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;completion_tokens&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;312&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;← token ที่ AI ตอบกลับ&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;total_tokens&quot;&lt;/span&gt;: &lt;span class=&quot;a-val&quot; style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;357&lt;/span&gt;&lt;span class=&quot;a-note&quot; style=&quot;box-sizing: border-box; color: #64748b; font-family: Sarabun, sans-serif; font-size: 13px; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;← รวม = เงินที่เสียไป 💸&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&amp;nbsp;&amp;nbsp;}&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;span class=&quot;a-key&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;finish_reason&lt;/code&gt; สำคัญมาก — ถ้าเป็น &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;length&lt;/code&gt; แปลว่าคำตอบถูกตัดออกเพราะ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;max_tokens&lt;/code&gt; หมด ต้องเพิ่ม limit หรือแบ่ง task ให้เล็กลง&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;6. เปรียบเทียบ LLM API ยอดนิยมสำหรับ PHP Dev&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow-x: auto; padding: 0px; text-align: start;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 15px; margin: 0px; padding: 0px; width: 780px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(37, 99, 235); box-sizing: border-box; color: white; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: left;&quot;&gt;Provider&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: left;&quot;&gt;Endpoint Base&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: left;&quot;&gt;Auth Header&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: left;&quot;&gt;Streaming&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: left;&quot;&gt;เหมาะสำหรับ&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #1a202c; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;OpenAI&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;api.openai.com/v1&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Bearer token&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;badge badge-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 11px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;✅ SSE&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Prototype เร็ว, ecosystem ใหญ่&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #1a202c; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Anthropic Claude&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;api.anthropic.com/v1&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;x-api-key header&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;badge badge-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 11px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;✅ SSE&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Long context, เหตุผลซับซ้อน&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #1a202c; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Google Gemini&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;generativelanguage.googleapis.com&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;API key param&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;badge badge-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 11px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;✅ SSE&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Context window ใหญ่ที่สุด&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(246, 248, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #1a202c; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Ollama (local)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;localhost:11434/api&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;ไม่ต้องใช้&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;badge badge-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 11px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;✅ JSON stream&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Dev/test ประหยัด, ข้อมูลลับ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #1a202c; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;OpenRouter&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;openrouter.ai/api/v1&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;Bearer token&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;badge badge-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 11px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;✅ SSE&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 10px 16px;&quot;&gt;เปลี่ยนโมเดลได้ทีเดียว&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class=&quot;callout tip&quot; style=&quot;align-items: flex-start; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-left: 3px solid rgb(124, 58, 237); border-radius: 10px; box-sizing: border-box; color: #1a202c; display: flex; font-family: Sarabun, sans-serif; font-size: 15px; gap: 12px; margin: 24px 0px; padding: 16px 20px; text-align: start;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;🔮&lt;/span&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Pro tip:&lt;/span&gt; ถ้าอยากเปลี่ยน provider ได้ง่ายในอนาคต ให้สร้าง interface &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;LlmInterface&lt;/code&gt; และ implement แต่ละ provider แยกกัน แล้วผูกผ่าน service container ของ Laravel หรือ DI ของ CI4&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;7. Streaming Response — ทำให้ UX ดีขึ้น&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;แทนที่ user จะรอ 10 วินาทีแล้วเห็นข้อความโผล่ทีเดียว — &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Streaming&lt;/span&gt; ทำให้ข้อความไหลออกมาทีละ chunk เหมือน ChatGPT พิมพ์ให้เห็น&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px 0px, rgba(0, 0, 0, 0.06) 0px 4px 16px 0px; box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px; text-align: start;&quot;&gt;&lt;div class=&quot;code-titlebar&quot; style=&quot;align-items: center; background: rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;stream-example.php (vanilla PHP)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ต้องปิด output buffering ก่อน&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ob_end_clean&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type: text/event-stream&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Cache-Control: no-cache&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$ch&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;curl_init&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;https://api.openai.com/v1/chat/completions&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;curl_setopt_array&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;, [&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;CURLOPT_POST&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;CURLOPT_HTTPHEADER&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Authorization: Bearer &#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$apiKey&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type: application/json&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;CURLOPT_POSTFIELDS&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;([&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;model&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;gpt-4o-mini&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;messages&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$prompt&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;stream&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// &amp;lt;-- ตรงนี้สำคัญ!&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;nu&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;CURLOPT_WRITEFUNCTION&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$chunk&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$chunk&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ob_flush&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$chunk&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;curl_exec&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;curl_close&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;va&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;);&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout warn&quot; style=&quot;align-items: flex-start; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 243, 199); border-left: 3px solid rgb(217, 119, 6); border-radius: 10px; box-sizing: border-box; color: #1a202c; display: flex; font-family: Sarabun, sans-serif; font-size: 15px; gap: 12px; margin: 24px 0px; padding: 16px 20px; text-align: start;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;⚠️&lt;/span&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;ข้อจำกัดของ PHP streaming:&lt;/span&gt; Shared hosting หลายเจ้าปิด output buffering หรือ timeout เร็ว ถ้าต้องการ streaming UX ที่ดีจริงๆ แนะนำให้ทำ proxy endpoint แยก หรือใช้ JavaScript (fetch + ReadableStream) ไปเรียก API ตรงจาก frontend แทน&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;8. LLM ไม่ใช่เพื่อนร่วมทีม — มันคือ Probabilistic Compiler&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;มีแนวคิดที่น่าสนใจจากชุมชน dev ในปี 2026 คือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;&quot;ถ้าคุณ treat LLM เหมือนเพื่อนร่วมทีม คุณจะผิดหวัง แต่ถ้า treat มันเหมือน compiler คุณจะส่ง product ได้จริง&quot;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;ความหมายในทางปฏิบัติสำหรับ PHP dev คือ:&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px 0px 0px 22px; text-align: start;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Input ต้องชัดเจน&lt;/span&gt; — ถ้า input มัว output ก็มัวแน่นอน ระบุ constraint ให้ครบ เช่น &quot;ใช้ PHP 8.2, CI4, ห้ามแก้ public interface&quot;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Context ต้องพอดี&lt;/span&gt; — ส่งเฉพาะสิ่งที่ AI ต้องรู้จริงๆ อย่า paste ทั้งไฟล์ถ้าไม่จำเป็น&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;ตรวจสอบ output เสมอ&lt;/span&gt; — LLM confident ได้แม้จะผิด (hallucination) อย่า merge โดยไม่ review&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;ใช้ไฟล์เป็น long-term memory&lt;/span&gt; — ให้ LLM เขียน decision/summary ลง markdown ไฟล์ใน repo แทนการเล่าซ้ำในทุก conversation&lt;/li&gt;&lt;/ul&gt;&lt;hr style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px; text-align: start;&quot; /&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 8px; text-align: start;&quot;&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;การ integrate LLM เข้าโปรเจกต์ PHP ไม่ได้ซับซ้อนกว่าการเรียก REST API ทั่วไปเลย — มันคือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;HTTP POST + JSON&lt;/span&gt; ธรรมดา สิ่งที่ต่างออกไปคือ latency ที่สูงกว่า, การจัดการ token budget, และการเข้าใจว่า response อาจมาแบบ streaming&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px; text-align: start;&quot;&gt;สรุปขั้นตอนที่ควรจำ:&lt;/p&gt;&lt;ol style=&quot;box-sizing: border-box; color: #1a202c; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px 0px 0px 22px; text-align: start;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;สร้าง Service class แยก — อย่าเรียก API ตรงใน Controller&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;เก็บ API key ใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/code&gt; เสมอ ห้าม commit เด็ดขาด&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ตรวจ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;finish_reason&lt;/code&gt; ทุกครั้ง — &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;length&lt;/code&gt; หมายถึงคำตอบขาดหาย&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;Monitor &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;usage.total_tokens&lt;/code&gt; เพื่อควบคุมค่าใช้จ่าย&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ออกแบบ prompt ให้ชัด ระบุ constraint ครบ ก่อนค่อย optimize&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6328547831723880092/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/llm-api-php-ai.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6328547831723880092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6328547831723880092'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/llm-api-php-ai.html' title='เบื้องหลัง LLM API: เมื่อโค้ด PHP ของคุณคุยกับ AI'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEicTR9bNuvgHDJjS257xcO0QOPyoO9QTixN-NY3a6EGHuL7y3YzOskJ_0zgWFOgJChmZOuHHJGPEwv6hrdyEIFWmlY8MlYEXxFeU21Zv-pFcSHUV0FogkP-TlDzRqhu8pbB8FqNgtbpijQL0sNVFVrnGwIPur3icuW_QlN6saZSK-NdkPKNg5ze4kf6BEo=s72-w681-h453-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6573204827682764224</id><published>2026-06-28T20:27:44.301+07:00</published><updated>2026-06-28T20:28:02.416+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>Production-Ready CodeIgniter 4 + Docker พร้อม CI/CD ใน 10 นาที</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjGluO6BsFEpbFvZlYOk5I0SMv7R2NMmBsfXB9nynANMkOnQBHN4dzoLCb2fa3ogn5Kl-q7lPsdbOoyMEkjXH_2lvzGIZoFLro1EAGEXzzkBHkAQbC01_1xO5HTjUuiRTrcVRRSaFEFmdam8ExjMZ9u3eHlt2eRxeMunOY0UQk68cJJRm0RD25e3wfjeVw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1492&quot; data-original-width=&quot;1054&quot; height=&quot;847&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjGluO6BsFEpbFvZlYOk5I0SMv7R2NMmBsfXB9nynANMkOnQBHN4dzoLCb2fa3ogn5Kl-q7lPsdbOoyMEkjXH_2lvzGIZoFLro1EAGEXzzkBHkAQbC01_1xO5HTjUuiRTrcVRRSaFEFmdam8ExjMZ9u3eHlt2eRxeMunOY0UQk68cJJRm0RD25e3wfjeVw=w634-h847&quot; width=&quot;634&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div class=&quot;hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(13, 17, 23) 0%, rgb(22, 27, 39) 50%, rgb(15, 31, 61) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px; overflow: hidden; padding: 64px 24px 56px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;hero-badge&quot; style=&quot;background: rgba(56, 139, 253, 0.15); border-radius: 20px; border: 1px solid rgba(56, 139, 253, 0.35); box-sizing: border-box; color: #79c0ff; display: inline-block; font-size: 13px; font-weight: 600; letter-spacing: 0.08em; margin: 0px 0px 20px; padding: 4px 14px; position: relative; text-transform: uppercase;&quot;&gt;🐳 Docker + CI/CD + CodeIgniter 4&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; color: #e6edf3; font-size: clamp(26px, 5vw, 44px); line-height: 1.25; margin: 0px auto 16px; max-width: 720px; padding: 0px; position: relative;&quot;&gt;Production-Ready &lt;span style=&quot;box-sizing: border-box; color: #388bfd; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4 + Docker&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;พร้อม CI/CD ใน 10 นาที&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 16px; margin: 0px auto; max-width: 560px; padding: 0px; position: relative;&quot;&gt;ตั้งค่าสภาพแวดล้อม PHP ระดับ Production ด้วย Docker, Nginx, MySQL, Redis และ GitHub Actions ในขั้นตอนเดียว&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; margin: 28px 0px 0px; padding: 0px; position: relative;&quot;&gt;&lt;span style=&quot;background: rgba(255, 255, 255, 0.07); border-radius: 6px; border: 1px solid rgba(255, 255, 255, 0.12); box-sizing: border-box; color: #8b949e; font-size: 13px; margin: 0px; padding: 4px 12px;&quot;&gt;🕐 อ่าน 8 นาที&lt;/span&gt;&lt;span style=&quot;background: rgba(255, 255, 255, 0.07); border-radius: 6px; border: 1px solid rgba(255, 255, 255, 0.12); box-sizing: border-box; color: #8b949e; font-size: 13px; margin: 0px; padding: 4px 12px;&quot;&gt;⚡ PHP-FPM 8.2&lt;/span&gt;&lt;span style=&quot;background: rgba(255, 255, 255, 0.07); border-radius: 6px; border: 1px solid rgba(255, 255, 255, 0.12); box-sizing: border-box; color: #8b949e; font-size: 13px; margin: 0px; padding: 4px 12px;&quot;&gt;🐳 Docker Compose&lt;/span&gt;&lt;span style=&quot;background: rgba(255, 255, 255, 0.07); border-radius: 6px; border: 1px solid rgba(255, 255, 255, 0.12); box-sizing: border-box; color: #8b949e; font-size: 13px; margin: 0px; padding: 4px 12px;&quot;&gt;🔁 GitHub Actions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;article-body&quot; style=&quot;box-sizing: border-box; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px auto; max-width: 780px; padding: 48px 24px 80px;&quot;&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;ปัญหาที่นักพัฒนา PHP ทุกคนเจอ&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ทุกครั้งที่เริ่มโปรเจกต์ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/strong&gt; ใหม่ ก่อนที่จะเขียน business logic สักบรรทัดเดียว เราต้องเสียเวลาหลายชั่วโมงกับการ setup: ทำให้ Docker ทำงานได้, ตั้งค่า Nginx, เชื่อม PHP-FPM, ติดตั้ง MySQL กับ Redis, ทำให้ PHPUnit รันได้ใน container และสุดท้ายก็ต้องนั่งหาว่าทำไม CI pipeline ถึง fail ตั้งแต่ push ครั้งแรก&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;เวลาที่ใช้ setup คือ &quot;เวลาสูญเปล่า&quot; ไม่ได้ช่วย ship feature และก็ต้องทำซ้ำในทุกโปรเจกต์&lt;/p&gt;&lt;div class=&quot;callout&quot; style=&quot;background: rgb(239, 246, 255); border-color: rgb(191, 219, 254) rgb(191, 219, 254) rgb(191, 219, 254) rgb(56, 139, 253); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #1e3a5f; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; margin: 0px 0px 4px; padding: 0px;&quot;&gt;💡 บทความนี้จะพาคุณ&lt;/strong&gt;ตั้งแต่ศูนย์ไปถึง environment ที่ tested และพร้อม production จริงๆ ด้วย CodeIgniter 4 + Docker stack ภายใน 10 นาที พร้อม GitHub Actions CI/CD ที่รัน PHPUnit, PHPStan และ Rector อัตโนมัติ&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Stack ที่ใช้ในโปรเจกต์นี้&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;stack ทั้งหมดถูกออกแบบมาให้ครอบคลุมตั้งแต่ development ไปจนถึง production โดยไม่ต้องเปลี่ยน config อะไรมาก&lt;/p&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;border-radius: 8px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 10px; box-sizing: border-box; margin: 28px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; font-size: 15px; margin: 0px; padding: 0px; width: 732px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: rgb(15, 31, 61); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;box-sizing: border-box; color: #e6edf3; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Component&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; color: #e6edf3; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Version&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; color: #e6edf3; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;หน้าที่&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;PHP-FPM&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;8.2&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;FastCGI runtime สำหรับรัน PHP&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(244, 247, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;CodeIgniter&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;4.7&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;MVC framework + Shield authentication&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Nginx&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;1.28-alpine&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Reverse proxy และ serve static files&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(244, 247, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;MySQL&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;8.4&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Primary database&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Redis&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;7-alpine&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Cache, sessions และ queue backend&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(244, 247, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Supervisor&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;system&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;PID-1 process manager ใน production&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;PHPStan&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;level 6&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Static analysis ตรวจ code ก่อน deploy&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(244, 247, 251); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #388bfd; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;PHPUnit&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;&lt;span class=&quot;badge&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 4px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 8px;&quot;&gt;10.5&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(233, 236, 239); box-sizing: border-box; color: #3d4451; margin: 0px; padding: 11px 16px; vertical-align: middle;&quot;&gt;Test suite พร้อม pcov driver&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;โครงสร้างไฟล์และ Docker Compose&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;โปรเจกต์แบ่งเป็นสองโหมดชัดเจน: &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Dockerfile.dev&lt;/code&gt; สำหรับ development (มี pcov + git support) และ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Dockerfile&lt;/code&gt; สำหรับ production (ใช้ Supervisor เป็น PID-1)&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;docker-compose.yml&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;3.9&#39;&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;services:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;build:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;context:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;dockerfile:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;Dockerfile.dev&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- .:/var/www/html&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;depends_on:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- db&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- redis&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;environment:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;CI_ENVIRONMENT:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_HOST:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;REDIS_HOST:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;redis&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;nginx:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;nginx:1.28-alpine&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;ports:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- &quot;8080:80&quot;&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- ./nginx/default.conf:/etc/nginx/conf.d/default.conf&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;depends_on:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- app&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;db:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;mysql:8.4&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;environment:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;MYSQL_ROOT_PASSWORD:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;MYSQL_DATABASE:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;ci4app&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;- db_data:/var/lib/mysql&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;redis:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;redis:7-alpine&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;db_data:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;รัน Stack ทั้งหมดด้วยคำสั่งเดียว&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ทุกอย่างถูก wrap ไว้ใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Makefile&lt;/code&gt; คำสั่ง &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;make setup&lt;/code&gt; จะ build images, start containers, รอ MySQL + Redis พร้อม, รัน migrations, seed database และ hit healthcheck endpoint อัตโนมัติ&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# Build, start, migrate, seed — ทุกอย่างในคำสั่งเดียว&lt;/span&gt; &lt;span class=&quot;c-cmd&quot; style=&quot;box-sizing: border-box; color: #56d364; margin: 0px; padding: 0px;&quot;&gt;make setup&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# ตรวจสอบว่า stack ทำงานปกติ&lt;/span&gt; &lt;span class=&quot;c-cmd&quot; style=&quot;box-sizing: border-box; color: #56d364; margin: 0px; padding: 0px;&quot;&gt;curl http://localhost:8080/health&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ถ้า stack ทำงานถูกต้อง จะได้ response JSON ดังนี้:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;healthcheck response&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;&quot;status&quot;&lt;/span&gt;: &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;ok&quot;&lt;/span&gt;, &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;&quot;database&quot;&lt;/span&gt;: &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;ok&quot;&lt;/span&gt;, &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;&quot;redis&quot;&lt;/span&gt;: &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;ok&quot;&lt;/span&gt;, &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;2026-06-26T15:00:00+00:00&quot;&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout success&quot; style=&quot;background: rgb(240, 253, 244); border-color: rgb(187, 247, 208) rgb(187, 247, 208) rgb(187, 247, 208) rgb(34, 197, 94); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #14532d; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; margin: 0px 0px 4px; padding: 0px;&quot;&gt;✅ เห็น JSON นี้ = สำเร็จ!&lt;/strong&gt;หมายความว่า PHP-FPM, Nginx, MySQL, Redis ทำงานครบ, migrations รันเรียบร้อย และ healthcheck ผ่านทั้งหมด&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;3 การตัดสินใจสำคัญที่ไม่ค่อยมีคนพูดถึง&lt;/h2&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;1. ใช้ Supervisor เป็น PID-1 แทน php-fpm โดยตรง&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ถ้ารัน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;php-fpm&lt;/code&gt; เป็น PID-1 ตรงๆ จะเกิดปัญหา zombie processes สะสมใน container ที่รันนานๆ Supervisor จัดการ signal forwarding ได้ถูกต้อง, reap child processes และ restart service ที่ crash อัตโนมัติ&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;Dockerfile (production)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;php:8.2-fpm-alpine&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;RUN&lt;/span&gt; apk add --no-cache supervisor &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# คัดลอก config ของ supervisor&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;COPY&lt;/span&gt; supervisord.conf /etc/supervisor/conf.d/app.conf &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# Healthcheck via FastCGI&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;HEALTHCHECK&lt;/span&gt; --interval=10s --timeout=3s \ &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;CMD&lt;/span&gt; cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1 &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;CMD&lt;/span&gt; [&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;/usr/bin/supervisord&quot;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;-c&quot;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;/etc/supervisor/supervisord.conf&quot;&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;2. SSH Key ใน Docker Container — ทำให้ถูกต้องและปลอดภัย&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ถ้า app ต้องใช้ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;git clone&lt;/code&gt; จาก private repo หรือ deploy ผ่าน SSH ภายใน container การจัดการ SSH key ต้องทำอย่างระมัดระวัง ห้าม hardcode key ใน Dockerfile เด็ดขาด ให้ใช้ Docker build argument แทน&lt;/p&gt;&lt;div class=&quot;callout warning&quot; style=&quot;background: rgb(255, 251, 235); border-color: rgb(253, 230, 138) rgb(253, 230, 138) rgb(253, 230, 138) rgb(245, 158, 11); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #78350f; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; margin: 0px 0px 4px; padding: 0px;&quot;&gt;⚠️ ข้อควรระวัง&lt;/strong&gt;อย่า &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;COPY ~/.ssh/id_rsa /root/.ssh/id_rsa&lt;/code&gt; ตรงๆ ใน Dockerfile เพราะ key จะถูก bake เข้าไปใน image layer และถ้าใครดึง image ไปก็จะได้ private key ของคุณไปด้วย&lt;/div&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;Dockerfile (SSH key ปลอดภัย)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# รับ SSH key ผ่าน build argument&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;ARG&lt;/span&gt; ssh_prv_key &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;ARG&lt;/span&gt; ssh_pub_key &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;RUN&lt;/span&gt; mkdir -p /root/.ssh &amp;amp;&amp;amp; \ echo &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;$ssh_prv_key&quot;&lt;/span&gt; &amp;gt; /root/.ssh/id_rsa &amp;amp;&amp;amp; \ echo &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;$ssh_pub_key&quot;&lt;/span&gt; &amp;gt; /root/.ssh/id_rsa.pub &amp;amp;&amp;amp; \ chmod 600 /root/.ssh/id_rsa &amp;amp;&amp;amp; \ chmod 600 /root/.ssh/id_rsa.pub &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# ลบ key หลัง build เสร็จ (ใช้ --squash)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;terminal — build command&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-cmd&quot; style=&quot;box-sizing: border-box; color: #56d364; margin: 0px; padding: 0px;&quot;&gt;docker build&lt;/span&gt; \ &lt;span class=&quot;c-val&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;--build-arg&lt;/span&gt; ssh_prv_key=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;$(cat ~/.ssh/id_rsa)&quot;&lt;/span&gt; \ &lt;span class=&quot;c-val&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;--build-arg&lt;/span&gt; ssh_pub_key=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;$(cat ~/.ssh/id_rsa.pub)&quot;&lt;/span&gt; \ &lt;span class=&quot;c-val&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;--squash&lt;/span&gt; \ &lt;span class=&quot;c-val&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;-t&lt;/span&gt; myapp .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;3. สองสภาพแวดล้อม ไฟล์เดียว .env&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ใช้ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/code&gt; แยก config ระหว่าง dev และ production อย่าเขียน credential ลงใน docker-compose.yml โดยตรง ใช้ variable substitution แทน&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;.env&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;CI_ENVIRONMENT&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;development&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_HOST&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_PORT&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;3306&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_DATABASE&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;ci4app&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_USERNAME&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;ci4user&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;DB_PASSWORD&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;REDIS_HOST&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;redis&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;REDIS_PORT&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;6379&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;GitHub Actions CI/CD Pipeline&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ทุก push และ pull request จะ trigger workflow อัตโนมัติ รัน PHPUnit, PHPStan และ Rector เพื่อให้มั่นใจว่า code ที่จะ merge เข้า main ผ่าน quality gate ทุกข้อ&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; flex-shrink: 0; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #484f58; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;.github/workflows/ci.yml&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;CI Pipeline&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;on:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;push:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;branches:&lt;/span&gt; [&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;main&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;develop&lt;/span&gt;] &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;pull_request:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;jobs:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;test:&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;runs-on:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;ubuntu-latest&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;steps:&lt;/span&gt; - &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;uses:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;actions/checkout@v4&lt;/span&gt; - &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;Build &amp;amp; Start Stack&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;make setup&lt;/span&gt; - &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;PHPStan — Static Analysis&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;docker compose exec app vendor/bin/phpstan analyse --level=6&lt;/span&gt; - &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;PHPUnit — Run Tests&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;docker compose exec app vendor/bin/phpunit --coverage-text&lt;/span&gt; - &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;Rector — Code Quality Check&lt;/span&gt; &lt;span class=&quot;c-key&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;run:&lt;/span&gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;docker compose exec app vendor/bin/rector process --dry-run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout&quot; style=&quot;background: rgb(239, 246, 255); border-color: rgb(191, 219, 254) rgb(191, 219, 254) rgb(191, 219, 254) rgb(56, 139, 253); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #1e3a5f; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; margin: 0px 0px 4px; padding: 0px;&quot;&gt;🔁 Flow ทำงานอย่างไร&lt;/strong&gt;&lt;ol style=&quot;box-sizing: border-box; color: #3d4451; margin: 8px 0px 18px; padding: 0px 0px 0px 20px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;Push code → GitHub Actions เริ่มทำงาน&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;make setup&lt;/code&gt; build Docker stack ทั้งหมด&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;PHPStan วิเคราะห์ type safety ระดับ 6&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;PHPUnit รัน test suite พร้อม code coverage&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;Rector ตรวจ code style ตาม PHP 8.2 standards&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ผ่านทุก step → merge ได้, fail → block merge ทันที&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Docker Best Practices ที่ต้องรู้&lt;/h2&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; counter-reset: step 0; display: flex; flex-direction: column; gap: 20px; margin: 24px 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 10px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 4px; box-sizing: border-box; display: flex; gap: 16px; margin: 0px; padding: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(15, 31, 61); border-radius: 50%; box-sizing: border-box; color: white; display: flex; flex-shrink: 0; font-size: 15px; font-weight: 700; height: 36px; justify-content: center; margin: 0px; padding: 0px; width: 36px;&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;h4 style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ใช้ Alpine image เสมอ&lt;/h4&gt;&lt;p style=&quot;box-sizing: border-box; color: #4b5563; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;เลือก &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;php:8.2-fpm-alpine&lt;/code&gt; และ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;nginx:alpine&lt;/code&gt; แทน full Debian image ขนาดเล็กกว่า 5–10 เท่า attack surface น้อยกว่า และ pull เร็วกว่ามาก&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 10px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 4px; box-sizing: border-box; display: flex; gap: 16px; margin: 0px; padding: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(15, 31, 61); border-radius: 50%; box-sizing: border-box; color: white; display: flex; flex-shrink: 0; font-size: 15px; font-weight: 700; height: 36px; justify-content: center; margin: 0px; padding: 0px; width: 36px;&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;h4 style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ห้ามใส่ secret ใน image layer&lt;/h4&gt;&lt;p style=&quot;box-sizing: border-box; color: #4b5563; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;ใช้ Docker build argument หรือ Docker secrets สำหรับ sensitive data ทุกชนิด ไม่ว่าจะเป็น API keys, SSH keys หรือ database passwords ถ้า key เข้าไปใน layer แล้วจะดึงออกยากมาก&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 10px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 4px; box-sizing: border-box; display: flex; gap: 16px; margin: 0px; padding: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(15, 31, 61); border-radius: 50%; box-sizing: border-box; color: white; display: flex; flex-shrink: 0; font-size: 15px; font-weight: 700; height: 36px; justify-content: center; margin: 0px; padding: 0px; width: 36px;&quot;&gt;3&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;h4 style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;ใช้ Healthcheck ทุก service&lt;/h4&gt;&lt;p style=&quot;box-sizing: border-box; color: #4b5563; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;Docker รู้ว่า container &quot;start&quot; แต่ไม่รู้ว่า service พร้อมรับ request แล้ว Healthcheck บอก Docker Compose ให้รอ service จริงๆ พร้อมก่อนจึงเริ่ม service ถัดไป&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 10px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 4px; box-sizing: border-box; display: flex; gap: 16px; margin: 0px; padding: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(15, 31, 61); border-radius: 50%; box-sizing: border-box; color: white; display: flex; flex-shrink: 0; font-size: 15px; font-weight: 700; height: 36px; justify-content: center; margin: 0px; padding: 0px; width: 36px;&quot;&gt;4&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;h4 style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;แยก Dockerfile ระหว่าง dev และ production&lt;/h4&gt;&lt;p style=&quot;box-sizing: border-box; color: #4b5563; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Dockerfile.dev&lt;/code&gt; มี pcov, xdebug, git, tools ต่างๆ ส่วน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Dockerfile&lt;/code&gt; production ต้องเบาที่สุด ไม่ต้องการ dev dependency ใดๆ ทั้งนั้น&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(56, 139, 253); box-sizing: border-box; color: #0f1f3d; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;สรุป: ทำไมต้อง Setup แบบนี้?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;การ setup CI4 + Docker stack แบบนี้ให้ประโยชน์ชัดเจนสามด้าน:&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ความเร็ว&lt;/strong&gt; — ไม่ต้องเสียเวลา setup ซ้ำทุกโปรเจกต์ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;make setup&lt;/code&gt; คำสั่งเดียวพร้อมพัฒนา&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ความสม่ำเสมอ&lt;/strong&gt; — ทุก developer ใน team รันบน environment เดียวกันทุกครั้ง ไม่มีปัญหา &quot;works on my machine&quot;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 6px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;คุณภาพ&lt;/strong&gt; — CI/CD pipeline บังคับให้ code ผ่าน test, static analysis และ code quality check ก่อน merge ทุกครั้ง&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;box-sizing: border-box; color: #3d4451; margin: 0px 0px 18px; padding: 0px;&quot;&gt;สำหรับมือใหม่ที่เริ่มต้นกับ CodeIgniter 4 การมี stack แบบนี้ตั้งแต่ต้นจะช่วยให้โฟกัสกับการเขียน business logic ได้เลย แทนที่จะมานั่ง debug environment ปัญหา&lt;/p&gt;&lt;div class=&quot;cta-box&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(15, 31, 61), rgb(26, 53, 96)); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 14px; box-shadow: rgba(15, 31, 61, 0.25) 0px 8px 32px; box-sizing: border-box; margin: 56px 0px 0px; padding: 44px 32px; text-align: center;&quot;&gt;&lt;h2 style=&quot;border-color: currentcolor; border-image: initial; border-style: none; border-width: medium; box-sizing: border-box; color: #e6edf3; font-size: 22px; margin: 48px 0px 12px; padding: 0px;&quot;&gt;🚀 ลองทำตามเลยวันนี้!&lt;/h2&gt;&lt;/div&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6573204827682764224/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/production-ready-codeigniter-4-docker.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6573204827682764224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6573204827682764224'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/production-ready-codeigniter-4-docker.html' title='Production-Ready CodeIgniter 4 + Docker พร้อม CI/CD ใน 10 นาที'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjGluO6BsFEpbFvZlYOk5I0SMv7R2NMmBsfXB9nynANMkOnQBHN4dzoLCb2fa3ogn5Kl-q7lPsdbOoyMEkjXH_2lvzGIZoFLro1EAGEXzzkBHkAQbC01_1xO5HTjUuiRTrcVRRSaFEFmdam8ExjMZ9u3eHlt2eRxeMunOY0UQk68cJJRm0RD25e3wfjeVw=s72-w634-h847-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-124296625225030408</id><published>2026-06-26T23:01:35.668+07:00</published><updated>2026-06-26T23:01:35.669+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>VibePHP: PHP Engine แห่งอนาคต ที่ใช้ AI แทน Interpreter</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiv39wjJFRFwSQk9zkUvq-1qpI1Bd21QhF5aCR4ct3h0XSLDwXImoRQbzvh88wDuJSmJkvPQlbCDoanmtp5Adb8BgFp2pbN13j4Mf3CmNwPTBZYwjlYODRNnRsPTE274XM7eOGKg2cC0ivdMmNdbu9buV7Ic4_-3DXGDKNFKG4zDBmx_qa0le1s4kdlfzw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;424&quot; data-original-width=&quot;1239&quot; height=&quot;232&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiv39wjJFRFwSQk9zkUvq-1qpI1Bd21QhF5aCR4ct3h0XSLDwXImoRQbzvh88wDuJSmJkvPQlbCDoanmtp5Adb8BgFp2pbN13j4Mf3CmNwPTBZYwjlYODRNnRsPTE274XM7eOGKg2cC0ivdMmNdbu9buV7Ic4_-3DXGDKNFKG4zDBmx_qa0le1s4kdlfzw=w680-h232&quot; width=&quot;680&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;section class=&quot;hero&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 23, 42); box-sizing: border-box; color: #f1f5f9; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px; overflow: hidden; padding: 72px 24px 60px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;hero-badge&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(99, 102, 241); border-radius: 99px; box-sizing: border-box; color: white; display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: 0.12em; margin: 0px 0px 20px; padding: 4px 14px; text-transform: uppercase;&quot;&gt;PHP Code Mania · 2026&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; font-size: clamp(2rem, 5vw, 3.2rem); letter-spacing: -0.01em; line-height: 1.2; margin: 0px 0px 18px; padding: 0px;&quot;&gt;VibePHP: &lt;span style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;PHP Engine แห่งอนาคต&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;ที่ใช้ AI แทน Interpreter&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #94a3b8; font-size: 1.05rem; margin: 0px auto 32px; max-width: 600px; padding: 0px;&quot;&gt;ไม่มี Parser ไม่มี Compiler ไม่มีแม้แต่ฐานข้อมูล — แค่ Vibe และ AI ที่คิดเอาเองว่าโค้ดของคุณควรทำอะไร&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; color: #64748b; display: flex; flex-wrap: wrap; font-size: 13px; gap: 24px; justify-content: center; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;📅 มิถุนายน 2026&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;⏱ อ่าน 7 นาที&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;🎯 Beginner–Intermediate&lt;/span&gt;&lt;/div&gt;&lt;/section&gt;&lt;div class=&quot;container post-body&quot; style=&quot;box-sizing: border-box; color: #1e293b; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px auto; max-width: 780px; padding: 56px 0px 80px;&quot;&gt;&lt;div class=&quot;tag-row&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 8px; margin: 0px 0px 36px; padding: 0px;&quot;&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;VibePHP&lt;/span&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;AI Runtime&lt;/span&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;Laravel&lt;/span&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;CodeIgniter 4&lt;/span&gt;&lt;span class=&quot;pill&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 99px; box-sizing: border-box; color: #5b21b6; font-size: 12px; font-weight: 600; letter-spacing: 0.04em; margin: 0px; padding: 4px 14px;&quot;&gt;Web Development&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;บทนำ: PHP ยุค &quot;Vibe-Driven Development&quot;&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ปี 2026 วงการ PHP ได้เห็นสิ่งที่ไม่มีใครคาดคิด — &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;VibePHP&lt;/span&gt; คือ PHP runtime ที่ไม่มี interpreter, ไม่มี compiler, และไม่มีแม้แต่ฐานข้อมูล แต่มันก็ยังสามารถ &quot;รัน&quot; โค้ด PHP ของคุณได้ เพราะมันใช้ AI อ่านซอร์สโค้ดแล้วปั้นผลลัพธ์ขึ้นมาตามความรู้สึก (vibes) ของมันเอง&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ฟังดูบ้าไหม? ใช่ครับ แต่นั่นคือประเด็น — VibePHP เป็นโปรเจกต์เสียดสีแนว satire ที่สร้างขึ้นโดย &lt;a href=&quot;https://github.com/mnapoli/vibephp&quot; style=&quot;box-sizing: border-box; color: #6366f1; margin: 0px; padding: 0px; text-decoration: none;&quot; target=&quot;_blank&quot;&gt;Matthieu Napoli&lt;/a&gt; เพื่อล้อเลียนเทรนด์ &quot;vibe coding&quot; ที่กำลังระบาดในวงการ dev โดยที่โค้ดเดอร์บางคนปล่อยให้ AI สร้างโค้ดโดยไม่ตรวจสอบหรือเข้าใจมันเลย&lt;/p&gt;&lt;div class=&quot;callout callout-fun&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(240, 253, 244); border-left: 4px solid rgb(34, 197, 94); border-radius: 0px 10px 10px 0px; box-sizing: border-box; color: #15803d; font-size: 15.5px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; font-size: 18px; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;😄&lt;/span&gt; &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;หมายเหตุ:&lt;/span&gt; VibePHP &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ไม่ใช่&lt;/em&gt; production framework จริง มันคืองาน satire ที่ฉลาดมาก และบทความนี้จะใช้มันเป็นจุดเริ่มต้นสอนแนวคิด PHP สมัยใหม่ที่คุณนำไปใช้จริงได้&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;VibePHP ทำงานอย่างไร?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;สถาปัตยกรรมของ VibePHP เรียบง่ายเหมือนชื่อมัน: Laravel ทำหน้าที่รับ HTTP request แล้วส่งซอร์สโค้ดให้ AI อ่าน จากนั้น AI จะ &quot;ประมวลผล&quot; ในหัว (literally) แล้วปั้น HTTP response ส่งกลับ&lt;/p&gt;&lt;div class=&quot;diagram&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-sizing: border-box; margin: 24px 0px; overflow-x: auto; padding: 24px 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #94a3b8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 0px;&quot;&gt;┌─────────────────┐ ส่งไฟล์ PHP ให้อ่าน (ไม่ได้รัน) │ Laravel │──────────────────────────────────┐ │ routes URL→file│ ▼ └─────────────────┘ ┌──────────────────────────────────┐ │ VibePhpRuntime (AI) │ HTTP response ◄─────────── │ &quot;ฉันคือ PHP engine ตอนนี้&quot; │ {status, headers, body} │ • ประมวลผลในจินตนาการ │ │ • ปั้นข้อมูลที่หายไปขึ้นมาเอง │ └──────────────────────────────────┘&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;เช่น ถ้าโค้ดของคุณเรียก &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;SELECT * FROM posts&lt;/code&gt; โดยที่ไม่มีฐานข้อมูลอยู่จริง — VibePHP จะปั้น &quot;blog posts&quot; ที่น่าเชื่อถือขึ้นมา 5 รายการให้คุณโดยที่คุณไม่ต้องทำอะไรเลย&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;ตัวอย่างโค้ด: PHP แบบ &quot;Vibe&quot; vs แบบ &quot;Real&quot;&lt;/h2&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.15rem; margin: 32px 0px 10px; padding: 0px;&quot;&gt;🌀 โค้ดสไตล์ VibePHP (ล้อเลียน)&lt;/h3&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;vibe_style.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ไม่มี $db, ไม่มีฐานข้อมูล, ไม่มี posts จริง ๆ&lt;/span&gt; &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แต่ VibePHP จะปั้นมาให้ 5 รายการ ✨&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$result&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;SELECT * FROM posts ORDER BY published_at DESC&quot;&lt;/span&gt;); &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ฟังก์ชันนี้ไม่ได้ define ไว้ที่ไหนเลย&lt;/span&gt; &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แต่จะ return อุณหภูมิที่ &quot;น่าเชื่อถือ&quot; ให้คุณ&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$temp&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;fetchTemperatureFromSomeApiThatDoesNotExist&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;Bangkok temperature: {$temp}°C&quot;&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.15rem; margin: 32px 0px 10px; padding: 0px;&quot;&gt;✅ โค้ดสไตล์ Real PHP ที่ใช้งานได้จริง (CodeIgniter 4)&lt;/h3&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;app/Controllers/PostController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Controllers; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Models\PostModel; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; CodeIgniter\Controller; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;PostController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;() { &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ใช้ Model จริง เชื่อมฐานข้อมูลจริง&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;PostModel&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/span&gt;] = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/span&gt; -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;orderBy&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;DESC&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;findAll&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;posts/index&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout&quot; style=&quot;background: rgba(237, 233, 254, 0.133); border-left: 4px solid rgb(99, 102, 241); border-radius: 0px 10px 10px 0px; box-sizing: border-box; font-size: 15.5px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; font-size: 18px; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;💡&lt;/span&gt; โค้ดจริงใน CodeIgniter 4 ต้องมี Model, Controller, และการเชื่อมต่อฐานข้อมูลที่ชัดเจน — ไม่มีใคร &quot;ปั้น&quot; ข้อมูลให้คุณในโลกจริง&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;ตัวอย่างใน Laravel: Route + Controller + View&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;VibePHP ตัวมันเองสร้างบน Laravel — ซึ่งทำให้เห็นชัดว่า Laravel เป็น framework ที่ทรงพลังมากพอจะเป็นโครงสร้างหลักให้กับ runtime ใหม่ ๆ ได้ ลองดูตัวอย่าง blog posts listing แบบ &quot;ของจริง&quot; ใน Laravel:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;routes/web.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Http\Controllers\PostController; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; Illuminate\Support\Facades\Route; Route::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/&#39;&lt;/span&gt;, [PostController::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;index&#39;&lt;/span&gt;]); Route::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/posts/{id}&#39;&lt;/span&gt;, [PostController::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;show&#39;&lt;/span&gt;]);&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;app/Http/Controllers/PostController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Http\Controllers; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Models\Post; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;PostController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = Post::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;latest&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;posts.index&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;compact&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/span&gt;)); } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$id&lt;/span&gt;) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt; = Post::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;findOrFail&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$id&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;posts.show&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;compact&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;post&#39;&lt;/span&gt;)); } }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;resources/views/posts/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;@extends&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;layouts.app&#39;&lt;/span&gt;) &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;@section&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;) &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;บทความล่าสุด&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;@foreach&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;) &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;article&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;-&amp;gt;title }}&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;-&amp;gt;excerpt }}&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/posts/{{ $post-&amp;gt;id }}&quot;&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;อ่านต่อ →&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;@endforeach&lt;/span&gt; &lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;@endsection&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;เปรียบเทียบ: VibePHP vs PHP จริง&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 28px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.067) 0px 2px 12px; font-size: 15px; margin: 0px; overflow: hidden; padding: 0px; width: 780px;&quot;&gt;&lt;thead style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 23, 42); box-sizing: border-box; color: #f1f5f9; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;box-sizing: border-box; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 14px 16px; text-align: left;&quot;&gt;คุณสมบัติ&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 14px 16px; text-align: left;&quot;&gt;VibePHP (Satire)&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 14px 16px; text-align: left;&quot;&gt;PHP จริง (CI4 / Laravel)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Runtime&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;AI อ่านโค้ดแล้วปั้นผลลัพธ์&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Interpreter/Compiler จริง (PHP-FPM)&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 245, 249); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ฐานข้อมูล&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;AI ปั้นข้อมูลขึ้นมาเอง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;MySQL, PostgreSQL, SQLite ที่ config จริง&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ความถูกต้อง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ไม่ deterministic เลย&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Deterministic ทุก request&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 245, 249); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ค่าใช้จ่าย&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;จ่ายต่อ &quot;particle-millisecond&quot; 💀&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ค่า server/hosting ปกติ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Generics&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&quot;ได้ เพราะไม่มีอะไรหยุดมัน&quot;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;PHP 8.x ยังไม่มี native generics&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 245, 249); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ใช้งาน production ได้?&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;❌ ไม่&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;✅ ได้ 100%&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #6366f1; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;เหมาะกับ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ขำ, เรียนรู้แนวคิด satire&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Web app จริงทุกขนาด&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;บทเรียนจาก VibePHP: Vibe Coding ภัยเงียบของโปรแกรมเมอร์&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;แม้ VibePHP จะเป็นโปรเจกต์ล้อเลียน แต่มันสะท้อนปัญหาจริงในปี 2026 — นั่นคือเทรนด์ &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;&quot;Vibe Coding&quot;&lt;/span&gt; ที่โปรแกรมเมอร์บางคนปล่อยให้ AI generate โค้ดโดยไม่อ่าน ไม่ทำความเข้าใจ แล้วก็ deploy ขึ้น production เลย&lt;/p&gt;&lt;div class=&quot;callout callout-warning&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 243, 199); border-left: 4px solid rgb(245, 158, 11); border-radius: 0px 10px 10px 0px; box-sizing: border-box; color: #92400e; font-size: 15.5px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; font-size: 18px; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;⚠️&lt;/span&gt; &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;Vibe Coding คือ:&lt;/span&gt; การเขียนโค้ดที่พึ่ง AI 100% โดยไม่ตรวจสอบ ไม่เข้าใจ logic และไม่รู้ว่าโค้ดมันทำอะไรจริง ๆ — ปัญหาที่ตามมาคือ security hole, bug ที่หาไม่เจอ, และ codebase ที่ maintain ไม่ได้&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ในฐานะ PHP developer ที่ดี สิ่งที่ควรทำคือ:&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 12px 0px 18px 24px; padding: 0px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ใช้ AI เป็น &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;เครื่องมือช่วย&lt;/span&gt; ไม่ใช่ให้ AI ทำงานทั้งหมดแทน&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 8px; padding: 0px;&quot;&gt;อ่านและทำความเข้าใจโค้ดทุกบรรทัดก่อน deploy&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 8px; padding: 0px;&quot;&gt;เขียน &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;unit test&lt;/span&gt; เพื่อยืนยันว่าโค้ดทำงานถูกต้อง&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px 0px 8px; padding: 0px;&quot;&gt;เรียนรู้ fundamental ของ PHP, SQL, และ HTTP เป็นของตัวเอง&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;PHP สมัยใหม่ที่ใช้ได้จริงใน 2026&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;แทนที่จะฝันถึง VibePHP มาดู feature จริงของ PHP ที่คุณใช้ได้เลยวันนี้:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 41, 59); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.133) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-bar&quot; style=&quot;align-items: center; background: rgb(26, 37, 64); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;modern_php.php — PHP 8.3+&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 20px 22px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;box-sizing: border-box; color: #f472b6; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Named Arguments (PHP 8.0+)&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;htmlspecialchars&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt;: &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$input&lt;/span&gt;, double_encode: &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;); &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Match Expression (PHP 8.0+)&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$label&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;match&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$status&lt;/span&gt;) { &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;active&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;✅ เปิดใช้งาน&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;pending&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;⏳ รอดำเนินการ&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;default&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;❌ ไม่ทราบสถานะ&#39;&lt;/span&gt;, }; &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Readonly Properties (PHP 8.1+)&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;User&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public readonly int&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$id&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public readonly string&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;public readonly string&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;, ) {} } &lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #64748b; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Fibers / Async-like (PHP 8.1+)&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$fiber&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;Fiber&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;(): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$value&lt;/span&gt; = Fiber::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;suspend&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;hello&#39;&lt;/span&gt;); &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;ได้รับค่า: {$value}\n&quot;&lt;/span&gt;; }); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$value&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$fiber&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;start&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #a78bfa; margin: 0px; padding: 0px;&quot;&gt;$fiber&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #38bdf8; margin: 0px; padding: 0px;&quot;&gt;resume&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;world&#39;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;hr style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(99, 102, 241); box-sizing: border-box; display: inline-block; font-size: 1.55rem; margin: 52px 0px 16px; padding: 0px 0px 10px;&quot;&gt;สรุป: Vibe หรือ Real — เลือกอะไร?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;VibePHP คือผลงาน satire ที่ฉลาดมาก มันสะท้อนให้เห็นว่าวงการ dev ในปี 2026 กำลังเดินไปในทิศทางที่น่าเป็นห่วง เมื่อ &quot;vibe&quot; มาก่อน &quot;understanding&quot; เสมอ&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;สำหรับคนที่อยากสร้าง web application จริง ๆ — ไม่ว่าจะด้วย &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/span&gt; หรือ &lt;span style=&quot;box-sizing: border-box; color: #6366f1; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/span&gt; — รากฐานสำคัญยังเป็นเรื่องเดิม: เข้าใจ HTTP, เขียน PHP ที่ deterministic, ใช้ฐานข้อมูลอย่างถูกต้อง และทำ code review อยู่เสมอ&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px;&quot;&gt;AI เป็นเครื่องมือที่ทรงพลัง ใช้มันให้ถูกทาง — ให้มันช่วยคิด ช่วย draft โค้ด แต่ความเข้าใจขั้นสุดท้ายต้องอยู่ที่คุณ ไม่ใช่ที่ vibe&lt;/p&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/124296625225030408/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/vibephp-php-engine-ai-interpreter.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/124296625225030408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/124296625225030408'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/vibephp-php-engine-ai-interpreter.html' title='VibePHP: PHP Engine แห่งอนาคต ที่ใช้ AI แทน Interpreter'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiv39wjJFRFwSQk9zkUvq-1qpI1Bd21QhF5aCR4ct3h0XSLDwXImoRQbzvh88wDuJSmJkvPQlbCDoanmtp5Adb8BgFp2pbN13j4Mf3CmNwPTBZYwjlYODRNnRsPTE274XM7eOGKg2cC0ivdMmNdbu9buV7Ic4_-3DXGDKNFKG4zDBmx_qa0le1s4kdlfzw=s72-w680-h232-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-2763653199257193065</id><published>2026-06-26T07:13:24.497+07:00</published><updated>2026-06-26T07:14:08.298+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>จัด โครงสร้าง PHP Project ให้เป็นระเบียบตั้งแต่วันแรก</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgz4v0kgYmliEcvx4ntHlvB_F5Kl2qnmrP2EMbZ6D556hf7rzDzBPj8KG7tXWlTy4p_UAJznZ3VcjmriEai9BhZACbjJLJVVj2Fk-q1gsJ6lrY74TlMZ8Ou2eU3CyIrHCF1bTfPXrSYqCvw8_GV7untKpWmHbFJTPdLebyjmQQtucdEZXKoGtP2aap-wcA&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1536&quot; data-original-width=&quot;1024&quot; height=&quot;904&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgz4v0kgYmliEcvx4ntHlvB_F5Kl2qnmrP2EMbZ6D556hf7rzDzBPj8KG7tXWlTy4p_UAJznZ3VcjmriEai9BhZACbjJLJVVj2Fk-q1gsJ6lrY74TlMZ8Ou2eU3CyIrHCF1bTfPXrSYqCvw8_GV7untKpWmHbFJTPdLebyjmQQtucdEZXKoGtP2aap-wcA=w603-h904&quot; width=&quot;603&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div class=&quot;hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(238, 240, 255) 0%, rgb(240, 247, 255) 50%, rgb(237, 250, 246) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px; overflow: hidden; padding: 64px 24px 56px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;hero-eyebrow&quot; style=&quot;background: rgba(124, 106, 247, 0.15); border-radius: 20px; border: 1px solid rgba(124, 106, 247, 0.4); box-sizing: border-box; color: #5b4de8; display: inline-block; font-size: 12px; font-weight: 600; letter-spacing: 2px; margin: 0px 0px 22px; padding: 5px 14px; text-transform: uppercase;&quot;&gt;PHP Best Practices&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; font-size: clamp(26px, 5vw, 46px); line-height: 1.25; margin: 0px auto 16px; max-width: 720px; padding: 0px;&quot;&gt;จัด &lt;span style=&quot;box-sizing: border-box; color: #5b4de8; margin: 0px; padding: 0px;&quot;&gt;โครงสร้าง PHP Project&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;ให้เป็นระเบียบตั้งแต่วันแรก&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-size: 15px; margin: 0px auto; max-width: 560px; padding: 0px;&quot;&gt;เทคนิคจัดโฟลเดอร์และไฟล์ที่นักพัฒนามืออาชีพใช้ รองรับทั้ง CodeIgniter 4 และ Laravel&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; color: #6b7494; display: flex; flex-wrap: wrap; font-size: 13px; gap: 20px; justify-content: center; margin: 24px 0px 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;🗂️ โครงสร้างโปรเจกต์&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;🐘 PHP 8+&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;⏱️ อ่าน 8 นาที&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;container&quot; style=&quot;box-sizing: border-box; color: #1e2235; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px auto; max-width: 800px; padding: 48px 24px;&quot;&gt;&lt;div class=&quot;intro-card&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #c8cbdf; font-size: 16px; line-height: 1.9; margin: 0px 0px 40px; padding: 28px 32px;&quot;&gt;คุณเคยเปิดโปรเจกต์ PHP เก่าของตัวเองแล้วรู้สึกหลงทางไหม? ไฟล์กระจัดกระจาย ไม่รู้ว่า Logic อยู่ตรงไหน Database อยู่ที่ไหน — ปัญหานี้เกิดจากการไม่มี &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โครงสร้างโปรเจกต์ที่ชัดเจน&lt;/strong&gt; ตั้งแต่แรก บทความนี้จะพาคุณเรียนรู้วิธีจัดระเบียบโปรเจกต์ PHP อย่างมืออาชีพ พร้อมตัวอย่างโค้ดจริงสำหรับ CodeIgniter 4 และ Laravel&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;ทำไมโครงสร้างโปรเจกต์ถึงสำคัญ?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;PHP ถูกใช้งานในเว็บไซต์กว่า 80% ทั่วโลก ตั้งแต่บล็อกเล็กๆ ไปจนถึงระบบขนาดใหญ่อย่าง Facebook, Wikipedia และ Slack ล้วนใช้ PHP เป็นแกนหลัก สิ่งที่ทำให้โปรเจกต์เหล่านี้ดูแลรักษาได้ง่ายคือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โครงสร้างไฟล์และโฟลเดอร์ที่มีระเบียบ&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;เมื่อโปรเจกต์ขยายตัว สมาชิกในทีมเพิ่มขึ้น หรือคุณต้องกลับมาแก้ไขโค้ดหลังจากผ่านไปหลายเดือน โครงสร้างที่ดีจะช่วยให้:&lt;/p&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgba(14, 164, 122, 0.07); border-radius: 10px; border: 1px solid rgba(14, 164, 122, 0.3); box-sizing: border-box; color: #0a5c45; font-size: 15px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;✅ ประโยชน์ของโครงสร้างที่ดี&lt;/strong&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;นำทางในโค้ดได้ง่าย · ทำงานร่วมกันในทีมได้ลื่นขึ้น · เพิ่มฟีเจอร์ใหม่โดยไม่กระทบส่วนอื่น · เขียน Unit Test ได้สะดวก · Deploy และ Maintain ได้ง่ายในระยะยาว&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;โครงสร้างโฟลเดอร์มาตรฐาน PHP&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;โปรเจกต์ PHP สมัยใหม่ควรแยกหน้าที่ของแต่ละส่วนออกจากกันอย่างชัดเจน นี่คือโครงสร้างที่นิยมใช้กัน:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;project-root/&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;bin/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# CLI scripts &amp;amp; console commands&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;config/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Configuration files (db, mail, cache)&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;public/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Web root — index.php, assets, images&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;src/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Application source code&lt;/span&gt; │ ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;Controllers/&lt;/span&gt; │ ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;Models/&lt;/span&gt; │ └── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;Services/&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;templates/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Views / Blade templates&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;tests/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Automated tests&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;var/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Logs, cache (ไม่ commit เข้า Git)&lt;/span&gt; ├── &lt;span class=&quot;c-dir&quot; style=&quot;box-sizing: border-box; color: #0e7490; margin: 0px; padding: 0px;&quot;&gt;vendor/&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Composer dependencies&lt;/span&gt; ├── &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/span&gt; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Environment variables (secret!)&lt;/span&gt; ├── &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;composer.json&lt;/span&gt; └── &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;README.md&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;หลักสำคัญคือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โฟลเดอร์ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public/&lt;/code&gt;&lt;/strong&gt; ควรเป็นจุดเดียวที่ Web Server เข้าถึงได้จากภายนอก ส่วนโค้ดหลักทั้งหมดอยู่ใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;src/&lt;/code&gt; ซึ่ง User ไม่สามารถเข้าถึงโดยตรงได้ เป็นการป้องกันความปลอดภัยขั้นพื้นฐาน&lt;/p&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;โครงสร้างใน CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;CodeIgniter 4 มาพร้อมโครงสร้างที่ออกแบบมาอย่างดี ทำให้ผู้เริ่มต้นเข้าใจง่าย มาดูตัวอย่าง Controller และ Model ที่เขียนถูกหลักการ:&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0ea47a; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;Controller — รับ Request และส่งต่อให้ Model&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Controllers/ArticleController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;App\Controllers&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;App\Models\ArticleModel&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter\HTTP\RedirectResponse&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleController&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;BaseController&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleModel&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;__construct&lt;/span&gt;() { &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model = &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleModel&lt;/span&gt;(); } &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แสดงรายการบทความทั้งหมด&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;(): &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; { &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt; = [ &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;articles&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model-&amp;gt;findAll(), &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;บทความทั้งหมด&#39;&lt;/span&gt;, ]; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;articles/index&#39;&lt;/span&gt;, &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;); } &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แสดงบทความเดียว&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$id&lt;/span&gt;): &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; { &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$article&lt;/span&gt; = &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model-&amp;gt;find(&lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$id&lt;/span&gt;); &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (! &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$article&lt;/span&gt;) { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;throw new&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;\CodeIgniter\Exceptions\PageNotFoundException&lt;/span&gt;(); } &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;articles/show&#39;&lt;/span&gt;, [&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;article&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$article&lt;/span&gt;]); } }&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0ea47a; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;Model — จัดการข้อมูลและ Business Logic&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Models/ArticleModel.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;App\Models&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter\Model&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleModel&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;Model&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt; = &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;articles&#39;&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$primaryKey&lt;/span&gt; = &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;id&#39;&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$returnType&lt;/span&gt; = &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;array&#39;&lt;/span&gt;; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// กำหนดฟิลด์ที่อนุญาตให้บันทึก (Mass Assignment Protection)&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$allowedFields&lt;/span&gt; = [&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;body&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;slug&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;author_id&#39;&lt;/span&gt;]; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Validation rules&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$validationRules&lt;/span&gt; = [ &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min_length[5]|max_length[200]&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;body&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min_length[20]&#39;&lt;/span&gt;, ]; &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ดึงบทความล่าสุด 10 รายการ&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;getLatest&lt;/span&gt;(&lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$limit&lt;/span&gt; = &lt;span class=&quot;c-num&quot; style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;10&lt;/span&gt;): &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;orderBy&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;created_at&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DESC&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;limit&lt;/span&gt;(&lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$limit&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;findAll&lt;/span&gt;(); } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;โครงสร้างใน Laravel — Blade Template&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Laravel ใช้ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Blade&lt;/strong&gt; เป็น Template Engine ที่ช่วยให้ View สะอาดและอ่านง่าย ตัวอย่างด้านล่างแสดงการใช้ Layout Inheritance และ Component:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;resources/views/layouts/app.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;c-attr&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;lang&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&quot;th&quot;&lt;/span&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;c-attr&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;charset&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;@yield(&#39;title&#39;, &#39;My App&#39;)&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt; @include(&#39;partials.navbar&#39;) &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;main&lt;/span&gt; &lt;span class=&quot;c-attr&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; @yield(&#39;content&#39;) {{-- ส่วนที่ Child View จะ inject เนื้อหาเข้ามา --}} &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/main&amp;gt;&lt;/span&gt; @stack(&#39;scripts&#39;) {{-- สำหรับ JavaScript เฉพาะหน้า --}} &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;resources/views/articles/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;@extends(&#39;layouts.app&#39;) @section(&#39;title&#39;, &#39;บทความทั้งหมด&#39;) @section(&#39;content&#39;) &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;บทความล่าสุด&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt; @forelse($articles as $article) &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;c-attr&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{ $article-&amp;gt;title }}&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ Str::limit($article-&amp;gt;body, 150) }}&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;c-attr&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&quot;{{ route(&#39;articles.show&#39;, $article) }}&quot;&lt;/span&gt;&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; อ่านต่อ → &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; @empty &lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;ยังไม่มีบทความ&lt;span class=&quot;c-tag&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt; @endforelse {{ $articles-&amp;gt;links() }} {{-- Pagination --}} @endsection&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;จัดการ Configuration อย่างปลอดภัย&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;หนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดของนักพัฒนาหน้าใหม่คือการ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;เขียน password หรือ API key ลงในโค้ดโดยตรง&lt;/strong&gt; วิธีที่ถูกต้องคือใช้ไฟล์ &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/code&gt; และโหลดค่าผ่าน Config Class:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;.env&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# ❌ อย่า commit ไฟล์นี้เข้า Git!&lt;/span&gt; DB_HOST=localhost DB_NAME=my_database DB_USER=root DB_PASS=supersecret123 MAIL_HOST=smtp.mailtrap.io MAIL_PORT=587 APP_DEBUG=false APP_ENV=production&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;config/Database.php (CI4 style)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;Config&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter\Database\Config&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;Database&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;Config&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$default&lt;/span&gt; = [ &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;hostname&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;localhost&#39;&lt;/span&gt;), &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;database&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DB_NAME&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;ci4app&#39;&lt;/span&gt;), &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;username&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DB_USER&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;root&#39;&lt;/span&gt;), &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;password&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DB_PASS&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;), &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;DBDriver&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;MySQLi&#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;charset&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;utf8mb4&#39;&lt;/span&gt;, ]; }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgba(14, 164, 122, 0.07); border-radius: 10px; border: 1px solid rgba(14, 164, 122, 0.3); box-sizing: border-box; color: #0a5c45; font-size: 15px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;💡 เคล็ดลับ:&lt;/strong&gt; เพิ่ม &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env&lt;/code&gt; เข้าไปใน &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.gitignore&lt;/code&gt; เสมอ แล้วสร้าง &lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;.env.example&lt;/code&gt; ที่มีแค่ชื่อตัวแปรโดยไม่มีค่าจริง เพื่อให้ทีมรู้ว่าต้องตั้งค่าอะไรบ้าง&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;เปรียบเทียบโครงสร้าง: CI4 vs Laravel&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;แม้ทั้งสองเฟรมเวิร์กจะมีแนวคิด MVC เหมือนกัน แต่มีความแตกต่างในโครงสร้างไฟล์ที่ควรรู้:&lt;/p&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 28px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 14.5px; margin: 0px; padding: 0px; width: 752px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 214, 232); box-sizing: border-box; color: #5b4de8; margin: 0px; padding: 12px 16px; text-align: left; white-space: nowrap;&quot;&gt;ส่วนประกอบ&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 214, 232); box-sizing: border-box; color: #5b4de8; margin: 0px; padding: 12px 16px; text-align: left; white-space: nowrap;&quot;&gt;CodeIgniter 4&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 214, 232); box-sizing: border-box; color: #5b4de8; margin: 0px; padding: 12px 16px; text-align: left; white-space: nowrap;&quot;&gt;Laravel 11+&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 214, 232); box-sizing: border-box; color: #5b4de8; margin: 0px; padding: 12px 16px; text-align: left; white-space: nowrap;&quot;&gt;หน้าที่&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Controllers&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Controllers/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Http/Controllers/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;รับ Request, เรียก Model, Return View&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Models&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Models/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Models/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;จัดการข้อมูลและ Business Logic&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Views&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Views/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;resources/views/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;HTML Template แสดงผล&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Routes&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Config/Routes.php&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;routes/web.php&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;กำหนด URL → Controller&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Config&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Config/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;config/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ค่าตั้งค่าระบบ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Migrations&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;app/Database/Migrations/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;database/migrations/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;สร้าง/แก้ไขตารางในฐานข้อมูล&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Assets&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;CSS, JS, Images ที่ Browser เข้าถึงได้&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Tests&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;tests/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;tests/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; color: #1e2235; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Automated Testing&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;เพิ่ม Service Layer — แยก Logic ออกจาก Controller&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;เมื่อ Business Logic ซับซ้อนขึ้น ควรแยกออกมาเป็น &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Service Class&lt;/strong&gt; เพื่อให้ Controller บางและทดสอบได้ง่าย:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(244, 246, 251); border-color: rgb(208, 214, 232); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 236, 245); border-bottom: 1px solid rgb(208, 214, 232); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #6b7494; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Services/ArticleService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #2d3250; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 20px 24px;&quot;&gt;&lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;App\Services&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;App\Models\ArticleModel&lt;/span&gt;; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleService&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;private readonly&lt;/span&gt; &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;ArticleModel&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/span&gt; ) {} &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;/** * สร้างบทความใหม่พร้อม slug อัตโนมัติ */&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;create&lt;/span&gt;(&lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;): &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; { &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;[&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;slug&#39;&lt;/span&gt;] = &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;makeSlug&lt;/span&gt;(&lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;[&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt;]); &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;[&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;author_id&#39;&lt;/span&gt;] = &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;user_id&lt;/span&gt;(); &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a9ab5; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// หรือ auth()-&amp;gt;id()&lt;/span&gt; &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model-&amp;gt;&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;insert&lt;/span&gt;(&lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$data&lt;/span&gt;); } &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;makeSlug&lt;/span&gt;(&lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$title&lt;/span&gt;): &lt;span class=&quot;c-cls&quot; style=&quot;box-sizing: border-box; color: #b45309; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; { &lt;span class=&quot;c-kw&quot; style=&quot;box-sizing: border-box; color: #7c3aed; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;strtolower&lt;/span&gt;(&lt;span class=&quot;c-fn&quot; style=&quot;box-sizing: border-box; color: #1d6fc4; margin: 0px; padding: 0px;&quot;&gt;str_replace&lt;/span&gt;(&lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39; &#39;&lt;/span&gt;, &lt;span class=&quot;c-str&quot; style=&quot;box-sizing: border-box; color: #16803c; margin: 0px; padding: 0px;&quot;&gt;&#39;-&#39;&lt;/span&gt;, &lt;span class=&quot;c-var&quot; style=&quot;box-sizing: border-box; color: #c2410c; margin: 0px; padding: 0px;&quot;&gt;$title&lt;/span&gt;)); } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(91, 77, 232); box-sizing: border-box; font-size: 22px; margin: 48px 0px 16px; padding: 0px 0px 0px 16px;&quot;&gt;สรุป: หลัก 5 ข้อในการจัดโครงสร้าง PHP Project&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;การจัดโครงสร้าง PHP Project ที่ดีไม่ใช่เรื่องซับซ้อน เพียงแค่ยึดหลักพื้นฐานเหล่านี้:&lt;/p&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgba(14, 164, 122, 0.07); border-radius: 10px; border: 1px solid rgba(14, 164, 122, 0.3); box-sizing: border-box; color: #0a5c45; font-size: 15px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;1. แยก public/ ออกจาก source code&lt;/strong&gt; — ป้องกันไม่ให้ User เข้าถึงโค้ดหลัก&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;2. ใช้ .env สำหรับค่า secret ทุกอย่าง&lt;/strong&gt; — ไม่เขียน password ลงในโค้ด&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;3. ยึดหลัก MVC อย่างเคร่งครัด&lt;/strong&gt; — Controller บาง, Model จัดการ Logic, View แสดงผลล้วนๆ&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;4. เพิ่ม Service Layer เมื่อ Logic ซับซ้อน&lt;/strong&gt; — ทำให้โค้ดทดสอบได้ง่าย&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0ea47a; margin: 0px; padding: 0px;&quot;&gt;5. เขียน Test ในโฟลเดอร์ tests/&lt;/strong&gt; — ป้องกัน Bug เมื่อแก้ไขโค้ดในอนาคต&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ทั้ง CodeIgniter 4 และ Laravel ต่างมีโครงสร้างที่ออกแบบมาตามหลักการเหล่านี้แล้ว สิ่งที่คุณต้องทำคือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ทำความเข้าใจว่าแต่ละส่วนทำหน้าที่อะไร&lt;/strong&gt; และเขียนโค้ดให้อยู่ในที่ที่ถูกต้อง เพียงเท่านี้โปรเจกต์ของคุณก็จะดูแลรักษาได้ง่ายขึ้นอย่างเห็นได้ชัด&lt;/p&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/2763653199257193065/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-project.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/2763653199257193065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/2763653199257193065'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-project.html' title='จัด โครงสร้าง PHP Project ให้เป็นระเบียบตั้งแต่วันแรก'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgz4v0kgYmliEcvx4ntHlvB_F5Kl2qnmrP2EMbZ6D556hf7rzDzBPj8KG7tXWlTy4p_UAJznZ3VcjmriEai9BhZACbjJLJVVj2Fk-q1gsJ6lrY74TlMZ8Ou2eU3CyIrHCF1bTfPXrSYqCvw8_GV7untKpWmHbFJTPdLebyjmQQtucdEZXKoGtP2aap-wcA=s72-w603-h904-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6399613178499819914</id><published>2026-06-23T07:17:52.287+07:00</published><updated>2026-06-23T07:17:52.287+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>สร้าง PHP Contact Form แบบไม่ใช้ฐานข้อมูล</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgOa0sEA-sW1G4eY7btJm7FLKRoBwU6cUxlyM3ZktAqzmRv36B5pFu2l59jr35RhPZNGwKilojUX1SQnlGORfbCn4J3rAGj7cYsfciGwYCOJ1jD1b3pOUjrzH14MzyJVyIgXiVXPlMi7DCE0T2NVNxVw9Z9t7gtIXkKM14Yy4R75rx6SRYr7SMtR_hpyBE&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1122&quot; data-original-width=&quot;1402&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgOa0sEA-sW1G4eY7btJm7FLKRoBwU6cUxlyM3ZktAqzmRv36B5pFu2l59jr35RhPZNGwKilojUX1SQnlGORfbCn4J3rAGj7cYsfciGwYCOJ1jD1b3pOUjrzH14MzyJVyIgXiVXPlMi7DCE0T2NVNxVw9Z9t7gtIXkKM14Yy4R75rx6SRYr7SMtR_hpyBE&quot; width=&quot;600&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;div class=&quot;hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(232, 244, 253) 0%, rgb(219, 234, 254) 50%, rgb(224, 242, 254) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px; overflow: hidden; padding: 56px 24px 48px; position: relative;&quot;&gt;&lt;div class=&quot;hero-eyebrow&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(221, 244, 255); border-radius: 20px; border: 1px solid rgba(88, 166, 255, 0.25); box-sizing: border-box; color: #0550ae; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; margin: 0px 0px 20px; padding: 4px 14px;&quot;&gt;PHP · Contact Form · No Database&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; font-size: clamp(26px, 5vw, 38px); line-height: 1.3; margin: 0px auto 16px; max-width: 700px; padding: 0px;&quot;&gt;สร้าง &lt;span style=&quot;box-sizing: border-box; color: #0969da; margin: 0px; padding: 0px;&quot;&gt;PHP Contact Form&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;แบบไม่ใช้ฐานข้อมูล&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #656d76; font-size: 15px; margin: 0px auto; max-width: 560px; padding: 0px;&quot;&gt;Lightweight Script ที่ทุกเว็บไซต์ควรมี — รับข้อมูลผู้ใช้แล้วส่ง Email แจ้งเตือนได้ทันที&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;content&quot; style=&quot;box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px auto; max-width: 780px; padding: 40px 24px 64px; text-align: start;&quot;&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;ทำไมต้องมี Contact Form?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ทุกเว็บไซต์ที่ต้องการรับ Feedback หรือสอบถามจากผู้ใช้ จำเป็นต้องมีหน้า &quot;ติดต่อเรา&quot; วิธีดั้งเดิมคือให้แสดง Email Address ตรงๆ แต่มีปัญหาเรื่อง Spam Bot มาดูดเอาไปใช้ แนวทางที่ดีกว่าคือใช้ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHP Contact Form&lt;/strong&gt; — ผู้ใช้กรอกข้อมูลในหน้าเว็บ แล้วให้ PHP จัดการส่ง Email ให้เบื้องหลัง&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;บทความนี้จะสอนสร้าง Contact Form แบบ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ไม่พึ่งฐานข้อมูล&lt;/strong&gt; โค้ดเบาสุด ติดตั้งง่าย เหมาะสำหรับเว็บไซต์ขนาดเล็กหรือ Landing Page และยังเป็นพื้นฐานที่จะต่อยอดเข้า CodeIgniter 4 หรือ Laravel ได้ในภายหลัง&lt;/p&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgba(88, 166, 255, 0.07); border-color: rgba(88, 166, 255, 0.3) rgba(88, 166, 255, 0.3) rgba(88, 166, 255, 0.3) rgb(9, 105, 218); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; font-size: 15px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0969da; margin: 0px; padding: 0px;&quot;&gt;สิ่งที่จะได้เรียนรู้:&lt;/strong&gt; HTML Form → PHP &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;$_POST&lt;/code&gt; → Validation → &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;mail()&lt;/code&gt; function → แสดง Success/Error Message&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Step 1 — สร้าง HTML Form&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;เริ่มด้วยไฟล์ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;contact.html&lt;/code&gt; (หรือ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;contact.php&lt;/code&gt;) ที่มี Form รับชื่อ, Email และข้อความ สังเกต attribute สำคัญ 2 ตัวบน &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;&amp;lt;form&amp;gt;&lt;/code&gt;:&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px 0px 16px 20px; padding: 0px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;method=&quot;POST&quot;&lt;/code&gt; — ซ่อนข้อมูลใน Request Body ไม่โชว์ใน URL&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;action=&quot;send.php&quot;&lt;/code&gt; — ส่งข้อมูลไปประมวลผลที่ไฟล์นี้&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;contact.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;lang&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;th&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;charset&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;ติดต่อเรา&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;body&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;bg-light py-5&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;container&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;style&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;max-width:560px&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;mb-4&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;ติดต่อเรา&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;method&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;POST&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;action&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;send.php&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;mb-3&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-label&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;ชื่อ-นามสกุล&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-control&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;กรอกชื่อของคุณ&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;mb-3&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-label&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;อีเมล&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-control&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;example@email.com&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;mb-3&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-label&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;ข้อความ&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;message&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;form-control&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;rows&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;5&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;พิมพ์ข้อความของคุณ...&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;submit&quot;&lt;/span&gt; &lt;span class=&quot;at&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;btn btn-primary w-100&quot;&lt;/span&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; ส่งข้อความ &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Step 2 — สร้าง PHP Handler (send.php)&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;นี่คือหัวใจหลักของระบบ ไฟล์ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;send.php&lt;/code&gt; จะรับค่าจาก &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;$_POST&lt;/code&gt;, Validate ข้อมูล, แล้วใช้ฟังก์ชัน &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;mail()&lt;/code&gt; ส่ง Email ไปยังกล่องจดหมายของเรา&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;send.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ป้องกัน Direct Access (ต้องมาจาก POST เท่านั้น)&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; ($_SERVER[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;REQUEST_METHOD&#39;&lt;/span&gt;] !== &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;POST&#39;&lt;/span&gt;) { &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Location: contact.php&#39;&lt;/span&gt;); &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;exit&lt;/span&gt;(); } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 1. รับค่าและทำความสะอาดข้อมูล (Sanitize)&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;trim&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;htmlspecialchars&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;strip_tags&lt;/span&gt;($_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;]))); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;trim&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;filter_var&lt;/span&gt;($_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;], FILTER_SANITIZE_EMAIL)); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$message&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;trim&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;htmlspecialchars&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;strip_tags&lt;/span&gt;($_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;message&#39;&lt;/span&gt;]))); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 2. Validate ข้อมูล&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt; = []; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;empty&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;)) { &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt;[] = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;กรุณากรอกชื่อ&#39;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;filter_var&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;, FILTER_VALIDATE_EMAIL)) { &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt;[] = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;รูปแบบอีเมลไม่ถูกต้อง&#39;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;strlen&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$message&lt;/span&gt;) &amp;lt; 10) { &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt;[] = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;ข้อความต้องมีอย่างน้อย 10 ตัวอักษร&#39;&lt;/span&gt;; } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 3. ถ้า Validate ไม่ผ่าน — แสดง Error แล้วหยุด&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;empty&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt;)) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$errors&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$err&lt;/span&gt;) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;&amp;lt;p style=&#39;color:red&#39;&amp;gt;&quot;&lt;/span&gt; . &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$err&lt;/span&gt; . &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;&amp;lt;/p&amp;gt;&quot;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;exit&lt;/span&gt;(); } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 4. เตรียม Email&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$to&lt;/span&gt; = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;your@email.com&#39;&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เปลี่ยนเป็น Email ของคุณ&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$subject&lt;/span&gt; = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;[Contact Form] ข้อความจาก &#39;&lt;/span&gt; . &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$body&lt;/span&gt; = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;ชื่อ: {$name}\n&quot;&lt;/span&gt; . &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;อีเมล: {$email}\n\n&quot;&lt;/span&gt; . &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;ข้อความ:\n{$message}&quot;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$headers&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;implode&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;\r\n&quot;&lt;/span&gt;, [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;From: noreply@yoursite.com&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Reply-To: &#39;&lt;/span&gt; . &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type: text/plain; charset=UTF-8&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;X-Mailer: PHP/&#39;&lt;/span&gt; . &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;phpversion&lt;/span&gt;(), ]); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 5. ส่ง Email&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;mail&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$to&lt;/span&gt;, &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$subject&lt;/span&gt;, &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$body&lt;/span&gt;, &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$headers&lt;/span&gt;)) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;&amp;lt;p style=&quot;color:green&quot;&amp;gt;✅ ส่งข้อความสำเร็จ! เราจะติดต่อกลับเร็วๆ นี้&amp;lt;/p&amp;gt;&#39;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;&amp;lt;p style=&quot;color:red&quot;&amp;gt;❌ เกิดข้อผิดพลาด ไม่สามารถส่งได้ กรุณาลองใหม่&amp;lt;/p&amp;gt;&#39;&lt;/span&gt;; } &lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;warn-box&quot; style=&quot;background: rgba(255, 189, 46, 0.07); border-color: rgba(255, 189, 46, 0.3) rgba(255, 189, 46, 0.3) rgba(255, 189, 46, 0.3) rgb(254, 188, 46); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; font-size: 15px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #febc2e; margin: 0px; padding: 0px;&quot;&gt;⚠️ หมายเหตุ:&lt;/strong&gt; ฟังก์ชัน &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;mail()&lt;/code&gt; ต้องมีการตั้งค่า SMTP บน Server ให้ถูกต้อง บน Localhost (XAMPP/Laragon) อาจต้องใช้ PHPMailer + Gmail SMTP แทน — จะอธิบายใน Step 4&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Step 3 — Security: ป้องกัน XSS และ Header Injection&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Contact Form ที่ไม่ได้ป้องกันเลยมีความเสี่ยง 2 อย่างหลัก:&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0969da; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;XSS (Cross-Site Scripting)&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ผู้ไม่หวังดีอาจส่ง &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;&amp;lt;script&amp;gt;alert(&#39;hacked&#39;)&amp;lt;/script&amp;gt;&lt;/code&gt; เข้ามาในช่องข้อความ แก้ด้วยการใช้ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;htmlspecialchars()&lt;/code&gt; และ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;strip_tags()&lt;/code&gt; ก่อนนำไปแสดงผล&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0969da; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;Email Header Injection&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ถ้าเอา &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;$email&lt;/code&gt; ที่รับมาใส่ใน Header โดยตรงโดยไม่ Sanitize อาจถูก Inject Header เพิ่มได้ โค้ดข้างบนใช้ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;FILTER_SANITIZE_EMAIL&lt;/code&gt; เพื่อตัดอักขระที่ไม่ถูกต้องออก&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;ตัวอย่าง Sanitize&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Safe — ใช้ filter functions ก่อนเสมอ&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;trim&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;htmlspecialchars&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;strip_tags&lt;/span&gt;($_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;]))); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;filter_var&lt;/span&gt;($_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;], FILTER_SANITIZE_EMAIL); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ❌ Unsafe — อย่าทำแบบนี้&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt; = $_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;]; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ไม่ได้ Sanitize เลย&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt; = $_POST[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;]; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เสี่ยง Header Injection&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;Step 4 — ใช้ PHPMailer แทน mail() (แนะนำ)&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ฟังก์ชัน &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;mail()&lt;/code&gt; แบบ Built-in ใช้ได้บน Shared Hosting ทั่วไป แต่ถ้าต้องการส่งผ่าน &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Gmail SMTP&lt;/strong&gt; หรือ Service อื่นเช่น SendGrid, Mailgun ควรใช้ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHPMailer&lt;/strong&gt; ซึ่งติดตั้งผ่าน Composer ได้เลย&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;composer require phpmailer/phpmailer&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;send_smtp.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; PHPMailer\PHPMailer\PHPMailer; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; PHPMailer\PHPMailer\Exception; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;vendor/autoload.php&#39;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;PHPMailer&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;try&lt;/span&gt; { &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// SMTP Settings&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;isSMTP(); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Host = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;smtp.gmail.com&#39;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;SMTPAuth = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Username = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;your@gmail.com&#39;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Password = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;app-password-here&#39;&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// App Password จาก Google&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;SMTPSecure = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;tls&#39;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Port = 587; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;CharSet = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;UTF-8&#39;&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ผู้ส่ง/ผู้รับ&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;setFrom(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;noreply@yoursite.com&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;My Website&#39;&lt;/span&gt;); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;addAddress(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;your@email.com&#39;&lt;/span&gt;); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;addReplyTo(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;, &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เนื้อหา Email&lt;/span&gt; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Subject = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;[Contact] ข้อความจาก &#39;&lt;/span&gt; . &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;Body = &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;ชื่อ: {$name}\nEmail: {$email}\n\n{$message}&quot;&lt;/span&gt;; &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$mail&lt;/span&gt;-&amp;gt;send(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;✅ ส่งสำเร็จแล้ว!&#39;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;catch&lt;/span&gt; (Exception &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$e&lt;/span&gt;) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&quot;❌ Error: {$mail-&amp;gt;ErrorInfo}&quot;&lt;/span&gt;; }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;เปรียบเทียบ mail() vs PHPMailer&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 24px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 14.5px; margin: 0px; padding: 0px; width: 732px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(234, 238, 242); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 215, 222); box-sizing: border-box; color: #0969da; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Feature&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 215, 222); box-sizing: border-box; color: #0969da; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;mail() Built-in&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(208, 215, 222); box-sizing: border-box; color: #0969da; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;PHPMailer&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;ติดตั้ง&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;ไม่ต้องติดตั้ง มีใน PHP ทันที&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;ต้องติดตั้งผ่าน Composer&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;SMTP Auth&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;❌ ไม่รองรับโดยตรง&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;✅ รองรับเต็มรูปแบบ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;Gmail/SendGrid&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;❌ ต้องตั้งค่า Server เอง&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;✅ ใช้งานได้ทันที&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;HTML Email&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;ทำได้ แต่ยุ่งยาก&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;✅ ง่ายมาก รองรับ Attachment ด้วย&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;Error Handling&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;คืนแค่ true/false&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;✅ มี Exception พร้อม Error Message&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 11px 16px;&quot;&gt;เหมาะกับ&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;Shared Hosting ทั่วไป&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; color: #1f2328; margin: 0px; padding: 11px 16px;&quot;&gt;ทุก Environment โดยเฉพาะ Production&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;ต่อยอดเข้า CodeIgniter 4 และ Laravel&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ถ้าใช้ Framework อยู่แล้ว ไม่จำเป็นต้องเขียน &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;send.php&lt;/code&gt; แยกออกมา ทั้ง CI4 และ Laravel มีโครงสร้างที่รองรับการทำ Contact Form ได้สวยงามกว่า:&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0969da; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;app/Controllers/ContactController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;tg&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Controllers; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; CodeIgniter\Controller; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ContactController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;send&lt;/span&gt;() { &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$rules&lt;/span&gt; = [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min_length[2]&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|valid_email&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;message&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min_length[10]&#39;&lt;/span&gt;, ]; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;validate&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$rules&lt;/span&gt;)) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;redirect&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;back&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;withInput&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;errors&#39;&lt;/span&gt;, &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;validator-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getErrors&lt;/span&gt;()); } &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;service&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setTo&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;your@email.com&#39;&lt;/span&gt;); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setSubject&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;Contact: &#39;&lt;/span&gt; . &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;request-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getPost&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;)); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;setMessage&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;request-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getPost&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;message&#39;&lt;/span&gt;)); &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;send&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;redirect&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;to&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;/contact&#39;&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;success&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;ส่งข้อความสำเร็จ!&#39;&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #0969da; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;Laravel (Mailable)&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.4) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 61); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #656d76; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 6px; padding: 0px;&quot;&gt;app/Http/Controllers/ContactController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; Illuminate\Http\Request; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; Illuminate\Support\Facades\Mail; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Mail\ContactMail; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;send&lt;/span&gt;(Request &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;) { &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$validated&lt;/span&gt; = &lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;validate&lt;/span&gt;([ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|string|max:100&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|email&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;message&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min:10&#39;&lt;/span&gt;, ]); Mail::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;to&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;your@email.com&#39;&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;send&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ContactMail&lt;/span&gt;(&lt;span class=&quot;vr&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$validated&lt;/span&gt;)); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;back&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;success&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;ขอบคุณ! เราจะติดต่อกลับเร็วๆ นี้&#39;&lt;/span&gt;); }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgba(88, 166, 255, 0.07); border-color: rgba(88, 166, 255, 0.3) rgba(88, 166, 255, 0.3) rgba(88, 166, 255, 0.3) rgb(9, 105, 218); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; font-size: 15px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #0969da; margin: 0px; padding: 0px;&quot;&gt;💡 เคล็ดลับ:&lt;/strong&gt; ใน Laravel ใช้คำสั่ง &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;php artisan make:mail ContactMail&lt;/code&gt; เพื่อสร้าง Mailable Class พร้อม Blade Template อัตโนมัติ สะอาดกว่าการ Hard-code HTML ใน Controller มาก&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; font-size: 22px; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Contact Form แบบ Lightweight ที่ไม่ใช้ฐานข้อมูลเป็นจุดเริ่มต้นที่ดีมากสำหรับมือใหม่ แค่ 2 ไฟล์ (&lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;contact.php&lt;/code&gt; + &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;send.php&lt;/code&gt;) ก็พร้อมใช้งานจริงบน Server แล้ว&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ขั้นตอนสำคัญที่ต้องจำ:&lt;/p&gt;&lt;div class=&quot;step-row&quot; style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 4px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-badge&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(9, 105, 218); border-radius: 50%; box-sizing: border-box; color: black; display: inline-flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 700; height: 28px; justify-content: center; margin: 0px 8px 0px 0px; padding: 0px; width: 28px;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;รับค่าจาก &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;$_POST&lt;/code&gt; แล้ว Sanitize ทันที&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step-row&quot; style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 4px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-badge&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(9, 105, 218); border-radius: 50%; box-sizing: border-box; color: black; display: inline-flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 700; height: 28px; justify-content: center; margin: 0px 8px 0px 0px; padding: 0px; width: 28px;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Validate ทุก Field ก่อนดำเนินการต่อ&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step-row&quot; style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 4px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-badge&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(9, 105, 218); border-radius: 50%; box-sizing: border-box; color: black; display: inline-flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 700; height: 28px; justify-content: center; margin: 0px 8px 0px 0px; padding: 0px; width: 28px;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ใช้ &lt;code style=&quot;background: rgba(247, 129, 102, 0.12); border-radius: 4px; box-sizing: border-box; color: #cf222e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin: 0px; padding: 2px 7px;&quot;&gt;mail()&lt;/code&gt; สำหรับ Hosting ทั่วไป หรือ PHPMailer สำหรับ SMTP&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step-row&quot; style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 4px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-badge&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(9, 105, 218); border-radius: 50%; box-sizing: border-box; color: black; display: inline-flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 700; height: 28px; justify-content: center; margin: 0px 8px 0px 0px; padding: 0px; width: 28px;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;แสดง Success/Error Message ให้ผู้ใช้รู้ผลทันที&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;step-row&quot; style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 4px; margin: 8px 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-badge&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(9, 105, 218); border-radius: 50%; box-sizing: border-box; color: black; display: inline-flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; font-weight: 700; height: 28px; justify-content: center; margin: 0px 8px 0px 0px; padding: 0px; width: 28px;&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ต่อยอดเข้า CI4 หรือ Laravel ด้วย Built-in Email Service&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;cta-box&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(219, 234, 254), rgb(224, 242, 254)); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 12px; border: 1px solid rgba(9, 105, 218, 0.25); box-sizing: border-box; margin: 48px 0px 0px; padding: 36px 28px; text-align: center;&quot;&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px 0px 10px; padding: 0px;&quot;&gt;อ่านบทความ PHP เพิ่มเติมที่ PHP Code Mania&lt;/h3&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6399613178499819914/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-contact-form.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6399613178499819914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6399613178499819914'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-contact-form.html' title='สร้าง PHP Contact Form แบบไม่ใช้ฐานข้อมูล'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgOa0sEA-sW1G4eY7btJm7FLKRoBwU6cUxlyM3ZktAqzmRv36B5pFu2l59jr35RhPZNGwKilojUX1SQnlGORfbCn4J3rAGj7cYsfciGwYCOJ1jD1b3pOUjrzH14MzyJVyIgXiVXPlMi7DCE0T2NVNxVw9Z9t7gtIXkKM14Yy4R75rx6SRYr7SMtR_hpyBE=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6101631278212076002</id><published>2026-06-22T07:28:54.251+07:00</published><updated>2026-06-22T07:28:54.251+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>ผมสร้างระบบ Login และ CRUD แบบง่าย ๆ ด้วย PHP + Bootstrap 5 (โปรเจกต์เริ่มต้นสำหรับมือใหม่)</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhS5bkfj18JRMffi2J3P-d6BnMXpFf0SkuKPD2r43fyVK8SbVZR7YjBTax7VDgiC2VZT5Eabubf0HNYQ6qiObWIzU-6RRTKzEjh8iAznjTGP1Y093Kv5QeIqMTeTOJTful2X7weCKHeRZo_ulRFP_bVQEIMomnvXLxMYbknCWJZReOMiJyYB0DHMTHQKKc&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1254&quot; data-original-width=&quot;1254&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhS5bkfj18JRMffi2J3P-d6BnMXpFf0SkuKPD2r43fyVK8SbVZR7YjBTax7VDgiC2VZT5Eabubf0HNYQ6qiObWIzU-6RRTKzEjh8iAznjTGP1Y093Kv5QeIqMTeTOJTful2X7weCKHeRZo_ulRFP_bVQEIMomnvXLxMYbknCWJZReOMiJyYB0DHMTHQKKc&quot; width=&quot;480&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div class=&quot;pcm-hero&quot; style=&quot;background-attachment: scroll, scroll, scroll; background-clip: border-box, border-box, border-box; background-image: radial-gradient(circle at 15% 20%, rgba(43, 224, 232, 0.18), rgba(0, 0, 0, 0) 45%), radial-gradient(circle at 85% 80%, rgba(255, 62, 138, 0.16), rgba(0, 0, 0, 0) 50%), linear-gradient(rgb(13, 13, 23) 0%, rgb(21, 21, 42) 100%); background-origin: padding-box, padding-box, padding-box; background-position: 0% 0%, 0% 0%, 0% 0%; background-repeat: repeat, repeat, repeat; background-size: auto, auto, auto; border-radius: 18px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 36px; overflow: hidden; padding: 52px 40px; position: relative;&quot;&gt;&lt;span class=&quot;pcm-eyebrow&quot; style=&quot;border-radius: 999px; border: 1px solid rgba(43, 224, 232, 0.4); box-sizing: border-box; color: #2be0e8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; letter-spacing: 0.16em; margin-bottom: 18px; padding: 5px 12px; position: relative;&quot;&gt;PHP PROJECT WALKTHROUGH&lt;/span&gt;&lt;h1 style=&quot;box-sizing: border-box; color: #f4efe6; font-size: 32px; line-height: 1.45; margin: 0px 0px 16px; position: relative;&quot;&gt;ผมสร้างระบบ &lt;span style=&quot;box-sizing: border-box; color: #ffb454;&quot;&gt;Login&lt;/span&gt; และ &lt;span style=&quot;box-sizing: border-box; color: #ffb454;&quot;&gt;CRUD&lt;/span&gt; แบบง่าย ๆ ด้วย PHP + Bootstrap 5&lt;br style=&quot;box-sizing: border-box;&quot; /&gt;(โปรเจกต์เริ่มต้นสำหรับมือใหม่)&lt;/h1&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px; max-width: 620px; position: relative;&quot;&gt;ก่อนจะกระโดดไปเรียน CodeIgniter 4 หรือ Laravel แบบเต็มตัว บทความนี้พาทำโปรเจกต์ Login + CRUD ด้วย PHP ล้วน ๆ ให้เห็นภาพว่า Framework ช่วยอะไรเราบ้าง พร้อมแก้จุดอ่อนด้านความปลอดภัยที่บทเรียนทั่วไปมักมองข้าม&lt;/p&gt;&lt;div class=&quot;pcm-hero-meta&quot; style=&quot;box-sizing: border-box; color: #2be0e8; display: flex; flex-wrap: wrap; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; gap: 18px; position: relative;&quot;&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px;&quot;&gt;⏱&lt;span style=&quot;box-sizing: border-box; color: #f4efe6;&quot;&gt;อ่านประมาณ 9 นาที&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px;&quot;&gt;🧩&lt;span style=&quot;box-sizing: border-box; color: #f4efe6;&quot;&gt;ระดับ: เริ่มต้น&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 6px;&quot;&gt;🛠&lt;span style=&quot;box-sizing: border-box; color: #f4efe6;&quot;&gt;PHP + MySQLi + Bootstrap 5&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;หลายคนเริ่มเรียน PHP จากการทำระบบ Login และ CRUD (Create, Read, Update, Delete) เป็นโปรเจกต์แรก เพราะมันคือแกนกลางของเว็บแอปแทบทุกประเภท ตั้งแต่ระบบจัดการนักเรียน ระบบสมาชิกร้านค้า ไปจนถึง Backoffice ขององค์กร ในบทความนี้เราจะสร้างระบบนี้ด้วย PHP ดิบ ๆ (Vanilla PHP) ร่วมกับ Bootstrap 5 ตั้งแต่ศูนย์ และที่สำคัญคือเราจะเขียนให้ &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;ปลอดภัยกว่าตัวอย่างทั่วไปที่หาอ่านได้ตามเว็บ&lt;/span&gt; เพราะ Tutorial ส่วนใหญ่มักสอนแบบ query ตรง ๆ ที่เปิดช่องให้เกิด SQL Injection และเก็บรหัสผ่านแบบไม่เข้ารหัส ซึ่งเป็นนิสัยที่ไม่ควรติดไปใช้ในงานจริง&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;เป้าหมายของบทความนี้ไม่ใช่แค่ &quot;ทำให้รัน&quot; แต่อยากให้มือใหม่เห็นว่าการเขียน PHP แบบดิบต้องดูแลเรื่องอะไรเองบ้าง เมื่อเทียบกับตอนที่เราย้ายไปใช้ CodeIgniter 4 หรือ Laravel ที่มีโครงสร้างพวกนี้เตรียมไว้ให้แล้ว&lt;/p&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;01&lt;/span&gt;สิ่งที่ต้องเตรียมก่อนเริ่ม&lt;/h2&gt;&lt;ul style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 20px; padding-left: 22px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin-bottom: 8px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Local server:&lt;/span&gt; XAMPP หรือ Laragon (มี Apache + MySQL + PHP ในตัว)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin-bottom: 8px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;พื้นฐาน PHP:&lt;/span&gt; ตัวแปร, ฟังก์ชัน, if/else, array เบื้องต้น&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin-bottom: 8px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;พื้นฐาน SQL:&lt;/span&gt; CREATE TABLE, SELECT, INSERT, UPDATE, DELETE&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin-bottom: 8px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Bootstrap 5:&lt;/span&gt; ใช้ผ่าน CDN ไม่ต้องติดตั้งอะไรเพิ่ม&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;02&lt;/span&gt;สร้างฐานข้อมูลและไฟล์เชื่อมต่อ&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;เริ่มจากสร้างฐานข้อมูลชื่อ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;pcm_demo&lt;/code&gt; และตาราง &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;users&lt;/code&gt; สำหรับ Login กับตาราง &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;students&lt;/code&gt; สำหรับฝึก CRUD&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;schema.sql&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;CREATE TABLE&lt;/span&gt; users ( id &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;AUTO_INCREMENT PRIMARY KEY&lt;/span&gt;, username &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;VARCHAR&lt;/span&gt;(50) &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;NOT NULL UNIQUE&lt;/span&gt;, password &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;VARCHAR&lt;/span&gt;(255) &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;NOT NULL&lt;/span&gt; ); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;CREATE TABLE&lt;/span&gt; students ( id &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;AUTO_INCREMENT PRIMARY KEY&lt;/span&gt;, name &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;VARCHAR&lt;/span&gt;(100) &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;NOT NULL&lt;/span&gt;, class &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;VARCHAR&lt;/span&gt;(20) &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;NOT NULL&lt;/span&gt;, marks &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;NOT NULL&lt;/span&gt; );&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;จากนั้นสร้างไฟล์เชื่อมต่อฐานข้อมูล โดยใช้ &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;MySQLi แบบ Object-Oriented&lt;/span&gt; และเปิด exception mode ไว้ เพื่อให้ error แสดงชัดเจนตอนพัฒนา&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;config/db.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; mysqli_report(&lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;MYSQLI_REPORT_ERROR&lt;/span&gt; | &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;MYSQLI_REPORT_STRICT&lt;/span&gt;); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;define&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;DB_HOST&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;localhost&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;define&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;DB_USER&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;root&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;define&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;DB_PASS&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;define&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;DB_NAME&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;pcm_demo&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;try&lt;/span&gt; { $conn = &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;mysqli&lt;/span&gt;(&lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;DB_HOST&lt;/span&gt;, &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;DB_USER&lt;/span&gt;, &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;DB_PASS&lt;/span&gt;, &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;DB_NAME&lt;/span&gt;); $conn-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;set_charset&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;utf8mb4&#39;&lt;/span&gt;); } &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;catch&lt;/span&gt; (mysqli_sql_exception $e) { &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;die&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Connection failed: &#39;&lt;/span&gt; . $e-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;getMessage&lt;/span&gt;()); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-callout&quot; style=&quot;background: rgb(255, 248, 232); border-left: 4px solid rgb(255, 180, 84); border-radius: 8px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 15.5px; margin: 20px 0px 28px; padding: 16px 20px;&quot;&gt;&lt;b style=&quot;box-sizing: border-box; color: #b9700a; display: block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; letter-spacing: 0.05em; margin-bottom: 4px;&quot;&gt;💡 ทำไมต้อง mysqli_report&lt;/b&gt;การเปิด &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;MYSQLI_REPORT_STRICT&lt;/code&gt; ทำให้ทุก query ที่ผิดพลาดโยน Exception ออกมาทันที แทนที่จะปล่อยให้ query ล้มเหลวเงียบ ๆ ซึ่งช่วยจับบั๊กได้เร็วกว่าการเช็ค &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;if ($result === false)&lt;/code&gt; ทุกจุด&lt;/div&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;03&lt;/span&gt;ระบบ Login ที่ปลอดภัยด้วย password_hash()&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;จุดที่ Tutorial ทั่วไปมักพลาดคือเก็บรหัสผ่านเป็น plain text หรือเทียบรหัสผ่านด้วย &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;==&lt;/code&gt; ตรง ๆ ในที่นี้เราจะใช้ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;password_hash()&lt;/code&gt; ตอนสมัครสมาชิก และ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;password_verify()&lt;/code&gt; ตอน Login พร้อม Prepared Statement เพื่อกัน SQL Injection&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;register.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;config/db.php&#39;&lt;/span&gt;; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; ($_SERVER[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;REQUEST_METHOD&#39;&lt;/span&gt;] === &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;POST&#39;&lt;/span&gt;) { $username = &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;trim&lt;/span&gt;($_POST[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;username&#39;&lt;/span&gt;]); $hashed = &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;password_hash&lt;/span&gt;($_POST[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;password&#39;&lt;/span&gt;], &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;PASSWORD_DEFAULT&lt;/span&gt;); $stmt = $conn-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;INSERT INTO users (username, password) VALUES (?, ?)&quot;&lt;/span&gt;); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;bind_param&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;ss&quot;&lt;/span&gt;, $username, $hashed); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;execute&lt;/span&gt;(); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Location: login.php?registered=1&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;exit&lt;/span&gt;; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;login.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;session_start&lt;/span&gt;(); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;config/db.php&#39;&lt;/span&gt;; $error = &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;null&lt;/span&gt;; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; ($_SERVER[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;REQUEST_METHOD&#39;&lt;/span&gt;] === &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;POST&#39;&lt;/span&gt;) { $username = &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;trim&lt;/span&gt;($_POST[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;username&#39;&lt;/span&gt;]); $password = $_POST[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;password&#39;&lt;/span&gt;]; $stmt = $conn-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;SELECT id, password FROM users WHERE username = ?&quot;&lt;/span&gt;); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;bind_param&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;s&quot;&lt;/span&gt;, $username); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;execute&lt;/span&gt;(); $result = $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;get_result&lt;/span&gt;(); $user = $result-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;fetch_assoc&lt;/span&gt;(); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; ($user &amp;amp;&amp;amp; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;password_verify&lt;/span&gt;($password, $user[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;password&#39;&lt;/span&gt;])) { &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;session_regenerate_id&lt;/span&gt;(&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;true&lt;/span&gt;); $_SESSION[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;] = $user[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;id&#39;&lt;/span&gt;]; $_SESSION[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;username&#39;&lt;/span&gt;] = $username; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Location: students.php&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;exit&lt;/span&gt;; } $error = &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Username หรือ Password ไม่ถูกต้อง&#39;&lt;/span&gt;; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-warn&quot; style=&quot;background: rgb(255, 238, 240); border-left: 4px solid rgb(255, 62, 90); border-radius: 8px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 15.5px; margin: 20px 0px 28px; padding: 16px 20px;&quot;&gt;&lt;b style=&quot;box-sizing: border-box; color: #c0203b; display: block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; letter-spacing: 0.05em; margin-bottom: 4px;&quot;&gt;⚠️ จุดที่มือใหม่พลาดบ่อย&lt;/b&gt;การเทียบรหัสผ่านด้วย &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;$password == $user[&#39;password&#39;]&lt;/code&gt; ใช้ไม่ได้กับ hash เพราะ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;password_hash()&lt;/code&gt; สร้าง salt แบบสุ่มทุกครั้ง ต้องใช้ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;password_verify()&lt;/code&gt; เท่านั้น และห้าม query แบบเอา &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;$_POST&lt;/code&gt; ไปต่อ string SQL ตรง ๆ เด็ดขาด เพราะนั่นคือช่องโหว่ SQL Injection แบบคลาสสิก&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;ส่วน Form ฝั่ง HTML ใช้ Bootstrap 5 แบบมาตรฐาน เช่น&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;login.php (HTML part)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;container mt-5&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;style&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;max-width:400px&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;h3&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;mb-4&quot;&lt;/span&gt;&amp;gt;เข้าสู่ระบบ&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;h3&lt;/span&gt;&amp;gt; &amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; ($error): ?&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;alert alert-danger&quot;&lt;/span&gt;&amp;gt;&amp;lt;?= &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;htmlspecialchars&lt;/span&gt;($error) ?&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;div&lt;/span&gt;&amp;gt; &amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;endif&lt;/span&gt;; ?&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;method&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;post&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;username&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;form-control mb-3&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;Username&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;required&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;password&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;password&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;form-control mb-3&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;placeholder&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;Password&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;required&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;btn btn-primary w-100&quot;&lt;/span&gt;&amp;gt;เข้าสู่ระบบ&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;button&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;form&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;04&lt;/span&gt;CRUD นักเรียนด้วย Bootstrap 5&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;หลัง Login สำเร็จ เราจะพาไปหน้า &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;students.php&lt;/code&gt; ที่แสดงตารางข้อมูล พร้อมปุ่มเพิ่ม/แก้ไข/ลบ ทุกหน้าต้องเช็ค session ก่อนเสมอ ไม่ใช่แค่ซ่อนปุ่มเฉย ๆ&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;students.php (Read)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;session_start&lt;/span&gt;(); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;isset&lt;/span&gt;($_SESSION[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;])) { &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Location: login.php&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;exit&lt;/span&gt;; } &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;config/db.php&#39;&lt;/span&gt;; $students = $conn-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;SELECT * FROM students ORDER BY id DESC&quot;&lt;/span&gt;); ?&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;table table-striped&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;tr&lt;/span&gt;&amp;gt;&amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;ชื่อ&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;&amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;ห้อง&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;&amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;คะแนน&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;&amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;th&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;tr&lt;/span&gt;&amp;gt; &amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;while&lt;/span&gt; ($row = $students-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;fetch_assoc&lt;/span&gt;()): ?&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;tr&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt;&amp;lt;?= &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;htmlspecialchars&lt;/span&gt;($row[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;name&#39;&lt;/span&gt;]) ?&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt;&amp;lt;?= &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;htmlspecialchars&lt;/span&gt;($row[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;class&#39;&lt;/span&gt;]) ?&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt;&amp;lt;?= $row[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;marks&#39;&lt;/span&gt;] ?&amp;gt;&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;edit.php?id=&amp;lt;?= $row[&#39;id&#39;] ?&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;btn btn-sm btn-warning&quot;&lt;/span&gt;&amp;gt;แก้ไข&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;a&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;delete.php?id=&amp;lt;?= $row[&#39;id&#39;] ?&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;btn btn-sm btn-danger&quot;&lt;/span&gt; &lt;span class=&quot;pcm-c-var&quot; style=&quot;box-sizing: border-box; color: #ffd27a;&quot;&gt;onclick&lt;/span&gt;=&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;return confirm(&#39;ลบรายการนี้?&#39;)&quot;&lt;/span&gt;&amp;gt;ลบ&amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;a&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;tr&lt;/span&gt;&amp;gt; &amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;endwhile&lt;/span&gt;; ?&amp;gt; &amp;lt;/&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;table&lt;/span&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 22, 34); border-radius: 12px; box-shadow: rgba(13, 13, 23, 0.18) 0px 8px 24px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 15, 25); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-code-dot r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-dot g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; display: inline-block; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-fname&quot; style=&quot;box-sizing: border-box; color: #8b889c; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;delete.php (Delete)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e5e2f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&amp;lt;?&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;php&lt;/span&gt; &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;session_start&lt;/span&gt;(); &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;isset&lt;/span&gt;($_SESSION[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;])) { &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Location: login.php&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;exit&lt;/span&gt;; } &lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;config/db.php&#39;&lt;/span&gt;; $id = (&lt;span class=&quot;pcm-c-kw&quot; style=&quot;box-sizing: border-box; color: #ff7ac6;&quot;&gt;int&lt;/span&gt;) ($_GET[&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;id&#39;&lt;/span&gt;] ?? 0); $stmt = $conn-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;DELETE FROM students WHERE id = ?&quot;&lt;/span&gt;); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;bind_param&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&quot;i&quot;&lt;/span&gt;, $id); $stmt-&amp;gt;&lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;execute&lt;/span&gt;(); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;header&lt;/span&gt;(&lt;span class=&quot;pcm-c-str&quot; style=&quot;box-sizing: border-box; color: #a8e89b;&quot;&gt;&#39;Location: students.php&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-c-fn&quot; style=&quot;box-sizing: border-box; color: #6fd1ff;&quot;&gt;exit&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;ส่วน &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;add.php&lt;/code&gt; และ &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;edit.php&lt;/code&gt; ก็ใช้แพทเทิร์นเดียวกัน คือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;เช็ค session → bind_param ทุก query → redirect หลังบันทึก&lt;/span&gt; ทำซ้ำแบบนี้ใน 4 ไฟล์ (add, edit, delete, login) คือสิ่งที่มือใหม่จะเริ่มรู้สึก &quot;เขียนซ้ำเยอะมาก&quot; และนั่นคือจุดเริ่มต้นที่ทำให้เราอยากมี Framework เข้ามาช่วย&lt;/p&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;05&lt;/span&gt;เขียนเองทั้งหมด vs ใช้ Framework&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;พอลองสร้างระบบ Login + CRUD ด้วย PHP ดิบจนจบ จะเห็นภาพชัดว่าอะไรที่เราต้อง &quot;คิดเอง ทำเอง&quot; ทั้งหมด ลองเทียบให้เห็นภาพกับ CodeIgniter 4 และ Laravel&lt;/p&gt;&lt;div class=&quot;pcm-table-wrap&quot; style=&quot;border-color: rgb(232, 223, 204); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 30px; overflow-x: auto;&quot;&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;border-collapse: collapse; font-size: 14.5px; min-width: 560px; width: 878px;&quot;&gt;&lt;tbody style=&quot;box-sizing: border-box;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 13, 23); box-sizing: border-box; color: #f4efe6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; font-weight: 500; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 13, 23); box-sizing: border-box; color: #f4efe6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; font-weight: 500; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;PHP ดิบ (Vanilla)&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 13, 23); box-sizing: border-box; color: #f4efe6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; font-weight: 500; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;CodeIgniter 4&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 13, 23); box-sizing: border-box; color: #f4efe6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; font-weight: 500; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;Laravel&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;ป้องกัน SQL Injection&lt;/td&gt;&lt;td class=&quot;pcm-mid&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #b9700a; font-weight: 600; padding: 13px 16px;&quot;&gt;ต้องเขียน prepared statement เอง&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;Query Builder ป้องกันให้อัตโนมัติ&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;Eloquent ป้องกันให้อัตโนมัติ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;เก็บรหัสผ่าน&lt;/td&gt;&lt;td class=&quot;pcm-mid&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #b9700a; font-weight: 600; padding: 13px 16px;&quot;&gt;ต้องเรียก password_hash() เอง&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;มี password helper ในตัว&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;Hash facade + bcrypt อัตโนมัติ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;โครงสร้างไฟล์&lt;/td&gt;&lt;td class=&quot;pcm-bad&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #c0203b; font-weight: 600; padding: 13px 16px;&quot;&gt;ปนกันหมดในไฟล์เดียว&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;MVC แยกชัดเจน&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;MVC + Service/Repository ได้&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;Validation ฟอร์ม&lt;/td&gt;&lt;td class=&quot;pcm-bad&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #c0203b; font-weight: 600; padding: 13px 16px;&quot;&gt;เขียน if/else เองทั้งหมด&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;Validation library ในตัว&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;Form Request Validation&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;ความเร็วในการเริ่มโปรเจกต์เล็ก&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;เร็วที่สุด ไม่ต้องตั้งค่าอะไร&lt;/td&gt;&lt;td class=&quot;pcm-mid&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #b9700a; font-weight: 600; padding: 13px 16px;&quot;&gt;ต้องตั้งค่าเริ่มต้นเล็กน้อย&lt;/td&gt;&lt;td class=&quot;pcm-mid&quot; style=&quot;background: rgb(255, 252, 246); border-bottom: 1px solid rgb(232, 223, 204); box-sizing: border-box; color: #b9700a; font-weight: 600; padding: 13px 16px;&quot;&gt;ตั้งค่าเริ่มต้นมากกว่า CI4&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #1c1b22; padding: 13px 16px;&quot;&gt;เหมาะกับโปรเจกต์ใหญ่ขึ้น&lt;/td&gt;&lt;td class=&quot;pcm-bad&quot; style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #c0203b; font-weight: 600; padding: 13px 16px;&quot;&gt;ดูแลยากเมื่อโค้ดเยอะ&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;รองรับงานระดับองค์กรได้ดี&lt;/td&gt;&lt;td class=&quot;pcm-good&quot; style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #1f9d6e; font-weight: 600; padding: 13px 16px;&quot;&gt;รองรับงานใหญ่ ระบบซับซ้อนได้ดี&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;สรุปง่าย ๆ คือ PHP ดิบเหมาะกับการ &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;เข้าใจกลไกเบื้องหลัง&lt;/span&gt; ว่า Login ทำงานยังไง CRUD เชื่อมฐานข้อมูลยังไง แต่พอจะทำงานจริงหรือโปรเจกต์ที่มีหลายหน้า หลายฟีเจอร์ Framework อย่าง CodeIgniter 4 หรือ Laravel จะช่วยลดงานซ้ำซ้อนและลดโอกาสพลาดเรื่องความปลอดภัยได้มาก&lt;/p&gt;&lt;hr class=&quot;pcm-divider&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(232, 223, 204); border-color: currentcolor; border-image: initial; border-style: none; border-width: medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; height: 1px; margin: 36px 0px;&quot; /&gt;&lt;h2 style=&quot;align-items: baseline; border-bottom: 2px solid rgb(232, 223, 204); box-sizing: border-box; color: #1c1b22; display: flex; font-family: Sarabun, sans-serif; font-size: 24px; gap: 10px; margin: 44px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;pcm-mono&quot; style=&quot;box-sizing: border-box; color: #ff3e8a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;06&lt;/span&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #1c1b22; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;โปรเจกต์ Login + CRUD ด้วย PHP + Bootstrap 5 เป็นจุดเริ่มต้นที่ดีมากสำหรับมือใหม่ เพราะครอบคลุมทักษะหลักที่ใช้ซ้ำในแทบทุกเว็บแอป ทั้งการเชื่อมต่อฐานข้อมูล การยืนยันตัวตน และการจัดการข้อมูลพื้นฐาน แต่สิ่งสำคัญที่อยากให้จำไว้คือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;อย่าก๊อปโค้ดจาก Tutorial ที่ไม่มี prepared statement หรือไม่ hash รหัสผ่าน&lt;/span&gt; เพราะนิสัยตอนเริ่มต้นมักติดตัวไปจนถึงงานจริง&lt;/p&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6101631278212076002/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/login-crud-php-bootstrap-5.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6101631278212076002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6101631278212076002'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/login-crud-php-bootstrap-5.html' title='ผมสร้างระบบ Login และ CRUD แบบง่าย ๆ ด้วย PHP + Bootstrap 5 (โปรเจกต์เริ่มต้นสำหรับมือใหม่)'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhS5bkfj18JRMffi2J3P-d6BnMXpFf0SkuKPD2r43fyVK8SbVZR7YjBTax7VDgiC2VZT5Eabubf0HNYQ6qiObWIzU-6RRTKzEjh8iAznjTGP1Y093Kv5QeIqMTeTOJTful2X7weCKHeRZo_ulRFP_bVQEIMomnvXLxMYbknCWJZReOMiJyYB0DHMTHQKKc=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-1167508421952488969</id><published>2026-06-21T07:59:17.693+07:00</published><updated>2026-06-21T07:59:17.694+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>Resumable Upload ด้วย tus Protocol: อัปโหลดไฟล์ใหญ่ เน็ตหลุดก็ไม่ต้องเริ่มใหม่</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh0AsTn6Lev6RTySW19Qp0YraoJVlnTA1nV2tRdFNc7OM2cz9hE1Gw7hiuVi1wF4XT-AEfUVnSVhmY9I9SFq8Nh97aiVjOAWNLEMXu6gqSeLGt3crYA4OBS8diYH0Rt2ckMCQxnS57fAwTh2M2xbmyik0m-Ql4o7r5VEq0uQvvtnIdaX76CjzWAT3GIJtM&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1536&quot; height=&quot;427&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh0AsTn6Lev6RTySW19Qp0YraoJVlnTA1nV2tRdFNc7OM2cz9hE1Gw7hiuVi1wF4XT-AEfUVnSVhmY9I9SFq8Nh97aiVjOAWNLEMXu6gqSeLGt3crYA4OBS8diYH0Rt2ckMCQxnS57fAwTh2M2xbmyik0m-Ql4o7r5VEq0uQvvtnIdaX76CjzWAT3GIJtM&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;pcm-hero&quot; style=&quot;background-attachment: scroll; background-clip: border-box; background-image: radial-gradient(circle at 18% 12%, rgb(29, 33, 48) 0%, rgb(17, 19, 26) 55%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 18px; box-sizing: border-box; color: #edeff5; font-family: Sarabun, sans-serif; margin-bottom: 36px; overflow: hidden; padding: 44px 32px 36px; position: relative;&quot;&gt;&lt;span class=&quot;pcm-eyebrow&quot; style=&quot;background: rgba(0, 217, 181, 0.1); border-radius: 999px; border: 1px solid rgba(0, 217, 181, 0.35); box-sizing: border-box; color: #00d9b5; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.14em; margin-bottom: 18px; padding: 5px 12px;&quot;&gt;PHP · CODEIGNITER 4 · LARAVEL&lt;/span&gt;&lt;h1 style=&quot;box-sizing: border-box; color: white; font-size: 30px; line-height: 1.35; margin: 0px 0px 14px;&quot;&gt;Resumable Upload ด้วย tus Protocol: อัปโหลดไฟล์ใหญ่ เน็ตหลุดก็ไม่ต้องเริ่มใหม่&lt;/h1&gt;&lt;p class=&quot;lead&quot; style=&quot;box-sizing: border-box; color: #b7bbc9; font-size: 16.5px; margin: 0px 0px 30px; max-width: 56ch;&quot;&gt;เคยอัปโหลดไฟล์ 2 GB ค้างอยู่ที่ 90% แล้วเน็ตหลุดไหมครับ? บทความนี้พาไปรู้จัก tus protocol และไลบรารี tus-php ที่ทำให้การอัปโหลดไฟล์ใหญ่ &quot;หยุดแล้วต่อ&quot; ได้จริง พร้อมตัวอย่างโค้ดสำหรับ CodeIgniter 4 และ Laravel&lt;/p&gt;&lt;div aria-hidden=&quot;true&quot; class=&quot;chunk-strip&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin-bottom: 14px;&quot;&gt;&lt;div class=&quot;chunk done&quot; style=&quot;background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(rgb(0, 217, 181) 0%, rgb(0, 168, 138) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 6px; box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk done&quot; style=&quot;background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(rgb(0, 217, 181) 0%, rgb(0, 168, 138) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 6px; box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk done&quot; style=&quot;background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(rgb(0, 217, 181) 0%, rgb(0, 168, 138) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 6px; box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk done&quot; style=&quot;background-attachment: scroll; background-clip: border-box; background-image: linear-gradient(rgb(0, 217, 181) 0%, rgb(0, 168, 138) 100%); background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-radius: 6px; box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk paused&quot; style=&quot;align-items: center; animation: 1.8s ease-in-out 0s infinite normal none running pcm-pulse; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(27, 30, 41); border-color: rgb(255, 176, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 6px; border-style: solid; border-width: 2px; box-sizing: border-box; display: flex; flex: 1 1 0%; height: 34px; justify-content: center; position: relative;&quot;&gt;&lt;div class=&quot;bars&quot; style=&quot;box-sizing: border-box; display: flex; gap: 3px;&quot;&gt;&lt;span style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 176, 32); border-radius: 1px; box-sizing: border-box; display: block; height: 12px; width: 3px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 176, 32); border-radius: 1px; box-sizing: border-box; display: block; height: 12px; width: 3px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 176, 32); border-radius: 1px; box-sizing: border-box; display: block; height: 12px; width: 3px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;chunk pending&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 6px; border: 2px dashed rgb(58, 63, 80); box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk pending&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 6px; border: 2px dashed rgb(58, 63, 80); box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;chunk pending&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 6px; border: 2px dashed rgb(58, 63, 80); box-sizing: border-box; flex: 1 1 0%; height: 34px; position: relative;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;chunk-caption&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; display: flex; flex-wrap: wrap; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; gap: 18px;&quot;&gt;&lt;span class=&quot;item&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 7px;&quot;&gt;&lt;span class=&quot;dot teal&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(0, 217, 181); border-radius: 3px; box-sizing: border-box; display: inline-block; height: 9px; width: 9px;&quot;&gt;&lt;/span&gt;อัปโหลดสำเร็จแล้ว&lt;/span&gt;&lt;span class=&quot;item&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 7px;&quot;&gt;&lt;span class=&quot;dot amber&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 176, 32); border-color: rgb(255, 176, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 3px; border-style: solid; border-width: 1px; box-sizing: border-box; display: inline-block; height: 9px; width: 9px;&quot;&gt;&lt;/span&gt;หลุดกลางทาง แต่ resume ต่อจากจุดเดิมได้&lt;/span&gt;&lt;span class=&quot;item&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 7px;&quot;&gt;&lt;span class=&quot;dot outline&quot; style=&quot;border-radius: 3px; border: 1.5px dashed rgb(58, 63, 80); box-sizing: border-box; display: inline-block; height: 9px; width: 9px;&quot;&gt;&lt;/span&gt;รอคิวอัปโหลด&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;01&lt;/span&gt;ทำไมการอัปโหลดไฟล์ใหญ่ถึง &quot;พัง&quot; ได้ง่าย&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ลองนึกภาพผู้ใช้กำลังอัปโหลดวิดีโอขนาด 1.5 GB ผ่านฟอร์ม HTML ธรรมดา ใช้เวลาไปแล้วกว่าครึ่งชั่วโมง แถบโปรเกรสขยับมาถึง 92% แล้วจู่ ๆ Wi-Fi ก็หลุด หรือเบราว์เซอร์แครช ผลลัพธ์คือไฟล์ที่อัปโหลดไปทั้งหมดสูญเปล่า ผู้ใช้ต้องกดอัปโหลดใหม่ตั้งแต่ไบต์แรก&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ปัญหานี้เกิดจากธรรมชาติของการอัปโหลดแบบ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;multipart/form-data&lt;/code&gt; ทั่วไป ซึ่งเซิร์ฟเวอร์มองไฟล์ทั้งก้อนเป็นคำขอเดียว ถ้าคำขอนั้นไม่จบสมบูรณ์ เซิร์ฟเวอร์จะไม่รู้เลยว่าไบต์ไหนมาถึงแล้วบ้าง และต้องทิ้งข้อมูลทั้งหมดไป ยิ่งผู้ใช้อยู่ในพื้นที่ที่สัญญาณอินเทอร์เน็ตไม่เสถียร เช่น ใช้เน็ตมือถือระหว่างเดินทาง ปัญหานี้ก็ยิ่งเกิดถี่ขึ้น&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ทางออกที่หลายระบบใหญ่ ๆ อย่าง Vimeo หรือ Google Drive ใช้กันคือการอัปโหลดแบบ &lt;strong style=&quot;box-sizing: border-box;&quot;&gt;resumable&lt;/strong&gt; นั่นคือแบ่งไฟล์เป็นชิ้นเล็ก ๆ (chunk) ส่งทีละชิ้น แล้วให้เซิร์ฟเวอร์จดจำว่าไบต์ล่าสุดที่ได้รับคือไบต์ที่เท่าไร เมื่อการเชื่อมต่อกลับมา ฝั่งไคลเอนต์ก็แค่ถามเซิร์ฟเวอร์ว่า &quot;ตอนนี้ได้รับไปถึงไหนแล้ว&quot; แล้วส่งต่อจากจุดนั้น ไม่ต้องเริ่มนับหนึ่งใหม่&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;02&lt;/span&gt;รู้จัก tus: มาตรฐานเปิดสำหรับ Resumable Upload&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;&lt;a href=&quot;https://tus.io/&quot; rel=&quot;noopener&quot; style=&quot;border-bottom: 1.5px solid rgba(0, 168, 138, 0.35); box-sizing: border-box; color: #00a88a; font-weight: 600; text-decoration: none;&quot; target=&quot;_blank&quot;&gt;tus&lt;/a&gt; เป็นโปรโตคอลแบบเปิดที่ถูกออกแบบมาเฉพาะสำหรับการอัปโหลดไฟล์แบบ resumable บน HTTP จุดเด่นของ tus คือมันกำหนดมาตรฐานชัดเจนว่าไคลเอนต์กับเซิร์ฟเวอร์ควรคุยกันอย่างไร ทำให้นักพัฒนาไม่ต้องคิดค้น protocol ของตัวเองตั้งแต่ศูนย์ และมีไลบรารีรองรับในหลายภาษา ทั้งฝั่ง server (PHP, Node.js, Go) และฝั่ง client (JavaScript, iOS, Android)&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;สำหรับฝั่ง PHP มีไลบรารีชื่อ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;ankitpokhrel/tus-php&lt;/code&gt; ซึ่งเป็น implementation ของ tus server แบบ framework-agnostic หมายความว่าเอาไปต่อกับ CodeIgniter, Laravel หรือ PHP ล้วน ๆ ก็ได้ทั้งนั้น&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;03&lt;/span&gt;tus ทำงานอย่างไรเบื้องหลัง&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;หัวใจของ tus คือแนวคิดเรื่อง &lt;strong style=&quot;box-sizing: border-box;&quot;&gt;offset&lt;/strong&gt; หรือ &quot;ตำแหน่งไบต์ล่าสุดที่อัปโหลดสำเร็จ&quot; ขั้นตอนคร่าว ๆ มีดังนี้&lt;/p&gt;&lt;ol style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding-left: 22px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;ไคลเอนต์ส่งคำขอ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;POST&lt;/code&gt; ไปยังเซิร์ฟเวอร์เพื่อ &quot;จอง&quot; การอัปโหลดใหม่ พร้อมแจ้งขนาดไฟล์ทั้งหมด เซิร์ฟเวอร์จะตอบกลับ URL เฉพาะสำหรับไฟล์นั้น&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;ไคลเอนต์ทยอยส่งข้อมูลเป็นชิ้น ๆ ด้วยคำขอ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;PATCH&lt;/code&gt; ไปยัง URL นั้น พร้อมระบุ offset ปัจจุบันในเฮดเดอร์&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;ถ้าการเชื่อมต่อขาดระหว่างทาง ไคลเอนต์สามารถส่งคำขอ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;HEAD&lt;/code&gt; ไปถาม URL เดิมเพื่อเช็กว่าตอนนี้เซิร์ฟเวอร์มีข้อมูลถึงไบต์ไหนแล้ว&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;จากนั้นไคลเอนต์ส่ง &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;PATCH&lt;/code&gt; ต่อจาก offset ที่ได้รับ โดยไม่ต้องส่งข้อมูลเดิมซ้ำเลย&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;pcm-callout&quot; style=&quot;background: rgb(255, 247, 232); border-radius: 12px; border: 1px solid rgb(242, 221, 168); box-sizing: border-box; font-size: 15px; margin: 0px 0px 18px; padding: 16px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #8a5a00;&quot;&gt;จุดสำคัญ:&lt;/strong&gt; ฝั่งเซิร์ฟเวอร์ต้องมีที่เก็บสถานะการอัปโหลด (เช่น ไฟล์ cache หรือ Redis) เพื่อจำว่าแต่ละ upload ID ไปถึงไบต์ไหนแล้ว ไลบรารี tus-php จัดการส่วนนี้ให้อัตโนมัติ&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;04&lt;/span&gt;ติดตั้งและสร้าง Server ด้วย tus-php&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;เริ่มจากติดตั้งไลบรารีผ่าน Composer&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;composer require ankitpokhrel/tus-php&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;โค้ดด้านล่างคือ tus server แบบมินิมอล ที่รับคำขอทุก method ของโปรโตคอล tus แล้วจัดการให้เองทั้งหมด&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;server.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&amp;lt;?php require __DIR__ . &#39;/vendor/autoload.php&#39;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;use&lt;/span&gt; TusPhp\Tus\Server &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;as&lt;/span&gt; TusServer; &lt;span class=&quot;com&quot; style=&quot;box-sizing: border-box; color: #6e7384; font-style: italic;&quot;&gt;// ใช้ &#39;file&#39; cache สำหรับเริ่มต้น (เปลี่ยนเป็น &#39;redis&#39; ได้เมื่อขึ้น production)&lt;/span&gt; $server = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffd479;&quot;&gt;TusServer&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;file&#39;&lt;/span&gt;); $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setApiPath&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;/files&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setUploadDir&lt;/span&gt;(__DIR__ . &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;/uploads&#39;&lt;/span&gt;); $response = $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;serve&lt;/span&gt;(); $response-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;send&lt;/span&gt;(); exit(0);&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;เพียงเท่านี้ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;server.php&lt;/code&gt; ตัวนี้ก็พร้อมรับคำขอ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;OPTIONS&lt;/code&gt;, &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;POST&lt;/code&gt;, &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;HEAD&lt;/code&gt;, &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;PATCH&lt;/code&gt; และ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;DELETE&lt;/code&gt; ตามสเปกของ tus แล้ว แต่ในงานจริงเราอยากผูกมันเข้ากับเฟรมเวิร์กที่ใช้อยู่มากกว่า ในส่วนถัดไปจะพาไปดูทั้ง CodeIgniter 4 และ Laravel&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;05&lt;/span&gt;ผูก tus-php เข้ากับ CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ใน CI4 เราสามารถสร้าง Controller ขึ้นมาตัวเดียวเพื่อรับทุกคำขอที่เกี่ยวกับการอัปโหลด แล้วส่งต่อให้ tus-php จัดการ จากนั้นแปลง response ของ tus-php กลับมาเป็น response ของ CI4&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;app/Controllers/UploadController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&amp;lt;?php &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;namespace&lt;/span&gt; App\Controllers; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;use&lt;/span&gt; TusPhp\Tus\Server &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;as&lt;/span&gt; TusServer; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffd479;&quot;&gt;UploadController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;extends&lt;/span&gt; BaseController { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;handle&lt;/span&gt;() { $server = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffd479;&quot;&gt;TusServer&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;file&#39;&lt;/span&gt;); $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setApiPath&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;/upload/files&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setUploadDir&lt;/span&gt;(WRITEPATH . &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;uploads&#39;&lt;/span&gt;); $response = $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;serve&lt;/span&gt;(); &lt;span class=&quot;com&quot; style=&quot;box-sizing: border-box; color: #6e7384; font-style: italic;&quot;&gt;// ส่ง response ที่ tus-php สร้างไว้กลับไปตรง ๆ&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;return&lt;/span&gt; $this-&amp;gt;response -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setStatusCode&lt;/span&gt;($response-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getStatusCode&lt;/span&gt;()) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setBody&lt;/span&gt;($response-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getContent&lt;/span&gt;()); } }&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;จากนั้นเปิดทางให้ทุก HTTP method ที่ tus ต้องใช้วิ่งเข้ามาที่ Controller เดียวกัน ใน &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;app/Config/Routes.php&lt;/code&gt;&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;app/Config/Routes.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;$routes-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;match&lt;/span&gt;( [&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;get&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;post&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;patch&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;head&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;options&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;delete&#39;&lt;/span&gt;], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;upload/files(.*)&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;UploadController::handle&#39;&lt;/span&gt; );&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;เก็บไฟล์ไว้ใต้ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;WRITEPATH&lt;/code&gt; ตามธรรมเนียมของ CI4 ก็ปลอดภัยกว่า เพราะโฟลเดอร์นี้อยู่นอก document root และคุมสิทธิ์การเข้าถึงได้ง่ายกว่าโฟลเดอร์ใน &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;public/&lt;/code&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;06&lt;/span&gt;ผูก tus-php เข้ากับ Laravel&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;แนวคิดเดียวกันสามารถนำไปใช้กับ Laravel ได้โดยประกาศ route แบบ closure ที่ดักทุก method และทุก path ย่อยภายใต้ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;/files&lt;/code&gt;&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;routes/web.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;use&lt;/span&gt; TusPhp\Tus\Server &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;as&lt;/span&gt; TusServer; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;use&lt;/span&gt; Illuminate\Support\Facades\Route; Route::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;match&lt;/span&gt;( [&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;get&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;post&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;patch&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;head&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;options&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;delete&#39;&lt;/span&gt;], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;/files/{any?}&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;function&lt;/span&gt; () { $server = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffd479;&quot;&gt;TusServer&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;file&#39;&lt;/span&gt;); $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setApiPath&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;/files&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;setUploadDir&lt;/span&gt;(storage_path(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;app/uploads&#39;&lt;/span&gt;)); $response = $server-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;serve&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;return&lt;/span&gt; response($response-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getContent&lt;/span&gt;(), $response-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getStatusCode&lt;/span&gt;()) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;withHeaders&lt;/span&gt;($response-&amp;gt;headers-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;all&lt;/span&gt;()); } )-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;any&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&#39;.*&#39;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ข้อดีของการใช้ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;storage_path(&#39;app/uploads&#39;)&lt;/code&gt; คือไฟล์ที่กำลังอัปโหลดอยู่จะไม่ถูกเข้าถึงโดยตรงจากเว็บ ต้องผ่าน Controller หรือ route ที่เรากำหนดเองเท่านั้น ตรงกับแนวทาง security ที่ Laravel แนะนำสำหรับไฟล์ที่ยังไม่พร้อมเผยแพร่&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;07&lt;/span&gt;ฝั่ง Client: อัปโหลดแบบ Resumable ด้วย tus-js-client&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;ฝั่งหน้าเว็บ เราไม่จำเป็นต้องเขียน logic เรื่อง offset หรือ retry เองเลย เพราะมีไลบรารี &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;tus-js-client&lt;/code&gt; ที่คุยกับ tus server ตามสเปกให้ครบแล้ว สิ่งที่เราต้องทำคือสร้าง instance ของ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;tus.Upload&lt;/code&gt; แล้วกำหนด endpoint กับ callback ต่าง ๆ&lt;/p&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;upload-form.html&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&amp;lt;input type=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;file&quot;&lt;/span&gt; id=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;fileInput&quot;&lt;/span&gt; /&amp;gt; &amp;lt;progress id=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;uploadProgress&quot;&lt;/span&gt; value=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;0&quot;&lt;/span&gt; max=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;100&quot;&lt;/span&gt;&amp;gt;&amp;lt;/progress&amp;gt; &amp;lt;button id=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;pauseBtn&quot;&lt;/span&gt;&amp;gt;Pause&amp;lt;/button&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 25, 34); border-radius: 12px; box-shadow: rgba(17, 19, 26, 0.55) 0px 14px 30px -16px; box-sizing: border-box; margin: 0px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;bar&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(39, 43, 56); box-sizing: border-box; display: flex; gap: 8px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;dot-traffic r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-traffic g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;filename&quot; style=&quot;box-sizing: border-box; color: #9aa0b4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; margin-left: 8px;&quot;&gt;upload.js&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #d9dce5; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;import&lt;/span&gt; * &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;as&lt;/span&gt; tus &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;tus-js-client&quot;&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;let&lt;/span&gt; upload; document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;fileInput&quot;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;change&quot;&lt;/span&gt;, (e) =&amp;gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;const&lt;/span&gt; file = e.target.files[0]; upload = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;new&lt;/span&gt; tus.&lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffd479;&quot;&gt;Upload&lt;/span&gt;(file, { endpoint: &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;/upload/files&quot;&lt;/span&gt;, retryDelays: [0, 3000, 5000, 10000], metadata: { filename: file.name, filetype: file.type, }, onError: (error) =&amp;gt; console.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;error&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;Upload failed:&quot;&lt;/span&gt;, error), onProgress: (bytesSent, bytesTotal) =&amp;gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;const&lt;/span&gt; percent = ((bytesSent / bytesTotal) * 100).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;toFixed&lt;/span&gt;(1); document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;uploadProgress&quot;&lt;/span&gt;).value = percent; }, onSuccess: () =&amp;gt; { console.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;Upload finished:&quot;&lt;/span&gt;, upload.url); }, }); &lt;span class=&quot;com&quot; style=&quot;box-sizing: border-box; color: #6e7384; font-style: italic;&quot;&gt;// ถ้ามี upload ที่ค้างไว้ก่อนหน้า ให้ resume ต่อแทนเริ่มใหม่&lt;/span&gt; upload.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;findPreviousUploads&lt;/span&gt;().&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;then&lt;/span&gt;((previousUploads) =&amp;gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;if&lt;/span&gt; (previousUploads.length) { upload.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;resumeFromPreviousUpload&lt;/span&gt;(previousUploads[0]); } upload.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;start&lt;/span&gt;(); }); }); document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;pauseBtn&quot;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #c9e26a;&quot;&gt;&quot;click&quot;&lt;/span&gt;, () =&amp;gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff8fb8;&quot;&gt;if&lt;/span&gt; (upload) upload.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7fd0ff;&quot;&gt;abort&lt;/span&gt;(); });&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;เมธอด &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;findPreviousUploads()&lt;/code&gt; คือกุญแจสำคัญของ &quot;resume&quot; ฝั่งไคลเอนต์ มันจะเช็ก localStorage ของเบราว์เซอร์ว่าไฟล์นี้เคยเริ่มอัปโหลดไว้หรือยัง ถ้าเจอก็เรียก &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;resumeFromPreviousUpload()&lt;/code&gt; เพื่อสานต่อจากจุดเดิมทันที โดยที่ผู้ใช้ไม่ต้องทำอะไรเพิ่มเลย แม้จะปิดแท็บแล้วเปิดใหม่ก็ตาม&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;08&lt;/span&gt;REST Endpoint ของ tus Server&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;เพื่อให้เห็นภาพว่าแต่ละคำขอ HTTP ทำหน้าที่อะไรบ้างในวงจรของ tus สรุปไว้ในตารางนี้&lt;/p&gt;&lt;div class=&quot;pcm-table-wrap&quot; style=&quot;border-color: rgb(232, 227, 214); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin-bottom: 8px; overflow: hidden;&quot;&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-collapse: collapse; width: 750px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(17, 19, 26); box-sizing: border-box; color: white; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; letter-spacing: 0.04em; padding: 12px 16px; text-align: left;&quot;&gt;Method&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(17, 19, 26); box-sizing: border-box; color: white; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; letter-spacing: 0.04em; padding: 12px 16px; text-align: left;&quot;&gt;Endpoint&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(17, 19, 26); box-sizing: border-box; color: white; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; letter-spacing: 0.04em; padding: 12px 16px; text-align: left;&quot;&gt;หน้าที่&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14.5px; font-weight: 600; padding: 13px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;OPTIONS&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;/files&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;ถาม server ว่ารองรับฟีเจอร์อะไรบ้าง เช่น ขนาดไฟล์สูงสุด&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14.5px; font-weight: 600; padding: 13px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;POST&lt;/td&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;/files&lt;/td&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;เริ่มอัปโหลดใหม่ แจ้งขนาดไฟล์ทั้งหมด ได้ URL เฉพาะกลับมา&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14.5px; font-weight: 600; padding: 13px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;HEAD&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;/files/{id}&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;เช็ก offset ปัจจุบันของไฟล์ที่กำลังอัปโหลดอยู่&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14.5px; font-weight: 600; padding: 13px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;PATCH&lt;/td&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;/files/{id}&lt;/td&gt;&lt;td style=&quot;background: rgb(252, 250, 244); border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;ส่งข้อมูล chunk ต่อจาก offset เดิมไปเรื่อย ๆ จนครบ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14.5px; font-weight: 600; padding: 13px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;DELETE&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;/files/{id}&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(232, 227, 214); box-sizing: border-box; font-size: 14.5px; padding: 13px 16px; vertical-align: top;&quot;&gt;ยกเลิกและล้าง upload ที่ค้างอยู่ ใช้ทำความสะอาด storage&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;09&lt;/span&gt;ข้อดี ข้อจำกัด และเมื่อไหร่ควรใช้&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;tus เหมาะมากกับงานที่ผู้ใช้ต้องอัปโหลดไฟล์ขนาดใหญ่ เช่น ระบบอัปโหลดวิดีโอ ไฟล์ backup หรือไฟล์ CAD แต่ก็ไม่ใช่ทุกโปรเจกต์ที่จำเป็นต้องใช้ ลองดูข้อพิจารณาเหล่านี้ก่อนตัดสินใจ&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding-left: 22px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;เหมาะ:&lt;/strong&gt; ไฟล์ขนาดใหญ่กว่า 50-100 MB ขึ้นไป หรือกลุ่มผู้ใช้ที่เน็ตไม่เสถียร เช่น ใช้งานผ่านมือถือนอกสถานที่&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;เหมาะ:&lt;/strong&gt; ระบบที่ต้องการให้ผู้ใช้สลับอุปกรณ์ได้ เช่น เริ่มอัปโหลดจากโน้ตบุ๊ก แล้วไปต่อจากมือถือ&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;ไม่จำเป็น:&lt;/strong&gt; ฟอร์มอัปโหลดรูปโปรไฟล์หรือเอกสารขนาดไม่กี่ MB การใช้ &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;multipart/form-data&lt;/code&gt; แบบปกติยังคุ้มค่ากว่าในแง่ความซับซ้อน&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; font-size: 16px; margin-bottom: 8px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;ข้อควรระวัง:&lt;/strong&gt; ต้องวางแผนเรื่อง storage สำหรับ chunk ที่ค้างไว้ และตั้งกลไกลบไฟล์ที่ไม่มีใครมา resume ต่อเป็นเวลานาน เพื่อไม่ให้ดิสก์เต็ม&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;hr class=&quot;div&quot; style=&quot;border-color: rgb(232, 227, 214) currentcolor currentcolor; border-image: initial; border-style: dashed none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; margin: 30px 0px;&quot; /&gt;&lt;div class=&quot;section&quot; style=&quot;box-sizing: border-box; color: #20222c; font-family: Sarabun, sans-serif; margin-bottom: 38px; padding: 0px 4px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(232, 227, 214); box-sizing: border-box; color: #11131a; font-size: 23px; line-height: 1.35; margin: 0px 0px 16px; padding-bottom: 10px;&quot;&gt;&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #00a88a; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 15px; margin-right: 10px;&quot;&gt;10&lt;/span&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;การอัปโหลดไฟล์ใหญ่ไม่จำเป็นต้องเป็นฝันร้ายของผู้ใช้อีกต่อไป ด้วย tus protocol และไลบรารี &lt;code style=&quot;background: rgb(239, 234, 217); border-radius: 5px; box-sizing: border-box; color: #8a4b00; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 7px;&quot;&gt;tus-php&lt;/code&gt; เราสามารถเปลี่ยนการอัปโหลดแบบ &quot;พังแล้วเริ่มใหม่ทั้งหมด&quot; ให้กลายเป็น &quot;หยุดตรงไหน ก็ต่อจากตรงนั้น&quot; ได้ โดยที่ไม่ต้องเขียนกลไก chunk และ offset เองตั้งแต่ศูนย์ ไม่ว่าจะใช้ CodeIgniter 4 หรือ Laravel แนวคิดก็เหมือนกันคือสร้าง endpoint เดียวให้รับทุก method ของ tus แล้วปล่อยให้ไลบรารีจัดการส่วนที่เหลือ&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 16px;&quot;&gt;สำหรับใครที่กำลังจะเริ่มฟีเจอร์อัปโหลดไฟล์ขนาดใหญ่ในโปรเจกต์ถัดไป ลองเริ่มจากการรันตัวอย่าง server แบบ minimal ในบทความนี้ดูก่อน แล้วค่อยปรับให้เข้ากับ authentication และ business logic ของระบบจริง&lt;/p&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/1167508421952488969/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/resumable-upload-tus-protocol.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/1167508421952488969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/1167508421952488969'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/resumable-upload-tus-protocol.html' title='Resumable Upload ด้วย tus Protocol: อัปโหลดไฟล์ใหญ่ เน็ตหลุดก็ไม่ต้องเริ่มใหม่'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEh0AsTn6Lev6RTySW19Qp0YraoJVlnTA1nV2tRdFNc7OM2cz9hE1Gw7hiuVi1wF4XT-AEfUVnSVhmY9I9SFq8Nh97aiVjOAWNLEMXu6gqSeLGt3crYA4OBS8diYH0Rt2ckMCQxnS57fAwTh2M2xbmyik0m-Ql4o7r5VEq0uQvvtnIdaX76CjzWAT3GIJtM=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-3547193345506195012</id><published>2026-06-20T19:38:57.333+07:00</published><updated>2026-06-20T19:38:57.333+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>เบื้องหลัง API Artisan: สร้าง Laravel API ที่นักพัฒนาอยากใช้จริง</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhp1Vd_lxncttYDzYIF6_Ddo8kZQtHg3UqBHs-Wm9o0wp9EyY30O4GhuGWdUStxlUK2I8bfEAEJp_7v5UtN6MgqFnIW0k7ExBrHLy6b7aGmICvZKFKqxcCFXvtuwLakBtOqxzHvwVsQ8PkGSmDSolZntlDixcAhjy5YUvHtQOgvYUJoke4NcfiHeecpW34&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1149&quot; data-original-width=&quot;1369&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhp1Vd_lxncttYDzYIF6_Ddo8kZQtHg3UqBHs-Wm9o0wp9EyY30O4GhuGWdUStxlUK2I8bfEAEJp_7v5UtN6MgqFnIW0k7ExBrHLy6b7aGmICvZKFKqxcCFXvtuwLakBtOqxzHvwVsQ8PkGSmDSolZntlDixcAhjy5YUvHtQOgvYUJoke4NcfiHeecpW34&quot; width=&quot;572&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt;&lt;div class=&quot;apiart-hero&quot; style=&quot;background: linear-gradient(rgba(24, 19, 17, 0.97), rgba(24, 19, 17, 0.99)) 0% 0% / auto repeat scroll padding-box border-box, repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.035) 0px, rgba(255, 255, 255, 0.035) 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 28px) 0% 0% / auto repeat scroll padding-box border-box, repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.035) 0px, rgba(255, 255, 255, 0.035) 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 28px) 0% 0% / auto repeat scroll padding-box border-box, none 0% 0% / auto repeat scroll padding-box border-box rgb(24, 19, 17); border-radius: 18px; box-sizing: border-box; color: #f4efe7; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 36px; overflow: hidden; padding: 56px 36px 44px; position: relative;&quot;&gt;&lt;span class=&quot;apiart-eyebrow&quot; style=&quot;align-items: center; box-sizing: border-box; color: #ff2d20; display: inline-flex; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; gap: 8px; letter-spacing: 0.14em; margin-bottom: 18px; text-transform: uppercase;&quot;&gt;PHP Code Mania · Laravel API&lt;/span&gt;&lt;h1 style=&quot;box-sizing: border-box; color: #fbf8f4; font-size: 34px; line-height: 1.35; margin: 0px 0px 14px;&quot;&gt;เบื้องหลัง API Artisan: สร้าง Laravel API ที่นักพัฒนาอยากใช้จริง&lt;/h1&gt;&lt;p class=&quot;lead&quot; style=&quot;box-sizing: border-box; color: #c9bfb3; font-size: 16.5px; margin: 0px 0px 28px; max-width: 600px;&quot;&gt;ตั้งแต่ออกแบบ endpoint แรก ไปจนถึง versioning และการเขียนเทสต์ — เคล็ดลับที่ทำให้ API ของคุณไม่ใช่แค่ &quot;ใช้งานได้&quot; แต่เป็น API ที่ทีมอื่นเปิดเอกสารแล้วยิ้ม&lt;/p&gt;&lt;div class=&quot;apiart-terminal&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 12px; border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: rgba(0, 0, 0, 0.35) 0px 18px 40px; box-sizing: border-box; max-width: 560px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-terminal-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); border-bottom: 1px solid rgba(255, 255, 255, 0.06); box-sizing: border-box; display: flex; gap: 7px; padding: 11px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-terminal-title&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;~/projects/api-artisan&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.9; margin: 0px; overflow-x: auto; padding: 18px 18px 20px;&quot;&gt;&lt;span class=&quot;c-prompt&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;$&lt;/span&gt; php artisan make:controller UserController --api &lt;span class=&quot;c-out&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;INFO&lt;/span&gt; Controller [app/Http/Controllers/UserController.php] created successfully. &lt;span class=&quot;c-prompt&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;$&lt;/span&gt; php artisan make:resource UserResource &lt;span class=&quot;c-out&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;INFO&lt;/span&gt; Resource [app/Http/Resources/UserResource.php] created successfully. &lt;span class=&quot;c-comment&quot; style=&quot;box-sizing: border-box; color: #8a7f72;&quot;&gt;# เริ่มต้นเหมือนช่างฝีมือ: เตรียมเครื่องมือก่อนลงมือ&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;คำว่า &lt;b style=&quot;box-sizing: border-box;&quot;&gt;Artisan&lt;/b&gt; ใน Laravel ไม่ได้แปลว่า &quot;เครื่องมือบรรทัดคำสั่ง&quot; เพียงอย่างเดียว แต่มันสะท้อนปรัชญาของเฟรมเวิร์กนี้ทั้งหมด นั่นคือ การเขียนโค้ดควรเป็นงานฝีมือที่ประณีต ไม่ใช่แค่โค้ดที่ &quot;รันผ่าน&quot; แล้วจบ และไม่มีที่ไหนที่ปรัชญานี้สำคัญเท่ากับตอนที่คุณกำลังออกแบบ &lt;b style=&quot;box-sizing: border-box;&quot;&gt;API&lt;/b&gt; เพราะ API ที่คุณสร้างวันนี้ จะกลายเป็นสัญญา (contract) ที่ทีม frontend, แอปมือถือ หรือแม้แต่ระบบภายนอกต้องพึ่งพาไปอีกหลายปี&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;บทความนี้เขียนขึ้นสำหรับนักพัฒนาที่คุ้นเคยกับ CodeIgniter 4 หรือเพิ่งเริ่มจับ Laravel และอยากเข้าใจว่า &quot;API ที่ดี&quot; ในมุมมองของ Laravel ควรหน้าตาเป็นอย่างไร เราจะไล่ตั้งแต่การวางแผน ไปจนถึงเรื่อง authentication, validation, performance และการเขียนเทสต์ — ครบทุกขั้นตอนที่ทำให้ API ของคุณ &quot;พร้อมใช้งานจริง&quot; ไม่ใช่แค่ดีโม&lt;/p&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;01&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;วางแผนก่อนเขียนโค้ดสักบรรทัด&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;นักพัฒนามือใหม่จำนวนมากเปิด editor แล้วเริ่มเขียน route ทันที แต่ช่างฝีมือที่ดีจะร่างแบบก่อนลงมือ ก่อนเขียนโค้ด ให้ถามตัวเองสามข้อ: API นี้มีไว้เพื่ออะไร, resource อะไรบ้างที่จะเปิดให้เข้าถึง และใครคือผู้ใช้งานปลายทาง (mobile app, SPA หรือระบบภายนอก)&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;เมื่อตอบคำถามเหล่านี้ได้แล้ว ให้ออกแบบ endpoint ตามหลัก &lt;b style=&quot;box-sizing: border-box;&quot;&gt;RESTful&lt;/b&gt; คือยึด resource เป็นหลักและใช้ HTTP method สื่อความหมายของการกระทำ เช่น &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;GET /api/users&lt;/span&gt; สำหรับดึงรายการ และ &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;POST /api/users&lt;/span&gt; สำหรับสร้างใหม่ แทนที่จะตั้งชื่อ endpoint แบบ &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;/api/getAllUsers&lt;/span&gt; ซึ่งไม่ตรงตามแบบแผนที่นักพัฒนาส่วนใหญ่คุ้นเคย&lt;/p&gt;&lt;div class=&quot;apiart-callout&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 233, 221); border-left: 4px solid rgb(255, 45, 32); border-radius: 0px 10px 10px 0px; box-sizing: border-box; font-size: 15.5px; margin: 18px 0px; padding: 16px 20px;&quot;&gt;&lt;b style=&quot;box-sizing: border-box; color: #c92418;&quot;&gt;เคล็ดลับ:&lt;/b&gt; เขียนเอกสาร API ไว้ตั้งแต่ก่อนเริ่มโค้ดจริง แม้จะเป็นแค่โน้ตสั้น ๆ ก็ช่วยให้ทีมเห็นภาพตรงกันก่อนที่จะแก้โครงสร้างทีหลัง ซึ่งมีต้นทุนสูงกว่ามาก&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;02&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;ใช้ Resource Controller จัดระเบียบ CRUD&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;Laravel มีคำสั่งสร้าง controller สำหรับ API โดยเฉพาะ ซึ่งจะมาพร้อมเมธอดมาตรฐานครบทั้ง 5 ตัวสำหรับ CRUD โดยไม่มีเมธอดสำหรับแสดงฟอร์ม (เพราะ API ไม่ต้องการ view)&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8a7f72;&quot;&gt;// สร้าง controller แบบ API (ไม่มี create/edit form)&lt;/span&gt; php artisan make:controller UserController --api&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;คำสั่งนี้จะสร้างเมธอด &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;index, store, show, update, destroy&lt;/span&gt; ให้พร้อมใช้ จากนั้นคุณแค่เติม logic เข้าไป โดยให้แต่ละเมธอดทำหน้าที่เดียวให้ชัดเจน ไม่ปนกัน&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;UserController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;index&lt;/span&gt;() { &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;return&lt;/span&gt; UserResource::collection(User::paginate(10)); } &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;show&lt;/span&gt;(User $user) { &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;return new&lt;/span&gt; UserResource($user); } &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;store&lt;/span&gt;(StoreUserRequest $request) { $user = User::create($request-&amp;gt;validated()); &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;return new&lt;/span&gt; UserResource($user); }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;03&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;แปลง Model เป็น JSON ด้วย API Resource&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;ปัญหาคลาสสิกของมือใหม่คือการ &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;return $user;&lt;/span&gt; ตรง ๆ จาก Eloquent ซึ่งจะส่งทุกคอลัมน์ในตาราง รวมถึง password hash หรือ token ที่ไม่ควรหลุดออกไปด้วย &lt;b style=&quot;box-sizing: border-box;&quot;&gt;API Resource&lt;/b&gt; คือชั้นที่ทำหน้าที่ &quot;คัดและจัดรูป&quot; ข้อมูลก่อนส่งออกไปเป็น JSON&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;php artisan make:resource UserResource&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;UserResource.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;toArray&lt;/span&gt;($request) { &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;id&#39;&lt;/span&gt; =&amp;gt; $this-&amp;gt;id, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; $this-&amp;gt;name, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;email&#39;&lt;/span&gt; =&amp;gt; $this-&amp;gt;email, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;joined_at&#39;&lt;/span&gt; =&amp;gt; $this-&amp;gt;created_at-&amp;gt;format(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;Y-m-d&#39;&lt;/span&gt;), ]; }&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;ข้อดีคือเมื่อโครงสร้างฐานข้อมูลเปลี่ยน คุณแก้แค่ที่เดียวในไฟล์ Resource โดยที่ฝั่ง client ไม่รู้สึกถึงผลกระทบเลย&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;04&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;Validate ทุกครั้งด้วย Form Request&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;อย่าไว้ใจข้อมูลที่ส่งเข้ามาจาก client เด็ดขาด ไม่ว่าจะเป็นแอปมือถือของทีมคุณเองก็ตาม Laravel แนะนำให้แยก logic การตรวจสอบข้อมูลออกจาก controller ไปไว้ในคลาส &lt;b style=&quot;box-sizing: border-box;&quot;&gt;Form Request&lt;/b&gt; โดยเฉพาะ เพื่อให้ controller อ่านง่ายและ validation rule นำกลับมาใช้ซ้ำได้&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;php artisan make:request StoreUserRequest&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;StoreUserRequest.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;rules&lt;/span&gt;() { &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;required|string|max:255&#39;&lt;/span&gt;, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;email&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;required|email|unique:users,email&#39;&lt;/span&gt;, ]; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;05&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;ยืนยันตัวตนด้วย Sanctum&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;สำหรับ API ที่ให้บริการ SPA หรือแอปมือถือ &lt;b style=&quot;box-sizing: border-box;&quot;&gt;Laravel Sanctum&lt;/b&gt; คือตัวเลือกที่เบาและตั้งค่าง่ายกว่า OAuth เต็มรูปแบบ เหมาะกับโปรเจกต์ส่วนใหญ่ที่ไม่ได้ต้องการระบบสิทธิ์ซับซ้อนระดับองค์กร&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;composer require laravel/sanctum&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;routes/api.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;Route::middleware([&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;auth:sanctum&#39;&lt;/span&gt;, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;throttle:60,1&#39;&lt;/span&gt;])-&amp;gt;group(&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;function&lt;/span&gt; () { Route::get(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;/profile&#39;&lt;/span&gt;, [ProfileController::class, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;show&#39;&lt;/span&gt;]); });&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;การห่อ route ไว้ใน middleware group แบบนี้ ทำให้คุณจัดการ authentication และ rate limiting ของหลาย endpoint พร้อมกันได้จากจุดเดียว ไม่ต้องเขียนซ้ำในทุกเมธอด&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;06&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;คุม Performance ด้วย Pagination และ Eager Loading&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;API ที่ตอบกลับข้อมูลทั้งตารางในครั้งเดียวคือระเบิดเวลา เพราะเมื่อข้อมูลในฐานข้อมูลโตขึ้น response time จะยิ่งช้าลงเรื่อย ๆ ใช้ &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;paginate()&lt;/span&gt; เพื่อจำกัดจำนวนต่อหน้าเสมอ&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;UserController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8a7f72;&quot;&gt;// ดึง user พร้อม posts ในคำสั่งเดียว แทนการ query วนลูป&lt;/span&gt; $users = User::with(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;posts&#39;&lt;/span&gt;)-&amp;gt;paginate(10);&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;การเรียก &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;with(&#39;posts&#39;)&lt;/span&gt; คือ eager loading ที่ช่วยแก้ปัญหา N+1 query ซึ่งเป็นสาเหตุอันดับต้น ๆ ที่ทำให้ API ของมือใหม่ช้าโดยไม่รู้ตัว เพราะถ้าไม่ใส่ Laravel จะยิง query แยกไปดึง posts ของ user แต่ละคนทีละแถว&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;07&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;ตอบ Error ให้สม่ำเสมอ และเปิด CORS อย่างปลอดภัย&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;ฝั่ง client จะเขียนโค้ดจัดการ error ได้ง่ายขึ้นมาก ถ้า API ของคุณตอบกลับ error format เดียวกันทุกครั้ง ไม่ใช่บางจุด throw exception เป็น HTML บางจุดเป็น JSON ปนกัน Laravel มีระบบ exception handler กลางที่ช่วยควบคุมเรื่องนี้ได้ในจุดเดียว&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;ส่วนเรื่อง CORS หากต้องเปิดให้ frontend จากโดเมนอื่นเรียก API ได้ ให้ตั้งค่าผ่านไฟล์ &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;config/cors.php&lt;/span&gt; โดยควรระบุโดเมนที่อนุญาตให้ชัดเจน แทนที่จะเปิดกว้างด้วย &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&#39;*&#39;&lt;/span&gt; ในระบบที่ใช้งานจริง เพราะนั่นเท่ากับเปิดให้เว็บไซต์ใดก็ได้เรียก API ของคุณ&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;08&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;Version API ไว้ตั้งแต่วันแรก&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;วันหนึ่งคุณจะต้องเปลี่ยนโครงสร้าง response แน่นอน ไม่ว่าจะเพิ่มฟิลด์หรือลบฟิลด์ที่ไม่ใช้แล้ว การมี version ใน path ตั้งแต่เริ่มต้น ช่วยให้คุณปล่อยเวอร์ชันใหม่ได้โดยไม่ทำให้แอปเวอร์ชันเก่าที่ยังเรียก API อยู่พังกะทันหัน&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;routes/api.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;Route::prefix(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;v1&#39;&lt;/span&gt;)-&amp;gt;group(&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;function&lt;/span&gt; () { Route::get(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;/users&#39;&lt;/span&gt;, [UserController::class, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;index&#39;&lt;/span&gt;]); });&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;09&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;เขียน Test ไว้ดักก่อนโค้ดพัง&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;Laravel มีเครื่องมือทดสอบ API ในตัวที่ใช้งานง่ายมาก แค่ยิง request จำลองแล้วตรวจสอบ response ที่ได้ การมีเทสต์เพียงไม่กี่เคสสำหรับ endpoint สำคัญ ช่วยให้คุณกล้า refactor โค้ดในอนาคตโดยไม่ต้องนั่งทดสอบมือทุกครั้ง&lt;/p&gt;&lt;div class=&quot;apiart-code&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(31, 26, 23); border-radius: 11px; box-shadow: rgba(24, 19, 17, 0.18) 0px 10px 26px; box-sizing: border-box; margin: 16px 0px 22px; overflow: hidden;&quot;&gt;&lt;div class=&quot;apiart-code-bar&quot; style=&quot;align-items: center; background: rgb(38, 32, 25); box-sizing: border-box; display: flex; gap: 7px; padding: 10px 14px;&quot;&gt;&lt;span class=&quot;apiart-dot red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;apiart-dot green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;fname&quot; style=&quot;box-sizing: border-box; color: #9a8f82; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 8px;&quot;&gt;UserApiTest.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #e8e3dc; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.85; margin: 0px; overflow-x: auto; padding: 16px 18px 18px;&quot;&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: #ff2d20;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #e8b065;&quot;&gt;test_user_can_register&lt;/span&gt;() { $response = $this-&amp;gt;postJson(&lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;/api/register&#39;&lt;/span&gt;, [ &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;CyberMan&#39;&lt;/span&gt;, &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;email&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot; style=&quot;box-sizing: border-box; color: #7dd89a;&quot;&gt;&#39;dev@example.com&#39;&lt;/span&gt;, ]); $response-&amp;gt;assertStatus(201); }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;apiart-section&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 46px 0px;&quot;&gt;&lt;div class=&quot;apiart-step&quot; style=&quot;align-items: baseline; box-sizing: border-box; display: flex; gap: 14px; margin-bottom: 14px;&quot;&gt;&lt;span class=&quot;apiart-step-num&quot; style=&quot;border-color: rgb(255, 45, 32); border-image: none 100% / 1 / 0 stretch; border-radius: 7px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #ff2d20; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; padding: 3px 9px;&quot;&gt;10&lt;/span&gt;&lt;h2 style=&quot;box-sizing: border-box; font-size: 23px; margin: 0px;&quot;&gt;ปิดท้ายด้วยเอกสาร API&lt;/h2&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 16px;&quot;&gt;API ที่ไม่มีเอกสาร คือ API ที่ทีมอื่นกลัวจะใช้ แพ็กเกจอย่าง &lt;span class=&quot;apiart-mono&quot; style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;l5-swagger&lt;/span&gt; ช่วยให้คุณเขียนคอมเมนต์รูปแบบ OpenAPI ไว้เหนือแต่ละเมธอด แล้วระบบจะ generate หน้าเอกสารแบบ interactive ให้อัตโนมัติ ทำให้นักพัฒนาฝั่งอื่นทดลองยิง request ได้จากเบราว์เซอร์โดยไม่ต้องถามคุณซ้ำ ๆ&lt;/p&gt;&lt;/div&gt;&lt;h2 style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 23px; margin: 46px 0px 0px;&quot;&gt;สรุปเช็กลิสต์: 8 เรื่องที่ API ของคุณควรมี&lt;/h2&gt;&lt;div class=&quot;apiart-table-wrap&quot; style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 18px 0px 26px; overflow-x: auto;&quot;&gt;&lt;table class=&quot;apiart-table&quot; style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; border-radius: 10px; font-size: 15px; overflow: hidden; width: 880px;&quot;&gt;&lt;tbody style=&quot;box-sizing: border-box;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(24, 19, 17); box-sizing: border-box; color: #f4efe7; font-size: 14px; padding: 12px 16px; text-align: left;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(24, 19, 17); box-sizing: border-box; color: #f4efe7; font-size: 14px; padding: 12px 16px; text-align: left;&quot;&gt;สิ่งที่ควรทำ&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(24, 19, 17); box-sizing: border-box; color: #f4efe7; font-size: 14px; padding: 12px 16px; text-align: left;&quot;&gt;เครื่องมือ/แพ็กเกจ&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;โครงสร้าง endpoint&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ยึดหลัก RESTful ตาม resource และ HTTP method&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;route:api&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;รูปแบบข้อมูลส่งออก&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ใช้ Resource คัดและจัดรูป JSON เสมอ&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;make:resource&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ตรวจสอบข้อมูลขาเข้า&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;แยก rule ไว้ใน Form Request&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;make:request&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;การยืนยันตัวตน&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ใช้ token-based auth ที่เบาและพอดีกับงาน&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;laravel/sanctum&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;จำกัดการเรียกใช้&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ตั้ง rate limit ป้องกัน abuse&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;throttle middleware&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ความเร็ว&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;paginate ทุก list และ eager load ความสัมพันธ์&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;with() / paginate()&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ความเข้ากันได้ย้อนหลัง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ใส่ version ใน path ตั้งแต่ต้น&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom: 1px solid rgb(228, 217, 200); box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;Route::prefix&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;ความมั่นใจในการแก้โค้ด&lt;/td&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; padding: 12px 16px; vertical-align: top;&quot;&gt;เขียนเทสต์ครอบ endpoint สำคัญ&lt;/td&gt;&lt;td class=&quot;tag&quot; style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #c92418; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 12px 16px; vertical-align: top; white-space: nowrap;&quot;&gt;postJson()&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 23px; margin: 0px;&quot;&gt;สรุป: API ที่ดีคืองานฝีมือ ไม่ใช่ของสำเร็จรูป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;ทั้งหมดนี้ไม่ใช่กฎตายตัวที่ต้องทำให้ครบในวันแรก แต่เป็นแนวทางที่ค่อย ๆ เก็บเพิ่มได้ทีละข้อ เริ่มจาก Resource Controller และ API Resource ก่อน เพราะสองตัวนี้จะวางรากฐานให้โค้ดอ่านง่าย จากนั้นค่อยเติม validation, authentication และ rate limiting เข้าไปตามความจำเป็นของโปรเจกต์&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #2a2420; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px;&quot;&gt;สำหรับใครที่คุ้นเคยกับ CodeIgniter 4 อยู่แล้ว แนวคิดเรื่อง resource-based routing, การแยก validation ออกจาก controller หรือการ version API ก็นำไปปรับใช้กับ CI4 ได้เช่นกัน เพียงแค่ syntax และชื่อคลาสจะต่างกันไปตามแต่ละเฟรมเวิร์ก แก่นของหลักการยังเหมือนเดิม&lt;/p&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/3547193345506195012/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/api-artisan-laravel-api.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3547193345506195012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3547193345506195012'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/api-artisan-laravel-api.html' title='เบื้องหลัง API Artisan: สร้าง Laravel API ที่นักพัฒนาอยากใช้จริง'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhp1Vd_lxncttYDzYIF6_Ddo8kZQtHg3UqBHs-Wm9o0wp9EyY30O4GhuGWdUStxlUK2I8bfEAEJp_7v5UtN6MgqFnIW0k7ExBrHLy6b7aGmICvZKFKqxcCFXvtuwLakBtOqxzHvwVsQ8PkGSmDSolZntlDixcAhjy5YUvHtQOgvYUJoke4NcfiHeecpW34=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-3557209185595355615</id><published>2026-06-19T21:54:09.641+07:00</published><updated>2026-06-19T21:54:09.641+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>Pinion: Resumable File Upload อัปโหลดไฟล์ขนาดใหญ่โดยไม่ต้องเริ่มใหม่</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiD9IPr9QV1VBIvUdm40cNk3ng1wABFcaJaHkGz4IXv8xaUCq4yVlhCtiWg7piehla0-AT1ygHUSnwt-93_Z_Wi9hwEEbGVlxXVFWQhOm1wGmv6dbYELTDPnhvHg6-JRWt-VQXrekfeExO-GlWJf1GqyMYvjtu-eou36oWKYlBtkur1ALRWK_EaPxesX5A&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1536&quot; data-original-width=&quot;1024&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiD9IPr9QV1VBIvUdm40cNk3ng1wABFcaJaHkGz4IXv8xaUCq4yVlhCtiWg7piehla0-AT1ygHUSnwt-93_Z_Wi9hwEEbGVlxXVFWQhOm1wGmv6dbYELTDPnhvHg6-JRWt-VQXrekfeExO-GlWJf1GqyMYvjtu-eou36oWKYlBtkur1ALRWK_EaPxesX5A=w427-h640&quot; width=&quot;427&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;div class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(15, 17, 23) 0%, rgb(26, 31, 46) 60%, rgb(14, 26, 46) 100%) rgb(249, 249, 247); border-radius: 0px 0px 16px 16px; color: #e2e8f0; font-family: Sarabun, sans-serif; font-size: 17px; margin-bottom: 40px; overflow: hidden; padding: 52px 36px 48px; position: relative;&quot;&gt;&lt;div class=&quot;hero-eyebrow&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.12em; margin-bottom: 12px; text-transform: uppercase;&quot;&gt;📦 PHP / CodeIgniter 4 / Laravel&lt;/div&gt;&lt;h1 style=&quot;color: white; font-size: 2rem; line-height: 1.3; margin: 0px 0px 14px;&quot;&gt;Pinion: Resumable File Upload&lt;br /&gt;อัปโหลดไฟล์ขนาดใหญ่โดยไม่ต้องเริ่มใหม่&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;color: #94a3b8; font-size: 15px; margin: 0px;&quot;&gt;ใช้ tus protocol + tus-php library แก้ปัญหาการอัปโหลดไฟล์ที่ค้างกลางทาง ครั้งเดียวจบ&lt;/p&gt;&lt;div class=&quot;tag-list&quot; style=&quot;display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgba(99, 179, 237, 0.15); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.3); color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; padding: 3px 12px;&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgba(99, 179, 237, 0.15); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.3); color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; padding: 3px 12px;&quot;&gt;CodeIgniter 4&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgba(99, 179, 237, 0.15); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.3); color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; padding: 3px 12px;&quot;&gt;Laravel&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgba(99, 179, 237, 0.15); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.3); color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; padding: 3px 12px;&quot;&gt;File Upload&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgba(99, 179, 237, 0.15); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.3); color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; padding: 3px 12px;&quot;&gt;tus-php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🤔 ปัญหาที่นักพัฒนา PHP ทุกคนเคยเจอ&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ลองนึกภาพสถานการณ์นี้ดู — ผู้ใช้งานของคุณพยายามอัปโหลดวิดีโอขนาด 2 GB ขึ้นไปยังเว็บแอปของคุณ รออยู่นาน 45 นาที แล้วอินเทอร์เน็ตก็ดับ หรือเบราว์เซอร์ค้าง ผลลัพธ์คือ? &lt;strong&gt;ต้องเริ่มอัปโหลดใหม่ตั้งแต่ต้น&lt;/strong&gt; ซึ่งเป็นประสบการณ์ที่แย่มากสำหรับผู้ใช้&lt;/p&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ปัญหานี้พบได้บ่อยมากในระบบที่ต้องรับไฟล์ขนาดใหญ่ เช่น ระบบ LMS ที่อัปโหลดวิดีโอบทเรียน, ระบบจัดการเอกสารของหน่วยงานภาครัฐ, หรือแอปพลิเคชัน Creative ที่รับไฟล์ RAW จากกล้อง&lt;/p&gt;&lt;div class=&quot;callout&quot; style=&quot;background: rgb(255, 248, 225); border-left: 4px solid rgb(246, 173, 85); border-radius: 0px 8px 8px 0px; color: #744210; font-family: Sarabun, sans-serif; font-size: 15px; margin: 24px 0px; padding: 14px 18px;&quot;&gt;&lt;span style=&quot;font-weight: 700;&quot;&gt;💡 แนวคิดหลัก:&lt;/span&gt; แทนที่จะอัปโหลดไฟล์ทั้งก้อนในครั้งเดียว ให้แบ่งไฟล์ออกเป็น &lt;em&gt;chunks&lt;/em&gt; เล็ก ๆ แล้วส่งทีละก้อน ถ้าขาดกลางทาง ครั้งหน้าก็เริ่มต่อจากก้อนที่ค้างไว้ได้เลย&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🔌 tus Protocol คืออะไร?&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;tus&lt;/strong&gt; (อ่านว่า &quot;tuːs&quot;) คือ open protocol สำหรับการอัปโหลดไฟล์แบบ resumable โดยเฉพาะ มันถูกออกแบบมาให้รองรับการหยุดกลางทาง ไม่ว่าจะโดยตั้งใจ (ผู้ใช้กด pause) หรือโดยอุบัติเหตุ (เน็ตหลุด, เบราว์เซอร์ปิด) แล้วสามารถกลับมาต่อจากจุดเดิมได้&lt;/p&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;จุดเด่นที่น่าสนใจอีกอย่างคือ คุณสามารถ&lt;strong&gt;เริ่มอัปโหลดจากแล็ปท็อป แล้วมาต่อบนมือถือ&lt;/strong&gt;ได้ เพราะ tus track ความคืบหน้าด้วย upload ID ที่ unique บน server ไม่ใช่บน device&lt;/p&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;📦 tus-php: Library ที่เราจะใช้&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;tus-php&lt;/strong&gt; คือ pure PHP library ที่ implement tus protocol v1.0.0 ครบทั้ง server และ client โดยไม่ผูกติดกับ framework ใด ๆ (framework agnostic) จึงใช้กับทั้ง &lt;strong&gt;CodeIgniter 4&lt;/strong&gt; และ &lt;strong&gt;Laravel&lt;/strong&gt; ได้สะดวก&lt;/p&gt;&lt;h3 style=&quot;background-color: #f9f9f7; color: #2d3748; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 28px 0px 10px;&quot;&gt;ติดตั้งผ่าน Composer&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;composer&lt;/span&gt; require ankitpokhrel/tus-php&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;⚙️ หลักการทำงานแบบ Step by Step&lt;/h2&gt;&lt;div class=&quot;steps&quot; style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;align-items: flex-start; display: flex; gap: 16px; margin-bottom: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(26, 31, 46); border-radius: 8px; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; height: 36px; justify-content: center; margin-top: 2px; min-width: 36px;&quot;&gt;01&lt;/div&gt;&lt;div class=&quot;step-body&quot;&gt;&lt;h3 style=&quot;color: #2d3748; font-size: 1.1rem; margin: 0px 0px 6px;&quot;&gt;Client แบ่งไฟล์เป็น Chunks&lt;/h3&gt;&lt;p style=&quot;color: #4a5568; font-size: 15px; margin: 0px;&quot;&gt;JavaScript ฝั่ง client แบ่งไฟล์ออกเป็นก้อนเล็ก ๆ (เช่น 5 MB ต่อก้อน) แล้วส่งทีละ request&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;align-items: flex-start; display: flex; gap: 16px; margin-bottom: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(26, 31, 46); border-radius: 8px; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; height: 36px; justify-content: center; margin-top: 2px; min-width: 36px;&quot;&gt;02&lt;/div&gt;&lt;div class=&quot;step-body&quot;&gt;&lt;h3 style=&quot;color: #2d3748; font-size: 1.1rem; margin: 0px 0px 6px;&quot;&gt;Server เก็บ Offset&lt;/h3&gt;&lt;p style=&quot;color: #4a5568; font-size: 15px; margin: 0px;&quot;&gt;Server (tus-php) เก็บค่า offset ไว้ใน Redis หรือ Cache ว่าไฟล์อัปโหลดมาถึงไบต์ที่เท่าไรแล้ว&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;align-items: flex-start; display: flex; gap: 16px; margin-bottom: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(26, 31, 46); border-radius: 8px; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; height: 36px; justify-content: center; margin-top: 2px; min-width: 36px;&quot;&gt;03&lt;/div&gt;&lt;div class=&quot;step-body&quot;&gt;&lt;h3 style=&quot;color: #2d3748; font-size: 1.1rem; margin: 0px 0px 6px;&quot;&gt;เกิดการขัดจังหวะ? ต่อได้เลย&lt;/h3&gt;&lt;p style=&quot;color: #4a5568; font-size: 15px; margin: 0px;&quot;&gt;Client ส่ง HEAD request มาถามว่า server รับข้อมูลถึงไหนแล้ว แล้วส่ง chunk ที่เหลือต่อทันที&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;align-items: flex-start; display: flex; gap: 16px; margin-bottom: 20px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(26, 31, 46); border-radius: 8px; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; font-weight: 700; height: 36px; justify-content: center; margin-top: 2px; min-width: 36px;&quot;&gt;04&lt;/div&gt;&lt;div class=&quot;step-body&quot;&gt;&lt;h3 style=&quot;color: #2d3748; font-size: 1.1rem; margin: 0px 0px 6px;&quot;&gt;ประกอบ Chunks เป็นไฟล์สมบูรณ์&lt;/h3&gt;&lt;p style=&quot;color: #4a5568; font-size: 15px; margin: 0px;&quot;&gt;เมื่อรับครบทุก chunk แล้ว server จะ merge เป็นไฟล์ต้นฉบับที่สมบูรณ์&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🖥️ ฝั่ง Server: สร้าง TUS Endpoint&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ไฟล์นี้ทำหน้าที่เป็น tus server — รับ request จาก client และจัดการ chunk ทั้งหมด ตัวอย่างด้านล่างใช้ Redis เป็น storage สำหรับเก็บ upload metadata&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;tus-server.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;vendor/autoload.php&#39;&lt;/span&gt;&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// สร้าง TUS server โดยใช้ Redis เก็บ upload state&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt; = &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;new&lt;/span&gt; \TusPhp\Tus\Server(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;redis&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// กำหนด path ที่จะเก็บไฟล์&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;setUploadDir&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/var/www/uploads&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// กำหนดขนาด chunk สูงสุด (5 MB)&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;setMaxUploadSize&lt;/span&gt;(&lt;span class=&quot;cn&quot; style=&quot;color: #fab387;&quot;&gt;5 * 1024 * 1024&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ให้ server จัดการ request ทั้งหมด&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt; = &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;serve&lt;/span&gt;(); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;send&lt;/span&gt;(); &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;cn&quot; style=&quot;color: #fab387;&quot;&gt;0&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// จำเป็นต้อง exit เพื่อหยุด PHP process&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;background-color: #f9f9f7; color: #2d3748; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 28px 0px 10px;&quot;&gt;ตั้งค่า Nginx ให้ชี้มาที่ server&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;nginx.conf&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;location&lt;/span&gt; /uploads { &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;try_files&lt;/span&gt; $uri $uri/ /tus-server.php?$query_string; }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🚀 ใช้กับ Laravel: ผ่าน Route&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ใน Laravel ไม่จำเป็นต้องแก้ไข Nginx config ตรง ๆ — ให้กำหนด route ใน &lt;code&gt;routes/web.php&lt;/code&gt; หรือ &lt;code&gt;routes/api.php&lt;/code&gt; แทน&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;routes/api.php (Laravel)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;use&lt;/span&gt; Illuminate\Support\Facades\Route; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;use&lt;/span&gt; App\Http\Controllers\TusUploadController; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// รองรับ TUS protocol ทุก HTTP method&lt;/span&gt; Route::&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;any&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/upload/{token?}&#39;&lt;/span&gt;, [TusUploadController::class, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;handle&#39;&lt;/span&gt;]) -&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;token&#39;&lt;/span&gt;, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;[0-9a-zA-Z\-]+&#39;&lt;/span&gt;); &lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;app/Http/Controllers/TusUploadController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;namespace&lt;/span&gt; App\Http\Controllers; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;use&lt;/span&gt; TusPhp\Tus\Server; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;TusUploadController&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;handle&lt;/span&gt;() { &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt; = &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Server&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;redis&#39;&lt;/span&gt;); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;setUploadDir&lt;/span&gt;(&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;storage_path&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;app/uploads&#39;&lt;/span&gt;)); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt; = &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;serve&lt;/span&gt;(); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;send&lt;/span&gt;(); &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;cn&quot; style=&quot;color: #fab387;&quot;&gt;0&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🔥 ใช้กับ CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;CI4 มี Router ที่ยืดหยุ่น สามารถ map ทุก HTTP method เข้า controller เดียวได้ง่าย&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;app/Config/Routes.php (CI4)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// รองรับทุก method สำหรับ TUS endpoint&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;upload/(:any)&#39;&lt;/span&gt;, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;TusUpload::handle/$1&#39;&lt;/span&gt;); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;upload&#39;&lt;/span&gt;, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;TusUpload::handle&#39;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;app/Controllers/TusUpload.php (CI4)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;namespace&lt;/span&gt; App\Controllers; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;use&lt;/span&gt; CodeIgniter\Controller; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;use&lt;/span&gt; TusPhp\Tus\Server; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;TusUpload&lt;/span&gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;handle&lt;/span&gt;() { &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt; = &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Server&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;redis&#39;&lt;/span&gt;); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;setUploadDir&lt;/span&gt;(&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;WRITEPATH&lt;/span&gt; . &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;uploads&#39;&lt;/span&gt;); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt; = &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;serve&lt;/span&gt;(); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$response&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;send&lt;/span&gt;(); &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;cn&quot; style=&quot;color: #fab387;&quot;&gt;0&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🌐 ฝั่ง Client: HTML Form + Uppy.js&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;tus-php ทำงานร่วมกับ JavaScript client library ได้หลายตัว ที่ได้รับความนิยมสูงสุดคือ &lt;strong&gt;Uppy.js&lt;/strong&gt; ซึ่ง support tus protocol แบบ built-in และมี UI สวยงาม พร้อม progress bar&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;upload.blade.php / upload.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;&amp;lt;!-- โหลด Uppy CSS --&amp;gt;&lt;/span&gt; &amp;lt;&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;rel&lt;/span&gt;=&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&quot;https://releases.transloadit.com/uppy/v3.3.1/uppy.min.css&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&quot;uppy-dashboard&quot;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;div&lt;/span&gt;&amp;gt; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;&amp;lt;!-- โหลด Uppy JS --&amp;gt;&lt;/span&gt; &amp;lt;&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&quot;https://releases.transloadit.com/uppy/v3.3.1/uppy.min.js&quot;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;script&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;script&lt;/span&gt;&amp;gt; &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;uppy&lt;/span&gt; = &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Uppy&lt;/span&gt;.&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Uppy&lt;/span&gt;() .&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;use&lt;/span&gt;(&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Uppy.Dashboard&lt;/span&gt;, { &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;target&lt;/span&gt;: &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;#uppy-dashboard&#39;&lt;/span&gt;, &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;inline&lt;/span&gt;: &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;true&lt;/span&gt; }) .&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;use&lt;/span&gt;(&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;Uppy.Tus&lt;/span&gt;, { &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ชี้ endpoint ไปที่ tus server&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;endpoint&lt;/span&gt;: &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/upload&#39;&lt;/span&gt;, &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ขนาด chunk: 5 MB&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;chunkSize&lt;/span&gt;: &lt;span class=&quot;cn&quot; style=&quot;color: #fab387;&quot;&gt;5 * 1024 * 1024&lt;/span&gt; }); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;uppy&lt;/span&gt;.&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;on&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;complete&#39;&lt;/span&gt;, (&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;result&lt;/span&gt;) =&amp;gt; { &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;อัปโหลดสำเร็จ:&#39;&lt;/span&gt;, &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;result&lt;/span&gt;.&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;successful&lt;/span&gt;); }); &amp;lt;/&lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;script&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;📊 เปรียบเทียบวิธีการอัปโหลดแบบต่าง ๆ&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;background-color: #f9f9f7; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px; overflow-x: auto;&quot;&gt;&lt;table style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; font-size: 15px; width: 780px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(26, 31, 46); color: #e2e8f0;&quot;&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;วิธีการ&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;Resumable&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;ไฟล์ขนาดใหญ่&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;ความยากติดตั้ง&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;เหมาะกับ&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;HTML Form อย่างเดียว&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(254, 226, 226); border-radius: 12px; color: #991b1b; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;❌ ไม่รองรับ&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(254, 226, 226); border-radius: 12px; color: #991b1b; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;❌ จำกัดมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;ง่ายมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ไฟล์เล็ก &amp;lt; 10 MB&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;PHP chunked upload (manual)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; color: #1e40af; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;⚠️ ทำเองได้&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; color: #1e40af; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;⚠️ พอใช้ได้&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(254, 226, 226); border-radius: 12px; color: #991b1b; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;ยากมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ระบบที่ต้อง custom เยอะ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;tus-php + tus protocol&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ รองรับเต็ม&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ไม่จำกัด&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; color: #1e40af; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ไฟล์ใหญ่, production&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;Cloud Storage (S3, GCS)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ รองรับ&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(254, 226, 226); border-radius: 12px; color: #991b1b; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;ซับซ้อน&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;Scale ใหญ่, enterprise&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🔧 ต้องการอะไรบ้าง?&lt;/h2&gt;&lt;div class=&quot;callout callout-info&quot; style=&quot;background: rgb(235, 248, 255); border-bottom-color: rgb(99, 179, 237); border-left: 4px solid rgb(99, 179, 237); border-radius: 0px 8px 8px 0px; border-right-color: rgb(99, 179, 237); border-top-color: rgb(99, 179, 237); color: #2a4365; font-family: Sarabun, sans-serif; font-size: 15px; margin: 24px 0px; padding: 14px 18px;&quot;&gt;&lt;span style=&quot;font-weight: 700;&quot;&gt;📋 System Requirements:&lt;/span&gt;&lt;br /&gt;PHP 7.4+ | Redis (แนะนำ) หรือ File-based cache | Composer | Nginx/Apache พร้อม URL Rewrite&lt;/div&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;background-color: #f9f9f7; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px; overflow-x: auto;&quot;&gt;&lt;table style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; font-size: 15px; width: 780px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(26, 31, 46); color: #e2e8f0;&quot;&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;Component&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;รายละเอียด&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;หมายเหตุ&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;code&gt;tus-php&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;Library หลัก&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;install via Composer&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;Redis&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;เก็บ upload state&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ใช้ file cache แทนได้&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;Uppy.js&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;JS client สำหรับ browser&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;หรือ tus-js-client&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;Writeable folder&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;เก็บ chunk และไฟล์สุดท้าย&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;code&gt;chmod 775&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;🎯 ทำอะไรหลังอัปโหลดเสร็จ?&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;tus-php มี event listener ให้คุณดักจับตอนที่ไฟล์ upload ครบ 100% ได้ เหมาะสำหรับ trigger งานต่อเนื่อง เช่น แปลงวิดีโอ, สร้าง thumbnail, หรือบันทึกข้อมูลลงฐานข้อมูล&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.18) 0px 4px 20px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-label&quot; style=&quot;color: #6b7280; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.05em; margin-left: auto;&quot;&gt;After Upload Hook&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cp&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$server&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;event&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;addListener&lt;/span&gt;( \TusPhp\Events\TusEvent::UPLOAD_COMPLETE, &lt;span class=&quot;ck&quot; style=&quot;color: #cba6f7;&quot;&gt;function&lt;/span&gt; (\TusPhp\Events\TusEvent &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$event&lt;/span&gt;) { &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$filePath&lt;/span&gt; = &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;getFile&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;getFilePath&lt;/span&gt;(); &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$fileName&lt;/span&gt; = &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$event&lt;/span&gt;-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;getFile&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;getName&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// บันทึกข้อมูลลงฐานข้อมูล&lt;/span&gt; \App\Models\MediaModel::&lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;create&lt;/span&gt;([ &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;filename&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$fileName&lt;/span&gt;, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;path&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$filePath&lt;/span&gt;, &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;size&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;cf&quot; style=&quot;color: #89dceb;&quot;&gt;filesize&lt;/span&gt;(&lt;span class=&quot;cv&quot; style=&quot;color: #89b4fa;&quot;&gt;$filePath&lt;/span&gt;), &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;status&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;cs&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;ready&#39;&lt;/span&gt;, ]); } );&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f9f9f7; border-bottom: 2px solid rgb(226, 232, 240); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 44px 0px 14px; padding-bottom: 8px;&quot;&gt;📝 สรุป&lt;/h2&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;การอัปโหลดไฟล์ขนาดใหญ่เป็นโจทย์ที่ดูเหมือนง่ายแต่มีรายละเอียดซ่อนอยู่มาก โดยเฉพาะเมื่อต้องรองรับผู้ใช้ที่มีอินเทอร์เน็ตไม่เสถียร &lt;strong&gt;tus protocol + tus-php library&lt;/strong&gt; ช่วยแก้ปัญหานี้ได้อย่างสง่างาม โดยคุณไม่ต้องสร้าง chunking logic ขึ้นมาเอง&lt;/p&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;background-color: #f9f9f7; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px; overflow-x: auto;&quot;&gt;&lt;table style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; font-size: 15px; width: 780px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(26, 31, 46); color: #e2e8f0;&quot;&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;สิ่งที่ได้จากบทความนี้&lt;/th&gt;&lt;th style=&quot;font-size: 13px; letter-spacing: 0.04em; padding: 13px 16px; text-align: left;&quot;&gt;สถานะ&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;เข้าใจหลักการ Resumable Upload&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ติดตั้งและตั้งค่า tus-php server&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ใช้งานกับ Laravel&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ใช้งานกับ CodeIgniter 4&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;ตั้งค่า Uppy.js client&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 250, 252);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;After-upload event hook&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); color: #374151; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 9px;&quot;&gt;✅ ครอบคลุม&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #f9f9f7; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ขั้นตอนต่อไปที่แนะนำคือ เพิ่ม &lt;strong&gt;authentication middleware&lt;/strong&gt; เพื่อป้องกัน upload endpoint, กำหนด file type validation ก่อนประกอบ chunk, และตั้งค่า cleanup job สำหรับไฟล์ chunk ที่อัปโหลดค้างนาน ๆ&lt;/p&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/3557209185595355615/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/pinion-resumable-file-upload.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3557209185595355615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3557209185595355615'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/pinion-resumable-file-upload.html' title='Pinion: Resumable File Upload อัปโหลดไฟล์ขนาดใหญ่โดยไม่ต้องเริ่มใหม่'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiD9IPr9QV1VBIvUdm40cNk3ng1wABFcaJaHkGz4IXv8xaUCq4yVlhCtiWg7piehla0-AT1ygHUSnwt-93_Z_Wi9hwEEbGVlxXVFWQhOm1wGmv6dbYELTDPnhvHg6-JRWt-VQXrekfeExO-GlWJf1GqyMYvjtu-eou36oWKYlBtkur1ALRWK_EaPxesX5A=s72-w427-h640-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6749652895082192685</id><published>2026-06-19T00:09:55.502+07:00</published><updated>2026-06-19T00:09:55.502+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>PHP ในปี 2026: ทุกอย่างที่นักพัฒนาต้องรู้</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgA-XImNvLcw-AhnCekBy3jQeKJ4mDzb-bkO1ai6wEGe_tu4nkVFCXOnZUD4dInPdUnF0Lsr18jprhGZLDFQcmvZYXonKd6EH_hjs14NuVAE1GYNvlU1A5ZQwEx29F_UTtu-laATGFJnAsCENuBFDK_6xeo8Hh5qwZXfoE1zsLUOIjkzBMr0IoH73pk4Ro&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgA-XImNvLcw-AhnCekBy3jQeKJ4mDzb-bkO1ai6wEGe_tu4nkVFCXOnZUD4dInPdUnF0Lsr18jprhGZLDFQcmvZYXonKd6EH_hjs14NuVAE1GYNvlU1A5ZQwEx29F_UTtu-laATGFJnAsCENuBFDK_6xeo8Hh5qwZXfoE1zsLUOIjkzBMr0IoH73pk4Ro=w640-h360&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;header class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(76, 29, 149) 0%, rgb(124, 58, 237) 55%, rgb(37, 99, 235) 100%) rgb(248, 249, 251); border-radius: 12px; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px 40px; overflow: hidden; padding: 36px 24px 32px; position: relative;&quot;&gt;&lt;div class=&quot;hero-eyebrow&quot; style=&quot;background: rgba(255, 255, 255, 0.18); border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.3); box-sizing: border-box; color: white; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.06em; margin: 0px 0px 18px; padding: 4px 14px;&quot;&gt;📰 PHP Internals · June 17, 2026&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; color: white; font-size: clamp(24px, 5vw, 36px); line-height: 1.3; margin: 0px 0px 16px; padding: 0px;&quot;&gt;PHP ในปี 2026:&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;ทุกอย่างที่นักพัฒนาต้องรู้&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; font-size: 16px; line-height: 1.7; margin: 0px 0px 14px; max-width: 560px; opacity: 0.85; padding: 0px;&quot;&gt;&lt;span style=&quot;color: #01ffff;&quot;&gt;PHP 8.5 มาแล้ว — พร้อม Pipe Operator, Partial Function Application, Clone with Properties และอีกมาก มาสำรวจว่าสัปดาห์นี้มีอะไรเกิดขึ้นในโลก PHP Internals และจะกระทบกับ CodeIgniter 4 &amp;amp; Laravel อย่างไร&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; color: white; display: flex; flex-wrap: wrap; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; gap: 20px; margin: 28px 0px 0px; opacity: 0.75; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;📅 17 มิถุนายน 2569&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;⏱ อ่าน ~7 นาที&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;🏷 PHP 8.5 · Laravel 13 · CI4&lt;/span&gt;&lt;/div&gt;&lt;/header&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🚀&lt;/span&gt;เปิดฉาก: ทำไมปี 2026 ถึงน่าตื่นเต้นสำหรับ PHP?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ถ้าคุณยังคิดว่า PHP เป็นภาษา &quot;โบราณ&quot; ขอบอกเลยว่าคิดผิดมากครับ ปี 2026 เป็นช่วงเวลาที่ PHP กำลังเดินหน้าอย่างมั่นคงด้วย &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHP 8.5&lt;/strong&gt; ที่ปล่อยออกมาช่วงปลายปี 2025 และนักพัฒนาส่วนใหญ่เพิ่งเริ่มนำมาใช้งานจริงในปีนี้&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ในแต่ละสัปดาห์ ชุมชน PHP Internals จะมีการพูดคุย ถกเถียง และโหวต RFC เพื่อกำหนดทิศทางของภาษา บทความนี้จะสรุปสิ่งที่เกิดขึ้น พร้อมตัวอย่างโค้ดที่คุณเอาไปใช้ใน &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/strong&gt; และ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/strong&gt; ได้เลย&lt;/p&gt;&lt;div class=&quot;callout callout-info&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-bottom-color: rgb(124, 58, 237); border-left: 4px solid rgb(124, 58, 237); border-radius: 6px; border-right-color: rgb(124, 58, 237); border-top-color: rgb(124, 58, 237); box-sizing: border-box; font-size: 15px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; font-size: 13px; letter-spacing: 0.05em; margin: 0px 0px 4px; padding: 0px; text-transform: uppercase;&quot;&gt;🎯 เหมาะสำหรับ&lt;/strong&gt;ผู้เริ่มต้นที่ใช้ CodeIgniter 4 หรือ Laravel และอยากตามทันฟีเจอร์ PHP ใหม่ ๆ ก่อนใคร&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🔧&lt;/span&gt;ฟีเจอร์ที่ 1: Pipe Operator&lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 17px; margin: 0px; padding: 0px;&quot;&gt;|&amp;gt;&lt;/code&gt;&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Pipe Operator คือฟีเจอร์ที่นักพัฒนา PHP รอคอยมานาน ไอเดียเรียบง่ายมาก: แทนที่จะซ้อนฟังก์ชันหลาย ๆ ชั้นจนอ่านยาก คุณสามารถ &quot;ส่งต่อ&quot; ค่าจากซ้ายไปขวาได้เลย&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ลองดูตัวอย่างแบบเดิมก่อนที่จะมี Pipe Operator:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;before_pipe.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แบบเดิม — อ่านจากในออกนอก (สับสนมาก)&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$result&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_sum&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_filter&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_map&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; * &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, [&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;] ), &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; &amp;gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;));&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;และแบบใหม่ด้วย Pipe Operator — อ่านจากบนลงล่าง เข้าใจง่ายกว่ามาก:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;after_pipe.php (PHP 8.5+)&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แบบใหม่ — อ่านจากซ้ายไปขวา ชัดเจนกว่า&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$result&lt;/span&gt; = [&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;] |&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_map&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; * &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;) |&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_filter&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; &amp;gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;) |&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_sum&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;callout callout-tip&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-bottom-color: rgb(5, 150, 105); border-left: 4px solid rgb(5, 150, 105); border-radius: 6px; border-right-color: rgb(5, 150, 105); border-top-color: rgb(5, 150, 105); box-sizing: border-box; font-size: 15px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; font-size: 13px; letter-spacing: 0.05em; margin: 0px 0px 4px; padding: 0px; text-transform: uppercase;&quot;&gt;💡 ใช้กับ Laravel ได้เลย&lt;/strong&gt;ใน Laravel Service หรือ Pipeline ที่มีการแปลงข้อมูลหลายขั้น Pipe Operator ช่วยให้โค้ดอ่านง่ายขึ้นมาก เหมาะกับ Data Transformation Layer ใน Clean Architecture เป็นพิเศษ&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;⚡&lt;/span&gt;ฟีเจอร์ที่ 2: Partial Function Application (PFA)&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;นี่คือฟีเจอร์ที่ทำให้ Pipe Operator &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ทรงพลังขึ้นอีกเท่าตัว&lt;/em&gt; ปลายปี 2025 RFC นี้ผ่านการโหวต และจะกลายเป็นคู่หูที่แยกกันไม่ออกกับ Pipe Operator&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;PFA ช่วยให้คุณสร้าง &quot;ฟังก์ชันสำเร็จรูปบางส่วน&quot; โดยใส่ &lt;code style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-radius: 4px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; margin: 0px; padding: 2px 7px;&quot;&gt;?&lt;/code&gt; เป็น placeholder สำหรับพารามิเตอร์ที่จะส่งทีหลัง:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;partial_function.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// PFA — ล็อกพารามิเตอร์บางตัวไว้ก่อน ค่อยส่งที่เหลือทีหลัง&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$double&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_map&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; * &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;?&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$moreThan4&lt;/span&gt; = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_filter&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;?&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$x&lt;/span&gt; &amp;gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// รวมกับ Pipe Operator — อ่านลื่นมาก&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$result&lt;/span&gt; = [&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #fab387; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;] |&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$double&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;) |&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$moreThan4&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;) |&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_sum&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;...&lt;/span&gt;); &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;var_dump&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$result&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// int(24) — ผลลัพธ์: (4+6+8+10) = 28, filter &amp;gt;4 = 6+8+10=24&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;📦&lt;/span&gt;ฟีเจอร์ที่ 3: Clone with Properties&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;PHP 8.5 เพิ่มความสามารถในการ Clone object พร้อมเปลี่ยนค่า property ได้ในทีเดียว มีประโยชน์มากสำหรับ Value Object และ Immutable Data ใน Domain Layer&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;clone_with.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ตัวอย่าง: Value Object สำหรับ User ใน Laravel&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;UserProfile&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public readonly string&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$name&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public readonly string&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$email&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public readonly string&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$role&lt;/span&gt; = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;, ) {} } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$original&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;UserProfile&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;สมชาย&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;somchai@example.com&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// PHP 8.5: clone พร้อมเปลี่ยน property ได้เลย&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$admin&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;clone&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$original&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;role&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;admin&#39;&lt;/span&gt; }; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$original&lt;/span&gt;-&amp;gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;role&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// &#39;user&#39; — ของเดิมไม่เปลี่ยน&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$admin&lt;/span&gt;-&amp;gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;role&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// &#39;admin&#39; — object ใหม่&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;callout callout-warn&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 243, 199); border-bottom-color: rgb(217, 119, 6); border-left: 4px solid rgb(217, 119, 6); border-radius: 6px; border-right-color: rgb(217, 119, 6); border-top-color: rgb(217, 119, 6); box-sizing: border-box; font-size: 15px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; display: block; font-size: 13px; letter-spacing: 0.05em; margin: 0px 0px 4px; padding: 0px; text-transform: uppercase;&quot;&gt;⚠️ หมายเหตุ&lt;/strong&gt;Syntax ของ Clone with Properties อาจปรับเปลี่ยนเล็กน้อยตาม RFC ล่าสุด ควรตรวจสอบที่&lt;strong style=&quot;box-sizing: border-box; display: block; font-size: 13px; letter-spacing: 0.05em; margin: 0px 0px 4px; padding: 0px; text-transform: uppercase;&quot;&gt;php.net/archive/2026&lt;/strong&gt;ก่อน upgrade production เสมอ&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🐛&lt;/span&gt;ฟีเจอร์ที่ 4: Backtrace สำหรับ Fatal Errors&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;เดิม PHP จะแสดง Fatal Error แบบกระชับ บอกแค่ไฟล์กับบรรทัด ทำให้ debug ยาก PHP 8.5 เพิ่ม stack trace ให้กับ Fatal Error เหมือนกับ Exception ทั่วไป&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;fatal_backtrace.txt — PHP 8.5 output&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;Fatal error: Maximum execution time of 1 second exceeded in example.php on line 6 #0 example.php(6): usleep(100000) #1 example.php(12): slowOperation() #2 example.php(20): processData() #3 {main}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;สำหรับโปรเจกต์ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CI4&lt;/strong&gt; และ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/strong&gt; นี่หมายความว่า log ที่ได้จาก error handler จะมีข้อมูลครบขึ้นมาก ช่วยลดเวลา debug ได้อย่างชัดเจน&lt;/p&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🌿&lt;/span&gt;Best Practices สำหรับ Laravel 13 ในปี 2026&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Laravel 12 และ 13 เป็น version ที่ได้รับการ support อย่างเป็นทางการในปีนี้ โดย Laravel 13 รองรับ PHP 8.3–8.5 และจะได้รับ security update ไปถึงปี 2028&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 18px; margin: 28px 0px 12px; padding: 0px;&quot;&gt;✅ ใช้ Form Request Validation แทน inline validation&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;app/Http/Requests/StoreProductRequest.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Http\Requests; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; Illuminate\Foundation\Http\FormRequest; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;StoreProductRequest&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;FormRequest&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;authorize&lt;/span&gt;(): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;rules&lt;/span&gt;(): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;string&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;max:255&#39;&lt;/span&gt;], &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;numeric&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;min:0&#39;&lt;/span&gt;], &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;category&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;required&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;exists:categories,id&#39;&lt;/span&gt;], ]; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;messages&lt;/span&gt;(): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name.required&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;กรุณาระบุชื่อสินค้า&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price.min&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;ราคาต้องไม่ติดลบ&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;category.exists&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;หมวดหมู่ที่เลือกไม่มีในระบบ&#39;&lt;/span&gt;, ]; } }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 18px; margin: 28px 0px 12px; padding: 0px;&quot;&gt;✅ ใช้ Service Class แยกธุรกิจออกจาก Controller&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;app/Services/ProductService.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Services; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Models\Product; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Http\Requests\StoreProductRequest; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ProductService&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;StoreProductRequest&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;): &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;Product&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;Product&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;create&lt;/span&gt;([ &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;validated&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;), &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;validated&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price&#39;&lt;/span&gt;), &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;category_id&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;validated&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;category&#39;&lt;/span&gt;), &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;created_by&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;auth&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;id&lt;/span&gt;(), ]); } } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Controller บางเฉียบ — แค่เรียก Service&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ProductController&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;store&lt;/span&gt;( &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;StoreProductRequest&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ProductService&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$service&lt;/span&gt; ) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$product&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$service&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;redirect&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;route&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;products.show&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$product&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;success&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;เพิ่มสินค้าเรียบร้อยแล้ว&#39;&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🔥&lt;/span&gt;สำหรับผู้ใช้ CodeIgniter 4: ใช้ PHP 8.5 ได้เลยไหม?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;CI4 รองรับ PHP 8.1+ อยู่แล้ว และ PHP 8.5 backward compatible กับโค้ดเดิมเป็นส่วนใหญ่ Pipe Operator และ PFA เป็น syntax ใหม่ที่ไม่ได้เปลี่ยนแปลงของเดิม คุณสามารถ upgrade PHP เวอร์ชันได้โดยไม่ต้องแก้โค้ด CI4 เดิม แล้วค่อย ๆ นำ syntax ใหม่มาใช้&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(30, 30, 46); border-color: rgb(61, 61, 92); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 24px 0px; box-sizing: border-box; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(42, 42, 62); border-bottom: 1px solid rgb(61, 61, 92); box-sizing: border-box; display: flex; gap: 10px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #a6adc8; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px 4px; padding: 0px;&quot;&gt;app/Models/ProductModel.php (CI4)&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;pre style=&quot;box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; line-height: 1.75; margin: 0px; padding: 0px; tab-size: 4;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Models; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; CodeIgniter\Model; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;ProductModel&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;Model&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt; = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;products&#39;&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$allowedFields&lt;/span&gt; = [&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price&#39;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;category_id&#39;&lt;/span&gt;]; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// PHP 8.5: ใช้ Pipe Operator ใน method ได้เลย&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;getExpensiveProducts&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$minPrice&lt;/span&gt;): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;array&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$items&lt;/span&gt; = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;findAll&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แบบเดิม&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_values&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;array_filter&lt;/span&gt;( &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$items&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$p&lt;/span&gt;) =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$p&lt;/span&gt;[&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;&#39;price&#39;&lt;/span&gt;] &amp;gt;= &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;$minPrice&lt;/span&gt; )); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แบบใหม่ (PHP 8.5) — อ่านง่ายกว่า&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// return $items&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// |&amp;gt; array_filter(?, fn($p) =&amp;gt; $p[&#39;price&#39;] &amp;gt;= $minPrice)&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// |&amp;gt; array_values(?);&lt;/span&gt; } }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;📊&lt;/span&gt;ตารางเปรียบเทียบ: PHP 8.4 vs 8.5 vs ที่กำลังจะมา&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 12px 0px; box-sizing: border-box; margin: 24px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-collapse: collapse; font-size: 15px; margin: 0px; padding: 0px; width: 484px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(124, 58, 237); box-sizing: border-box; color: white; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 13px 16px; text-align: left;&quot;&gt;ฟีเจอร์&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(124, 58, 237); box-sizing: border-box; color: white; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 13px 16px; text-align: left;&quot;&gt;PHP 8.4&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(124, 58, 237); box-sizing: border-box; color: white; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 13px 16px; text-align: left;&quot;&gt;PHP 8.5&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(124, 58, 237); box-sizing: border-box; color: white; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 13px 16px; text-align: left;&quot;&gt;กำลังจะมา&lt;/th&gt;&lt;th style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(124, 58, 237); box-sizing: border-box; color: white; font-size: 14px; letter-spacing: 0.03em; margin: 0px; padding: 13px 16px; text-align: left;&quot;&gt;ประโยชน์หลัก&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Pipe Operator &lt;code style=&quot;box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; margin: 0px; padding: 0px;&quot;&gt;|&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ มีแล้ว&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;อ่านโค้ด transform ข้อมูลได้ง่ายขึ้น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Partial Function Application&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ มีแล้ว&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;สร้าง reusable function fragment ได้&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Clone with Properties&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ มีแล้ว&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Immutable Value Object สะอาดขึ้น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Fatal Error Backtrace&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ มีแล้ว&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Debug production ได้ง่ายขึ้นมาก&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Closures in Attributes&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ มีแล้ว&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Attribute-driven metadata ยืดหยุ่นขึ้น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Property Hooks (get/set)&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-purple&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(237, 233, 254); border-radius: 20px; box-sizing: border-box; color: #5b21b6; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ PHP 8.4&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;✅&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;แทน getter/setter ซ้ำซ้อนได้&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Generics / Type System ขั้นสูง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;❌&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-orange&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(254, 243, 199); border-radius: 20px; box-sizing: border-box; color: #92400e; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;RFC กำลังพิจารณา&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Type safety เทียบเท่า TypeScript&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Laravel 13 + PHP 8.5&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 3px 10px;&quot;&gt;✅ รองรับ&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-bottom: 1px solid rgb(226, 230, 237); box-sizing: border-box; line-height: 1.6; margin: 0px; padding: 12px 16px; vertical-align: top;&quot;&gt;Security update ถึง 2028&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(237, 233, 254); box-sizing: border-box; color: #7c3aed; display: flex; font-size: 19px; gap: 10px; margin: 0px 0px 16px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px; padding: 0px;&quot;&gt;🎯&lt;/span&gt;สรุป&lt;/h2&gt;&lt;div class=&quot;conclusion-card&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 12px 0px; box-sizing: border-box; margin: 20px 0px 0px; padding: 24px 20px;&quot;&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;สัปดาห์นี้ใน PHP Internals บอกเราได้ชัดว่า &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHP กำลังวิ่งไปข้างหน้าอย่างไม่หยุด&lt;/strong&gt; ฟีเจอร์อย่าง Pipe Operator และ Partial Function Application ไม่ใช่แค่ syntactic sugar แต่เป็นการเปลี่ยน paradigm การเขียนโค้ดของ PHP ให้ใกล้เคียงกับ functional programming มากขึ้น&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;สิ่งที่คุณควรทำหลังอ่านบทความนี้:&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; line-height: 2.2; margin: 0px 0px 14px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;🔄 &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;อัปเกรด&lt;/strong&gt;โปรเจกต์ CI4 / Laravel ให้ใช้ PHP 8.5&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;✍️ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ทดลองเขียน&lt;/strong&gt; Pipe Operator กับโค้ด data transformation ที่มีอยู่&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;📖 &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ติดตาม&lt;/strong&gt; RFC ที่ php.net/archive/2026 อย่างสม่ำเสมอ&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;🛡️ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ตรวจสอบ&lt;/strong&gt; ว่า Laravel ของคุณเป็น version 12 หรือ 13 เพื่อรับ security patch ถึงปี 2028&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHP ในปี 2026 ไม่ใช่ภาษาเดิมที่คุณรู้จักอีกต่อไปแล้วครับ — มันกำลัง mature ขึ้นทุกวัน&lt;/p&gt;&lt;/div&gt;&lt;/section&gt;&lt;div class=&quot;cta-box&quot; style=&quot;background: linear-gradient(135deg, rgb(76, 29, 149), rgb(37, 99, 235)) rgb(248, 249, 251); border-radius: 12px; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 44px 0px 0px; padding: 24px 20px; text-align: center;&quot;&gt;&lt;h3 style=&quot;box-sizing: border-box; color: white; font-size: 20px; margin: 0px 0px 12px; padding: 0px;&quot;&gt;🚀 อยากพัฒนาทักษะ PHP &amp;amp; Laravel ให้เป็นมืออาชีพ?&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px 0px 24px; opacity: 0.88; padding: 0px;&quot;&gt;&lt;span style=&quot;color: white;&quot;&gt;ติดตาม &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PHP Code Mania&lt;/strong&gt; สำหรับบทความภาษาไทยเชิงลึกเกี่ยวกับ PHP, CodeIgniter 4, Laravel และ Algorithmic Trading ทุกสัปดาห์&lt;/span&gt;&lt;/p&gt;&lt;a class=&quot;cta-btn&quot; href=&quot;https://www.facebook.com/phpcodemania&quot; rel=&quot;noopener&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 8px; box-sizing: border-box; color: #7c3aed; display: inline-block; font-size: 15px; font-weight: 700; margin: 0px; padding: 12px 32px; text-decoration: none; transition: opacity 0.2s;&quot; target=&quot;_blank&quot;&gt;👉 ติดตามได้ที่&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;tags&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 17px; gap: 8px; margin: 32px 0px 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;PHP 8.5&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;Laravel 13&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;CodeIgniter 4&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;Pipe Operator&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;Partial Function Application&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;PHP Internals&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;PHP 2026&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 247); border-color: rgb(226, 230, 237); border-image: none 100% / 1 / 0 stretch; border-radius: 20px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #6b7591; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin: 0px; padding: 4px 12px;&quot;&gt;Web Development&lt;/span&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6749652895082192685/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-2026.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6749652895082192685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6749652895082192685'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-2026.html' title='PHP ในปี 2026: ทุกอย่างที่นักพัฒนาต้องรู้'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgA-XImNvLcw-AhnCekBy3jQeKJ4mDzb-bkO1ai6wEGe_tu4nkVFCXOnZUD4dInPdUnF0Lsr18jprhGZLDFQcmvZYXonKd6EH_hjs14NuVAE1GYNvlU1A5ZQwEx29F_UTtu-laATGFJnAsCENuBFDK_6xeo8Hh5qwZXfoE1zsLUOIjkzBMr0IoH73pk4Ro=s72-w640-h360-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-8123584424294512526</id><published>2026-06-17T20:56:58.065+07:00</published><updated>2026-06-17T20:56:58.066+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>ยังควรใช้ PHP ทำ API และเว็บเพจในปี 2026 อยู่ไหม?</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgl0wHUG_AD6Y7V9KM357_mWZMyeG9ytoTYaqIzpmqiptqEmkHKe8SIFy0NouYEayvUZwFy-5qwll13jtqBHCUD32GnlGSyWHj0RtFdQ0YkRL1U0mrjbI2vNh_fDBhJIMHFwRCyPdxiO4t-GRDCSfFnCqLrjun5hl7H_IWI1Ad1lZPtgCJ0buWVA2BcTWE&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1536&quot; height=&quot;427&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgl0wHUG_AD6Y7V9KM357_mWZMyeG9ytoTYaqIzpmqiptqEmkHKe8SIFy0NouYEayvUZwFy-5qwll13jtqBHCUD32GnlGSyWHj0RtFdQ0YkRL1U0mrjbI2vNh_fDBhJIMHFwRCyPdxiO4t-GRDCSfFnCqLrjun5hl7H_IWI1Ad1lZPtgCJ0buWVA2BcTWE&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;pmc-hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(15, 15, 26) 0%, rgb(26, 26, 46) 60%, rgb(22, 33, 62) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 16px; color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin-bottom: 40px; overflow: hidden; padding: 52px 40px 48px; position: relative;&quot;&gt;&lt;div class=&quot;pmc-hero-eyebrow&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 2.5px; margin-bottom: 14px; text-transform: uppercase;&quot;&gt;PHP Code Mania · June 2026&lt;/div&gt;&lt;h1 style=&quot;color: #e2e8f0; font-size: 2rem; line-height: 1.35; margin: 0px 0px 18px;&quot;&gt;ยังควรใช้ &lt;span style=&quot;color: #63b3ed;&quot;&gt;PHP&lt;/span&gt; ทำ API&lt;br /&gt;และเว็บเพจในปี 2026 อยู่ไหม?&lt;/h1&gt;&lt;div class=&quot;pmc-hero-meta&quot; style=&quot;color: #718096; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px;&quot;&gt;อ่านประมาณ 8 นาที · เหมาะสำหรับ: Beginner → Intermediate&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ถ้าคุณเริ่มต้นเรียน web development ในยุคนี้ คุณอาจถามตัวเองว่า &lt;em&gt;&quot;PHP ยังคุ้มค่าที่จะเรียนอยู่ไหม?&quot;&lt;/em&gt; — คำตอบสั้นๆ คือ &lt;strong&gt;ใช่&lt;/strong&gt; แต่มันซับซ้อนกว่านั้นนิดหน่อย บทความนี้จะพาคุณดูข้อมูลจากการสำรวจ &lt;strong&gt;JetBrains State of PHP 2025&lt;/strong&gt; พร้อมตัวอย่างโค้ดจริงทั้งใน &lt;strong&gt;CodeIgniter 4&lt;/strong&gt; และ &lt;strong&gt;Laravel&lt;/strong&gt; เพื่อให้คุณตัดสินใจได้อย่างมั่นใจมากขึ้น&lt;/p&gt;&lt;div class=&quot;pmc-callout&quot; style=&quot;background: rgb(235, 248, 255); border-left: 4px solid rgb(49, 130, 206); border-radius: 0px 10px 10px 0px; color: #2c5282; font-family: Sarabun, sans-serif; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;color: #1a365d;&quot;&gt;📊 ที่มาข้อมูล:&lt;/strong&gt; JetBrains Developer Ecosystem Survey 2025 สำรวจ PHP developer จำนวน 1,720 คนทั่วโลก รวมถึง Japan, USA, Russia, China และ France&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;PHP ยังมีชีวิตอยู่จริงๆ — ตัวเลขพูดแทน&lt;/h2&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;หลายคนคิดว่า PHP กำลังจะตาย แต่ข้อมูลจริงบอกอีกอย่าง นักพัฒนาที่ใช้ PHP มาเกิน 3 ปีมีถึง 88% และกลุ่มใหญ่สุดอยู่ในช่วง 6–10 ปีของประสบการณ์ ซึ่งแสดงให้เห็นว่า ecosystem มีความสมบูรณ์สูง&lt;/p&gt;&lt;div class=&quot;pmc-stats&quot; style=&quot;color: #1e1e2e; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 17px; gap: 12px; margin: 24px 0px;&quot;&gt;&lt;div class=&quot;pmc-stat&quot; style=&quot;background: rgb(26, 26, 46); border-radius: 10px; color: #e2e8f0; flex: 1 1 140px; padding: 14px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;pmc-stat-num&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 2rem; font-weight: 700; line-height: 1.1;&quot;&gt;89%&lt;/div&gt;&lt;div class=&quot;pmc-stat-label&quot; style=&quot;color: #a0aec0; font-size: 12px; margin-top: 4px;&quot;&gt;ใช้ PHP 8.x แล้ว&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;pmc-stat&quot; style=&quot;background: rgb(26, 26, 46); border-radius: 10px; color: #e2e8f0; flex: 1 1 140px; padding: 14px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;pmc-stat-num&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 2rem; font-weight: 700; line-height: 1.1;&quot;&gt;64%&lt;/div&gt;&lt;div class=&quot;pmc-stat-label&quot; style=&quot;color: #a0aec0; font-size: 12px; margin-top: 4px;&quot;&gt;นิยม Laravel&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;pmc-stat&quot; style=&quot;background: rgb(26, 26, 46); border-radius: 10px; color: #e2e8f0; flex: 1 1 140px; padding: 14px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;pmc-stat-num&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 2rem; font-weight: 700; line-height: 1.1;&quot;&gt;58%&lt;/div&gt;&lt;div class=&quot;pmc-stat-label&quot; style=&quot;color: #a0aec0; font-size: 12px; margin-top: 4px;&quot;&gt;ไม่มีแผนย้ายภาษา&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;pmc-stat&quot; style=&quot;background: rgb(26, 26, 46); border-radius: 10px; color: #e2e8f0; flex: 1 1 140px; padding: 14px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;pmc-stat-num&quot; style=&quot;color: #63b3ed; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 2rem; font-weight: 700; line-height: 1.1;&quot;&gt;23%&lt;/div&gt;&lt;div class=&quot;pmc-stat-label&quot; style=&quot;color: #a0aec0; font-size: 12px; margin-top: 4px;&quot;&gt;ใช้ Symfony&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;น่าสนใจที่ว่า &lt;strong&gt;58% ไม่มีแผนย้ายไปภาษาอื่น&lt;/strong&gt;ในอีก 1 ปีข้างหน้า และสำหรับคนที่คิดจะเรียนภาษาเพิ่ม ส่วนใหญ่เลือก Go และ Python ซึ่งนั่นไม่ได้หมายความว่าทิ้ง PHP แต่เป็นการเพิ่มทักษะเข้าไปอีกชั้นหนึ่ง&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;PHP ทำ API ได้ดีแค่ไหนในปี 2026?&lt;/h2&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;PHP สมัยใหม่ (เวอร์ชัน 8.x) มาพร้อม Features ที่ทำให้เขียน API ได้สะอาดและมีประสิทธิภาพมากขึ้น ไม่ว่าจะเป็น &lt;code&gt;Named Arguments&lt;/code&gt;, &lt;code&gt;Fibers&lt;/code&gt;, &lt;code&gt;Enums&lt;/code&gt;, และ &lt;code&gt;readonly Properties&lt;/code&gt; — ทั้งหมดนี้ทำให้ logic ชัดเจนและ debug ง่ายขึ้น&lt;/p&gt;&lt;h3 style=&quot;color: #2d3748; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 28px 0px 8px;&quot;&gt;ตัวอย่าง: REST API ง่ายๆ ด้วย CodeIgniter 4&lt;/h3&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;CI4 มี RESTful routing แบบ clean มาให้ในตัว เหมาะมากสำหรับ project ขนาดกลางที่ต้องการความเร็วในการพัฒนาและ overhead น้อย&lt;/p&gt;&lt;div class=&quot;pmc-code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pmc-code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); display: flex; gap: 8px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;pmc-code-dot red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot amber&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;span style=&quot;color: #8b949e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px;&quot;&gt;app/Controllers/Api/ProductController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 18px;&quot;&gt;&amp;lt;?php &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;namespace&lt;/span&gt; App\Controllers\Api; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; CodeIgniter\RESTful\ResourceController; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; App\Models\ProductModel; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;ProductController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;extends&lt;/span&gt; ResourceController { &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$modelName&lt;/span&gt; = ProductModel::class; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$format&lt;/span&gt; = &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;json&#39;&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;color: #8b949e; font-style: italic;&quot;&gt;// GET /api/products&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;index&lt;/span&gt;(): mixed { &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;respond&lt;/span&gt;([ &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;status&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;success&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;data&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;findAll&lt;/span&gt;(), ]); } &lt;span class=&quot;cm&quot; style=&quot;color: #8b949e; font-style: italic;&quot;&gt;// POST /api/products&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;create&lt;/span&gt;(): mixed { &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$rules&lt;/span&gt; = [ &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;required|min_length[3]&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;price&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;required|numeric&#39;&lt;/span&gt;, ]; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;validate&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$rules&lt;/span&gt;)) { &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;failValidationErrors&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;validator-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;getErrors&lt;/span&gt;()); } &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$id&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;model-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;insert&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;getJSON&lt;/span&gt;(assoc: &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;true&lt;/span&gt;)); &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;respondCreated&lt;/span&gt;([ &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;status&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;created&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;id&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$id&lt;/span&gt;, ]); } }&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;สังเกตว่า CI4 ใช้ &lt;code&gt;ResourceController&lt;/code&gt; เป็น base class ที่มี method &lt;code&gt;respond()&lt;/code&gt;, &lt;code&gt;respondCreated()&lt;/code&gt;, และ &lt;code&gt;failValidationErrors()&lt;/code&gt; มาให้แล้ว ทำให้ response format สม่ำเสมอโดยไม่ต้องเขียน boilerplate เอง&lt;/p&gt;&lt;h3 style=&quot;color: #2d3748; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 28px 0px 8px;&quot;&gt;ตัวอย่าง: API Route ด้วย Laravel 11&lt;/h3&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;Laravel เหมาะสำหรับ project ที่ต้องการ ecosystem ครบ เช่น Authentication, Queue, Events และ Telescope สำหรับ debug&lt;/p&gt;&lt;div class=&quot;pmc-code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pmc-code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); display: flex; gap: 8px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;pmc-code-dot red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot amber&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;span style=&quot;color: #8b949e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px;&quot;&gt;routes/api.php + app/Http/Controllers/Api/ProductController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 18px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #8b949e; font-style: italic;&quot;&gt;// routes/api.php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; App\Http\Controllers\Api\ProductController; Route::&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;apiResource&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;products&#39;&lt;/span&gt;, ProductController::class); &lt;span class=&quot;cm&quot; style=&quot;color: #8b949e; font-style: italic;&quot;&gt;// ────────────────────────────────────────────────────────&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;color: #8b949e; font-style: italic;&quot;&gt;// app/Http/Controllers/Api/ProductController.php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;namespace&lt;/span&gt; App\Http\Controllers\Api; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; App\Http\Requests\StoreProductRequest; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; App\Http\Resources\ProductResource; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; App\Models\Product; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;use&lt;/span&gt; Illuminate\Http\Resources\Json\AnonymousResourceCollection; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;ProductController&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;index&lt;/span&gt;(): AnonymousResourceCollection { &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;return&lt;/span&gt; ProductResource::&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;collection&lt;/span&gt;( Product::&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;latest&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;paginate&lt;/span&gt;(20) ); } &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;store&lt;/span&gt;(StoreProductRequest &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$request&lt;/span&gt;): ProductResource { &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt; = Product::&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;create&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;validated&lt;/span&gt;()); &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;new&lt;/span&gt; ProductResource(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pmc-callout&quot; style=&quot;background: rgb(235, 248, 255); border-left: 4px solid rgb(49, 130, 206); border-radius: 0px 10px 10px 0px; color: #2c5282; font-family: Sarabun, sans-serif; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;color: #1a365d;&quot;&gt;💡 เปรียบเทียบสั้นๆ:&lt;/strong&gt; CI4 เหมาะถ้าคุณต้องการควบคุม logic ด้วยตัวเอง และ overhead น้อย ส่วน Laravel เหมาะถ้าคุณอยากได้ ecosystem ครบพร้อม เช่น Auth, Queue, Broadcasting&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;ทำเว็บเพจแบบดั้งเดิมยังได้อยู่ไหม?&lt;/h2&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;แน่นอน — และนั่นคือจุดแข็งที่ยังไม่มีใครสู้ PHP ได้ง่ายๆ สำหรับ server-rendered HTML ที่ต้องการ dynamic content เช่น ระบบสมาชิก, หน้าสินค้า, หรือ dashboard ภายใน PHP ยังคงเป็นตัวเลือกที่ deploy ง่ายและ hosting ราคาถูกรองรับ&lt;/p&gt;&lt;h3 style=&quot;color: #2d3748; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 28px 0px 8px;&quot;&gt;ตัวอย่าง: Blade Template ใน Laravel&lt;/h3&gt;&lt;div class=&quot;pmc-code-wrap&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pmc-code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); display: flex; gap: 8px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;pmc-code-dot red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot amber&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pmc-code-dot green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; height: 11px; width: 11px;&quot;&gt;&lt;/div&gt;&lt;span style=&quot;color: #8b949e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px;&quot;&gt;resources/views/products/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #e6edf3; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 18px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@extends&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;layouts.app&#39;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@section&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;content&#39;&lt;/span&gt;) &amp;lt;div class=&quot;container&quot;&amp;gt; &amp;lt;h1&amp;gt;รายการสินค้า&amp;lt;/h1&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@forelse&lt;/span&gt; (&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$products&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt;) &amp;lt;div class=&quot;product-card&quot;&amp;gt; &amp;lt;h2&amp;gt;{{ &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt;-&amp;gt;name }}&amp;lt;/h2&amp;gt; &amp;lt;p&amp;gt;ราคา: {{ &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;number_format&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt;-&amp;gt;price, 2) }} บาท&amp;lt;/p&amp;gt; &amp;lt;a href=&quot;{{ &lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;route&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a5d6ff;&quot;&gt;&#39;products.show&#39;&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$product&lt;/span&gt;) }}&quot;&amp;gt;ดูรายละเอียด&amp;lt;/a&amp;gt; &amp;lt;/div&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@empty&lt;/span&gt; &amp;lt;p&amp;gt;ยังไม่มีสินค้า&amp;lt;/p&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@endforelse&lt;/span&gt; {{ &lt;span class=&quot;var&quot; style=&quot;color: #ffa657;&quot;&gt;$products&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #d2a8ff;&quot;&gt;links&lt;/span&gt;() }} &amp;lt;/div&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #ff7b72;&quot;&gt;@endsection&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;Blade ทำให้ template ภาษา PHP อ่านง่ายมาก directive อย่าง &lt;code&gt;@forelse&lt;/code&gt; จัดการกรณี empty state ได้ในบรรทัดเดียว และ &lt;code&gt;$products-&amp;gt;links()&lt;/code&gt; render pagination อัตโนมัติโดยไม่ต้องเขียน HTML เอง&lt;/p&gt;&lt;hr class=&quot;pmc-divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 17px; margin: 36px 0px;&quot; /&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;เปรียบเทียบ: PHP (CI4 / Laravel) vs ทางเลือกอื่น&lt;/h2&gt;&lt;div class=&quot;pmc-table-wrap&quot; style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow-x: auto;&quot;&gt;&lt;table class=&quot;pmc-table&quot; style=&quot;border-collapse: collapse; font-size: 14.5px; width: 820px;&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; padding: 12px 16px; text-align: left;&quot;&gt;ด้าน&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; padding: 12px 16px; text-align: left;&quot;&gt;CodeIgniter 4&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; padding: 12px 16px; text-align: left;&quot;&gt;Laravel 11&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; padding: 12px 16px; text-align: left;&quot;&gt;Node.js (Express)&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 26, 46); color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.5px; padding: 12px 16px; text-align: left;&quot;&gt;Go (Fiber)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;ความเร็ว Learn&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ง่าย&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-yellow&quot; style=&quot;background: rgb(254, 252, 191); border-radius: 4px; color: #744210; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ยากกว่า&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;Ecosystem / Packages&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ครบมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ครบมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-yellow&quot; style=&quot;background: rgb(254, 252, 191); border-radius: 4px; color: #744210; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;เล็กกว่า&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;API Performance&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ดี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ดี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;เร็วมาก&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;Web Page (SSR)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;Hosting ราคาประหยัด&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;หาง่ายมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;หาง่าย&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-yellow&quot; style=&quot;background: rgb(254, 252, 191); border-radius: 4px; color: #744210; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ต้องการ Node server&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-yellow&quot; style=&quot;background: rgb(254, 252, 191); border-radius: 4px; color: #744210; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ต้องการ VPS&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;strong&gt;Community (ปี 2025)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ใหญ่มาก (64%)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(198, 246, 213); border-radius: 4px; color: #22543d; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;ใหญ่มาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;background: rgb(247, 250, 252); border-bottom: 1px solid rgb(226, 232, 240); padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(190, 227, 248); border-radius: 4px; color: #2a4365; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 8px;&quot;&gt;กำลังโต&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;สรุปว่าควรใช้ PHP เมื่อไหร่?&lt;/h2&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;PHP ยังเป็นตัวเลือกที่ดีเยี่ยมใน scenario เหล่านี้:&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;✅ เว็บไซต์ทั่วไปและ CMS&lt;/strong&gt; — WordPress ยังครอง 43% ของเว็บทั่วโลก และ ecosystem รอบๆ PHP-based CMS ยังแข็งแกร่งมาก&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;✅ REST API สำหรับ SME&lt;/strong&gt; — CI4 หรือ Laravel ทำ API ได้รวดเร็ว deploy ง่าย และ shared hosting รองรับได้ทันที เหมาะมากสำหรับ startup หรือ project ที่ budget จำกัด&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;✅ Server-Rendered Web App&lt;/strong&gt; — ถ้าต้องการ SEO ดีโดยไม่ต้องพึ่ง SSR framework อย่าง Next.js PHP + Blade คือคำตอบที่ตรงไปตรงมาที่สุด&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;&lt;strong&gt;⚠️ พิจารณาทางเลือกอื่น ถ้า...&lt;/strong&gt; คุณต้องการ real-time heavy (WebSocket-first), high-throughput microservice ที่ต้องการ performance สูงสุด หรือ team ที่คุ้นเคยกับ Go/Node อยู่แล้ว&lt;/p&gt;&lt;div class=&quot;pmc-callout&quot; style=&quot;background: rgb(235, 248, 255); border-left: 4px solid rgb(49, 130, 206); border-radius: 0px 10px 10px 0px; color: #2c5282; font-family: Sarabun, sans-serif; font-size: 15px; margin: 24px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;color: #1a365d;&quot;&gt;🔑 Key Insight จากข้อมูล:&lt;/strong&gt; PHP developer ที่เก่งในปี 2026 ไม่ใช่คนที่เลือกระหว่าง PHP กับภาษาอื่น แต่คือคนที่รู้ว่าเมื่อไหร่ควรใช้ PHP และเมื่อไหร่ควรหยิบเครื่องมืออื่น — เหมือนที่ JetBrains Developer Advocate พูดว่า &lt;em&gt;&quot;PHP has areas where it shines, but there are also problems better solved with Go or Rust&quot;&lt;/em&gt;&lt;/div&gt;&lt;hr class=&quot;pmc-divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 17px; margin: 36px 0px;&quot; /&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(235, 244, 255); color: #1a202c; font-family: Sarabun, sans-serif; font-size: 1.35rem; margin: 40px 0px 12px; padding-bottom: 8px;&quot;&gt;บทสรุป&lt;/h2&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ในปี 2026 PHP ยัง &lt;strong&gt;ไม่ตาย&lt;/strong&gt; — ตรงกันข้าม มันกำลัง modernize ตัวเองด้วย PHP 8.x features ที่น่าใช้ และ community ที่กำลังดึงดูด นักพัฒนาหน้าใหม่มากขึ้นเรื่อยๆ&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;สำหรับมือใหม่ที่อยากทำ web app: &lt;strong&gt;Laravel&lt;/strong&gt; คือ investment ที่คืนทุนเร็ว เพราะ documentation ดี ชุมชนใหญ่ และ job market ยังแข็งแกร่ง ถ้าต้องการ lightweight กว่านั้นหรือทำงานกับ legacy system ที่ใช้ CI3 อยู่ &lt;strong&gt;CodeIgniter 4&lt;/strong&gt; ก็เป็นการอัปเกรดที่สมเหตุสมผลมาก&lt;/p&gt;&lt;p style=&quot;color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;สิ่งสำคัญกว่าการเลือกภาษาคือ &lt;strong&gt;การเข้าใจ fundamentals&lt;/strong&gt; — HTTP, database, security, architecture — ซึ่ง PHP เป็นแพลตฟอร์มที่ดีเยี่ยม สำหรับการเรียนรู้สิ่งเหล่านี้&lt;/p&gt;&lt;div class=&quot;pmc-cta&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(26, 26, 46), rgb(22, 33, 62)); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 16px; color: #1e1e2e; font-family: Sarabun, sans-serif; font-size: 17px; margin-top: 48px; padding: 40px 36px; text-align: center;&quot;&gt;&lt;h3 style=&quot;color: #e2e8f0; font-size: 1.3rem; margin: 0px 0px 10px;&quot;&gt;📚 อยากลองสร้าง API ด้วย CI4 หรือ Laravel?&lt;/h3&gt;&lt;p style=&quot;color: #a0aec0; font-size: 15px; margin: 0px 0px 22px;&quot;&gt;ติดตามบทความในซีรีส์ &quot;PHP Modern Dev&quot; ที่จะพาคุณสร้าง REST API จนถึง Deploy จริงๆ&lt;/p&gt;&lt;a href=&quot;https://www.facebook.com/phpcodemania&quot; rel=&quot;noopener&quot; style=&quot;background: rgb(49, 130, 206); border-radius: 8px; color: white; display: inline-block; font-size: 15px; font-weight: 600; padding: 12px 28px; text-decoration: none; transition: background 0.2s;&quot; target=&quot;_blank&quot;&gt;ติดตาม PHP Code Mania →&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;pmc-tags&quot; style=&quot;color: #1e1e2e; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 17px; gap: 8px; margin-top: 32px;&quot;&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;CodeIgniter4&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;Laravel&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;REST API&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;Web Development&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;PHP 8&lt;/span&gt;&lt;span class=&quot;pmc-tag&quot; style=&quot;background: rgb(235, 244, 255); border-radius: 6px; color: #3182ce; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; padding: 4px 12px;&quot;&gt;2026&lt;/span&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/8123584424294512526/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-api-2026.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8123584424294512526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8123584424294512526'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-api-2026.html' title='ยังควรใช้ PHP ทำ API และเว็บเพจในปี 2026 อยู่ไหม?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgl0wHUG_AD6Y7V9KM357_mWZMyeG9ytoTYaqIzpmqiptqEmkHKe8SIFy0NouYEayvUZwFy-5qwll13jtqBHCUD32GnlGSyWHj0RtFdQ0YkRL1U0mrjbI2vNh_fDBhJIMHFwRCyPdxiO4t-GRDCSfFnCqLrjun5hl7H_IWI1Ad1lZPtgCJ0buWVA2BcTWE=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-1642923139707774323</id><published>2026-06-17T07:06:47.145+07:00</published><updated>2026-06-17T07:06:47.145+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>สร้าง MCP Server ของคุณเองด้วย Laravel</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjhBAHlHzzEf_Av4aKqhPsRMNySPeGC1VQmcQO-PH-mvKf6ROZWNE78jJ_m6s-4cvOadAMTsPT77q6mLeOx5-Qj99OhogPB7OO-kXNbCX6TvbAA_evJfeIb49dXKGHDKlPnDb4yI7ZFsnKhEvflgPt5XSotINnANl3rwYCNAFl7kbMQdF6zNO3YLXzRyag&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;333&quot; data-original-width=&quot;1021&quot; height=&quot;209&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjhBAHlHzzEf_Av4aKqhPsRMNySPeGC1VQmcQO-PH-mvKf6ROZWNE78jJ_m6s-4cvOadAMTsPT77q6mLeOx5-Qj99OhogPB7OO-kXNbCX6TvbAA_evJfeIb49dXKGHDKlPnDb4yI7ZFsnKhEvflgPt5XSotINnANl3rwYCNAFl7kbMQdF6zNO3YLXzRyag&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;pcm-hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(232, 244, 253) 0%, rgb(219, 234, 254) 60%, rgb(237, 233, 254) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 5px solid rgb(59, 130, 246); border-radius: 16px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 32px 0px 40px; overflow: hidden; padding: 48px 40px 40px; position: relative;&quot;&gt;&lt;span class=&quot;pcm-topic-badge&quot; style=&quot;background: rgb(59, 130, 246); border-radius: 20px; color: white; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; letter-spacing: 0.06em; margin-bottom: 16px; padding: 4px 12px;&quot;&gt;TOPIC #7 · Laravel × MCP&lt;/span&gt;&lt;h1 style=&quot;color: #1e40af; font-size: 2rem; line-height: 1.3; margin: 0px 0px 12px;&quot;&gt;สร้าง MCP Server ของคุณเองด้วย Laravel&lt;/h1&gt;&lt;p style=&quot;color: #374151; font-size: 16px; margin: 0px 0px 18px; max-width: 560px;&quot;&gt;เปิดประตูสู่ยุค AI-first Development — ให้ Laravel เป็น backend ที่ AI Agent พูดคุยได้โดยตรง&lt;/p&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ในช่วงปี 2025–2026 คำว่า &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; กลายเป็นหัวข้อร้อนแรงในวงการ AI Development เพราะมันเป็นมาตรฐานกลางที่ทำให้ AI Agent เช่น Claude, Cursor หรือ VS Code Copilot สามารถ &quot;เรียกใช้&quot; เครื่องมือของเราได้โดยตรง เหมือน REST API แต่ออกแบบมาเพื่อ LLM โดยเฉพาะ&lt;/p&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;แล้ว Laravel เกี่ยวอะไรด้วย? คำตอบคือ Laravel มีทุกอย่างที่ต้องการสำหรับสร้าง MCP Server ตั้งแต่ Routing ที่ clean, Middleware, Eloquent ORM ไปจนถึง JSON response ที่สวยงาม — บทความนี้จะพาทุกคนสร้าง MCP Server ตั้งแต่ศูนย์ แบบที่เข้าใจได้แม้ยังเป็นมือใหม่&lt;/p&gt;&lt;div class=&quot;pcm-info&quot; style=&quot;background: rgb(239, 246, 255); border-left: 4px solid rgb(59, 130, 246); border-radius: 0px 8px 8px 0px; color: #1e3a5f; font-family: Sarabun, sans-serif; font-size: 15.5px; margin: 20px 0px 28px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;color: #1d4ed8;&quot;&gt;💡 MCP คืออะไรในสองประโยค?&lt;/strong&gt;&lt;br /&gt;MCP (Model Context Protocol) คือโปรโตคอลเปิดที่กำหนดวิธีที่ AI Model จะ &quot;เรียกฟังก์ชัน&quot; บน server ของเรา — แทนที่จะต้องตั้ง REST API เอง MCP มี spec กลางที่ AI รู้จักอยู่แล้ว เราแค่ implement ตาม spec นั้น&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🚀 ทำความรู้จัก MCP ก่อนลงมือ&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;MCP ทำงานด้วยโมเดลง่าย ๆ — AI Agent จะส่ง JSON-RPC request มาถามว่า &quot;มี tool อะไรบ้าง?&quot; แล้วเราตอบกลับด้วยรายการ tools พร้อม schema ของ parameter ต่าง ๆ จากนั้นเมื่อ AI ต้องการใช้ tool ก็จะส่ง request อีกครั้งพร้อม arguments เราก็ประมวลผลแล้วตอบกลับด้วยผลลัพธ์&lt;/p&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;โครงสร้างหลักของ MCP Server มี 3 endpoint ที่ต้องรู้จัก:&lt;/p&gt;&lt;div class=&quot;pcm-table-wrap&quot; style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px 32px; overflow-x: auto;&quot;&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 6px; font-size: 15px; overflow: hidden; width: 820px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(29, 78, 216); color: white;&quot;&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;Endpoint / Method&lt;/th&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;หน้าที่&lt;/th&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;ตัวอย่าง Response&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-badge pcm-badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; color: #1d4ed8; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 10px;&quot;&gt;initialize&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;AI ทักทาย ขอข้อมูล server&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ชื่อ server, version, capabilities&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(240, 244, 255);&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-badge pcm-badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 10px;&quot;&gt;tools/list&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ส่งรายการ tool ทั้งหมด&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;Array of tool schemas (JSON Schema)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-badge pcm-badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 12px; color: #065f46; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 10px;&quot;&gt;tools/call&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;รัน tool ที่ AI เลือก&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ผลลัพธ์จาก tool นั้น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(240, 244, 255);&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-badge pcm-badge-gray&quot; style=&quot;background: rgb(243, 244, 246); border-radius: 12px; color: #374151; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 10px;&quot;&gt;resources/list&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ประกาศ data source&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;URI, description ของ resource&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;span class=&quot;pcm-badge pcm-badge-gray&quot; style=&quot;background: rgb(243, 244, 246); border-radius: 12px; color: #374151; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; padding: 2px 10px;&quot;&gt;prompts/list&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;เสนอ prompt template&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;Template สำเร็จรูปสำหรับ AI&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;⚙️ ติดตั้ง Laravel และสร้างโปรเจกต์ใหม่&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;เริ่มต้นด้วยการสร้างโปรเจกต์ Laravel ใหม่ผ่าน Composer หรือ Laravel Installer ได้เลย:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;# วิธีที่ 1: ใช้ Laravel Installer&lt;/span&gt; laravel new my-mcp-server &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;# วิธีที่ 2: ใช้ Composer โดยตรง&lt;/span&gt; composer create-project laravel/laravel my-mcp-server &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;# เข้าไปในโฟลเดอร์แล้วรัน server&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;cd&lt;/span&gt; my-mcp-server php artisan serve&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;เมื่อ server ขึ้นแล้ว เราจะสร้างโครงสร้างไฟล์สำหรับ MCP Server ของเรา โดยมีไฟล์หลัก 3 ไฟล์ที่ต้องสร้าง:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;php artisan make:controller McpController php artisan make:service McpToolService &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;# สร้างเอง หรือวาง class ใน app/Services/&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🛣️ กำหนด Routes สำหรับ MCP&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;MCP ใช้ JSON-RPC 2.0 ผ่าน HTTP POST ที่ endpoint เดียว ซึ่ง Laravel จัดการได้ง่ายมาก เปิดไฟล์ &lt;code&gt;routes/api.php&lt;/code&gt; แล้วเพิ่ม:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;routes/api.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; App\Http\Controllers\McpController; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; Illuminate\Support\Facades\Route; &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// MCP Server endpoint — รับ JSON-RPC ทุก method ที่นี่&lt;/span&gt; Route::&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;/mcp&#39;&lt;/span&gt;, [McpController::&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;handle&#39;&lt;/span&gt;]); &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// SSE endpoint สำหรับ streaming (optional)&lt;/span&gt; Route::&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;/mcp/sse&#39;&lt;/span&gt;, [McpController::&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;sse&#39;&lt;/span&gt;]);&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🧩 สร้าง McpController — หัวใจของ Server&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;Controller นี้คือตัวกลางที่รับ JSON-RPC request จาก AI แล้ว dispatch ไปยัง handler ที่ถูกต้อง:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;app/Http/Controllers/McpController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;namespace&lt;/span&gt; App\Http\Controllers; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; App\Services\McpToolService; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; Illuminate\Http\Request; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; Illuminate\Http\JsonResponse; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;McpController&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;extends&lt;/span&gt; Controller { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;__construct&lt;/span&gt;( &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private&lt;/span&gt; McpToolService &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$toolService&lt;/span&gt; ) {} &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;handle&lt;/span&gt;(Request &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;): JsonResponse { &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$method&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;input&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;method&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$params&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;input&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;params&#39;&lt;/span&gt;, []); &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$id&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;input&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;id&#39;&lt;/span&gt;); &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$result&lt;/span&gt; = &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;match&lt;/span&gt; (&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$method&lt;/span&gt;) { &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;initialize&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;initialize&lt;/span&gt;(), &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;tools/list&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;listTools&lt;/span&gt;(), &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;tools/call&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;callTool&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$params&lt;/span&gt;), &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;default&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;error&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;Method not found&#39;&lt;/span&gt;], }; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;response&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;json&lt;/span&gt;([ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;jsonrpc&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;2.0&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;id&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$id&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;result&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$result&lt;/span&gt;, ]); } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;initialize&lt;/span&gt;(): array { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;protocolVersion&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;2024-11-05&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;serverInfo&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;my-laravel-mcp&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;version&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;1.0.0&#39;&lt;/span&gt;, ], &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;capabilities&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;tools&#39;&lt;/span&gt; =&amp;gt; (object) []], ]; } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;listTools&lt;/span&gt;(): array { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;tools&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;toolService-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;getToolSchemas&lt;/span&gt;()]; } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;callTool&lt;/span&gt;(array &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$params&lt;/span&gt;): array { &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$name&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$params&lt;/span&gt;[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt;] ?? &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;&#39;&lt;/span&gt;; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$params&lt;/span&gt;[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;arguments&#39;&lt;/span&gt;] ?? []; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$output&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;toolService-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;execute&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$name&lt;/span&gt;, &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;); &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;content&#39;&lt;/span&gt; =&amp;gt; [[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;text&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;text&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$output&lt;/span&gt;]], ]; } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🔧 สร้าง Tool จริง — ตัวอย่าง: ค้นหาสินค้าจาก Database&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ถึงเวลาสร้าง Tool ที่ AI จะเรียกใช้ได้จริง ตัวอย่างนี้เราสร้าง tool ชื่อ &lt;code&gt;search_products&lt;/code&gt; ที่ให้ AI ค้นหาสินค้าจากฐานข้อมูล:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;app/Services/McpToolService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;namespace&lt;/span&gt; App\Services; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; App\Models\Product; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;McpToolService&lt;/span&gt; { &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;/** * ประกาศ schema ของ tools ทั้งหมดที่ server นี้มี * AI จะนำไปเข้าใจว่าแต่ละ tool รับ argument อะไร */&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;getToolSchemas&lt;/span&gt;(): array { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; [ [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;search_products&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;description&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;ค้นหาสินค้าจากชื่อหรือหมวดหมู่&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;inputSchema&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;object&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;properties&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;keyword&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;string&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;description&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;คำค้นหา&#39;&lt;/span&gt;, ], &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;limit&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;integer&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;description&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;จำนวนผลลัพธ์สูงสุด&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;default&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-num&quot; style=&quot;color: #d19a66;&quot;&gt;10&lt;/span&gt;, ], ], &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;required&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;keyword&#39;&lt;/span&gt;], ], ], [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;get_order_status&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;description&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;ตรวจสถานะ order จาก order ID&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;inputSchema&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;object&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;properties&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;order_id&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;integer&#39;&lt;/span&gt;, ], ], &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;required&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;order_id&#39;&lt;/span&gt;], ], ], ]; } &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;/** * Execute tool ตาม name ที่ AI ส่งมา */&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;execute&lt;/span&gt;(string &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$name&lt;/span&gt;, array &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;): string { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return match&lt;/span&gt; (&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$name&lt;/span&gt;) { &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;search_products&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;searchProducts&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;), &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;get_order_status&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;getOrderStatus&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;), &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;default&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;ไม่พบ tool ที่ระบุ&#39;&lt;/span&gt;, }; } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;searchProducts&lt;/span&gt;(array &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;): string { &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$keyword&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;keyword&#39;&lt;/span&gt;]; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$limit&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;limit&#39;&lt;/span&gt;] ?? &lt;span class=&quot;pcm-num&quot; style=&quot;color: #d19a66;&quot;&gt;10&lt;/span&gt;; &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// ใช้ Eloquent ค้นหาสินค้า&lt;/span&gt; &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$products&lt;/span&gt; = Product::&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;like&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;%{$keyword}%&quot;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;orWhere&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;category&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;like&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;%{$keyword}%&quot;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;limit&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$limit&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;get&lt;/span&gt;([&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;id&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;name&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;price&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;category&#39;&lt;/span&gt;]); &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$products&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;isEmpty&lt;/span&gt;()) { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;ไม่พบสินค้าที่ตรงกับ: {$keyword}&quot;&lt;/span&gt;; } &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// ส่งกลับเป็น JSON string ให้ AI อ่านได้&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;json_encode&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$products&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;toArray&lt;/span&gt;(), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;private function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;getOrderStatus&lt;/span&gt;(array &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;): string { &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$orderId&lt;/span&gt; = (int) (&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$args&lt;/span&gt;[&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;order_id&#39;&lt;/span&gt;] ?? &lt;span class=&quot;pcm-num&quot; style=&quot;color: #d19a66;&quot;&gt;0&lt;/span&gt;); &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// ... query จาก orders table ...&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;Order #{$orderId}: กำลังจัดส่ง&quot;&lt;/span&gt;; } }&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;📋 เปรียบเทียบ: MCP Server vs REST API&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;หลายคนอาจสงสัยว่า MCP Server กับ REST API ต่างกันยังไง ตารางนี้สรุปให้ชัด:&lt;/p&gt;&lt;div class=&quot;pcm-table-wrap&quot; style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px 32px; overflow-x: auto;&quot;&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 6px; font-size: 15px; overflow: hidden; width: 820px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(29, 78, 216); color: white;&quot;&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;ประเด็น&lt;/th&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;REST API&lt;/th&gt;&lt;th style=&quot;padding: 13px 16px; text-align: left;&quot;&gt;MCP Server&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;เป้าหมายหลัก&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;Frontend / Mobile / Third-party&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;AI Agent โดยเฉพาะ&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(240, 244, 255);&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;Protocol&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;HTTP + JSON (custom schema)&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;JSON-RPC 2.0 ตาม MCP Spec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;AI รู้จัก&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ต้อง describe ใน system prompt&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;AI อ่าน tool schema ได้เอง&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(240, 244, 255);&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ต้องเขียน Swagger / OpenAPI&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;Schema คือ doc ในตัว&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;ความซับซ้อน&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;ยืดหยุ่นกว่า มาก endpoint&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;Simple — endpoint เดียว&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(240, 244, 255);&quot;&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;&lt;strong&gt;ใช้กับ Laravel&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;✅ ทำได้สะดวก&lt;/td&gt;&lt;td style=&quot;border-top: 1px solid rgb(229, 231, 235); padding: 11px 16px;&quot;&gt;✅ ทำได้เช่นกัน (บทความนี้!)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🔒 เพิ่ม Middleware รักษาความปลอดภัย&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;MCP Server ที่ Production-ready ต้องมี authentication ด้วย วิธีง่ายที่สุดคือใช้ Bearer Token ผ่าน Laravel Middleware:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;app/Http/Middleware/McpAuthMiddleware.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;namespace&lt;/span&gt; App\Http\Middleware; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; Closure; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;use&lt;/span&gt; Illuminate\Http\Request; &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;McpAuthMiddleware&lt;/span&gt; { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;handle&lt;/span&gt;(Request &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;, Closure &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$next&lt;/span&gt;) { &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$token&lt;/span&gt; = &lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;bearerToken&lt;/span&gt;(); &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$token&lt;/span&gt; !== &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;config&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;mcp.secret_token&#39;&lt;/span&gt;)) { &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;response&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;json&lt;/span&gt;([ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;jsonrpc&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;2.0&#39;&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;error&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;code&#39;&lt;/span&gt; =&amp;gt; -&lt;span class=&quot;pcm-num&quot; style=&quot;color: #d19a66;&quot;&gt;32001&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;message&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;Unauthorized&#39;&lt;/span&gt;, ], ], &lt;span class=&quot;pcm-num&quot; style=&quot;color: #d19a66;&quot;&gt;401&lt;/span&gt;); } &lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;$next&lt;/span&gt;(&lt;span class=&quot;pcm-var&quot; style=&quot;color: #e06c75;&quot;&gt;$request&lt;/span&gt;); } } &lt;span class=&quot;pcm-cm&quot; style=&quot;color: #5c6370; font-style: italic;&quot;&gt;// ใน routes/api.php — ครอบ middleware&lt;/span&gt; Route::&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;middleware&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;mcp.auth&#39;&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;pcm-fn&quot; style=&quot;color: #61afef;&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;/mcp&#39;&lt;/span&gt;, [McpController::&lt;span class=&quot;pcm-kw&quot; style=&quot;color: #c678dd;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;handle&#39;&lt;/span&gt;]);&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(219, 234, 254); color: #1e40af; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 48px 0px 16px; padding-bottom: 8px;&quot;&gt;🧪 ทดสอบ MCP Server ด้วย curl&lt;/h2&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ก่อนต่อกับ AI จริง ทดสอบด้วย curl ได้เลย — ลอง call &lt;code&gt;tools/list&lt;/code&gt; ดูก่อน:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;terminal — ทดสอบ tools/list&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;curl -X POST http://localhost:8000/api/mcp \ -H &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; \ -H &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;Authorization: Bearer your-secret-token&quot;&lt;/span&gt; \ -d &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;{ &quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;id&quot;: 1, &quot;method&quot;: &quot;tools/list&quot;, &quot;params&quot;: {} }&#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 18px;&quot;&gt;ถ้า response ส่ง array ของ tools กลับมา แสดงว่า MCP Server ทำงานถูกต้องแล้ว จากนั้นลอง call tool จริง:&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 33, 40); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 20px; color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin: 20px 0px 28px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(45, 49, 57); display: flex; gap: 10px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;pcm-dots&quot; style=&quot;display: flex; gap: 6px;&quot;&gt;&lt;div class=&quot;pcm-dot pcm-dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;pcm-dot pcm-dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; height: 12px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;pcm-code-label&quot; style=&quot;color: #8b929e; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; margin-left: 4px;&quot;&gt;terminal — ทดสอบ tools/call&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #abb2bf; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;curl -X POST http://localhost:8000/api/mcp \ -H &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; \ -H &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&quot;Authorization: Bearer your-secret-token&quot;&lt;/span&gt; \ -d &lt;span class=&quot;pcm-str&quot; style=&quot;color: #98c379;&quot;&gt;&#39;{ &quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;id&quot;: 2, &quot;method&quot;: &quot;tools/call&quot;, &quot;params&quot;: { &quot;name&quot;: &quot;search_products&quot;, &quot;arguments&quot;: { &quot;keyword&quot;: &quot;กาแฟ&quot;, &quot;limit&quot;: 5 } } }&#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-info&quot; style=&quot;background: rgb(239, 246, 255); border-left: 4px solid rgb(59, 130, 246); border-radius: 0px 8px 8px 0px; color: #1e3a5f; font-family: Sarabun, sans-serif; font-size: 15.5px; margin: 20px 0px 28px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;color: #1d4ed8;&quot;&gt;🔗 ต่อกับ Claude Desktop&lt;/strong&gt;&lt;br /&gt;เมื่อ server พร้อมแล้ว เพิ่มใน &lt;code&gt;claude_desktop_config.json&lt;/code&gt; ได้เลย:&lt;br /&gt;&lt;code&gt;&quot;url&quot;: &quot;http://localhost:8000/api/mcp&quot;&lt;/code&gt; พร้อม header Authorization — Claude จะเห็น tools ของเราทันที!&lt;/div&gt;&lt;div class=&quot;pcm-conclusion&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 12px; border: 1px solid rgb(229, 231, 235); color: #1e2128; font-family: Sarabun, sans-serif; font-size: 17px; margin-top: 40px; padding: 28px 32px;&quot;&gt;&lt;h2 style=&quot;border-bottom: 2px solid rgb(229, 231, 235); color: #1e40af; font-size: 1.45rem; margin: 0px 0px 16px; padding-bottom: 8px;&quot;&gt;🎯 สรุป&lt;/h2&gt;&lt;p style=&quot;margin: 0px 0px 18px;&quot;&gt;การสร้าง MCP Server ด้วย Laravel ไม่ได้ซับซ้อนอย่างที่คิด เพราะ Laravel มี building block ครบครัน — Routing, Controller, Service class, Middleware และ Eloquent — ทำให้เราโฟกัสที่ logic ของ tool ได้เลย โดยไม่ต้องเสียเวลาสร้าง infrastructure ใหม่&lt;/p&gt;&lt;p style=&quot;margin: 0px 0px 18px;&quot;&gt;สิ่งที่เราได้เรียนรู้ในบทความนี้:&lt;/p&gt;&lt;p style=&quot;margin: 0px 0px 18px;&quot;&gt;✅ MCP คืออะไรและทำงานอย่างไรในแบบ JSON-RPC 2.0&lt;br /&gt;✅ โครงสร้าง Laravel สำหรับ MCP Server (Controller + Service)&lt;br /&gt;✅ การประกาศ Tool Schema ให้ AI เข้าใจ&lt;br /&gt;✅ การรักษาความปลอดภัยด้วย Bearer Token Middleware&lt;br /&gt;✅ วิธีทดสอบก่อน deploy จริง&lt;/p&gt;&lt;p style=&quot;margin: 0px 0px 18px;&quot;&gt;ก้าวต่อไปคือเพิ่ม tools ที่จำเป็นสำหรับธุรกิจของคุณ เช่น ค้นหาข้อมูล, อัปเดตสถานะ, หรือดึงรายงาน — แล้ว AI Agent จะกลายเป็น &quot;พนักงาน&quot; ที่ใช้งาน Laravel app ของคุณได้จริง&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;pcm-cta&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(29, 78, 216) 0%, rgb(79, 70, 229) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 14px; color: white; font-family: Sarabun, sans-serif; font-size: 17px; margin-top: 52px; padding: 40px 36px; text-align: center;&quot;&gt;&lt;h3 style=&quot;font-size: 1.3rem; margin: 0px 0px 12px;&quot;&gt;🚀 พร้อมต่อยอดเพิ่มเติมไหม?&lt;/h3&gt;&lt;p style=&quot;color: #bfdbfe; font-size: 15px; margin: 0px 0px 24px;&quot;&gt;ติดตาม PHP Code Mania เพื่อรับบทความ Laravel, CodeIgniter และ AI Development ในภาษาไทย — อัปเดตสม่ำเสมอสำหรับนักพัฒนา PHP ทุกระดับ&lt;/p&gt;&lt;a class=&quot;pcm-cta-btn&quot; href=&quot;https://www.facebook.com/phpcodemania&quot; rel=&quot;noopener&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 8px; color: #1d4ed8; display: inline-block; font-size: 15px; font-weight: 700; padding: 12px 28px; text-decoration: none;&quot; target=&quot;_blank&quot;&gt;📖 ติดตาม PHP Code Mania&lt;/a&gt;&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/1642923139707774323/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/blog-post_17.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/1642923139707774323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/1642923139707774323'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/blog-post_17.html' title='สร้าง MCP Server ของคุณเองด้วย Laravel'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjhBAHlHzzEf_Av4aKqhPsRMNySPeGC1VQmcQO-PH-mvKf6ROZWNE78jJ_m6s-4cvOadAMTsPT77q6mLeOx5-Qj99OhogPB7OO-kXNbCX6TvbAA_evJfeIb49dXKGHDKlPnDb4yI7ZFsnKhEvflgPt5XSotINnANl3rwYCNAFl7kbMQdF6zNO3YLXzRyag=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-7553604550384888420</id><published>2026-06-17T00:06:31.977+07:00</published><updated>2026-06-17T00:06:31.977+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>คู่มือเปลี่ยนเว็บเป็น Real-Time UX ไม่ต้องง้อ WebSockets ด้วย Livewire Polling, Events และ Lazy Loading</title><content type='html'>&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgqxuw2LvAHCqYfOmjNwIJLog6pfcFhijw0NP1smZh2YTbxxvsoINzJZyC3OhZ5rWvvz3qREayypCIE3jSgEY9OXCTBmT_tjSS-yrUqhwW2roPEiPe-5wJVvE0jBK7IB9fZvDrpkp0DowRYqMeXDOZyUfJA59odZKOAxD9DX0NdJVJCVcxEOgj9tK7l8YM&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1536&quot; height=&quot;427&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgqxuw2LvAHCqYfOmjNwIJLog6pfcFhijw0NP1smZh2YTbxxvsoINzJZyC3OhZ5rWvvz3qREayypCIE3jSgEY9OXCTBmT_tjSS-yrUqhwW2roPEiPe-5wJVvE0jBK7IB9fZvDrpkp0DowRYqMeXDOZyUfJA59odZKOAxD9DX0NdJVJCVcxEOgj9tK7l8YM&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;background-color: #fdfbf7; color: #334155; font-family: &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif; line-height: 1.8; margin: 0px auto; max-width: 800px; padding: 20px;&quot;&gt; &lt;p&gt;สวัสดีครับเพื่อนๆ นักพัฒนาเว็บทุกคน! ยินดีต้อนรับสู่ยุคที่ผู้ใช้งานคาดหวังความลื่นไหลระดับสิบ แอปพลิเคชันยุคนี้ถ้าต้องคอยกด F5 เพื่อรีเฟรชหน้าจอเพื่อดูข้อมูลใหม่ๆ คงโดนผู้ใช้บ่นแน่นอน ไม่ว่าจะเป็นระบบแสดงผลยอดขาย Real-time, ระบบแจ้งเตือน (Notifications), หรือแดชบอร์ดสรุปผลวิเคราะห์ข้อมูล (Analytics Dashboard)&lt;/p&gt; &lt;p&gt;เมื่อพูดถึง &quot;Real-Time Web App&quot; ภาพในหัวของใครหลายคนคงนึกถึงระบบที่ขับเคลื่อนด้วย WebSockets หรือเครื่องมือยอดฮิตอย่าง Laravel Echo ร่วมกับ Pusher / Soketi แต่สำหรับเหล่านักพัฒนามือใหม่ หรือทีมที่กำลังเริ่มทำโปรเจกต์ด้วย &lt;strong&gt;Laravel&lt;/strong&gt; และ &lt;strong&gt;CodeIgniter 4 (CI4)&lt;/strong&gt; การตั้งค่าเซิร์ฟเวอร์สำหรับ WebSocket, การจัดการสิทธิ์, และการควบคุม Memory Leak อาจเป็นเรื่องที่ยุ่งยาก ซับซ้อน และเกินความจำเป็นสำหรับแอปพลิเคชันที่เพิ่งเริ่มต้น&lt;/p&gt; &lt;p&gt;วันนี้ผมจะมาแนะนำ &quot;อาวุธลับ&quot; ที่จะช่วยให้แอปพลิเคชันของคุณเปลี่ยนเป็นระบบ Real-time ได้ในพริบตาเดียวโดย&lt;strong&gt;ไม่ต้องใช้ WebSockets แม้แต่บรรทัดเดียว!&lt;/strong&gt; ผ่านฟีเจอร์เด่นของ &lt;strong&gt;Laravel Livewire v4&lt;/strong&gt; ได้แก่ &lt;strong&gt;Polling, Events และ Lazy Loading&lt;/strong&gt; ที่ใช้งานง่ายจนคุณต้องร้องว้าว!&lt;/p&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;ทำความเข้าใจก่อนเริ่ม: Polling vs WebSockets&lt;/h2&gt; &lt;p&gt;ก่อนที่เราจะดิ่งลึกไปที่โค้ด เรามาเข้าใจความแตกต่างระหว่างสองแนวคิดนี้ก่อน เพื่อให้คุณเลือกใช้งานได้อย่างเหมาะสมกับสเกลของระบบ&lt;/p&gt; &lt;ul style=&quot;margin-bottom: 25px; padding-left: 20px;&quot;&gt; &lt;li style=&quot;margin-bottom: 10px;&quot;&gt;&lt;strong&gt;WebSockets:&lt;/strong&gt; เป็นการเปิดท่อการเชื่อมต่อแบบถาวร (Persistent Connection) ระหว่างเบราว์เซอร์กับเซิร์ฟเวอร์ ข้อดีคือเซิร์ฟเวอร์สามารถดันข้อมูล (Push) หาคลายเอนต์ได้ทันทีเมื่อมีข้อมูลใหม่เกิดขึ้น แต่ข้อเสียคือต้องการแรมเซิร์ฟเวอร์สูง และสถาปัตยกรรมค่อนข้างซับซ้อน&lt;/li&gt; &lt;li style=&quot;margin-bottom: 10px;&quot;&gt;&lt;strong&gt;HTTP Polling:&lt;/strong&gt; คือเทคนิคการสั่งให้เบราว์เซอร์ส่งคำขอ (Request) ไปถามเซิร์ฟเวอร์เป็นระยะๆ (เช่น ทุกๆ 5 วินาที) ว่า &quot;มีข้อมูลใหม่ไหม?&quot; ถ้ามีก็นำมาแสดงผล แม้จะดูเป็นวิธีดั้งเดิม แต่ด้วยเทคโนโลยีของ Livewire v4 ทำให้การทำ Polling มีประสิทธิภาพสูงมาก เขียนง่าย และลดภาระของเซิร์ฟเวอร์ได้อย่างชาญฉลาด&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;ตารางเปรียบเทียบต่อไปนี้จะช่วยให้คุณเห็นภาพชัดเจนขึ้นว่าเมื่อไหร่ควรใช้เครื่องมือตัวไหนสำหรับโปรเจกต์ของคุณ:&lt;/p&gt; &lt;div style=&quot;border-radius: 8px; border: 1px solid rgb(226, 232, 240); margin: 25px 0px; overflow-x: auto;&quot;&gt; &lt;table style=&quot;border-collapse: collapse; font-size: 14px; text-align: left; width: 100%;&quot;&gt; &lt;thead&gt; &lt;tr style=&quot;background-color: #0f172a; color: white;&quot;&gt; &lt;th style=&quot;font-weight: 600; padding: 12px 15px;&quot;&gt;คุณสมบัติ&lt;/th&gt; &lt;th style=&quot;font-weight: 600; padding: 12px 15px;&quot;&gt;Livewire Polling (HTTP)&lt;/th&gt; &lt;th style=&quot;font-weight: 600; padding: 12px 15px;&quot;&gt;WebSockets (Laravel Echo)&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr style=&quot;background-color: white; border-bottom: 1px solid rgb(226, 232, 240);&quot;&gt; &lt;td style=&quot;color: #1e293b; font-weight: bold; padding: 12px 15px;&quot;&gt;ความยากในการตั้งค่า&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;ง่ายมาก (เขียนแค่คำสั่งบน Blade แท็กเดียว)&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;ปานกลาง - สูง (ต้องตั้งค่า Server เพิ่มเติม)&lt;/td&gt; &lt;/tr&gt; &lt;tr style=&quot;background-color: #f8fafc; border-bottom: 1px solid rgb(226, 232, 240);&quot;&gt; &lt;td style=&quot;color: #1e293b; font-weight: bold; padding: 12px 15px;&quot;&gt;การกินทรัพยากร&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;ต่ำ (Livewire v4 มีระบบ Throttling อัจฉริยะ)&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;ปานกลาง (ต้องคงสถานะการเชื่อมต่อตลอดเวลา)&lt;/td&gt; &lt;/tr&gt; &lt;tr style=&quot;background-color: white; border-bottom: 1px solid rgb(226, 232, 240);&quot;&gt; &lt;td style=&quot;color: #1e293b; font-weight: bold; padding: 12px 15px;&quot;&gt;ความเร็วในการอัปเดต&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;ใกล้เคียง Real-time (ขึ้นอยู่กับ Interval)&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;Real-time ทันทีในระดับมิลลิวินาที&lt;/td&gt; &lt;/tr&gt; &lt;tr style=&quot;background-color: #f8fafc;&quot;&gt; &lt;td style=&quot;color: #1e293b; font-weight: bold; padding: 12px 15px;&quot;&gt;เหมาะสำหรับระบบ&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;Dashboard, สถิติยอดขาย, ดึงข้อมูลจาก APIs&lt;/td&gt; &lt;td style=&quot;color: #475569; padding: 12px 15px;&quot;&gt;แชทสด (Chat App), ระบบประมูล, หุ้นคริปโต&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;/div&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;ฟีเจอร์ที่ 1: ตื่นตาตื่นใจกับ wire:poll ของ Livewire&lt;/h2&gt; &lt;p&gt;ใน Livewire เวอร์ชันล่าสุด การทำ Polling ทำได้ง่ายมาก เพียงแค่เพิ่มแอตทริบิวต์ &lt;code&gt;wire:poll&lt;/code&gt; เข้าไปในโครงสร้าง HTML ของคุณ คอมโพเนนต์นั้นก็จะรีเฟรชตัวเองโดยอัตโนมัติ&lt;/p&gt; &lt;h3 style=&quot;color: #1e293b; font-size: 16px; font-weight: 600; margin-bottom: 10px; margin-top: 20px;&quot;&gt;ตัวอย่างโค้ด: ระบบนับยอดผู้ติดตาม (Subscriber Counter)&lt;/h3&gt; &lt;p&gt;สมมติว่าคุณกำลังทำหน้าแดชบอร์ดส่วนตัว และต้องการให้ตัวเลขผู้ติดตามอัปเดตตลอดเวลาโดยไม่ต้องกดรีเฟรชหน้าเว็บ&lt;/p&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;SubscriberCounter.php (Backend)&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;PHP&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;namespace&lt;/span&gt; App\Livewire; &lt;span style=&quot;color: #569cd6;&quot;&gt;use&lt;/span&gt; Livewire\Component; &lt;span style=&quot;color: #569cd6;&quot;&gt;use&lt;/span&gt; App\Models\User; &lt;span style=&quot;color: #569cd6;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;SubscriberCounter&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;extends&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;Component&lt;/span&gt; { &lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;render&lt;/span&gt;() { &lt;span style=&quot;color: #569cd6;&quot;&gt;return&lt;/span&gt; view(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;livewire.subscriber-counter&#39;&lt;/span&gt;, [ &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&#39;count&#39;&lt;/span&gt; =&amp;gt; User::where(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;is_subscribed&#39;&lt;/span&gt;, &lt;span style=&quot;color: #569cd6;&quot;&gt;true&lt;/span&gt;)-&amp;gt;count(), ]); } }&lt;/pre&gt; &lt;/div&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;subscriber-counter.blade.php (Frontend)&lt;/span&gt; &lt;span style=&quot;color: #e34c26;&quot;&gt;Blade&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;wire:poll&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;class&lt;/span&gt;=&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;ยอดผู้ติดตามปัจจุบัน&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;{{&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$count&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;}}&lt;/span&gt; คน&lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/pre&gt; &lt;/div&gt; &lt;p&gt;เพียงแค่คุณใส่คำว่า &lt;code&gt;wire:poll&lt;/code&gt; ลงไปในแท็กครอบด้านบนสุด ตัว Livewire จะแอบส่งสัญญาณ Request ไปอัปเดตข้อมูลให้คุณทุกๆ 2.5 วินาทีโดยอัตโนมัติ! สะดวกสุดๆ ไปเลยใช่ไหมครับ?&lt;/p&gt; &lt;div style=&quot;background-color: #fef3c7; border-left: 4px solid rgb(245, 158, 11); border-radius: 4px; margin: 20px 0px; padding: 15px;&quot;&gt; &lt;strong style=&quot;color: #92400e; display: block; margin-bottom: 5px;&quot;&gt;⚠️ ควบคุม Performance ด้วย Modifiers ของ Livewire v4:&lt;/strong&gt; &lt;p style=&quot;color: #78350f; font-size: 14px; margin: 0px;&quot;&gt; - &lt;strong&gt;wire:poll.15s&lt;/strong&gt;: ปรับเวลาเป็นทุกๆ 15 วินาที เพื่อไม่ให้เซิร์ฟเวอร์ทำงานหนักเกินไป&lt;br /&gt; - &lt;strong&gt;wire:poll.visible&lt;/strong&gt;: ระบบจะทำ Polling เฉพาะเมื่อผู้ใช้งานสกรอลล์หน้าจอมาเห็นคอมโพเนนต์นี้เท่านั้น!&lt;br /&gt; - &lt;strong&gt;Background Tab Throttling&lt;/strong&gt;: เมื่อผู้ใช้เปิดแท็บอื่นค้างไว้ Livewire จะลดการยิงคำขอลง 95% ทันทีโดยอัตโนมัติ &lt;/p&gt; &lt;/div&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;ฟีเจอร์ที่ 2: ผสานพลังไอเดียด้วย Livewire Events&lt;/h2&gt; &lt;p&gt;บางครั้งเราไม่จำเป็นต้องตั้งเวลา Polling ตลอดเวลา แต่เราต้องการให้ Component หนึ่ง สั่งให้อีก Component หนึ่งอัปเดตตัวตามเมื่อเกิดการกระทำบางอย่าง (Event-driven Architecture)&lt;/p&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;ProductComponent.php (ฝั่งผู้ส่ง)&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;PHP&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;addToCart&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$productId&lt;/span&gt;) { &lt;span style=&quot;color: #6a9955;&quot;&gt;// โค้ดเพิ่มสินค้าลงระบบตะกร้า&lt;/span&gt; &lt;span style=&quot;color: #6a9955;&quot;&gt;// ส่งสัญญาณ Event ออกไปทั่วทั้งหน้าเว็บ&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$this&lt;/span&gt;-&amp;gt;dispatch(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;cart-updated&#39;&lt;/span&gt;); }&lt;/pre&gt; &lt;/div&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;CartIcon.php (ฝั่งผู้รับ)&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;PHP&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;use&lt;/span&gt; Livewire\Attributes\On; &lt;span style=&quot;color: #569cd6;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;CartIcon&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;extends&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;Component&lt;/span&gt; { &lt;span style=&quot;color: #569cd6;&quot;&gt;#&lt;/span&gt;[On(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;cart-updated&#39;&lt;/span&gt;)] &lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;refreshCartCount&lt;/span&gt;() { &lt;span style=&quot;color: #6a9955;&quot;&gt;// เมธอดนี้จะทำงานและดึงข้อมูลยอดใหม่ทันทีที่ได้รับสัญญาณ&lt;/span&gt; } }&lt;/pre&gt; &lt;/div&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;ฟีเจอร์ที่ 3: โหลดหน้าเว็บเร็วปานสายฟ้าด้วย Lazy Loading&lt;/h2&gt; &lt;p&gt;เมื่อเรานำข้อมูลภายนอก (Third-party APIs) เช่น การดึงราคาน้ำมัน หรือวิเคราะห์ SQL ซับซ้อน หากเขียนแอปพลิเคชันแบบปกติ หน้าเว็บจะหมุนค้างและแสดงหน้ากระดาษสีขาวจนกว่าข้อมูลจะเสร็จ แต่ Livewire มอบฟีเจอร์ &lt;strong&gt;Lazy Loading&lt;/strong&gt; ที่จะโหลดหน้าเว็บโครงสร้างหลักขึ้นมาก่อน แล้วค่อยโหลด Component ตามมาทีหลัง&lt;/p&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;WeatherWidget.php (Lazy Component)&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;PHP&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;namespace&lt;/span&gt; App\Livewire; &lt;span style=&quot;color: #6a9955;&quot;&gt;// เปิดใช้งาน Lazy Loading ด้วย Attribute&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;#&lt;/span&gt;[\Livewire\Attributes\Lazy] &lt;span style=&quot;color: #569cd6;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;WeatherWidget&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;extends&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;Component&lt;/span&gt; { &lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;render&lt;/span&gt;() { &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$response&lt;/span&gt; = Http::get(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;https://api.weatherapi.com/v1/current.json&#39;&lt;/span&gt;); &lt;span style=&quot;color: #569cd6;&quot;&gt;return&lt;/span&gt; view(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;livewire.weather-widget&#39;&lt;/span&gt;); } &lt;span style=&quot;color: #6a9955;&quot;&gt;// แสดง Skeleton Screen ระหว่างรอข้อมูล&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;placeholder&lt;/span&gt;() { &lt;span style=&quot;color: #569cd6;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;&amp;lt;div class=&quot;loading&quot;&amp;gt;กำลังโหลดข้อมูลสภาพอากาศ...&amp;lt;/div&amp;gt;&#39;&lt;/span&gt;; } }&lt;/pre&gt; &lt;/div&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;แล้วถ้าหากคุณเป็นนักพัฒนา CodeIgniter 4 ล่ะ?&lt;/h2&gt; &lt;p&gt;ถึงแม้ว่า Livewire จะเป็นของ Laravel แต่สำหรับสาย &lt;strong&gt;CodeIgniter 4 (CI4)&lt;/strong&gt; คุณก็สามารถสร้าง UX แบบ Real-time ที่ดีเยี่ยมนี้ได้เช่นเดียวกัน โดยผสมผสานสถาปัตยกรรม &lt;strong&gt;AJAX Polling&lt;/strong&gt; ร่วมกับฟังก์ชันพื้นฐานของ CI4 ดังนี้ครับ:&lt;/p&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;app/Controllers/Dashboard.php&lt;/span&gt; &lt;span style=&quot;color: #4ec9b0;&quot;&gt;PHP&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;public function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;getLatestSales&lt;/span&gt;() { &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$model&lt;/span&gt; = &lt;span style=&quot;color: #569cd6;&quot;&gt;new&lt;/span&gt; OrderModel(); &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$totalSales&lt;/span&gt; = &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$model&lt;/span&gt;-&amp;gt;sum(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;amount&#39;&lt;/span&gt;); &lt;span style=&quot;color: #569cd6;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$this&lt;/span&gt;-&amp;gt;response-&amp;gt;setJSON([ &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;status&#39;&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;success&#39;&lt;/span&gt;, &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;total_sales&#39;&lt;/span&gt; =&amp;gt; number_format(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$totalSales&lt;/span&gt;, &lt;span style=&quot;color: #b5cea8;&quot;&gt;2&lt;/span&gt;) ]); }&lt;/pre&gt; &lt;/div&gt; &lt;div style=&quot;margin: 20px 0px;&quot;&gt; &lt;div style=&quot;background-color: #1e1e1e; border-bottom: 1px solid rgb(45, 45, 45); border-top-left-radius: 6px; border-top-right-radius: 6px; color: grey; display: flex; font-family: monospace; font-size: 12px; justify-content: space-between; padding: 6px 16px;&quot;&gt; &lt;span&gt;dashboard_view.php (Frontend AJAX)&lt;/span&gt; &lt;span style=&quot;color: #f1e05a;&quot;&gt;JavaScript&lt;/span&gt; &lt;/div&gt; &lt;pre style=&quot;background: rgb(30, 30, 30); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; color: #d4d4d4; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 13px; line-height: 1.5; margin: 0px; overflow-x: auto; padding: 16px;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;function&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;updateSales&lt;/span&gt;() { &lt;span style=&quot;color: #dcdcaa;&quot;&gt;fetch&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;&amp;lt;?= base_url(\&#39;dashboard/getLatestSales\&#39;) ?&amp;gt;&#39;&lt;/span&gt;) .&lt;span style=&quot;color: #dcdcaa;&quot;&gt;then&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;response&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;json&lt;/span&gt;()) .&lt;span style=&quot;color: #dcdcaa;&quot;&gt;then&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;data&lt;/span&gt; &lt;span style=&quot;color: #569cd6;&quot;&gt;=&amp;gt;&lt;/span&gt; { &lt;span style=&quot;color: #569cd6;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #9cdcfe;&quot;&gt;data&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;status&lt;/span&gt; === &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;success&#39;&lt;/span&gt;) { &lt;span style=&quot;color: #9cdcfe;&quot;&gt;document&lt;/span&gt;.&lt;span style=&quot;color: #dcdcaa;&quot;&gt;getElementById&lt;/span&gt;(&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;sales-amount&#39;&lt;/span&gt;).&lt;span style=&quot;color: #9cdcfe;&quot;&gt;innerText&lt;/span&gt; = &lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;฿&#39;&lt;/span&gt; + &lt;span style=&quot;color: #9cdcfe;&quot;&gt;data&lt;/span&gt;.&lt;span style=&quot;color: #9cdcfe;&quot;&gt;total_sales&lt;/span&gt;; } }); } &lt;span style=&quot;color: #6a9955;&quot;&gt;// สั่งให้ระบบส่งคำขอซ้ำทุกๆ 5 วินาที&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;setInterval&lt;/span&gt;(updateSales, &lt;span style=&quot;color: #b5cea8;&quot;&gt;5000&lt;/span&gt;);&lt;/pre&gt; &lt;/div&gt; &lt;hr style=&quot;background: rgb(226, 232, 240); border: 0px; height: 1px; margin: 40px 0px;&quot; /&gt; &lt;h2 style=&quot;border-left: 5px solid rgb(59, 130, 246); color: #0f172a; font-size: 22px; font-weight: 700; margin-bottom: 20px; padding-left: 12px;&quot;&gt;สรุป: เทคนิคไหนที่ใช่สำหรับคุณ?&lt;/h2&gt; &lt;p&gt;การทำให้เว็บแอปพลิเคชันตอบสนองแบบเรียลไทม์ไม่จำเป็นต้องลงเอยด้วยสถาปัตยกรรม WebSockets ที่ซับซ้อนเสมอไป การเลือกใช้ HTTP Polling ที่มีการจัดการอัจฉริยะอย่าง &lt;strong&gt;Livewire v4&lt;/strong&gt; หรือโครงสร้าง &lt;strong&gt;AJAX บน CI4&lt;/strong&gt; ก็สามารถส่งมอบประสบการณ์ผู้ใช้ที่ดีเยี่ยม ลื่นไหล และประหยัดทรัพยากรฝั่งเซิร์ฟเวอร์ได้อย่างน่าอัศจรรย์ใจครับ&lt;/p&gt; &lt;div style=&quot;background-color: #f0fdf4; border-radius: 8px; border: 1px solid rgb(187, 247, 208); margin-top: 40px; padding: 25px;&quot;&gt; &lt;h4 style=&quot;color: #166534; font-size: 18px; font-weight: 700; margin-top: 0px;&quot;&gt;🚀 มาร่วมสนุกและแชร์ไอเดียกัน!&lt;/h4&gt; &lt;p style=&quot;color: #14532d; font-size: 14px; margin: 10px 0px;&quot;&gt;ตอนนี้แอปพลิเคชันของคุณใช้ระบบอัปเดตข้อมูลแบบไหนกันอยู่ครับ? ประสบปัญหาเว็บหน่วงหรือเซิร์ฟเวอร์ล่มกันบ้างไหม? คอมเมนต์พูดคุยแลกเปลี่ยนประสบการณ์ หรือสอบถามวิธีการเขียนโค้ดเพิ่มเติมด้านล่างนี้ได้เลยนะครับ! และอย่าลืมกดแชร์บทความนี้ให้กับเพื่อนๆ นักพัฒนาสาย PHP ด้วยล่ะ!&lt;/p&gt; &lt;/div&gt; &lt;/div&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/7553604550384888420/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/real-time-ux-websockets-livewire.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/7553604550384888420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/7553604550384888420'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/real-time-ux-websockets-livewire.html' title='คู่มือเปลี่ยนเว็บเป็น Real-Time UX ไม่ต้องง้อ WebSockets ด้วย Livewire Polling, Events และ Lazy Loading'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgqxuw2LvAHCqYfOmjNwIJLog6pfcFhijw0NP1smZh2YTbxxvsoINzJZyC3OhZ5rWvvz3qREayypCIE3jSgEY9OXCTBmT_tjSS-yrUqhwW2roPEiPe-5wJVvE0jBK7IB9fZvDrpkp0DowRYqMeXDOZyUfJA59odZKOAxD9DX0NdJVJCVcxEOgj9tK7l8YM=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-7989722804480872040</id><published>2026-06-16T07:43:18.523+07:00</published><updated>2026-06-16T07:43:18.524+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Laravel"/><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>Scheduler List: Web Dashboard สำหรับจัดการ Laravel Scheduled Tasks</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgddmG7ZnjTaICbX5AePY-goOcM7NPr1El6OXUxEptQ3UyaGyNzNIWPoVIOhWdWlWy2QDpm5UvV_CqxS_xZJgBzOoRl6OajygUMCVphuc1vxuF6iZwlYJcUK1_ErZQOkbxSLz0VmXyr-X8XgmF6egguPmM8wRc03C_dz5893vGWblIGtpO2zYy7qbec2Xo&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgddmG7ZnjTaICbX5AePY-goOcM7NPr1El6OXUxEptQ3UyaGyNzNIWPoVIOhWdWlWy2QDpm5UvV_CqxS_xZJgBzOoRl6OajygUMCVphuc1vxuF6iZwlYJcUK1_ErZQOkbxSLz0VmXyr-X8XgmF6egguPmM8wRc03C_dz5893vGWblIGtpO2zYy7qbec2Xo=w640-h360&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(30, 34, 53) 0%, rgb(45, 53, 97) 60%, rgb(61, 77, 183) 100%) rgb(248, 249, 251); border-radius: 16px; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 32px 0px 40px; overflow: hidden; padding: 52px 40px; position: relative;&quot;&gt;&lt;div class=&quot;hero-badge&quot; style=&quot;background: rgba(91, 110, 245, 0.25); border-radius: 20px; border: 1px solid rgba(91, 110, 245, 0.5); box-sizing: border-box; color: #a5b4fc; display: inline-block; font-size: 13px; font-weight: 600; letter-spacing: 0.08em; margin: 0px 0px 18px; padding: 4px 14px; text-transform: uppercase;&quot;&gt;Laravel · Scheduled Tasks · Dashboard&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; color: white; font-size: clamp(1.6rem, 4vw, 2.2rem); line-height: 1.3; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Scheduler List: Web Dashboard&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;สำหรับจัดการ Laravel Scheduled Tasks&lt;/h1&gt;&lt;p style=&quot;box-sizing: border-box; color: #a8b4d0; font-size: 16px; line-height: 1.7; margin: 0px 0px 14px; max-width: 580px; padding: 0px;&quot;&gt;สร้าง Dashboard ดู Cron Jobs ทั้งหมดของโปรเจกต์ Laravel ผ่านหน้าเว็บ แบบไม่ต้อง SSH เข้า Server ทุกครั้ง&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;tags&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 17px; gap: 8px; margin: 0px 0px 32px; padding: 0px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 20px; box-sizing: border-box; color: #3d4db7; font-size: 13px; font-weight: 600; margin: 0px; padding: 4px 12px;&quot;&gt;Laravel&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 20px; box-sizing: border-box; color: #3d4db7; font-size: 13px; font-weight: 600; margin: 0px; padding: 4px 12px;&quot;&gt;Scheduled Tasks&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 20px; box-sizing: border-box; color: #3d4db7; font-size: 13px; font-weight: 600; margin: 0px; padding: 4px 12px;&quot;&gt;Cron Job&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 20px; box-sizing: border-box; color: #3d4db7; font-size: 13px; font-weight: 600; margin: 0px; padding: 4px 12px;&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 20px; box-sizing: border-box; color: #3d4db7; font-size: 13px; font-weight: 600; margin: 0px; padding: 4px 12px;&quot;&gt;Web Dashboard&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;①&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/span&gt;ปัญหาคลาสสิกของ Cron Jobs&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ใครที่เคยทำงาน Backend มาสักระยะ คงเคยเจอคำถามนี้จากทีมหรือลูกค้า: &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;Cron Job มันรันอยู่ไหม? ทำอะไรไปบ้าง?&quot;&lt;/strong&gt; — แล้วคุณก็ต้อง SSH เข้า Server ไปดู log หรือพิมพ์คำสั่ง &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;crontab -l&lt;/code&gt; ซึ่งไม่ใช่วิธีที่สะดวกเลย โดยเฉพาะถ้าทีมมีคนที่ไม่ถนัด Command Line&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;บทความนี้จะพาคุณสร้าง &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Scheduler List Dashboard&lt;/strong&gt; — หน้าเว็บที่แสดงรายการ Scheduled Tasks ทั้งหมดของ Laravel พร้อม Schedule Expression, สถานะ, และประวัติการรัน โดยใช้ฟีเจอร์ที่มีอยู่ใน Laravel อยู่แล้ว ไม่ต้องลง Package เพิ่ม&lt;/p&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-left: 4px solid rgb(91, 110, 245); border-radius: 0px 10px 10px 0px; box-sizing: border-box; color: #2d3561; font-size: 15px; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #5b6ef5; margin: 0px; padding: 0px;&quot;&gt;💡 เหมาะสำหรับ:&lt;/strong&gt; ผู้ที่เริ่มต้นกับ Laravel และต้องการเข้าใจ Task Scheduling รวมถึงทีมที่ต้องการ Visibility ของ Background Jobs โดยไม่ต้องเปิด Terminal&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;②&lt;/span&gt;Laravel Task Scheduling คืออะไร?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Laravel มี Built-in Task Scheduler ที่ให้คุณนิยาม Scheduled Jobs ทั้งหมดใน &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โค้ด PHP&lt;/strong&gt; แทนการเขียน Cron หลาย ๆ บรรทัดใน Server — ทำให้ Version Control ได้, อ่านง่าย, และ Deploy พร้อมกับโค้ดเลย&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;สิ่งที่ต้องมีใน Server มีเพียงบรรทัดเดียวใน Crontab:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;crontab&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# Server Cron - รันทุกนาที แค่บรรทัดเดียว&lt;/span&gt; * * * * * cd /var/www/html &amp;amp;&amp;amp; php artisan schedule:run &amp;gt;&amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;แล้ว Laravel จะจัดการ Tasks ที่ถึงเวลาแต่ละตัวให้เอง งานทั้งหมดนิยามใน &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;app/Console/Kernel.php&lt;/code&gt; (Laravel 10 ลงไป) หรือใช้ &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;Schedule&lt;/code&gt; Facade ใน &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;routes/console.php&lt;/code&gt; (Laravel 11+)&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Console/Kernel.php (Laravel 10)&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;protected function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;schedule&lt;/span&gt;(&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Schedule&lt;/span&gt; $schedule): &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; { &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// รายงานยอดขายทุกวันเที่ยงคืน&lt;/span&gt; $schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;report:daily-sales&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;dailyAt&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;00:00&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;withoutOverlapping&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// ลบ Log เก่ากว่า 30 วัน ทุกอาทิตย์&lt;/span&gt; $schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;logs:cleanup&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;weekly&lt;/span&gt;() -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;sundays&lt;/span&gt;() -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;02:00&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// ส่ง Email สรุปทุก 6 ชั่วโมง&lt;/span&gt; $schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;email:summary&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;everySixHours&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// Sync ข้อมูลกับ API ภายนอก ทุก 15 นาที&lt;/span&gt; $schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;() { &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;ExternalApiSync&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;run&lt;/span&gt;(); })-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;everyFifteenMinutes&lt;/span&gt;(); }&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;③&lt;/span&gt;Frequency Methods ที่ใช้บ่อย&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Laravel มี Helper Methods สำหรับกำหนดความถี่ในการรัน Task ให้ใช้ได้เลยโดยไม่ต้องจำ Cron Syntax:&lt;/p&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 20px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 15px; margin: 0px; min-width: 520px; padding: 0px; width: 780px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Method&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Cron Expression&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;ความหมาย&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;Use Case&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;everyMinute()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;* * * * *&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุกนาที&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-orange&quot; style=&quot;background: rgb(255, 247, 237); border-radius: 12px; box-sizing: border-box; color: #c2410c; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Health Check&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;everyFifteenMinutes()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;*/15 * * * *&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุก 15 นาที&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;API Sync&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;hourly()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;0 * * * *&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุกชั่วโมง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-purple&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 12px; box-sizing: border-box; color: #5b6ef5; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Cache Refresh&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;dailyAt(&#39;08:00&#39;)&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;0 8 * * *&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุกวัน เวลาที่กำหนด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 12px; box-sizing: border-box; color: #16a34a; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;รายงานประจำวัน&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;weekly()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;0 0 * * 0&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุกอาทิตย์&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgb(219, 234, 254); border-radius: 12px; box-sizing: border-box; color: #1d4ed8; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Cleanup&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;monthly()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;0 0 1 * *&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทุกเดือน&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-orange&quot; style=&quot;background: rgb(255, 247, 237); border-radius: 12px; box-sizing: border-box; color: #c2410c; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Invoice&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;-&amp;gt;cron(&#39;30 9 * * 1-5&#39;)&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Custom&lt;/td&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;วันทำการ 09:30 น.&lt;/td&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-purple&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-radius: 12px; box-sizing: border-box; color: #5b6ef5; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Custom Schedule&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;④&lt;/span&gt;สร้าง Scheduler List Dashboard&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;เราจะสร้าง Route + Controller + Blade View เพื่อดึง Scheduled Tasks ออกมาแสดงบนหน้าเว็บ Laravel มี &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;app(&#39;Illuminate\Console\Scheduling\Schedule&#39;)&lt;/code&gt; ที่ให้ดึงรายการ Events ออกมาได้เลย&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;Step 1: สร้าง Controller&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Http/Controllers/SchedulerController.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;namespace&lt;/span&gt; App\Http\Controllers; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Illuminate\Console\Scheduling\Schedule&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Illuminate\Http\Request&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Carbon\Carbon&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;SchedulerController&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Controller&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Schedule&lt;/span&gt; $schedule) { $events = &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;collect&lt;/span&gt;($schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;events&lt;/span&gt;()) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;($event) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;command&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;str_replace&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;\&#39;artisan\&#39; &#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;, $event-&amp;gt;command), &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;expression&#39;&lt;/span&gt; =&amp;gt; $event-&amp;gt;expression, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;description&#39;&lt;/span&gt;=&amp;gt; $event-&amp;gt;description ?? &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;-&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;timezone&#39;&lt;/span&gt; =&amp;gt; $event-&amp;gt;timezone ?? &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;config&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;app.timezone&#39;&lt;/span&gt;), &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;without_overlapping&#39;&lt;/span&gt; =&amp;gt; $event-&amp;gt;withoutOverlapping, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;run_in_background&#39;&lt;/span&gt; =&amp;gt; $event-&amp;gt;runInBackground, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;next_run&#39;&lt;/span&gt; =&amp;gt; $event-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;nextRunDate&lt;/span&gt;(&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Carbon&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;now&lt;/span&gt;(), &lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;), ]; }); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;scheduler.index&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;compact&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;events&#39;&lt;/span&gt;)); } }&lt;/div&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;Step 2: เพิ่ม Route&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;routes/web.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; App\Http\Controllers\&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;SchedulerController&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// ป้องกันด้วย Middleware auth ก่อน Deploy จริง&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;middleware&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;auth&#39;&lt;/span&gt;])-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;() { &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;/admin/scheduler&#39;&lt;/span&gt;, [&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;SchedulerController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;index&#39;&lt;/span&gt;]) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;scheduler.index&#39;&lt;/span&gt;); });&lt;/div&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;Step 3: สร้าง Blade View&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;resources/views/scheduler/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;@&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;layouts.app&#39;&lt;/span&gt;) @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;container mx-auto py-8 px-4&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;flex items-center justify-between mb-6&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h1&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;text-2xl font-bold text-gray-800&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; 📅 Scheduled Tasks &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;span&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;text-sm text-gray-500&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; ทั้งหมด {{ $events-&amp;gt;count() }} Tasks &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;overflow-x-auto rounded-xl shadow&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;table&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;w-full bg-white text-sm&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;thead&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;bg-indigo-50 text-indigo-900&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;th&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-3 text-left&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;Command&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;th&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-3 text-left&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;Expression&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;th&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-3 text-left&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;Next Run&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;th&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-3 text-left&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;Options&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;tbody&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;divide-y divide-gray-100&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;forelse&lt;/span&gt;($events &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; $event) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;tr&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;hover:bg-gray-50&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;td&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-4&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;code&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;bg-indigo-50 text-indigo-700 px-2 py-1 rounded text-xs&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; {{ $event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;command&#39;&lt;/span&gt;] }} &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/code&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt;($event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;description&#39;&lt;/span&gt;] !== &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;-&#39;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;text-gray-500 mt-1 text-xs&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;{{ $event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;description&#39;&lt;/span&gt;] }}&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;td&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-4 font-mono text-xs text-gray-600&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; {{ $event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;expression&#39;&lt;/span&gt;] }} &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;td&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-4 text-gray-700&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; {{ $event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;next_run&#39;&lt;/span&gt;] }} &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;td&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-4&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt;($event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;without_overlapping&#39;&lt;/span&gt;]) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;span&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;bg-green-100 text-green-700 text-xs px-2 py-0.5 rounded-full mr-1&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; no-overlap &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;endif&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt;($event[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;run_in_background&#39;&lt;/span&gt;]) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;span&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;bg-blue-100 text-blue-700 text-xs px-2 py-0.5 rounded-full&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; background &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;td&lt;/span&gt; colspan=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;4&quot;&lt;/span&gt; class=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&quot;px-5 py-8 text-center text-gray-400&quot;&lt;/span&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt; ยังไม่มี Scheduled Tasks &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;endforelse&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; @&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;endsection&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;⑤&lt;/span&gt;เพิ่ม Description และ Security&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ก่อน Deploy จริง ต้องทำ 2 อย่างนี้เสมอ:&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;เพิ่ม Description ให้แต่ละ Task&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;app/Console/Kernel.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;$schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;report:daily-sales&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;dailyAt&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;00:00&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;withoutOverlapping&lt;/span&gt;() -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;description&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;สร้างรายงานยอดขายประจำวัน ส่ง Email Admin&#39;&lt;/span&gt;) &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// ✅&lt;/span&gt; -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;appendOutputTo&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;storage_path&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;logs/daily-sales.log&#39;&lt;/span&gt;)); $schedule-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;logs:cleanup&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;weekly&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;sundays&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;02:00&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;description&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;ลบ Log ไฟล์เก่ากว่า 30 วัน&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// ✅&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;ป้องกันด้วย Middleware&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;routes/web.php&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// วิธีที่ 1: ใช้ Auth Middleware (แนะนำ)&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;middleware&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;auth&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;can:view-admin&#39;&lt;/span&gt;]) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;/admin/scheduler&#39;&lt;/span&gt;, [&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;SchedulerController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;index&#39;&lt;/span&gt;]); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;// วิธีที่ 2: จำกัด IP (สำหรับ Internal Tools)&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;middleware&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;auth&#39;&lt;/span&gt;]) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;/admin/scheduler&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;in_array&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;request&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;ip&lt;/span&gt;(), &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;explode&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;,&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;env&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;ADMIN_IPS&#39;&lt;/span&gt;)))) { &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;abort&lt;/span&gt;(&lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;403&lt;/span&gt;); } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;app&lt;/span&gt;(&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;SchedulerController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;app&lt;/span&gt;(&lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Schedule&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;)); });&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(238, 240, 255); border-left: 4px solid rgb(91, 110, 245); border-radius: 0px 10px 10px 0px; box-sizing: border-box; color: #2d3561; font-size: 15px; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #5b6ef5; margin: 0px; padding: 0px;&quot;&gt;⚠️ สำคัญมาก:&lt;/strong&gt; หน้า Scheduler Dashboard ควรอยู่หลัง Authentication เสมอ เพราะแสดงข้อมูล Internal Tasks ของระบบ อย่าเปิด Public โดยเด็ดขาด&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;⑥&lt;/span&gt;คำสั่งที่ควรรู้จัก&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Laravel มี Artisan Commands สำหรับจัดการ Scheduler โดยเฉพาะ ใช้ได้ตั้งแต่ Development จนถึง Production:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(13, 17, 23); border-color: rgb(48, 54, 61); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(22, 27, 34); border-bottom: 1px solid rgb(48, 54, 61); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-red&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-yellow&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-green&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-filename&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-size: 12px; margin: 0px 0px 0px 8px; padding: 0px;&quot;&gt;Terminal&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;code-body&quot; style=&quot;box-sizing: border-box; color: #e6edf3; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px 22px; white-space: pre;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# ดูรายการ Scheduled Tasks ทั้งหมด (แบบ CLI)&lt;/span&gt; php artisan schedule:list &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# รัน Scheduler ทันที (ทดสอบ)&lt;/span&gt; php artisan schedule:run &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# รัน Scheduler แบบ Loop ทุกนาที (สำหรับ Local Dev)&lt;/span&gt; php artisan schedule:work &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# รัน Task เฉพาะตัว โดยไม่รอ Schedule&lt;/span&gt; php artisan schedule:run --task=&quot;report:daily-sales&quot; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; margin: 0px; padding: 0px;&quot;&gt;# ดู Log ของ Scheduler&lt;/span&gt; tail -f storage/logs/laravel.log&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;คำสั่ง &lt;code style=&quot;background: rgb(238, 240, 255); border-radius: 4px; box-sizing: border-box; color: #3d4db7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88em; margin: 0px; padding: 2px 7px;&quot;&gt;php artisan schedule:list&lt;/code&gt; คือต้นแบบของ Dashboard ที่เราสร้าง แต่เราเปลี่ยนจาก Terminal Output มาเป็นหน้าเว็บที่ทีมทุกคนเข้าดูได้แทน&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;section&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;align-items: center; border-bottom: 2px solid rgb(238, 240, 255); box-sizing: border-box; display: flex; font-size: 1.45rem; gap: 10px; margin: 0px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;h2-icon&quot; style=&quot;align-items: center; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-flex; flex-shrink: 0; font-size: 14px; height: 30px; justify-content: center; margin: 0px; padding: 0px; width: 30px;&quot;&gt;⑦&lt;/span&gt;สรุป: ทำไม Scheduler Dashboard ถึงสำคัญ&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;การมี Web Dashboard สำหรับ Scheduled Tasks ช่วยให้ทีมพัฒนาและ Operations เห็นภาพรวมของ Background Jobs ทั้งหมดได้ทันที โดยไม่ต้องให้ทุกคนมีสิทธิ์ SSH เข้า Production Server&lt;/p&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 20px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 15px; margin: 0px; min-width: 520px; padding: 0px; width: 780px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(241, 243, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;สิ่งที่ได้&lt;/th&gt;&lt;th style=&quot;border-bottom: 2px solid rgb(228, 230, 240); box-sizing: border-box; color: #1a1d23; font-size: 14px; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;ประโยชน์&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ดู Tasks ทั้งหมดบนเว็บ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ไม่ต้อง SSH เข้า Server&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;background: rgb(245, 246, 255); border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;แสดง Cron Expression&lt;/td&gt;&lt;td style=&quot;background: rgb(245, 246, 255); border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ทีม Non-tech เข้าใจ Schedule ได้&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;แสดง Next Run Time&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;วางแผน Maintenance ได้ถูกต้อง&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ป้องกันด้วย Auth&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(228, 230, 240); box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;ปลอดภัย เฉพาะ Admin เท่านั้น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Code อยู่ใน Codebase&lt;/td&gt;&lt;td style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; color: #52576b; margin: 0px; padding: 11px 16px; vertical-align: top;&quot;&gt;Version Control ได้, Deploy พร้อมกัน&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ขั้นต่อไปที่ทำได้คือ เพิ่ม Audit Log บันทึกว่า Task รันสำเร็จหรือไม่, เพิ่มปุ่ม &quot;Run Now&quot; สำหรับ Admin, หรือแม้แต่ต่อ Webhook ส่ง Notification ไปที่ LINE/Slack เมื่อ Task ล้มเหลว&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;cta-box&quot; style=&quot;background: linear-gradient(135deg, rgb(30, 34, 53) 0%, rgb(45, 53, 97) 100%) rgb(248, 249, 251); border-radius: 14px; box-sizing: border-box; color: #1a1d23; font-family: Sarabun, sans-serif; font-size: 17px; margin: 48px 0px 0px; padding: 36px 32px; text-align: center;&quot;&gt;&lt;h3 style=&quot;box-sizing: border-box; color: white; font-size: 1.3rem; margin: 28px 0px 10px; padding: 0px;&quot;&gt;📖 อ่านบทความ PHP / Laravel เพิ่มเติม&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #a8b4d0; font-size: 15px; margin: 0px 0px 22px; padding: 0px;&quot;&gt;บทความใหม่ทุกสัปดาห์เกี่ยวกับ PHP, Laravel, CodeIgniter 4 และ Web Development สำหรับนักพัฒนาไทย&lt;/p&gt;&lt;a class=&quot;cta-btn&quot; href=&quot;https://www.facebook.com/phpcodemania&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(91, 110, 245); border-radius: 8px; box-sizing: border-box; color: white; display: inline-block; font-size: 15px; font-weight: 600; margin: 0px; padding: 12px 30px; text-decoration: none; transition: opacity 0.2s;&quot;&gt;ไปที่ PHP Code Mania →&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/7989722804480872040/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/scheduler-list-web-dashboard-laravel.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/7989722804480872040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/7989722804480872040'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/scheduler-list-web-dashboard-laravel.html' title='Scheduler List: Web Dashboard สำหรับจัดการ Laravel Scheduled Tasks'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgddmG7ZnjTaICbX5AePY-goOcM7NPr1El6OXUxEptQ3UyaGyNzNIWPoVIOhWdWlWy2QDpm5UvV_CqxS_xZJgBzOoRl6OajygUMCVphuc1vxuF6iZwlYJcUK1_ErZQOkbxSLz0VmXyr-X8XgmF6egguPmM8wRc03C_dz5893vGWblIGtpO2zYy7qbec2Xo=s72-w640-h360-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-8094583268777560134</id><published>2026-06-15T06:52:27.202+07:00</published><updated>2026-06-15T06:52:27.202+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>จัดการ &quot;เงิน&quot; ใน PHP ให้ถูกต้อง: Money Value Object vs brick/money (สำหรับ Laravel/CI4)</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEivTNK2ntqsT8lipJjAEBqDQW0KRaudgtixc6U4YVNWgd4UPM3lTxBLSNvtHXhRlrsqAw0nX1Li1ClaX5bl9A2E_zgSZspfzpnLk8LS67kqs7B1bAdiC3WHtd0r4cTlArtGIV4fwoJx6LRXVnbMwrSb9SwMvgyyyhZtOZYu3yq2wvc2r56mfdMvYsTcWso&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1024&quot; data-original-width=&quot;1535&quot; height=&quot;427&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEivTNK2ntqsT8lipJjAEBqDQW0KRaudgtixc6U4YVNWgd4UPM3lTxBLSNvtHXhRlrsqAw0nX1Li1ClaX5bl9A2E_zgSZspfzpnLk8LS67kqs7B1bAdiC3WHtd0r4cTlArtGIV4fwoJx6LRXVnbMwrSb9SwMvgyyyhZtOZYu3yq2wvc2r56mfdMvYsTcWso&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; &lt;div&gt;&lt;p class=&quot;lead&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(240, 238, 252) 0%, rgb(232, 244, 253) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 5px solid rgb(108, 92, 231); border-radius: 8px; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 18px; margin-bottom: 28px; padding: 18px 22px;&quot;&gt;เคยเจอบั๊กแบบนี้ไหมครับ... ลูกค้าโทรมาบอกว่าโดนเก็บเงินเกิน 1 สตางค์ แล้วทีมบัญชีก็ส่งมาถามว่า &quot;ทำไมยอดมันไม่ตรง?&quot; พอไปดูโค้ดก็เจอว่าเราเก็บราคาเป็น &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;float&lt;/code&gt; หรือ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;decimal&lt;/code&gt; แล้วบวกลบกันไปมาจนค่ามันคลาดเคลื่อน นี่ไม่ใช่บั๊กเล็ก ๆ เลยครับ เพราะมันเกี่ยวกับ &quot;เงิน&quot; ของลูกค้าโดยตรง&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ปัญหานี้เกิดจากแนวคิดพื้นฐานที่หลายคนมองข้าม คือ &lt;strong&gt;&quot;เงิน&quot; ไม่ใช่แค่ตัวเลข&lt;/strong&gt; มันคือจำนวนเงินที่ผูกอยู่กับสกุลเงิน และมีกฎเกณฑ์ทางธุรกิจที่ตัวเลขล้วน ๆ ไม่สามารถบอกเราได้ เช่น เราไม่สามารถเอา 10 USD ไปบวกกับ 10 EUR ได้ตรง ๆ และเมื่อต้องหารเงินแบบไม่ลงตัว ใครจะเป็นคนรับเศษสตางค์ที่เหลือ?&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ในบทความนี้ เราจะมาดูกันว่าทำไมการเก็บเงินด้วยตัวเลขธรรมดาถึงอันตราย แล้วจะแก้ปัญหาด้วยการสร้าง &lt;strong&gt;Value Object&lt;/strong&gt; ของตัวเอง หรือจะใช้ไลบรารีสำเร็จรูปอย่าง &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; ดีกว่ากัน รวมถึงแนวทางการออกแบบให้ทั้งสองแบบสามารถสลับใช้งานกันได้ในอนาคต เหมาะสำหรับคนที่กำลังพัฒนาเว็บแอปด้วย CodeIgniter 4 หรือ Laravel ครับ&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 3px solid rgb(108, 92, 231); color: #1a1a2e; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-bottom: 10px;&quot;&gt;🔍 ปัญหาที่ซ่อนอยู่ 3 อย่างของการเก็บเงินแบบ &quot;ตัวเลขดิบ&quot;&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ก่อนจะไปถึงทางแก้ เรามาดูกันก่อนว่าทำไมการเก็บราคาเป็น &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;float&lt;/code&gt; หรือแม้แต่ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;int&lt;/code&gt;/&lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;decimal&lt;/code&gt; แบบไม่มีการจัดการที่ดี ถึงนำไปสู่ปัญหาในระยะยาว&lt;/p&gt;&lt;h3 style=&quot;color: #4834d4; font-family: Sarabun, sans-serif; font-size: 20px; margin-bottom: 12px; margin-top: 28px;&quot;&gt;1. ปัญหา Floating Point (จุดทศนิยมไม่เที่ยง)&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;คอมพิวเตอร์เก็บเลขทศนิยมในรูปแบบ binary fraction ซึ่งตัวเลขอย่าง 0.10 ไม่สามารถแทนค่าได้แม่นยำ 100% ในระบบไบนารี เมื่อเราบวกราคาสินค้าหลายพันรายการเข้าด้วยกัน ความผิดพลาดเล็ก ๆ นี้จะสะสมจนกลายเป็นยอดเงินที่ผิดจริง ๆ&lt;/p&gt;&lt;h3 style=&quot;color: #4834d4; font-family: Sarabun, sans-serif; font-size: 20px; margin-bottom: 12px; margin-top: 28px;&quot;&gt;2. ปัญหาสกุลเงินที่หายไป&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ตัวเลขเปล่า ๆ อย่าง &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;10&lt;/code&gt; ไม่สามารถบอกได้ว่าหมายถึง 10 ดอลลาร์ หรือ 10 เยน ถ้าระบบของเรามีหลายสกุลเงิน แล้วดันเผลอเอายอด USD ไปบวกกับ JPY ตรง ๆ โดยไม่มีการตรวจสอบ ผลลัพธ์ที่ได้ก็จะเป็นตัวเลขที่ &quot;รันได้&quot; แต่ไม่มีความหมายทางธุรกิจเลย&lt;/p&gt;&lt;h3 style=&quot;color: #4834d4; font-family: Sarabun, sans-serif; font-size: 20px; margin-bottom: 12px; margin-top: 28px;&quot;&gt;3. ปัญหากฎการปัดเศษ (Rounding)&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ลองสมมติว่าต้องหารส่วนลด 10.00 บาท ออกเป็น 3 รายการเท่า ๆ กัน จะได้ 3.333... บาทต่อรายการ คำถามคือใครจะรับเศษสตางค์ที่เหลือไป? ถ้าเราปล่อยให้แต่ละจุดในโค้ดปัดเศษกันเอง โดยไม่มีกฎกลางที่ชัดเจน ผลรวมที่ได้อาจไม่เท่ากับยอดตั้งต้น และนี่คือต้นเหตุของรายงานบัญชีที่ไม่ลงตัว&lt;/p&gt;&lt;table style=&quot;border-collapse: collapse; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.06) 0px 4px 16px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 24px 0px; overflow: hidden; width: 898px;&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(108, 92, 231); color: white; font-size: 15px; padding: 14px 16px; text-align: left;&quot;&gt;ปัญหา&lt;/th&gt;&lt;th style=&quot;background: rgb(108, 92, 231); color: white; font-size: 15px; padding: 14px 16px; text-align: left;&quot;&gt;สาเหตุ&lt;/th&gt;&lt;th style=&quot;background: rgb(108, 92, 231); color: white; font-size: 15px; padding: 14px 16px; text-align: left;&quot;&gt;ทางแก้&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;Floating point ไม่เที่ยง&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;เก็บเงินเป็น float/decimal โดยตรง&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;เก็บเป็นจำนวนเต็มในหน่วยย่อยที่สุด (สตางค์/เซนต์)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;สกุลเงินหายไป&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;ใช้ตัวเลขเปล่า ๆ แทนเงิน&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom: 1px solid rgb(238, 238, 238); font-size: 15px; padding: 14px 16px;&quot;&gt;ผูกสกุลเงินไว้กับจำนวนเงินเสมอ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; font-size: 15px; padding: 14px 16px;&quot;&gt;ปัดเศษไม่สม่ำเสมอ&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; font-size: 15px; padding: 14px 16px;&quot;&gt;ปัดเศษกระจายอยู่ทั่วโค้ด&lt;/td&gt;&lt;td style=&quot;background: rgb(255, 255, 255); border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; font-size: 15px; padding: 14px 16px;&quot;&gt;กำหนดกฎปัดเศษเป็น method กลางในโดเมน&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 style=&quot;border-bottom: 3px solid rgb(108, 92, 231); color: #1a1a2e; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-bottom: 10px;&quot;&gt;🛠️ แนวทางที่ 1: สร้าง Money Value Object เอง&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;แนวคิดหลักของ Value Object คือการสร้างคลาสที่ &lt;strong&gt;immutable&lt;/strong&gt; (เปลี่ยนค่าไม่ได้หลังสร้าง) ปลอดภัยเรื่องสกุลเงิน และเก็บจำนวนเงินเป็นจำนวนเต็มในหน่วยย่อยที่สุด เช่น เก็บ 199.99 บาท เป็น 19999 สตางค์&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;เริ่มจากกำหนดสกุลเงินเป็น enum เพื่อให้ PHP ช่วยตรวจสอบความถูกต้องให้เราตั้งแต่ตอน compile:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;Currency.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;enum Currency: string { case USD = &#39;USD&#39;; case EUR = &#39;EUR&#39;; case THB = &#39;THB&#39;; case JPY = &#39;JPY&#39;; public function minorUnitDecimals(): int { return match ($this) { Currency::JPY =&amp;gt; 0, default =&amp;gt; 2, }; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;สังเกตว่า &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;minorUnitDecimals()&lt;/code&gt; สำคัญมาก เพราะ JPY ไม่มีทศนิยม ในขณะที่ USD, EUR, THB มี 2 ตำแหน่ง ถ้าเราใช้สูตรปัดเศษเดียวกันกับทุกสกุลเงิน ผลลัพธ์ของเยนจะผิดทันที&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ต่อมาคือคลาส &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;Money&lt;/code&gt; ที่เป็น Value Object หลัก:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;Money.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;final class Money { private function __construct( private readonly int $amountInMinorUnits, private readonly Currency $currency, ) {} public static function fromMinorUnits(int $amount, Currency $currency): self { return new self($amount, $currency); } public function add(Money $other): self { $this-&amp;gt;assertSameCurrency($other); return new self( $this-&amp;gt;amountInMinorUnits + $other-&amp;gt;amountInMinorUnits, $this-&amp;gt;currency, ); } private function assertSameCurrency(Money $other): void { if ($this-&amp;gt;currency !== $other-&amp;gt;currency) { throw new InvalidArgumentException( &#39;Cannot operate on different currencies.&#39; ); } } public function getAmount(): int { return $this-&amp;gt;amountInMinorUnits; } public function getCurrency(): Currency { return $this-&amp;gt;currency; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;จุดสำคัญของโค้ดนี้คือ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;assertSameCurrency()&lt;/code&gt; ถ้ามีการเอา Money สองสกุลที่ไม่ตรงกันมาบวกกัน ระบบจะ throw exception ทันที แทนที่จะให้ผลลัพธ์เป็นตัวเลขผิด ๆ ที่กลายเป็นปัญหาในอีก 3 สัปดาห์ข้างหน้า&lt;/p&gt;&lt;h3 style=&quot;color: #4834d4; font-family: Sarabun, sans-serif; font-size: 20px; margin-bottom: 12px; margin-top: 28px;&quot;&gt;การจัดการเรื่องปัดเศษด้วย Allocation&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ส่วนที่ยากที่สุดของการจัดการเงินไม่ใช่การบวกลบ แต่คือการ &quot;หาร&quot; ลองดูตัวอย่างการแบ่งส่วนลด 1000 สตางค์ออกเป็น 3 ส่วน:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;Money.php — allocate()&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;final class Money { // ... โค้ดด้านบน /** * แบ่งจำนวนเงินออกเป็น N ส่วน โดยผลรวมต้องเท่ากับ * จำนวนเงินตั้งต้นเสมอ เศษสตางค์ที่เหลือจะถูกมอบให้ * กับส่วนแรก ๆ เพื่อไม่ให้มีเงินงอกหรือหายไป */ public function allocate(int $parts): array { $base = intdiv($this-&amp;gt;amountInMinorUnits, $parts); $remainder = $this-&amp;gt;amountInMinorUnits % $parts; $result = []; for ($i = 0; $i &amp;lt; $parts; $i++) { $amount = $base + ($i &amp;lt; $remainder ? 1 : 0); $result[] = new self($amount, $this-&amp;gt;currency); } return $result; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;tip-box&quot; style=&quot;background: rgb(255, 248, 225); border-left: 5px solid rgb(255, 189, 46); border-radius: 8px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; padding: 16px 20px;&quot;&gt;💡 &lt;strong&gt;ตัวอย่าง:&lt;/strong&gt; ถ้าเราแบ่ง 1000 สตางค์ออกเป็น 3 ส่วน จะได้ 334, 333, 333 ซึ่งรวมกันได้ 1000 พอดี ไม่มีเงินงอกขึ้นมาจากไหน และไม่มีสตางค์หายไปไหน กฎการปัดเศษนี้ถูกเขียนไว้เป็น method ที่อ่านง่าย ทดสอบได้ และเป็นเจ้าของโดยโดเมนของเราเอง&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 3px solid rgb(108, 92, 231); color: #1a1a2e; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-bottom: 10px;&quot;&gt;📦 แนวทางที่ 2: ใช้ brick/money ไลบรารีสำเร็จรูป&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;เมื่อระบบของเราซับซ้อนขึ้น เช่น ต้องรองรับหลายสกุลเงินจริงจัง ต้องแปลงสกุลเงินตามอัตราแลกเปลี่ยน หรือต้องใช้กฎการปัดเศษหลายรูปแบบ (round half up, round half even ฯลฯ) การเขียน Value Object เองอาจไม่คุ้มค่าอีกต่อไป ตรงนี้แหละที่ไลบรารี &lt;a href=&quot;https://github.com/brick/money&quot; style=&quot;border-bottom: 1px dashed rgb(108, 92, 231); color: #6c5ce7; font-weight: 600; text-decoration: none;&quot; target=&quot;_blank&quot;&gt;brick/money&lt;/a&gt; เข้ามาช่วยได้&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ติดตั้งผ่าน Composer:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;terminal&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;composer require brick/money&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ตัวอย่างการใช้งานเบื้องต้น:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;example.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;use Brick\Money\Money; use Brick\Math\RoundingMode; $price = Money::of(&#39;199.99&#39;, &#39;THB&#39;); $discount = $price-&amp;gt;multipliedBy(&#39;0.1&#39;, RoundingMode::HALF_UP); $finalPrice = $price-&amp;gt;minus($discount); echo $finalPrice-&amp;gt;getAmount(); // 179.99 echo $finalPrice-&amp;gt;getCurrency()-&amp;gt;getCurrencyCode(); // THB&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;&lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; จัดการเรื่อง currency, rounding mode, และการแบ่งส่วน (allocation) ให้ครบแล้ว ทำให้เราไม่ต้องเขียนโค้ดเหล่านี้ซ้ำเอง&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 3px solid rgb(108, 92, 231); color: #1a1a2e; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-bottom: 10px;&quot;&gt;🚪 ทางออกที่ยั่งยืน: ซ่อน brick/money ไว้หลัง Port ของโดเมนตัวเอง&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;คำถามคือ ถ้าใช้ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; โดยตรงทั่วทั้งโปรเจกต์ แล้ววันหนึ่งอยากเปลี่ยนไลบรารี หรืออยากเพิ่มกฎทางธุรกิจเฉพาะของบริษัทเราเองล่ะ? คำตอบคือการสร้าง &lt;strong&gt;Port&lt;/strong&gt; หรือ interface ของโดเมนเราเองขึ้นมาครอบไว้อีกชั้น&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;MoneyServiceInterface.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;interface MoneyServiceInterface { public function create(string $amount, string $currency): MoneyValue; public function add(MoneyValue $a, MoneyValue $b): MoneyValue; public function allocate(MoneyValue $money, int $parts): array; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;จากนั้นสร้าง implementation ที่ใช้ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; อยู่ภายใน:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;BrickMoneyService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;use Brick\Money\Money as BrickMoney; use Brick\Math\RoundingMode; class BrickMoneyService implements MoneyServiceInterface { public function create(string $amount, string $currency): MoneyValue { $money = BrickMoney::of($amount, $currency); return new MoneyValue( $money-&amp;gt;getMinorAmount()-&amp;gt;toInt(), $currency ); } public function add(MoneyValue $a, MoneyValue $b): MoneyValue { $brickA = BrickMoney::ofMinor($a-&amp;gt;amount, $a-&amp;gt;currency); $brickB = BrickMoney::ofMinor($b-&amp;gt;amount, $b-&amp;gt;currency); $result = $brickA-&amp;gt;plus($brickB); return new MoneyValue( $result-&amp;gt;getMinorAmount()-&amp;gt;toInt(), $a-&amp;gt;currency ); } public function allocate(MoneyValue $money, int $parts): array { $brick = BrickMoney::ofMinor($money-&amp;gt;amount, $money-&amp;gt;currency); $ratios = array_fill(0, $parts, 1); $allocated = $brick-&amp;gt;allocate(...$ratios); return array_map( fn ($m) =&amp;gt; new MoneyValue($m-&amp;gt;getMinorAmount()-&amp;gt;toInt(), $money-&amp;gt;currency), $allocated ); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ในโค้ด Controller หรือ Service ของ Laravel/CodeIgniter 4 เราจะเรียกผ่าน &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;MoneyServiceInterface&lt;/code&gt; เสมอ ไม่เรียก &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;BrickMoney&lt;/code&gt; ตรง ๆ:&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 8px 24px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 62); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;dot dot-red&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-yellow&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot dot-green&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;code-filename&quot; style=&quot;color: #8a8aa0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;OrderService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px 20px;&quot;&gt;&lt;code style=&quot;background: none; color: #e0e0f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;class OrderService { public function __construct( private MoneyServiceInterface $moneyService, ) {} public function splitDiscount(string $amount, string $currency, int $items): array { $money = $this-&amp;gt;moneyService-&amp;gt;create($amount, $currency); return $this-&amp;gt;moneyService-&amp;gt;allocate($money, $items); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;tip-box&quot; style=&quot;background: rgb(255, 248, 225); border-left: 5px solid rgb(255, 189, 46); border-radius: 8px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; padding: 16px 20px;&quot;&gt;💡 &lt;strong&gt;ข้อดีของแนวทางนี้:&lt;/strong&gt; ถ้าวันหนึ่งทีมตัดสินใจเปลี่ยนจาก &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; ไปใช้ไลบรารีอื่น หรือกลับมาเขียน Value Object เองทั้งหมด เราแค่เขียน implementation ใหม่ของ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;MoneyServiceInterface&lt;/code&gt; โดยไม่ต้องแก้โค้ดส่วน business logic เลยแม้แต่บรรทัดเดียว นี่คือหลักการเดียวกับ Hexagonal Architecture ที่ว่า &quot;กฎการปัดเศษอยู่ในโดเมนของเรา ส่วนไลบรารีเป็นแค่ตัวที่สลับเปลี่ยนได้&quot;&lt;/div&gt;&lt;h2 style=&quot;border-bottom: 3px solid rgb(108, 92, 231); color: #1a1a2e; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-bottom: 10px;&quot;&gt;📌 สรุป&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;การจัดการ &quot;เงิน&quot; ในแอปพลิเคชัน PHP ไม่ใช่เรื่องของการเลือก data type ให้ถูกต้องเพียงอย่างเดียว แต่เป็นเรื่องของการออกแบบให้กฎทางธุรกิจ เช่น การปัดเศษ การแบ่งส่วน และการตรวจสอบสกุลเงิน อยู่ในที่เดียวที่ชัดเจนและทดสอบได้ ไม่ว่าจะเลือกเขียน Value Object เอง หรือใช้ &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; สิ่งสำคัญคือต้องห่อหุ้มมันไว้หลัง interface ของโดเมนตัวเอง เพื่อให้ระบบยืดหยุ่นและรองรับการเปลี่ยนแปลงในอนาคตได้โดยไม่ต้องรื้อทั้งโปรเจกต์&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;สำหรับโปรเจกต์เล็ก ๆ ที่มีสกุลเงินเดียวและกฎไม่ซับซ้อน การเขียน Value Object เองก็เพียงพอและช่วยให้โค้ดเบาขึ้น แต่ถ้าโปรเจกต์เริ่มโตขึ้นและต้องรองรับหลายสกุลเงินหรือกฎการปัดเศษที่ซับซ้อน &lt;code style=&quot;background: rgb(240, 238, 252); border-radius: 4px; color: #6c5ce7; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; padding: 2px 8px;&quot;&gt;brick/money&lt;/code&gt; พร้อม Port ของตัวเองคือคำตอบที่คุ้มค่ากว่าในระยะยาว&lt;/p&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/8094583268777560134/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/blog-post.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8094583268777560134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8094583268777560134'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/blog-post.html' title='จัดการ &quot;เงิน&quot; ใน PHP ให้ถูกต้อง: Money Value Object vs brick/money (สำหรับ Laravel/CI4)'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEivTNK2ntqsT8lipJjAEBqDQW0KRaudgtixc6U4YVNWgd4UPM3lTxBLSNvtHXhRlrsqAw0nX1Li1ClaX5bl9A2E_zgSZspfzpnLk8LS67kqs7B1bAdiC3WHtd0r4cTlArtGIV4fwoJx6LRXVnbMwrSb9SwMvgyyyhZtOZYu3yq2wvc2r56mfdMvYsTcWso=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-775270257258239089</id><published>2026-06-13T23:59:02.454+07:00</published><updated>2026-06-13T23:59:02.455+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="เขียนโปรแกรม"/><title type='text'>SDK PHP ช่วยลดโค้ดเชื่อมต่อ API ได้นับร้อยบรรทัดอย่างไร</title><content type='html'>&lt;div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg9dEPv2tsrHtIWf6i6f3cEMRyuHTu1tbJX-AMt83cfFJ_5CaIkS08FvpbcVcJUK8Ap_oIDJo1uCWFG780lDH3akimaicrIKIoTh-6X7LLI4S3HJJjU5jdnbBvUg5ZqeDHu6UjmseQQgLRQOfWhObSWTrqMtZCPCEVX3gGc0zVJ91-yx6LeivpaeX4H1iE&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg9dEPv2tsrHtIWf6i6f3cEMRyuHTu1tbJX-AMt83cfFJ_5CaIkS08FvpbcVcJUK8Ap_oIDJo1uCWFG780lDH3akimaicrIKIoTh-6X7LLI4S3HJJjU5jdnbBvUg5ZqeDHu6UjmseQQgLRQOfWhObSWTrqMtZCPCEVX3gGc0zVJ91-yx6LeivpaeX4H1iE=w640-h360&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;เคยไหมครับ ที่ต้องเชื่อมต่อระบบของตัวเองเข้ากับบริการภายนอก เช่น ระบบบัญชี ระบบจัดส่งสินค้า หรือ Payment Gateway แล้วต้องมานั่งเขียนโค้ดเรียก API ด้วย cURL เอง ตั้งค่า Header เอง แปลง JSON เอง จัดการ Error เอง... ทำซ้ำแบบนี้ทุกครั้งที่มี Endpoint ใหม่ จนโค้ดในโปรเจกต์เต็มไปด้วยฟังก์ชันเรียก API ที่หน้าตาคล้ายกันแต่กระจัดกระจายอยู่ทั่วทุกที่&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ปัญหานี้พบได้บ่อยมากในงานพัฒนาเว็บแอปด้วย PHP โดยเฉพาะตอนที่ต้องเชื่อมต่อกับบริการอย่าง QuickBooks สำหรับงานบัญชี หรือระบบอีคอมเมิร์ซต่าง ๆ ที่มี API ให้เรียกใช้จำนวนมาก ถ้าทุกอย่างต้องเขียนเองด้วย cURL ดิบ ๆ โอกาสที่โค้ดจะซ้ำซ้อนและบั๊กแอบซ่อนอยู่นั้นสูงมาก&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;บทความนี้จะพาไปดูว่า &quot;SDK&quot; (Software Development Kit) คืออะไร ทำไมการใช้ SDK ที่มีคนทำไว้แล้ว หรือการสร้าง SDK ของตัวเอง ถึงช่วยลดโค้ดได้เป็นร้อยบรรทัด พร้อมตัวอย่างการนำไปใช้งานจริงใน CodeIgniter 4 และ Laravel สำหรับมือใหม่ที่อยากเขียนโค้ดให้สะอาดและดูแลง่ายขึ้น&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;SDK คืออะไร แล้วต่างจากการเรียก API ตรง ๆ ยังไง&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;SDK ก็คือชุดไลบรารีที่ห่อหุ้ม (wrap) การเรียก API ของบริการหนึ่ง ๆ ไว้ในรูปแบบของคลาสและฟังก์ชันที่ใช้งานง่าย แทนที่เราจะต้องจำ Endpoint, Header, รูปแบบ JSON เอง SDK จะเตรียมเมธอดสำเร็จรูปให้เรียกใช้ตรง ๆ เช่น แทนที่จะต้องยิง cURL ไปที่ &lt;code&gt;/v3/company/123/customer&lt;/code&gt; พร้อมแนบ Token เอง เราอาจแค่เรียก &lt;code&gt;$client-&amp;gt;customers()-&amp;gt;create($data)&lt;/code&gt; เพียงบรรทัดเดียว&lt;/p&gt;&lt;div class=&quot;pcm-callout&quot; style=&quot;background: rgb(238, 242, 255); border-left: 5px solid rgb(99, 102, 241); border-radius: 8px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;span class=&quot;pcm-callout-title&quot; style=&quot;color: #4338ca; display: block; font-weight: 700; margin-bottom: 6px;&quot;&gt;💡 มุมมองง่าย ๆ&lt;/span&gt;ลองนึกภาพว่า API คือ &quot;ปลั๊กไฟดิบ&quot; ที่ต้องต่อสายเอง ระมัดระวังเรื่องไฟดูด ส่วน SDK คือ &quot;ปลั๊กพ่วงพร้อมสวิตช์&quot; ที่ต่อแล้วใช้ได้เลย ปลอดภัยกว่า และมีคนทดสอบมาให้แล้วว่าใช้งานได้จริง&lt;/div&gt;&lt;h3 style=&quot;color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 20px; margin-bottom: 12px; margin-top: 28px;&quot;&gt;ตัวอย่างปัญหา: เรียก API ด้วย cURL ดิบ ๆ&lt;/h3&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ลองดูตัวอย่างการเรียก API เพื่อสร้างลูกค้าใหม่ในระบบบัญชีแบบ QuickBooks ด้วย cURL ตรง ๆ ดูครับ จะเห็นว่าต้องเขียนโค้ดจัดการ Header, Token, และ Error เองทั้งหมด&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;raw_curl_example.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php function createCustomerRaw($accessToken, $realmId, $customerData) { $url = &quot;https://sandbox-quickbooks.api.intuit.com/v3/company/{$realmId}/customer&quot;; $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ &quot;Authorization: Bearer {$accessToken}&quot;, &quot;Content-Type: application/json&quot;, &quot;Accept: application/json&quot;, ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($customerData)); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (curl_errno($ch)) { $error = curl_error($ch); curl_close($ch); throw new Exception(&quot;cURL Error: {$error}&quot;); } curl_close($ch); if ($httpCode &amp;gt;= 400) { throw new Exception(&quot;API Error ({$httpCode}): {$response}&quot;); } return json_decode($response, true); } // ทุกครั้งที่ต้องเรียก Endpoint ใหม่ ต้องเขียนซ้ำแบบนี้อีก... function getCustomerRaw($accessToken, $realmId, $customerId) { $url = &quot;https://sandbox-quickbooks.api.intuit.com/v3/company/{$realmId}/customer/{$customerId}&quot;; // ... โค้ด cURL เหมือนเดิมอีกชุด } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;จะเห็นว่าแค่ 2 ฟังก์ชันก็ปาไปแล้วเกือบ 40 บรรทัด และถ้าระบบมี Endpoint ที่ต้องใช้สัก 10-20 จุด โค้ดส่วนที่ทำซ้ำ ๆ (ตั้ง Header, เช็ค Error, แปลง JSON) จะเกิดขึ้นนับร้อยบรรทัด ซึ่งถ้าวันหนึ่งบริการเปลี่ยนวิธี Authentication เราต้องไปแก้ทุกจุดที่เขียนซ้ำไว้&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;ใช้ SDK แทน: ลดโค้ดเหลือไม่กี่บรรทัด&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ถ้าบริการนั้นมี SDK สำหรับ PHP ให้ใช้ (เช่นโหลดผ่าน Composer) เราสามารถลดงานข้างต้นทั้งหมดให้เหลือเพียงไม่กี่บรรทัด เพราะ SDK จัดการเรื่อง Authentication, Header, และการแปลงข้อมูลให้เราหมดแล้ว&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;with_sdk_example.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php use QuickBooksOnline\API\DataService\DataService; use QuickBooksOnline\API\Data\IPPCustomer; $dataService = DataService::Configure([ &#39;auth_mode&#39; =&amp;gt; &#39;oauth2&#39;, &#39;ClientID&#39; =&amp;gt; env(&#39;QB_CLIENT_ID&#39;), &#39;ClientSecret&#39; =&amp;gt; env(&#39;QB_CLIENT_SECRET&#39;), &#39;accessTokenKey&#39; =&amp;gt; $accessToken, &#39;refreshTokenKey&#39; =&amp;gt; $refreshToken, &#39;baseUrl&#39; =&amp;gt; &#39;development&#39;, ]); $customer = new IPPCustomer(); $customer-&amp;gt;DisplayName = $customerData[&#39;name&#39;]; $customer-&amp;gt;PrimaryEmailAddr = [&#39;Address&#39; =&amp;gt; $customerData[&#39;email&#39;]]; $result = $dataService-&amp;gt;Add($customer); $error = $dataService-&amp;gt;getLastError(); if ($error) { throw new Exception($error-&amp;gt;getResponseBody()); } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;จะเห็นว่าเราไม่ต้องไปยุ่งกับ cURL, Header หรือ URL ของ Endpoint เลย SDK จัดการให้หมด สิ่งที่เราทำคือ &quot;ตั้งค่า&quot; และ &quot;เรียกใช้เมธอด&quot; เท่านั้น โค้ดสั้นลง อ่านง่ายขึ้น และลดความเสี่ยงเรื่องบั๊กจากการเขียน HTTP Request เองไปได้มาก&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;นำ SDK มาใช้ใน CodeIgniter 4&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ใน CodeIgniter 4 เราสามารถสร้าง Service หรือ Library Class แยกไว้สำหรับห่อหุ้มการเรียกใช้ SDK อีกชั้นหนึ่ง เพื่อให้ Controller เรียกใช้งานได้สะดวก และถ้าวันหนึ่งต้องเปลี่ยน SDK ก็แก้แค่จุดนี้ที่เดียว&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;app/Libraries/AccountingService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php namespace App\Libraries; use QuickBooksOnline\API\DataService\DataService; use QuickBooksOnline\API\Data\IPPCustomer; class AccountingService { protected DataService $dataService; public function __construct() { $this-&amp;gt;dataService = DataService::Configure([ &#39;auth_mode&#39; =&amp;gt; &#39;oauth2&#39;, &#39;ClientID&#39; =&amp;gt; getenv(&#39;QB_CLIENT_ID&#39;), &#39;ClientSecret&#39; =&amp;gt; getenv(&#39;QB_CLIENT_SECRET&#39;), &#39;accessTokenKey&#39; =&amp;gt; getenv(&#39;QB_ACCESS_TOKEN&#39;), &#39;refreshTokenKey&#39; =&amp;gt; getenv(&#39;QB_REFRESH_TOKEN&#39;), &#39;baseUrl&#39; =&amp;gt; &#39;development&#39;, ]); } public function createCustomer(array $data): array { $customer = new IPPCustomer(); $customer-&amp;gt;DisplayName = $data[&#39;name&#39;]; $customer-&amp;gt;PrimaryEmailAddr = [&#39;Address&#39; =&amp;gt; $data[&#39;email&#39;]]; $result = $this-&amp;gt;dataService-&amp;gt;Add($customer); $error = $this-&amp;gt;dataService-&amp;gt;getLastError(); if ($error) { throw new \RuntimeException($error-&amp;gt;getResponseBody()); } return (array) $result; } } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;app/Controllers/CustomerController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php namespace App\Controllers; use App\Libraries\AccountingService; class CustomerController extends BaseController { public function store() { $accounting = new AccountingService(); try { $result = $accounting-&amp;gt;createCustomer([ &#39;name&#39; =&amp;gt; $this-&amp;gt;request-&amp;gt;getPost(&#39;name&#39;), &#39;email&#39; =&amp;gt; $this-&amp;gt;request-&amp;gt;getPost(&#39;email&#39;), ]); return $this-&amp;gt;response-&amp;gt;setJSON([ &#39;status&#39; =&amp;gt; &#39;success&#39;, &#39;data&#39; =&amp;gt; $result, ]); } catch (\RuntimeException $e) { return $this-&amp;gt;response-&amp;gt;setStatusCode(500) -&amp;gt;setJSON([&#39;status&#39; =&amp;gt; &#39;error&#39;, &#39;message&#39; =&amp;gt; $e-&amp;gt;getMessage()]); } } } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;สังเกตว่า Controller ไม่รู้เรื่องรายละเอียดการเชื่อมต่อ API เลยแม้แต่นิดเดียว มันแค่เรียก &lt;code&gt;createCustomer()&lt;/code&gt; แล้วรับผลลัพธ์กลับมา ถ้าวันหนึ่งเปลี่ยนผู้ให้บริการบัญชีจาก QuickBooks เป็นระบบอื่น เราแก้แค่ใน &lt;code&gt;AccountingService&lt;/code&gt; เท่านั้น ไม่ต้องไปไล่แก้ทุก Controller&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;นำ SDK มาใช้ใน Laravel&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ใน Laravel แนวคิดเดียวกันนี้ทำได้สะดวกขึ้นด้วยการใช้ Service Container ผ่านการสร้าง Service Provider แล้ว Bind คลาส Service ของเราไว้ เพื่อให้สามารถ Inject เข้าไปใช้ใน Controller ผ่าน Dependency Injection ได้เลย&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;app/Services/AccountingService.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php namespace App\Services; use QuickBooksOnline\API\DataService\DataService; use QuickBooksOnline\API\Data\IPPCustomer; class AccountingService { protected DataService $dataService; public function __construct() { $this-&amp;gt;dataService = DataService::Configure([ &#39;auth_mode&#39; =&amp;gt; &#39;oauth2&#39;, &#39;ClientID&#39; =&amp;gt; config(&#39;services.quickbooks.client_id&#39;), &#39;ClientSecret&#39; =&amp;gt; config(&#39;services.quickbooks.client_secret&#39;), &#39;accessTokenKey&#39; =&amp;gt; config(&#39;services.quickbooks.access_token&#39;), &#39;refreshTokenKey&#39; =&amp;gt; config(&#39;services.quickbooks.refresh_token&#39;), &#39;baseUrl&#39; =&amp;gt; &#39;development&#39;, ]); } public function createCustomer(array $data): array { $customer = new IPPCustomer(); $customer-&amp;gt;DisplayName = $data[&#39;name&#39;]; $customer-&amp;gt;PrimaryEmailAddr = [&#39;Address&#39; =&amp;gt; $data[&#39;email&#39;]]; $result = $this-&amp;gt;dataService-&amp;gt;Add($customer); if ($error = $this-&amp;gt;dataService-&amp;gt;getLastError()) { throw new \RuntimeException($error-&amp;gt;getResponseBody()); } return (array) $result; } } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;app/Http/Controllers/CustomerController.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php namespace App\Http\Controllers; use App\Services\AccountingService; use Illuminate\Http\Request; class CustomerController extends Controller { public function __construct(protected AccountingService $accounting) {} public function store(Request $request) { $validated = $request-&amp;gt;validate([ &#39;name&#39; =&amp;gt; &#39;required|string|max:255&#39;, &#39;email&#39; =&amp;gt; &#39;required|email&#39;, ]); try { $result = $this-&amp;gt;accounting-&amp;gt;createCustomer($validated); return response()-&amp;gt;json([&#39;status&#39; =&amp;gt; &#39;success&#39;, &#39;data&#39; =&amp;gt; $result]); } catch (\RuntimeException $e) { return response()-&amp;gt;json([&#39;status&#39; =&amp;gt; &#39;error&#39;, &#39;message&#39; =&amp;gt; $e-&amp;gt;getMessage()], 500); } } } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;เพราะ Laravel มี Dependency Injection มาในตัว เราจึงไม่ต้อง &lt;code&gt;new AccountingService()&lt;/code&gt; เองในทุก Controller เพียงแค่ใส่ Type-hint ใน Constructor ระบบจะสร้าง Object ให้อัตโนมัติ ทำให้การ Mock สำหรับ Unit Test ก็ทำได้ง่ายขึ้นด้วย&lt;/p&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;เปรียบเทียบ: เรียก API ตรง ๆ vs ใช้ SDK&lt;/h2&gt;&lt;table class=&quot;pcm-table&quot; style=&quot;border-collapse: collapse; color: #2d2d2d; font-family: Sarabun, sans-serif; font-size: 15px; margin: 20px 0px; width: 800px;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(99, 102, 241); color: white; padding: 12px 14px; text-align: left;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;background: rgb(99, 102, 241); color: white; padding: 12px 14px; text-align: left;&quot;&gt;เรียก API ด้วย cURL ตรง ๆ&lt;/th&gt;&lt;th style=&quot;background: rgb(99, 102, 241); color: white; padding: 12px 14px; text-align: left;&quot;&gt;ใช้ SDK&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(249, 250, 251);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;จำนวนโค้ดต่อ Endpoint&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;20-40 บรรทัด ต่อจุด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;3-10 บรรทัด ต่อจุด&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;การจัดการ Authentication&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;ต้องเขียนเอง ทุกจุด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;ตั้งค่าครั้งเดียว ใช้ได้ทุกที่&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(249, 250, 251);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;การจัดการ Error&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;เขียนเอง เสี่ยงพลาด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;มี Method ตรวจสอบให้&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;การอัปเดตเมื่อ API เปลี่ยน&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;ต้องไล่แก้ทุกจุดในโค้ด&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;อัปเดต Package ผ่าน Composer&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(249, 250, 251);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;ความเหมาะสมกับมือใหม่&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;เข้าใจหลักการ HTTP ดี แต่ยุ่งยาก&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 12px 14px;&quot;&gt;เริ่มต้นได้เร็ว เน้นที่ Logic ธุรกิจ&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;ถ้าบริการไม่มี SDK ให้ ทำยังไง&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;ไม่ใช่ทุกบริการที่จะมี SDK สำหรับ PHP ให้พร้อมใช้งาน บางครั้งมีแค่เอกสาร API แบบ REST เปล่า ๆ ในกรณีนี้ เราสามารถสร้าง &quot;Mini SDK&quot; ของตัวเองขึ้นมาได้ง่าย ๆ โดยใช้หลักการเดียวกัน คือห่อหุ้มการเรียก HTTP ไว้ในคลาสเดียว แล้วเปิดเมธอดให้ใช้งานเฉพาะที่จำเป็น&lt;/p&gt;&lt;div class=&quot;pcm-code-block&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.15) 0px 4px 12px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; overflow: hidden;&quot;&gt;&lt;div class=&quot;pcm-code-header&quot; style=&quot;align-items: center; background: rgb(42, 42, 60); display: flex; gap: 8px; padding: 10px 16px;&quot;&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-dot&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pcm-code-filename&quot; style=&quot;color: #9ca3af; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13px; margin-left: 8px;&quot;&gt;app/Services/SimpleApiClient.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;margin: 0px; overflow-x: auto; padding: 18px;&quot;&gt;&lt;code style=&quot;color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 14px; line-height: 1.6;&quot;&gt;&amp;lt;?php namespace App\Services; use Illuminate\Support\Facades\Http; class SimpleApiClient { public function __construct( protected string $baseUrl, protected string $apiKey ) {} public function get(string $endpoint, array $query = []): array { $response = Http::withToken($this-&amp;gt;apiKey) -&amp;gt;get(&quot;{$this-&amp;gt;baseUrl}/{$endpoint}&quot;, $query); return $this-&amp;gt;handleResponse($response); } public function post(string $endpoint, array $data = []): array { $response = Http::withToken($this-&amp;gt;apiKey) -&amp;gt;post(&quot;{$this-&amp;gt;baseUrl}/{$endpoint}&quot;, $data); return $this-&amp;gt;handleResponse($response); } protected function handleResponse($response): array { if ($response-&amp;gt;failed()) { throw new \RuntimeException( &quot;API request failed: {$response-&amp;gt;status()} - {$response-&amp;gt;body()}&quot; ); } return $response-&amp;gt;json(); } } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;เพียงเท่านี้ เราก็มี &quot;SDK เล็ก ๆ&quot; ของตัวเองที่ใช้ซ้ำได้ทั่วทั้งโปรเจกต์ ไม่ว่าจะเป็นการเรียก API ของระบบจัดส่งสินค้า ระบบแจ้งเตือน หรือ Payment Gateway ก็สามารถสร้างคลาสลูกที่ Extend จาก &lt;code&gt;SimpleApiClient&lt;/code&gt; นี้ได้ ทำให้โค้ดในโปรเจกต์เป็นระเบียบและทดสอบได้ง่าย&lt;/p&gt;&lt;div class=&quot;pcm-warning&quot; style=&quot;background: rgb(255, 247, 237); border-left: 5px solid rgb(249, 115, 22); border-radius: 8px; color: #2d2d2d; font-family: Sarabun, sans-serif; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;span class=&quot;pcm-callout-title&quot; style=&quot;color: #4338ca; display: block; font-weight: 700; margin-bottom: 6px;&quot;&gt;⚠️ ข้อควรระวัง&lt;/span&gt;ไม่ว่าจะใช้ SDK ของผู้ให้บริการ หรือสร้างเอง อย่าเก็บ API Key หรือ Token ไว้ใน Source Code ตรง ๆ ให้ใช้ไฟล์ &lt;code&gt;.env&lt;/code&gt; และเรียกผ่าน &lt;code&gt;config()&lt;/code&gt; หรือ &lt;code&gt;getenv()&lt;/code&gt; เสมอ เพื่อความปลอดภัยและสะดวกในการสลับค่าระหว่าง Development กับ Production&lt;/div&gt;&lt;h2 style=&quot;border-left: 5px solid rgb(99, 102, 241); color: #1a1a1a; font-family: Sarabun, sans-serif; font-size: 26px; margin-bottom: 16px; margin-top: 40px; padding-left: 12px;&quot;&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;การเรียก API ด้วย cURL ดิบ ๆ ไม่ใช่เรื่องผิด แต่ถ้าโปรเจกต์มีการเชื่อมต่อกับบริการภายนอกหลายจุด การใช้ SDK ที่มีคนทำไว้แล้ว หรือสร้าง SDK เล็ก ๆ ของตัวเองในรูปแบบ Service Class จะช่วยให้โค้ดสะอาดขึ้น ลดความซ้ำซ้อน และทำให้การดูแลรักษาในระยะยาวง่ายขึ้นมาก ทั้งใน CodeIgniter 4 ที่ใช้ Library Class และใน Laravel ที่ใช้ Service Provider กับ Dependency Injection หลักการสำคัญคือ &quot;แยกรายละเอียดการเชื่อมต่อ API ออกจาก Business Logic&quot; เพื่อให้ทั้งสองส่วนเปลี่ยนแปลงได้อย่างเป็นอิสระจากกัน&lt;/p&gt;&lt;p style=&quot;color: #2d2d2d; font-family: Sarabun, sans-serif; margin-bottom: 16px;&quot;&gt;สำหรับมือใหม่ ขอแนะนำให้เริ่มจากการสร้าง Service Class ง่าย ๆ แบบในตัวอย่างนี้ก่อน แล้วค่อย ๆ ขยายเมธอดเพิ่มตามที่โปรเจกต์ต้องการ เมื่อคุ้นเคยแล้วจะพบว่าการจัดการ API หลาย ๆ ตัวในโปรเจกต์ใหญ่ ๆ ไม่ได้น่ากลัวอย่างที่คิด&lt;/p&gt;&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/775270257258239089/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/sdk-php-api.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/775270257258239089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/775270257258239089'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/sdk-php-api.html' title='SDK PHP ช่วยลดโค้ดเชื่อมต่อ API ได้นับร้อยบรรทัดอย่างไร'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEg9dEPv2tsrHtIWf6i6f3cEMRyuHTu1tbJX-AMt83cfFJ_5CaIkS08FvpbcVcJUK8Ap_oIDJo1uCWFG780lDH3akimaicrIKIoTh-6X7LLI4S3HJJjU5jdnbBvUg5ZqeDHu6UjmseQQgLRQOfWhObSWTrqMtZCPCEVX3gGc0zVJ91-yx6LeivpaeX4H1iE=s72-w640-h360-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-2608854519938039366</id><published>2026-06-11T06:44:32.956+07:00</published><updated>2026-06-11T06:44:32.957+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CodeIgniter"/><category scheme="http://www.blogger.com/atom/ns#" term="Laravel"/><title type='text'>Laravel vs CodeIgniter ปี 2026 เลือกอะไรดี?</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiYCLpNf9hf_XQn3JBEWUVQU3w7ABqgApY_HeZMJortQ0WPv9wZU_nG3JnfgHIGd0JekIT0m6KCDZNnoytoR4Vq_XipQFz9idHpY9_5F8BzLtqpqWi4tqXpdsFx2bJErhTjNlVC7jDvW31ZzeNRiPeRX5F8RiT-8uYEqhwUAOMe1xgTYGB5LbJrzPLEMBM&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiYCLpNf9hf_XQn3JBEWUVQU3w7ABqgApY_HeZMJortQ0WPv9wZU_nG3JnfgHIGd0JekIT0m6KCDZNnoytoR4Vq_XipQFz9idHpY9_5F8BzLtqpqWi4tqXpdsFx2bJErhTjNlVC7jDvW31ZzeNRiPeRX5F8RiT-8uYEqhwUAOMe1xgTYGB5LbJrzPLEMBM&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;header class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(15, 17, 23) 0%, rgb(26, 31, 46) 50%, rgb(15, 17, 23) 100%) rgb(248, 249, 251); border-radius: 12px; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 40px; overflow: hidden; padding: 52px 40px; position: relative;&quot;&gt;&lt;p class=&quot;hero-eyebrow&quot; style=&quot;box-sizing: border-box; color: #f05340; font-size: 11px; font-weight: 600; letter-spacing: 2.5px; margin: 0px 0px 16px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP Code Mania · Framework Showdown&lt;/p&gt;&lt;h1 style=&quot;box-sizing: border-box; color: white; font-size: clamp(1.8rem, 4vw, 2.6rem); line-height: 1.3; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Laravel &lt;span class=&quot;vs&quot; style=&quot;box-sizing: border-box; color: #f05340; margin: 0px; padding: 0px;&quot;&gt;vs&lt;/span&gt; CodeIgniter&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;ปี 2026 เลือกอะไรดี?&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #94a3b8; font-size: 15px; line-height: 1.7; margin: 0px 0px 14px; max-width: 560px; padding: 0px;&quot;&gt;เปรียบเทียบแบบ Developer-to-Developer: สองกรอบงาน PHP ที่ครองตลาดมาหลายสิบปี ตรงไหนเหมือน ตรงไหนต่าง และสถานการณ์ไหนควรเลือกอะไร&lt;/p&gt;&lt;div class=&quot;hero-badges&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 8px; margin: 24px 0px 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;badge badge-laravel&quot; style=&quot;align-items: center; background: rgba(240, 83, 64, 0.15); border-radius: 20px; border: 1px solid rgba(240, 83, 64, 0.3); box-sizing: border-box; color: #f87171; display: inline-flex; font-size: 11px; font-weight: 600; gap: 5px; letter-spacing: 0.5px; margin: 0px; padding: 4px 10px;&quot;&gt;Laravel 11&lt;/span&gt;&lt;span class=&quot;badge badge-ci&quot; style=&quot;align-items: center; background: rgba(37, 99, 235, 0.15); border-radius: 20px; border: 1px solid rgba(37, 99, 235, 0.3); box-sizing: border-box; color: #93c5fd; display: inline-flex; font-size: 11px; font-weight: 600; gap: 5px; letter-spacing: 0.5px; margin: 0px; padding: 4px 10px;&quot;&gt;CodeIgniter 4&lt;/span&gt;&lt;span class=&quot;badge badge-php&quot; style=&quot;align-items: center; background: rgba(124, 58, 237, 0.15); border-radius: 20px; border: 1px solid rgba(124, 58, 237, 0.3); box-sizing: border-box; color: #c4b5fd; display: inline-flex; font-size: 11px; font-weight: 600; gap: 5px; letter-spacing: 0.5px; margin: 0px; padding: 4px 10px;&quot;&gt;PHP 8.3+&lt;/span&gt;&lt;/div&gt;&lt;/header&gt;&lt;section style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ถ้าคุณเริ่มต้นเขียน PHP หรือกำลังหา Framework ตัวใหม่สำหรับโปรเจกต์ถัดไป คำถามที่แทบทุกคนต้องเจอคือ — &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Laravel หรือ CodeIgniter ดีกว่ากัน?&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ตอบตรง ๆ ก็คือ ไม่มีคำตอบที่ถูกที่สุดสำหรับทุกคน แต่มีคำตอบที่ถูกที่สุด &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;สำหรับโปรเจกต์ของคุณ&lt;/em&gt; บทความนี้จะพา Walk-through ทั้งสอง Framework แบบตรงประเด็น พร้อม Code Example จริง ๆ เพื่อให้คุณตัดสินใจได้โดยไม่ต้องเดา&lt;/p&gt;&lt;div class=&quot;callout callout-info&quot; style=&quot;background: rgb(239, 246, 255); border-bottom-color: rgb(59, 130, 246); border-left: 4px solid rgb(59, 130, 246); border-radius: 6px; border-right-color: rgb(59, 130, 246); border-top-color: rgb(59, 130, 246); box-sizing: border-box; color: #1e3a5f; font-size: 14px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;p class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 700; margin: 0px 0px 4px; padding: 0px;&quot;&gt;🎯 บทความนี้เหมาะสำหรับใคร?&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a1f2e; margin: 0px 0px 14px; padding: 0px;&quot;&gt;นักพัฒนา PHP ที่เริ่มต้นหรือมีประสบการณ์ระดับกลาง ที่กำลังเลือก Framework สำหรับโปรเจกต์ใหม่ หรือพิจารณา Migrate จาก CI3 ขึ้นไป CI4 หรือ Laravel&lt;/p&gt;&lt;/div&gt;&lt;/section&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;🔍&lt;/span&gt; รู้จักทั้งสองก่อน&lt;/h2&gt;&lt;div class=&quot;framework-intro&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; display: grid; font-family: Sarabun, sans-serif; font-size: 16px; gap: 16px; grid-template-columns: 1fr 1fr; margin: 24px 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;fw-card laravel&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(240, 83, 64) rgb(226, 230, 239) rgb(226, 230, 239); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 3px 1px 1px; box-sizing: border-box; margin: 0px; padding: 24px;&quot;&gt;&lt;p class=&quot;fw-card-logo&quot; style=&quot;box-sizing: border-box; color: #f05340; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; margin: 0px 0px 8px; padding: 0px; text-transform: uppercase;&quot;&gt;Laravel&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 0px 0px 10px; padding: 0px;&quot;&gt;The Artisan&#39;s Framework&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #5a6478; font-size: 13px; margin: 0px 0px 12px; padding: 0px;&quot;&gt;สร้างโดย Taylor Otwell ปี 2011 ดีไซน์มาเพื่อ &quot;ทำให้การเขียนโปรแกรมสนุก&quot; ด้วย Syntax ที่อ่านง่ายและ Ecosystem ที่ครบครัน&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px; padding: 0px 0px 0px 18px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Eloquent ORM (Expressive)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Artisan CLI + Migration&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Blade Template Engine&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Laravel Breeze/Jetstream Auth&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Queues, Events, Broadcasting&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class=&quot;fw-card ci&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(37, 99, 235) rgb(226, 230, 239) rgb(226, 230, 239); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 3px 1px 1px; box-sizing: border-box; margin: 0px; padding: 24px;&quot;&gt;&lt;p class=&quot;fw-card-logo&quot; style=&quot;box-sizing: border-box; color: #2563eb; font-size: 11px; font-weight: 700; letter-spacing: 1.5px; margin: 0px 0px 8px; padding: 0px; text-transform: uppercase;&quot;&gt;CodeIgniter 4&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; font-size: 1.1rem; margin: 0px 0px 10px; padding: 0px;&quot;&gt;The Pragmatic Choice&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; color: #5a6478; font-size: 13px; margin: 0px 0px 12px; padding: 0px;&quot;&gt;เริ่มต้นปี 2006 ปรัชญาคือ &quot;ทำให้น้อย แต่ทำให้ดี&quot; เน้น Footprint เล็ก เรียนรู้ง่าย และ Deploy ได้ทุกที่&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px; padding: 0px 0px 0px 18px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Query Builder (ตรงไปตรงมา)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Built-in Form Validation&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Lightweight (~2MB)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Spark CLI (CI4)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 5px; padding: 0px;&quot;&gt;Shared Hosting Friendly&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;🛣️&lt;/span&gt; Routing: วิธีกำหนด URL&lt;/h2&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;หัวใจสำคัญของ Web Framework คือวิธีจัดการ URL ทั้งสองทำได้ แต่ปรัชญาต่างกันชัดเจน&lt;/p&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;Laravel — Expressive Route Definition&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;routes/web.php · Laravel 11&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Basic Route&lt;/cm&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;/about&#39;&lt;/str&gt;, &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;function&lt;/kw&gt;() { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;return&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;view&lt;/cl&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;about&#39;&lt;/str&gt;); }); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Controller Route&lt;/cm&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;/users&#39;&lt;/str&gt;, [&lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;UserController&lt;/cl&gt;::&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;index&#39;&lt;/str&gt;]); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ RESTful Resource (7 routes ใน 1 บรรทัด!)&lt;/cm&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;resource&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/str&gt;, &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PostController&lt;/cl&gt;::&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt;); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Named Route + Middleware&lt;/cm&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Route&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;/dashboard&#39;&lt;/str&gt;, [&lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;DashboardController&lt;/cl&gt;::&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;index&#39;&lt;/str&gt;]) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;middleware&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;auth&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;name&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;dashboard&#39;&lt;/str&gt;);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;CodeIgniter 4 — Straightforward Routing&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;app/Config/Routes.php · CodeIgniter 4&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Basic Route&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;about&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;PagesController::about&#39;&lt;/str&gt;); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Controller Route&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;users&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;UserController::index&#39;&lt;/str&gt;); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ RESTful Resource&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;resource&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/str&gt;); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// ✅ Route Group พร้อม Filter (Middleware)&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;group&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;admin&#39;&lt;/str&gt;, [&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;filter&#39;&lt;/str&gt; =&amp;gt; &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;auth&#39;&lt;/str&gt;], &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;function&lt;/kw&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;) { &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;dashboard&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;AdminController::dashboard&#39;&lt;/str&gt;); &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$routes&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;get&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;users&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;AdminController::users&#39;&lt;/str&gt;); });&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout callout-tip&quot; style=&quot;background: rgb(240, 253, 244); border-bottom-color: rgb(34, 197, 94); border-left: 4px solid rgb(34, 197, 94); border-radius: 6px; border-right-color: rgb(34, 197, 94); border-top-color: rgb(34, 197, 94); box-sizing: border-box; color: #14532d; font-family: Sarabun, sans-serif; font-size: 14px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;p class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 700; margin: 0px 0px 4px; padding: 0px;&quot;&gt;💡 สรุป Routing&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a1f2e; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ทั้งสองรองรับ RESTful Resource Routing ได้ครบ Laravel อ่านเป็น Method Chain ได้ลื่นกว่า ส่วน CI4 อ่านตรงไปตรงมา ไม่มีความซับซ้อนซ่อนอยู่ใต้ Magic&lt;/p&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;🗄️&lt;/span&gt; Database: ORM vs Query Builder&lt;/h2&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;นี่คือจุดที่ทั้งสองต่างกันมากที่สุด Laravel ใช้ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Eloquent ORM&lt;/span&gt; ที่แมป Object กับ Database Table โดยตรง ส่วน CI4 ใช้ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Query Builder&lt;/span&gt; ที่ให้คุณควบคุม SQL ได้ใกล้ชิดกว่า&lt;/p&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;Laravel Eloquent ORM&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;app/Models/Post.php + Controller · Laravel&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// Model: กำหนด Relationship ครั้งเดียว ใช้ได้ตลอด&lt;/cm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/cl&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Model&lt;/cl&gt; { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$fillable&lt;/vr&gt; = [&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;body&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/str&gt;]; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/kw&gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;user&lt;/fn&gt;(): &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;BelongsTo&lt;/cl&gt; { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;return&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;belongsTo&lt;/fn&gt;(&lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;User&lt;/cl&gt;::&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt;); } &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/kw&gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;tags&lt;/fn&gt;(): &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;BelongsToMany&lt;/cl&gt; { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;return&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;belongsToMany&lt;/fn&gt;(&lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Tag&lt;/cl&gt;::&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt;); } } &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// Controller: ดึงข้อมูลพร้อม Relationship แบบ Eager Load&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/vr&gt; = &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;with&lt;/fn&gt;([&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;tags&#39;&lt;/str&gt;]) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;where&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;published&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;latest&lt;/fn&gt;() -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;paginate&lt;/fn&gt;(&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;10&lt;/nm&gt;); &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// สร้าง Record ใหม่ — ง่ายมาก&lt;/cm&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/cl&gt;::&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;create&lt;/fn&gt;([ &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/str&gt; =&amp;gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/vr&gt;-&amp;gt;title, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;body&#39;&lt;/str&gt; =&amp;gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$request&lt;/vr&gt;-&amp;gt;body, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/str&gt; =&amp;gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;auth&lt;/fn&gt;()-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;id&lt;/fn&gt;(), ]);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;CodeIgniter 4 Query Builder&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;app/Models/PostModel.php · CodeIgniter 4&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PostModel&lt;/cl&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;extends&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Model&lt;/cl&gt; { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/vr&gt; = &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/str&gt;; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$allowedFields&lt;/vr&gt; = [&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;body&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/str&gt;]; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;protected&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$returnType&lt;/vr&gt; = &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;array&#39;&lt;/str&gt;; &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// หรือ &#39;object&#39; ก็ได้&lt;/cm&gt; &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// Custom method ดึง Published Posts&lt;/cm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;public function&lt;/kw&gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;getPublished&lt;/fn&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$limit&lt;/vr&gt; = &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;10&lt;/nm&gt;): &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;array&lt;/kw&gt; { &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;return&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt; -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;select&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts.*, users.name as author_name&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;join&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;users&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;users.id = posts.user_id&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;where&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts.status&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;published&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;orderBy&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;posts.created_at&#39;&lt;/str&gt;, &lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;DESC&#39;&lt;/str&gt;) -&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;paginate&lt;/fn&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$limit&lt;/vr&gt;); } } &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;// Controller: ใช้งาน Model&lt;/cm&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/vr&gt; = &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;new&lt;/kw&gt; &lt;cl style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;PostModel&lt;/cl&gt;(); &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/vr&gt; = &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;getPublished&lt;/fn&gt;(&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;10&lt;/nm&gt;); &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$pager&lt;/vr&gt; = &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$model&lt;/vr&gt;-&amp;gt;pager;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;🎨&lt;/span&gt; Template Engine: Blade vs PHP Native&lt;/h2&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;Laravel มาพร้อม &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Blade&lt;/span&gt; ซึ่งเป็น Template Engine ที่ทรงพลังมาก ส่วน CI4 ใช้ PHP ปกติ (มี Parser ให้ด้วย แต่คนส่วนใหญ่ใช้ PHP อยู่ดี)&lt;/p&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;Laravel Blade Template&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;resources/views/posts/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@extends&lt;/nm&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;layouts.app&#39;&lt;/str&gt;) &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@section&lt;/nm&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/str&gt;) &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class=&lt;/nm&gt;&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;container&quot;&lt;/str&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@foreach&lt;/nm&gt; (&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/vr&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;as&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;) &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;article&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h2&amp;gt;&lt;/nm&gt;{{ &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;-&amp;gt;title }}&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&amp;gt;&lt;/nm&gt;โดย: {{ &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;-&amp;gt;user-&amp;gt;name }}&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@if&lt;/nm&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;-&amp;gt;tags-&amp;gt;count()) &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@foreach&lt;/nm&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;-&amp;gt;tags &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;as&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$tag&lt;/vr&gt;) &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;span&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class=&lt;/nm&gt;&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;tag&quot;&lt;/str&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/nm&gt;{{ &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$tag&lt;/vr&gt;-&amp;gt;name }}&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/span&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@endforeach&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@endif&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/article&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@endforeach&lt;/nm&gt; &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;{{-- Pagination ใน 1 บรรทัด --}}&lt;/cm&gt; {{ &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;links&lt;/fn&gt;() }} &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;@endsection&lt;/nm&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.1rem; margin: 24px 0px 10px; padding: 0px;&quot;&gt;CodeIgniter 4 View (PHP Native)&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(15, 17, 23); border-radius: 12px; border: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 20px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 39); border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;code-dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 10px; margin: 0px; padding: 0px; width: 10px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;code-label&quot; style=&quot;box-sizing: border-box; color: #475569; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; letter-spacing: 0.5px; margin: 0px; padding: 0px;&quot;&gt;app/Views/posts/index.php · CodeIgniter 4&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; margin: 0px; overflow-x: auto; padding: 20px 22px;&quot;&gt;&lt;code style=&quot;box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;!-- Include Header --&amp;gt;&lt;/cm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;extend&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;layouts/main&#39;&lt;/str&gt;); &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;section&lt;/fn&gt;(&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/str&gt;); &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;div&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;class=&lt;/nm&gt;&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;container&quot;&lt;/str&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/nm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php foreach&lt;/kw&gt; (&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/vr&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;as&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;): &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;article&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;h2&amp;gt;&lt;/nm&gt;&lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?=&lt;/kw&gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;esc&lt;/fn&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;[&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/str&gt;]) &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;p&amp;gt;&lt;/nm&gt;โดย: &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?=&lt;/kw&gt; &lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;esc&lt;/fn&gt;(&lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/vr&gt;[&lt;str style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&#39;author_name&#39;&lt;/str&gt;]) &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt;&lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/p&amp;gt;&lt;/nm&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/article&amp;gt;&lt;/nm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php endforeach; ?&amp;gt;&lt;/kw&gt; &lt;cm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;!-- Pagination --&amp;gt;&lt;/cm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?=&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$pager&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;links&lt;/fn&gt;() &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt; &lt;nm style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/nm&gt; &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;?php&lt;/kw&gt; &lt;vr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;$this&lt;/vr&gt;-&amp;gt;&lt;fn style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;endSection&lt;/fn&gt;(); &lt;kw style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;?&amp;gt;&lt;/kw&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f8f9fb; border-color: rgb(226, 230, 239) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 16px; margin: 36px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;📊&lt;/span&gt; ตารางเปรียบเทียบฉบับสมบูรณ์&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;background-color: #f8f9fb; border-color: rgb(226, 230, 239); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-shadow: rgba(0, 0, 0, 0.05) 0px 2px 8px; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 24px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 14px; margin: 0px; padding: 0px; width: 818px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: rgb(15, 17, 23); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #94a3b8; font-size: 12px; letter-spacing: 0.8px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #fca5a5; font-size: 12px; letter-spacing: 0.8px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;🔴 Laravel 11&lt;/th&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(30, 37, 56); box-sizing: border-box; color: #93c5fd; font-size: 12px; letter-spacing: 0.8px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;🔵 CodeIgniter 4&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Learning Curve&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;สูง — มี Concept เยอะ (IoC, Facades, Service Provider)&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-c&quot; style=&quot;align-items: center; box-sizing: border-box; color: #2563eb; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ ต่ำกว่า&lt;/span&gt; — เริ่มต้นได้ภายในวันเดียว&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Performance&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ช้ากว่าเล็กน้อย (Framework Overhead มากกว่า)&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-c&quot; style=&quot;align-items: center; box-sizing: border-box; color: #2563eb; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ เร็วกว่า&lt;/span&gt; — Footprint เล็ก ~2MB&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ORM / Database&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Eloquent ORM&lt;/span&gt; — Relationship ทำงานได้งดงาม&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Query Builder — ควบคุม SQL ได้ใกล้ชิดกว่า&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Template Engine&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Blade&lt;/span&gt; — ทรงพลัง, มี Component &amp;amp; Directive&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;PHP Native (มี Parser แต่นิยมน้อย)&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Authentication&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Built-in Breeze/Jetstream&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ต้องเขียนเอง หรือใช้ Shield Library&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;CLI Tools&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Artisan&lt;/span&gt; — Command มากมาย&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Spark CLI — พื้นฐาน ครอบคลุมพอดี&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Ecosystem &amp;amp; Packages&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ ใหญ่มาก&lt;/span&gt; — Forge, Vapor, Nova, Octane&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;เล็กกว่า แต่เพียงพอสำหรับงานส่วนใหญ่&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Testing Support&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ PHPUnit + Pest&lt;/span&gt; พร้อม HTTP Testing Helpers&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;PHPUnit รองรับ แต่ Helper น้อยกว่า&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Shared Hosting&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ยากขึ้น (ต้องการ Composer, PHP 8.2+)&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-c&quot; style=&quot;align-items: center; box-sizing: border-box; color: #2563eb; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ ง่ายกว่า&lt;/span&gt; — รันบน Hosting ทั่วไปได้สบาย&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Real-time / WebSocket&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Laravel Echo + Broadcasting&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ต้องใช้ Library ภายนอก&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;API Development&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Sanctum/Passport&lt;/span&gt; Token Auth ในตัว&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;รองรับ แต่ต้องเซ็ต Token เอง&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Migration/Schema&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ Version-controlled Migration&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Forge Migration มีใน CI4 แต่น้อยกว่า&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom: 1px solid rgb(226, 230, 239); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Documentation&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-tie&quot; style=&quot;align-items: center; box-sizing: border-box; color: #059669; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;≈ ทั้งคู่ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-tie&quot; style=&quot;align-items: center; box-sizing: border-box; color: #059669; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;≈ ทั้งคู่ดีมาก&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 600; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Community Size&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;win win-l&quot; style=&quot;align-items: center; box-sizing: border-box; color: #f05340; display: inline-flex; font-weight: 600; gap: 4px; margin: 0px; padding: 0px;&quot;&gt;✓ ใหญ่กว่า&lt;/span&gt; — GitHub Stars สูงกว่ามาก&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Active Community ขนาดกลาง&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;🧭&lt;/span&gt; คุณควรเลือกอะไร?&lt;/h2&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;แทนที่จะบอกว่าอันไหน &quot;ดีกว่า&quot; ขอให้ดูที่ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;โปรเจกต์และทีมของคุณ&lt;/span&gt; เป็นตัวตัดสิน&lt;/p&gt;&lt;div class=&quot;decision-grid&quot; style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; display: grid; font-family: Sarabun, sans-serif; font-size: 16px; gap: 16px; grid-template-columns: 1fr 1fr; margin: 24px 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;decision-card pick-laravel&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 230, 239); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 0px; padding: 22px;&quot;&gt;&lt;h4 style=&quot;border-bottom: 2px solid rgb(240, 83, 64); border-left-color: rgb(240, 83, 64); border-right-color: rgb(240, 83, 64); border-top-color: rgb(240, 83, 64); box-sizing: border-box; color: #f05340; font-size: 14px; margin: 0px 0px 12px; padding: 0px 0px 8px;&quot;&gt;🔴 เลือก Laravel เมื่อ...&lt;/h4&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px; padding: 0px 0px 0px 18px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ต้องการ Full-featured Application ที่มีทั้ง Auth, Queue, Event, API พร้อมกัน&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ทีมมีเวลาเรียนรู้ และพร้อมลงทุนระยะยาว&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;โปรเจกต์ขนาดใหญ่ เช่น SaaS, E-commerce, Enterprise System&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ต้องการ Real-time Feature (WebSocket, Notification)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ต้องการ Ecosystem ครบวงจร (Forge, Vapor, Nova)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class=&quot;decision-card pick-ci&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(226, 230, 239); border-image: none 100% / 1 / 0 stretch; border-radius: 12px; border-style: solid; border-width: 1px; box-sizing: border-box; margin: 0px; padding: 22px;&quot;&gt;&lt;h4 style=&quot;border-bottom: 2px solid rgb(37, 99, 235); border-left-color: rgb(37, 99, 235); border-right-color: rgb(37, 99, 235); border-top-color: rgb(37, 99, 235); box-sizing: border-box; color: #2563eb; font-size: 14px; margin: 0px 0px 12px; padding: 0px 0px 8px;&quot;&gt;🔵 เลือก CodeIgniter 4 เมื่อ...&lt;/h4&gt;&lt;ul style=&quot;box-sizing: border-box; margin: 0px; padding: 0px 0px 0px 18px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;โปรเจกต์ขนาดเล็ก-กลาง ต้องการความเร็วในการ Deliver&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ทีมหรือนักพัฒนาเพิ่งเริ่มต้นกับ PHP Framework&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;จำเป็นต้อง Deploy บน Shared Hosting หรือ Server ธรรมดา&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;ต้องการ Performance สูงสุดด้วย Resource น้อย&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; color: #5a6478; font-size: 14px; margin: 0px 0px 8px; padding: 0px;&quot;&gt;Migrate จาก CI3 ขึ้นมา (ความคุ้นเคยช่วยมาก)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;callout callout-warning&quot; style=&quot;background: rgb(255, 251, 235); border-bottom-color: rgb(245, 158, 11); border-left: 4px solid rgb(245, 158, 11); border-radius: 6px; border-right-color: rgb(245, 158, 11); border-top-color: rgb(245, 158, 11); box-sizing: border-box; color: #78350f; font-family: Sarabun, sans-serif; font-size: 14px; line-height: 1.7; margin: 20px 0px; padding: 16px 20px;&quot;&gt;&lt;p class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #1a1f2e; font-weight: 700; margin: 0px 0px 4px; padding: 0px;&quot;&gt;⚠️ สำหรับนักพัฒนา CI3 ที่กำลังพิจารณา&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #1a1f2e; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ถ้าคุณใช้ CI3 อยู่และกำลังจะ Upgrade — &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;CI4 คือก้าวแรกที่สมเหตุสมผลที่สุด&lt;/span&gt; เพราะ Architecture คล้ายกัน แต่ปรับปรุงให้รองรับ PHP 8.x อย่างเต็มที่ ส่วนการข้ามไป Laravel ทันทีนั้นเป็นไปได้ แต่ต้องใช้เวลาเรียนรู้ Concept ใหม่ทั้งหมด&lt;/p&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f8f9fb; border-bottom: 2px solid rgb(226, 230, 239); box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 40px 0px 14px; padding: 0px 0px 10px;&quot;&gt;&lt;span class=&quot;icon&quot; style=&quot;box-sizing: border-box; margin: 0px 8px 0px 0px; padding: 0px;&quot;&gt;✅&lt;/span&gt; สรุป&lt;/h2&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;ทั้ง Laravel และ CodeIgniter 4 ต่างเป็น PHP Framework คุณภาพสูงที่ยังมีการพัฒนาอย่างต่อเนื่องในปี 2026 ไม่มีคำตอบ Universal ที่ถูกสำหรับทุกคน&lt;/p&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/span&gt; ชนะด้วยความครบครันของ Feature, Ecosystem ขนาดใหญ่ และ Developer Experience ที่ดีเยี่ยม เหมาะกับโปรเจกต์ที่ต้องการ Scale และทีมที่พร้อมลงทุนเวลาเรียนรู้&lt;/p&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/span&gt; ชนะด้วยความเรียบง่าย, Performance, และความง่ายในการ Deploy เหมาะกับโปรเจกต์ที่ต้องการ Deliver เร็ว หรือทีมที่มาจาก Background CI เดิม&lt;/p&gt;&lt;p style=&quot;background-color: #f8f9fb; box-sizing: border-box; color: #1a1f2e; font-family: Sarabun, sans-serif; font-size: 16px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;สิ่งที่สำคัญที่สุดคือ &lt;span style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;เลือก Framework ที่คุณจะเขียนมันจริง ๆ&lt;/span&gt; Framework ที่ดีที่สุดคือที่ช่วยให้คุณ Ship โปรเจกต์ได้ ไม่ใช่ที่อยู่ใน Wishlist&lt;span style=&quot;background-color: transparent; color: #674ea7; text-align: center;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: #e06666; text-align: center;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: #c27ba0; text-align: center;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: #d5a6bd; text-align: center;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: #674ea7; text-align: center;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: orange; text-align: center;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/p&gt; &lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/2608854519938039366/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-vs-codeigniter-2026.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/2608854519938039366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/2608854519938039366'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-vs-codeigniter-2026.html' title='Laravel vs CodeIgniter ปี 2026 เลือกอะไรดี?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiYCLpNf9hf_XQn3JBEWUVQU3w7ABqgApY_HeZMJortQ0WPv9wZU_nG3JnfgHIGd0JekIT0m6KCDZNnoytoR4Vq_XipQFz9idHpY9_5F8BzLtqpqWi4tqXpdsFx2bJErhTjNlVC7jDvW31ZzeNRiPeRX5F8RiT-8uYEqhwUAOMe1xgTYGB5LbJrzPLEMBM=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-6979638803918936715</id><published>2026-06-10T17:00:00.000+07:00</published><updated>2026-06-10T17:00:00.109+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Laravel"/><title type='text'>เพิ่มความเร็ว Laravel สำหรับ High-Traffic Database Optimization ที่นักพัฒนา 90% ยังไม่รู้</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEilZfeMMQDSranfR-2wyWNnacBPLGFAGTTPQG4pabm-RrzNORL2zSKiOb93OP6iiYAFN4KRD08tG-Wh-qm2_dvbxQWHj43ox-vtJfF9rQfT13b9QtMtcwcaQ9vjcQKtuaeTGp56N1aOAdsOdxTU6qv2DvkkFwbZroGngvAWLHYjFPTUgPkdUdcDfkOFng8&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEilZfeMMQDSranfR-2wyWNnacBPLGFAGTTPQG4pabm-RrzNORL2zSKiOb93OP6iiYAFN4KRD08tG-Wh-qm2_dvbxQWHj43ox-vtJfF9rQfT13b9QtMtcwcaQ9vjcQKtuaeTGp56N1aOAdsOdxTU6qv2DvkkFwbZroGngvAWLHYjFPTUgPkdUdcDfkOFng8&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt; &lt;div class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(30, 37, 53) 0%, rgb(45, 58, 82) 60%, rgb(59, 79, 114) 100%) rgb(248, 249, 252); border-radius: 16px; box-sizing: border-box; color: #1e2535; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 48px; overflow: hidden; padding: 48px 40px 44px; position: relative;&quot;&gt;&lt;div class=&quot;hero-eyebrow&quot; style=&quot;background: rgba(99, 179, 237, 0.18); border-radius: 20px; border: 1px solid rgba(99, 179, 237, 0.25); box-sizing: border-box; color: #63b3ed; display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: 1.6px; margin: 0px 0px 18px; padding: 4px 12px; text-transform: uppercase;&quot;&gt;Laravel Performance Series · EP.1&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; color: #f0f4ff; font-size: clamp(22px, 4vw, 30px); line-height: 1.4; margin: 0px 0px 16px; padding: 0px;&quot;&gt;เพิ่มความเร็ว Laravel สำหรับ &lt;span style=&quot;box-sizing: border-box; color: #63b3ed; margin: 0px; padding: 0px;&quot;&gt;High-Traffic&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;Database Optimization ที่นักพัฒนา 90% ยังไม่รู้&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #9db4cc; font-size: 15px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;ตั้งแต่ N+1 Query, Eager Loading, Indexing ไปจนถึง Route/Config Caching — ทุก Technique ในบทความเดียว&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 20px; margin: 24px 0px 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; color: #7a95b0; display: flex; font-size: 13px; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot&quot; style=&quot;align-items: center; background: rgb(99, 179, 237); border-radius: 50%; box-sizing: border-box; display: flex; flex-shrink: 0; gap: 6px; height: 6px; margin: 0px; padding: 0px; width: 6px;&quot;&gt;&lt;/span&gt;อ่านประมาณ 8 นาที&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; color: #7a95b0; display: flex; font-size: 13px; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot&quot; style=&quot;align-items: center; background: rgb(99, 179, 237); border-radius: 50%; box-sizing: border-box; display: flex; flex-shrink: 0; gap: 6px; height: 6px; margin: 0px; padding: 0px; width: 6px;&quot;&gt;&lt;/span&gt;Laravel 10 / 11&lt;/span&gt;&lt;span style=&quot;align-items: center; box-sizing: border-box; color: #7a95b0; display: flex; font-size: 13px; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot&quot; style=&quot;align-items: center; background: rgb(99, 179, 237); border-radius: 50%; box-sizing: border-box; display: flex; flex-shrink: 0; gap: 6px; height: 6px; margin: 0px; padding: 0px; width: 6px;&quot;&gt;&lt;/span&gt;ระดับ Beginner → Intermediate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;series-tag&quot; style=&quot;align-items: center; background: rgb(240, 244, 255); border-radius: 20px; border: 1px solid rgb(199, 212, 237); box-sizing: border-box; color: #3b4f72; display: inline-flex; font-family: Sarabun, sans-serif; font-size: 13px; font-weight: 600; gap: 8px; margin: 0px 0px 32px; padding: 6px 14px;&quot;&gt;📚 PHP Code Mania — Laravel Optimization Series&lt;/div&gt;&lt;span face=&quot;Sarabun, sans-serif&quot; style=&quot;background-color: #f8f9fc; color: #1e2535; font-size: 17px;&quot;&gt;&lt;/span&gt;&lt;div class=&quot;prose&quot; style=&quot;background-color: #f8f9fc; box-sizing: border-box; color: #1e2535; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px; padding: 0px;&quot;&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;ทำไม Laravel ถึง &quot;คิดนาน&quot; เกินไป?&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ลองนึกภาพว่าคุณเปิดร้านอาหาร แต่ทุกครั้งที่ลูกค้าสั่งข้าว พ่อครัวต้องไปอ่านสูตรอาหารใหม่ทุกครั้ง นั่นคือสิ่งที่เกิดขึ้นกับ Laravel ที่ไม่ได้ optimize — Framework กำลังทำงานซ้ำๆ ที่ไม่จำเป็นในทุก Request&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ปัญหาหลักที่ทำให้ Laravel Application ช้าในสภาพแวดล้อม Production มักจะมาจาก 3 แหล่ง ได้แก่ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;N+1 Query Problem&lt;/strong&gt;, &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Missing Database Index&lt;/strong&gt;, และ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Framework overhead ที่ไม่จำเป็น&lt;/strong&gt; บทความนี้จะพาไปแก้ทีละจุด พร้อม Code Example ที่ใช้ได้จริง&lt;/p&gt;&lt;div class=&quot;callout info&quot; style=&quot;align-items: flex-start; background: rgb(235, 248, 255); border-left: 4px solid rgb(59, 130, 246); border-radius: 10px; box-sizing: border-box; display: flex; gap: 14px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;💡&lt;/span&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; font-size: 15.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;เหมาะสำหรับใคร?&lt;/strong&gt; นักพัฒนาที่ใช้ Laravel (หรือ CodeIgniter 4) ที่เริ่มพบปัญหา Application ช้าเมื่อมี User มากขึ้น หรืออยากเตรียมรับมือตั้งแต่ต้น&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;1. ปัญหา N+1 Query — ศัตรูเงียบของ Database&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;N+1 Problem คือปัญหาที่พบบ่อยที่สุดใน ORM ทุกตัว รวมถึง Laravel Eloquent เกิดขึ้นเมื่อโค้ดดึงข้อมูล Parent แล้ว Loop ดึง Child ทีละรายการ&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;❌ โค้ดที่มีปัญหา (N+1)&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Eloquent (Bad)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ดึง Posts ทั้งหมด → 1 Query&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;all&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;) { &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ดึง Author ของแต่ละ Post → N Queries!&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;; } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ถ้ามี 100 Posts = 1 + 100 = 101 Queries 🔥&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;✅ แก้ด้วย Eager Loading&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Eloquent (Good)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// with() โหลด Author พร้อมกันใน 1 Query เพิ่ม&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;author&#39;&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;) { &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;name&lt;/span&gt;; } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 100 Posts = 2 Queries เท่านั้น ✅&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;✅ Nested Eager Loading (Relationship ซ้อนกัน)&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Eloquent&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// โหลด author และ comments ของแต่ละ post พร้อมกัน&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;author&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;comments.user&#39;&lt;/span&gt;])&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เลือกเฉพาะ Column ที่ต้องการ เพื่อลด Memory&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;([ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;author:id,name,avatar&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;comments&#39;&lt;/span&gt; &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;fn&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$q&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$q&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;latest&lt;/span&gt;()&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;limit&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;) ])&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;paginate&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;20&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout tip&quot; style=&quot;align-items: flex-start; background: rgb(240, 255, 244); border-left: 4px solid rgb(16, 185, 129); border-radius: 10px; box-sizing: border-box; display: flex; gap: 14px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;🛠️&lt;/span&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; font-size: 15.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;ติดตั้ง &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;barryvdh/laravel-debugbar&lt;/code&gt; หรือ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;spatie/laravel-query-detector&lt;/code&gt; เพื่อจับ N+1 Query ใน Development โดยอัตโนมัติ&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;2. Database Indexing — ทำ Query ให้เร็วขึ้น 100x&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;Index คือ &quot;สารบัญ&quot; ของตาราง Database ถ้าไม่มี Index MySQL ต้องสแกนทุก Row เพื่อหาข้อมูลที่ต้องการ (Full Table Scan) ซึ่งช้ามากเมื่อข้อมูลมีหลายล้านแถว&lt;/p&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;เพิ่ม Index ผ่าน Laravel Migration&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Migration&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Schema&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;create&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Blueprint&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;) { &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;id&lt;/span&gt;(); &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;foreignId&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;constrained&lt;/span&gt;(); &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;slug&#39;&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;unique&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Unique Index&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/span&gt;); &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;timestamp&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;nullable&lt;/span&gt;(); &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;timestamps&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Composite Index — Query บ่อยด้วย 2 Column นี้พร้อมกัน&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;]); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Index สำหรับ Foreign Key&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;); });&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;เพิ่ม Index ให้ตารางที่มีอยู่แล้ว&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Migration (Add Index)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Schema&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;table&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Blueprint&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;) { &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;idx_posts_user_id&#39;&lt;/span&gt;); &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$table&lt;/span&gt;&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;index&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;idx_posts_status_date&#39;&lt;/span&gt;); });&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout warn&quot; style=&quot;align-items: flex-start; background: rgb(255, 248, 225); border-left: 4px solid rgb(245, 158, 11); border-radius: 10px; box-sizing: border-box; display: flex; gap: 14px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;⚠️&lt;/span&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; font-size: 15.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;ใส่ Index มากเกินไปก็ไม่ดี เพราะ INSERT/UPDATE จะช้าลง ใส่เฉพาะ Column ที่ใช้ใน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;WHERE&lt;/code&gt;, &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;ORDER BY&lt;/code&gt;, &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;JOIN&lt;/code&gt; เท่านั้น&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;3. Select เฉพาะ Column ที่ต้องการ — อย่าดึง * ทุกครั้ง&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;การใช้ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;Post::all()&lt;/code&gt; หรือ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;select *&lt;/code&gt; จะดึงข้อมูลทุก Column แม้แต่ Column ที่หนัก เช่น &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;content&lt;/code&gt; หรือ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;metadata&lt;/code&gt; ที่ไม่ได้ใช้&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Eloquent&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ❌ ดึงข้อมูลทั้งหมด รวมถึง Column ที่ไม่ใช้&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;all&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ เลือกเฉพาะที่ต้องการ&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;select&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;id&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;slug&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;status&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published&#39;&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;latest&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published_at&#39;&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;paginate&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;15&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ ใช้ cursor() สำหรับ Large Dataset แทน get()&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;select&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;id&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;cursor&lt;/span&gt;()&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;each&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; (&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;) { &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Process ทีละ Row ไม่โหลด Memory ทั้งหมดพร้อมกัน&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;processPost&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$post&lt;/span&gt;); });&lt;/pre&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;4. Route &amp;amp; Config Cache — เคล็ดลับ 30ms ที่คนมองข้าม&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;โดย Default ทุกครั้งที่มี HTTP Request เข้ามา Laravel จะทำการ compile Regex Pattern ของทุก Route และสร้าง Routing Table ใน Memory ใหม่ทุกครั้ง ถ้ามี 200 Routes และ Request 1 ล้านครั้งต่อวัน นั่นหมายถึง CPU เสียไปกว่า 8 ชั่วโมง เพียงเพื่อหาว่าต้องเรียก Controller ไหน&lt;/p&gt;&lt;div class=&quot;stat-row&quot; style=&quot;box-sizing: border-box; display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin: 28px 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;stat-card&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 12px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.04) 0px 2px 8px; box-sizing: border-box; margin: 0px; padding: 22px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;num bad&quot; style=&quot;box-sizing: border-box; color: #ef4444; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 32px; font-weight: 700; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;~30ms&lt;/div&gt;&lt;div class=&quot;label&quot; style=&quot;box-sizing: border-box; color: #718096; font-size: 13px; margin: 6px 0px 0px; padding: 0px;&quot;&gt;Routing Overhead (ไม่มี Cache)&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;stat-card&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 12px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.04) 0px 2px 8px; box-sizing: border-box; margin: 0px; padding: 22px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;num good&quot; style=&quot;box-sizing: border-box; color: #10b981; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 32px; font-weight: 700; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;~2ms&lt;/div&gt;&lt;div class=&quot;label&quot; style=&quot;box-sizing: border-box; color: #718096; font-size: 13px; margin: 6px 0px 0px; padding: 0px;&quot;&gt;Routing Overhead (มี Cache)&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;stat-card&quot; style=&quot;background: rgb(255, 255, 255); border-radius: 12px; border: 1px solid rgb(226, 232, 240); box-shadow: rgba(0, 0, 0, 0.04) 0px 2px 8px; box-sizing: border-box; margin: 0px; padding: 22px 20px; text-align: center;&quot;&gt;&lt;div class=&quot;num good&quot; style=&quot;box-sizing: border-box; color: #10b981; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 32px; font-weight: 700; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;15×&lt;/div&gt;&lt;div class=&quot;label&quot; style=&quot;box-sizing: border-box; color: #718096; font-size: 13px; margin: 6px 0px 0px; padding: 0px;&quot;&gt;เร็วขึ้นด้วย Command เดียว&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;คำสั่ง Optimize สำหรับ Production&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;Shell · Artisan&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# คำสั่งเดียวที่ครอบคลุม &quot;Big Four&quot; Cache&lt;/span&gt; php artisan optimize &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# เทียบเท่ากับการรันพร้อมกัน 4 คำสั่งนี้:&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# php artisan config:cache&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# php artisan route:cache&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# php artisan view:cache&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# php artisan event:cache&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# ล้าง Cache ทั้งหมดก่อน (สำคัญมาก!)&lt;/span&gt; php artisan optimize:clear&lt;/pre&gt;&lt;/div&gt;&lt;h3 style=&quot;box-sizing: border-box; color: #2d3a52; font-size: 17px; margin: 28px 0px 10px; padding: 0px;&quot;&gt;ตัวอย่าง Deployment Script (CI/CD)&lt;/h3&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;Shell · Deploy Script&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;#!/bin/bash&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# deploy.sh — ใช้ใน GitHub Actions / GitLab CI&lt;/span&gt; composer install --no-dev --optimize-autoloader php artisan migrate --force php artisan optimize:clear &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# ล้างก่อนเสมอ&lt;/span&gt; php artisan optimize &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# Cache ใหม่&lt;/span&gt; php artisan storage:link&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout danger&quot; style=&quot;align-items: flex-start; background: rgb(255, 245, 245); border-left: 4px solid rgb(239, 68, 68); border-radius: 10px; box-sizing: border-box; display: flex; gap: 14px; margin: 24px 0px; padding: 18px 20px;&quot;&gt;&lt;span class=&quot;callout-icon&quot; style=&quot;box-sizing: border-box; flex-shrink: 0; font-size: 20px; margin: 1px 0px 0px; padding: 0px;&quot;&gt;🚨&lt;/span&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; font-size: 15.5px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;อย่าลืม &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;optimize:clear&lt;/code&gt; ก่อน Deploy ทุกครั้ง ถ้า Cache Route เก่าค้างอยู่ Route ใหม่จะ&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ไม่ทำงาน&lt;/strong&gt; จนกว่าจะ Clear Cache&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;5. Query Caching ด้วย Laravel Cache&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;สำหรับข้อมูลที่ไม่เปลี่ยนบ่อย เช่น Category, Setting, หรือ Dashboard Stats การ Cache ผลลัพธ์ Query ไว้ใน Redis/Memcached จะลด Database Load ได้มหาศาล&lt;/p&gt;&lt;div class=&quot;code-block&quot; style=&quot;background: rgb(13, 17, 23); border-radius: 12px; border: 1px solid rgb(33, 38, 45); box-shadow: rgba(0, 0, 0, 0.13) 0px 4px 24px; box-sizing: border-box; margin: 24px 0px 32px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-block-header&quot; style=&quot;align-items: center; background: rgb(22, 27, 34); border-bottom: 1px solid rgb(33, 38, 45); box-sizing: border-box; display: flex; justify-content: space-between; margin: 0px; padding: 10px 18px;&quot;&gt;&lt;div class=&quot;dots&quot; style=&quot;box-sizing: border-box; display: flex; gap: 6px; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; box-sizing: border-box; height: 11px; margin: 0px; padding: 0px; width: 11px;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #58a6ff; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 0px; text-transform: uppercase;&quot;&gt;PHP · Cache with Eloquent&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;box-sizing: border-box; color: #c9d1d9; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; line-height: 1.75; margin: 0px; overflow-x: auto; padding: 22px 24px;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Illuminate\Support\Facades\Cache&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Cache ผลลัพธ์ไว้ 60 นาที&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$categories&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Cache&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;remember&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;all_categories&#39;&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;3600&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Category&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;children&#39;&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;active&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;orderBy&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;sort_order&#39;&lt;/span&gt;) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(); }); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ล้าง Cache เมื่อข้อมูลเปลี่ยน (ใน Observer หรือ Service)&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Cache&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;forget&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;all_categories&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #8b949e; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// หรือใช้ Cache Tags (Redis เท่านั้น)&lt;/span&gt; &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;$posts&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Cache&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;tags&lt;/span&gt;([&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;posts&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;published&#39;&lt;/span&gt;]) &lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;remember&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #a5d6ff; margin: 0px; padding: 0px;&quot;&gt;&#39;homepage_posts&#39;&lt;/span&gt;, &lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;1800&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; () { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #ff7b72; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;box-sizing: border-box; color: #ffa657; margin: 0px; padding: 0px;&quot;&gt;Post&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;published&lt;/span&gt;()&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;latest&lt;/span&gt;()&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;nm&quot; style=&quot;box-sizing: border-box; color: #79c0ff; margin: 0px; padding: 0px;&quot;&gt;10&lt;/span&gt;)&lt;span class=&quot;op&quot; style=&quot;box-sizing: border-box; color: #f97316; margin: 0px; padding: 0px;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #d2a8ff; margin: 0px; padding: 0px;&quot;&gt;get&lt;/span&gt;(); });&lt;/pre&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;6. สรุปเปรียบเทียบ: ก่อน vs หลัง Optimize&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;box-sizing: border-box; margin: 28px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;background: rgb(255, 255, 255); border-collapse: collapse; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 12px; font-size: 14.5px; margin: 0px; overflow: hidden; padding: 0px; width: 732px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: rgb(30, 37, 53); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;box-sizing: border-box; color: #e2e8f0; font-size: 13px; letter-spacing: 0.4px; margin: 0px; padding: 13px 18px; text-align: left;&quot;&gt;Technique&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; color: #e2e8f0; font-size: 13px; letter-spacing: 0.4px; margin: 0px; padding: 13px 18px; text-align: left;&quot;&gt;ก่อน Optimize&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; color: #e2e8f0; font-size: 13px; letter-spacing: 0.4px; margin: 0px; padding: 13px 18px; text-align: left;&quot;&gt;หลัง Optimize&lt;/th&gt;&lt;th style=&quot;box-sizing: border-box; color: #e2e8f0; font-size: 13px; letter-spacing: 0.4px; margin: 0px; padding: 13px 18px; text-align: left;&quot;&gt;ผลลัพธ์&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;N+1 Query&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;101 Queries (100 posts)&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;2 Queries&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;-98%&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(247, 249, 252); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Route Cache&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;~30ms overhead/request&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;~2ms overhead/request&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;15× เร็วขึ้น&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Missing Index&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;Full Table Scan&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;Index Seek&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;สูงสุด 100×&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(247, 249, 252); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Select *&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;โหลดทุก Column&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;เฉพาะที่ต้องการ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-yellow&quot; style=&quot;background: rgb(254, 243, 199); border-radius: 20px; box-sizing: border-box; color: #92400e; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;ลด Memory&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Query Cache&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;DB Hit ทุก Request&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;Redis/Memory Hit&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(209, 250, 229); border-radius: 20px; box-sizing: border-box; color: #065f46; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;ลด DB Load 90%+&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(247, 249, 252); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ไม่มีอะไรเลย&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;App ช้า, DB เจ๊ง&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;—&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(232, 238, 248); box-sizing: border-box; color: #2d3a52; margin: 0px; padding: 12px 18px;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(254, 226, 226); border-radius: 20px; box-sizing: border-box; color: #991b1b; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 9px;&quot;&gt;ต้องแก้ด่วน!&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;7. Production Checklist ก่อน Go-Live&lt;/h2&gt;&lt;ul class=&quot;step-list&quot; style=&quot;box-sizing: border-box; color: #2e3a50; list-style: none; margin: 20px 0px 18px; padding: 0px 0px 0px 22px;&quot;&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;รัน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;php artisan telescope:install&lt;/code&gt; หรือ DebugBar ใน Dev เพื่อหา N+1 Queries&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;02&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;ตรวจ Migration ทุกตัร — มี Index บน Column ที่ใช้ใน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;WHERE&lt;/code&gt; และ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;JOIN&lt;/code&gt; ครบหรือยัง&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;เปลี่ยน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;APP_ENV=production&lt;/code&gt; และ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;APP_DEBUG=false&lt;/code&gt; ใน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;.env&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;04&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;รัน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;php artisan optimize&lt;/code&gt; ใน Deployment Script เสมอ&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;05&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;ตั้งค่า Redis เป็น Cache Driver และใช้ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;Cache::remember()&lt;/code&gt; สำหรับ Query ที่ดึงบ่อย&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 14px; margin: 0px 0px 14px; padding: 0px;&quot;&gt;&lt;span class=&quot;step-num&quot; style=&quot;align-items: center; background: rgb(30, 37, 53); border-radius: 50%; box-sizing: border-box; color: #63b3ed; display: flex; flex-shrink: 0; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 12px; font-weight: 700; height: 28px; justify-content: center; margin: 0px; padding: 0px; width: 28px;&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;step-text&quot; style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 3px 0px 0px;&quot;&gt;ใช้ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;paginate()&lt;/code&gt; แทน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;get()&lt;/code&gt; เสมอสำหรับ List ข้อมูล&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(99, 179, 237); box-sizing: border-box; font-size: 20px; line-height: 1.4; margin: 44px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;สรุป&lt;/h2&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;การ Optimize Laravel Application ไม่ได้ซับซ้อนอย่างที่คิด เพียงแค่เข้าใจต้นเหตุของปัญหา และใช้ Tool ที่ Framework มีให้อยู่แล้ว Techniques ที่พูดถึงในบทความนี้สามารถ ลด Query จาก 100+ เหลือ 2, ลด Routing Overhead ลง 15 เท่า และลด Database Load ได้มากกว่า 90%&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;จุดเริ่มต้นที่ดีที่สุดคือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;หา N+1 Query ก่อน&lt;/strong&gt; ติดตั้ง DebugBar รัน Application แล้วดูว่ามี Query ซ้ำกี่ตัว จากนั้นค่อยๆ ใส่ &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;with()&lt;/code&gt;, เพิ่ม Index, และสุดท้ายรัน &lt;code style=&quot;background: rgb(232, 238, 248); border-radius: 5px; border: 1px solid rgb(213, 223, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 13.5px; margin: 0px; padding: 2px 7px;&quot;&gt;php artisan optimize&lt;/code&gt; ก่อน Deploy&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #2e3a50; margin: 0px 0px 18px; padding: 0px;&quot;&gt;แค่นี้ Application ของคุณก็พร้อมรับ Traffic หนักๆ ได้แล้ว 🚀&lt;/p&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/6979638803918936715/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-high-traffic-database.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6979638803918936715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/6979638803918936715'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-high-traffic-database.html' title='เพิ่มความเร็ว Laravel สำหรับ High-Traffic Database Optimization ที่นักพัฒนา 90% ยังไม่รู้'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEilZfeMMQDSranfR-2wyWNnacBPLGFAGTTPQG4pabm-RrzNORL2zSKiOb93OP6iiYAFN4KRD08tG-Wh-qm2_dvbxQWHj43ox-vtJfF9rQfT13b9QtMtcwcaQ9vjcQKtuaeTGp56N1aOAdsOdxTU6qv2DvkkFwbZroGngvAWLHYjFPTUgPkdUdcDfkOFng8=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-3559716973291210109</id><published>2026-06-10T12:30:00.000+07:00</published><updated>2026-06-10T12:30:00.108+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Spring Boot API"/><title type='text'>เชื่อมต่อ Spring Boot API กับ Vanilla HTML/CSS/JS Frontend</title><content type='html'>&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEi81OT58ETFE2AemXa4Lf7vhm2IJA09NWGWB88MOhME4iVjMdVhVwo-u2BxDcPVGsPNxSCEFc03u1CTioFy66zz217nJojQclRcQXc2UUZu1JhH7ARm39OSJEamJCbNiVGQ4lpMk2xjpIG8bTZG-1SOapwmfXLmh-Tenxh8P_aiYA2nQ6-Zf-iRFR5X8Ak&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1536&quot; data-original-width=&quot;2752&quot; height=&quot;357&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEi81OT58ETFE2AemXa4Lf7vhm2IJA09NWGWB88MOhME4iVjMdVhVwo-u2BxDcPVGsPNxSCEFc03u1CTioFy66zz217nJojQclRcQXc2UUZu1JhH7ARm39OSJEamJCbNiVGQ4lpMk2xjpIG8bTZG-1SOapwmfXLmh-Tenxh8P_aiYA2nQ6-Zf-iRFR5X8Ak&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt; &lt;div class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(26, 60, 94) 0%, rgb(46, 125, 190) 100%) rgb(255, 255, 255); border-radius: 12px; box-sizing: border-box; color: white; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 44px; padding: 52px 40px 44px;&quot;&gt;&lt;span class=&quot;hero-tag&quot; style=&quot;box-sizing: border-box; color: #93c5fd; display: block; font-size: 12px; letter-spacing: 2px; margin: 0px 0px 14px; padding: 0px; text-transform: uppercase;&quot;&gt;Dev Blog · Spring Boot · Vanilla JS&lt;/span&gt;&lt;h1 style=&quot;box-sizing: border-box; font-size: 32px; line-height: 1.3; margin: 0px 0px 14px; padding: 0px;&quot;&gt;เชื่อมต่อ Spring Boot API&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;กับ Vanilla HTML/CSS/JS Frontend&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #bfdbfe; font-size: 16px; line-height: 1.6; margin: 0px 0px 22px; padding: 0px;&quot;&gt;ทำ REST API ให้คุยกับ Frontend แบบ Pure JS ไม่ง้อ Framework — ครอบคลุม CORS, Fetch API และ JWT Authentication&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; color: #93c5fd; display: flex; flex-wrap: wrap; font-size: 13px; gap: 20px; margin: 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;June 2025&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Spring Boot 3&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Java 17&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;อ่าน ~8 นาที&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;toc&quot; style=&quot;background: rgb(240, 247, 255); border-radius: 10px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 40px; padding: 24px 28px;&quot;&gt;&lt;div class=&quot;toc-title&quot; style=&quot;box-sizing: border-box; color: #1a3c5e; font-size: 14px; font-weight: 700; letter-spacing: 1px; margin: 0px 0px 14px; padding: 0px; text-transform: uppercase;&quot;&gt;📋 สารบัญ&lt;/div&gt;&lt;ol style=&quot;box-sizing: border-box; margin: 0px 0px 18px; padding: 0px 0px 0px 20px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#why&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;ทำไมต้อง Vanilla JS?&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#architecture&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;Architecture Overview&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#springboot&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;ตั้งค่า Spring Boot&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#frontend&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;Vanilla JS Frontend&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#jwt&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;JWT Authentication&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#problems&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;ปัญหาที่พบบ่อย&lt;/a&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 6px 0px; padding: 0px;&quot;&gt;&lt;a href=&quot;https://www.claudeusercontent.com/?domain=claude.ai&amp;amp;parentOrigin=https%3A%2F%2Fclaude.ai&amp;amp;errorReportingMode=parent&amp;amp;formattedSpreadsheets=true#checklist&quot; style=&quot;box-sizing: border-box; color: #2e7dbe; font-size: 15px; margin: 0px; padding: 0px; text-decoration: none;&quot;&gt;Checklist ก่อน Deploy&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;h2 id=&quot;why&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;🚀 ทำไมต้อง Vanilla JS?&lt;/h2&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;หลายคนอาจสงสัยว่าในยุคที่ React, Vue, Angular ครองตลาด แล้วทำไมเราถึงยังพูดถึง Vanilla HTML/CSS/JS อยู่?&lt;/p&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;คำตอบง่ายมาก — บางโปรเจกต์ไม่ต้องการ Framework หนักๆ ก็ได้ โดยเฉพาะ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Admin Panel เล็กๆ&lt;/strong&gt;, &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Prototype&lt;/strong&gt;, หรือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ระบบภายในองค์กร&lt;/strong&gt; ที่ต้องส่งมอบเร็ว ไม่มี Build Pipeline ให้ยุ่งยาก&lt;/p&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;บทความนี้จะพาเดินทางตั้งแต่ต้นจนจบ: ตั้งค่า Spring Boot → เปิด CORS → เรียก API จาก JS → จัดการ Auth แบบ JWT ทั้งหมดโดยไม่ต้องพึ่ง Build Tool ฝั่ง Frontend เลยแม้แต่น้อย&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;architecture&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;🏗 Architecture Overview&lt;/h2&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ก่อนลงมือ ดู Big Picture กันก่อน:&lt;/p&gt;&lt;div class=&quot;arch-diagram&quot; style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #94a3b8; font-family: &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 1.9; margin: 24px 0px 32px; overflow-x: auto; padding: 28px;&quot;&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 10px; box-sizing: border-box; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt; ┌─────────────────┐ ┌──────────────────────────┐ │ &lt;span class=&quot;hl&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;Browser&lt;/span&gt; │ fetch() │ &lt;span class=&quot;hl2&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;Spring Boot App&lt;/span&gt; │ │ (HTML/CSS/JS) │ ───────► │ :8080 │ │ :3000 / file │ ◄─────── │ REST API + Security │ └─────────────────┘ JSON └──────────────────────────┘ │ ┌──────────▼──────────┐ │ &lt;span class=&quot;hl3&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;Database (H2/MySQL)&lt;/span&gt; │ └─────────────────────┘&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;note&quot; style=&quot;background: rgb(255, 251, 235); border-left: 4px solid rgb(245, 158, 11); border-radius: 0px 8px 8px 0px; box-sizing: border-box; color: #78350f; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 20px 0px; padding: 14px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;⚠️ สำคัญ:&lt;/strong&gt; Browser และ Spring Boot อาจรันคนละ Port (Cross-Origin) ดังนั้น &lt;strong style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;CORS คือสิ่งแรกที่ต้องจัดการ&lt;/strong&gt; ถ้าลืมจะเจอ Error ทันที&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;springboot&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;⚙️ Part 1: ตั้งค่า Spring Boot&lt;/h2&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;1.1 สร้างโปรเจกต์ด้วย Spring Initializr&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ไปที่ &lt;a href=&quot;https://start.spring.io/&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; target=&quot;_blank&quot;&gt;start.spring.io&lt;/a&gt; แล้วเลือก Dependencies ดังนี้:&lt;/p&gt;&lt;ul style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;Spring Web&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;Spring Security&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;Spring Data JPA&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;H2 Database (ทดสอบ) หรือ MySQL Driver (Production)&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;Lombok&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;1.2 ตั้งค่า CORS — หัวใจสำคัญ&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;CORS (Cross-Origin Resource Sharing) คือกลไกที่ Browser ใช้ตรวจสอบว่าเว็บที่ต้องการเรียก API ได้รับอนุญาตหรือไม่ ถ้าไม่ตั้งค่า จะเจอ Error นี้ทันที:&lt;/p&gt;&lt;div class=&quot;error-box&quot; style=&quot;background: rgb(254, 242, 242); border-left: 4px solid rgb(239, 68, 68); border-radius: 0px 8px 8px 0px; box-sizing: border-box; color: #7f1d1d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 20px 0px; padding: 14px 18px;&quot;&gt;&lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;Access to fetch at &#39;http://localhost:8080/api/...&#39; from origin &#39;http://localhost:3000&#39; has been blocked by CORS policy.&lt;/code&gt;&lt;/div&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;แก้ด้วย Global CORS Configuration:&lt;/p&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;Java&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@Configuration&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public class&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #f0abfc; margin: 0px; padding: 0px;&quot;&gt;CorsConfig&lt;/span&gt; { &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@Bean&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; WebMvcConfigurer &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;corsConfigurer&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return new&lt;/span&gt; WebMvcConfigurer() { &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@Override&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public void&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;addCorsMappings&lt;/span&gt;(CorsRegistry registry) { registry.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;addMapping&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/api/**&quot;&lt;/span&gt;) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;allowedOrigins&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;http://localhost:3000&quot;&lt;/span&gt;) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;allowedMethods&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;GET&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;POST&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;PUT&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;DELETE&quot;&lt;/span&gt;, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;allowedHeaders&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;*&quot;&lt;/span&gt;) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;allowCredentials&lt;/span&gt;(&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;); } }; } }&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;note&quot; style=&quot;background: rgb(255, 251, 235); border-left: 4px solid rgb(245, 158, 11); border-radius: 0px 8px 8px 0px; box-sizing: border-box; color: #78350f; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 20px 0px; padding: 14px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;📌 Production:&lt;/strong&gt; เปลี่ยน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;allowedOrigins&lt;/code&gt; เป็น domain จริง เช่น &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;https://myapp.com&lt;/code&gt; — อย่าใช้ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;*&lt;/code&gt; กับ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;allowCredentials(true)&lt;/code&gt; พร้อมกัน&lt;/div&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;1.3 สร้าง REST Controller&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ตัวอย่าง Product API อย่างง่าย:&lt;/p&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;Java&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@RestController&lt;/span&gt; &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@RequestMapping&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/api/products&quot;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public class&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #f0abfc; margin: 0px; padding: 0px;&quot;&gt;ProductController&lt;/span&gt; { &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@Autowired&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;private&lt;/span&gt; ProductService productService; &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@GetMapping&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;List&amp;lt;Product&amp;gt;&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getAll&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; ResponseEntity.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;ok&lt;/span&gt;(productService.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;findAll&lt;/span&gt;()); } &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@PostMapping&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;Product&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;create&lt;/span&gt;(&lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@RequestBody&lt;/span&gt; Product product) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; ResponseEntity.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;status&lt;/span&gt;(HttpStatus.CREATED) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;body&lt;/span&gt;(productService.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;save&lt;/span&gt;(product)); } &lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@DeleteMapping&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/{id}&quot;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;Void&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;delete&lt;/span&gt;(&lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@PathVariable&lt;/span&gt; Long id) { productService.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;delete&lt;/span&gt;(id); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; ResponseEntity.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;noContent&lt;/span&gt;().&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;build&lt;/span&gt;(); } }&lt;/code&gt;&lt;/pre&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;frontend&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;🌐 Part 2: Vanilla JS Frontend&lt;/h2&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;2.1 โครงสร้าง Project&lt;/h3&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;Structure&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;frontend/ ├── index.html ├── css/ │ └── style.css └── js/ ├── api.js ← ตัวกลางเรียก API ทั้งหมด ├── auth.js ← จัดการ Token └── app.js ← Business Logic / UI&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;2.2 สร้าง API Client — api.js&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;แยก Logic การเรียก API ออกมาเป็น Module เดียว ทำให้ดูแลง่าย ไม่ต้องเขียน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;fetch()&lt;/code&gt; ซ้ำทุกที่:&lt;/p&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;JavaScript&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// js/api.js&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BASE_URL = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;http://localhost:8080/api&#39;&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;async function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;apiFetch&lt;/span&gt;(endpoint, options = {}) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; token = localStorage.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getItem&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;jwt_token&#39;&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; defaultHeaders = { &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;application/json&#39;&lt;/span&gt;, ...(token ? { &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;Authorization&#39;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;`Bearer ${token}`&lt;/span&gt; } : {}) }; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; response = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;fetch&lt;/span&gt;(`${BASE_URL}${endpoint}`, { ...options, headers: { ...defaultHeaders, ...options.headers } }); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (response.status === &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;401&lt;/span&gt;) { localStorage.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;removeItem&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;jwt_token&#39;&lt;/span&gt;); window.location.href = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/login.html&#39;&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// Token หมดอายุ&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!response.ok) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; error = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; response.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;json&lt;/span&gt;().&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;catch&lt;/span&gt;(() =&amp;gt; ({})); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;throw new&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #f0abfc; margin: 0px; padding: 0px;&quot;&gt;Error&lt;/span&gt;(error.message || `HTTP ${response.status}`); } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (response.status === &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;204&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return null&lt;/span&gt;; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// No Content&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; response.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;json&lt;/span&gt;(); } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// Export ฟังก์ชันสำหรับ Product&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; ProductAPI = { getAll: () =&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;apiFetch&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/products&#39;&lt;/span&gt;), create: (data) =&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;apiFetch&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/products&#39;&lt;/span&gt;, { method: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;POST&#39;&lt;/span&gt;, body: JSON.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;stringify&lt;/span&gt;(data) }), delete: (id) =&amp;gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;apiFetch&lt;/span&gt;(`/products/${id}`, { method: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;DELETE&#39;&lt;/span&gt; }), };&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;2.3 แสดงข้อมูลใน HTML&lt;/h3&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;HTML&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt; &amp;lt;div id=&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;product-list&quot;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt; &amp;lt;button id=&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;btn-load&quot;&lt;/span&gt;&amp;gt;โหลดสินค้า&amp;lt;/button&amp;gt; &amp;lt;script src=&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;js/api.js&quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt; &amp;lt;script src=&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;js/app.js&quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;JavaScript&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// js/app.js&lt;/span&gt; document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;btn-load&#39;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;click&#39;&lt;/span&gt;, &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;async&lt;/span&gt; () =&amp;gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;try&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; products = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; ProductAPI.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getAll&lt;/span&gt;(); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; container = document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;product-list&#39;&lt;/span&gt;); container.innerHTML = products.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;map&lt;/span&gt;(p =&amp;gt; &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;` &amp;lt;div class=&quot;product-card&quot;&amp;gt; &amp;lt;h3&amp;gt;${p.name}&amp;lt;/h3&amp;gt; &amp;lt;p&amp;gt;฿${p.price.toLocaleString()}&amp;lt;/p&amp;gt; &amp;lt;button onclick=&quot;deleteProduct(${p.id})&quot;&amp;gt;ลบ&amp;lt;/button&amp;gt; &amp;lt;/div&amp;gt; `&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;join&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;); } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;catch&lt;/span&gt; (err) { &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;alert&lt;/span&gt;(`เกิดข้อผิดพลาด: ${err.message}`); } }); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;async function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;deleteProduct&lt;/span&gt;(id) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;confirm&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;ยืนยันการลบ?&#39;&lt;/span&gt;)) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; ProductAPI.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;delete&lt;/span&gt;(id); document.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;btn-load&#39;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;click&lt;/span&gt;(); &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// Reload list&lt;/span&gt; }&lt;/code&gt;&lt;/pre&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;jwt&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;🔐 Part 3: JWT Authentication&lt;/h2&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;3.1 Login Flow&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;Flow การ Login แบบ JWT มีขั้นตอนดังนี้:&lt;/p&gt;&lt;ol style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;User กรอก username/password แล้วกด Submit&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;JS ส่ง &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;POST&lt;/code&gt; ไปที่ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;/api/auth/login&lt;/code&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;Spring Boot ตรวจสอบ แล้วคืน JWT Token&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;JS เก็บ Token ใน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;localStorage&lt;/code&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 7px 0px; padding: 0px;&quot;&gt;ทุก Request ถัดไปแนบ Token ใน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;Authorization: Bearer ...&lt;/code&gt; Header&lt;/li&gt;&lt;/ol&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;JavaScript&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// js/auth.js&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;async function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;login&lt;/span&gt;(username, password) { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; response = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;fetch&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;http://localhost:8080/api/auth/login&#39;&lt;/span&gt;, { method: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;POST&#39;&lt;/span&gt;, headers: { &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;application/json&#39;&lt;/span&gt; }, body: JSON.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;stringify&lt;/span&gt;({ username, password }) }); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!response.ok) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;throw new&lt;/span&gt; &lt;span class=&quot;cl&quot; style=&quot;box-sizing: border-box; color: #f0abfc; margin: 0px; padding: 0px;&quot;&gt;Error&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;Login failed&#39;&lt;/span&gt;); &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; data = &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;await&lt;/span&gt; response.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;json&lt;/span&gt;(); localStorage.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;setItem&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;jwt_token&#39;&lt;/span&gt;, data.token); window.location.href = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/dashboard.html&#39;&lt;/span&gt;; } &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;logout&lt;/span&gt;() { localStorage.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;removeItem&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;jwt_token&#39;&lt;/span&gt;); window.location.href = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/login.html&#39;&lt;/span&gt;; } &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// ตรวจสอบสิทธิ์ก่อนโหลดหน้า — เรียกบนทุกหน้าที่ต้อง Login&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;requireAuth&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!localStorage.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;getItem&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;jwt_token&#39;&lt;/span&gt;)) { window.location.href = &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&#39;/login.html&#39;&lt;/span&gt;; } }&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;note&quot; style=&quot;background: rgb(255, 251, 235); border-left: 4px solid rgb(245, 158, 11); border-radius: 0px 8px 8px 0px; box-sizing: border-box; color: #78350f; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 20px 0px; padding: 14px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;📌 Security Note:&lt;/strong&gt; &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;localStorage&lt;/code&gt; ไม่ปลอดภัยสำหรับ Token ที่ Sensitive มาก — Production ควรพิจารณาใช้ &lt;strong style=&quot;box-sizing: border-box; color: #d97706; margin: 0px; padding: 0px;&quot;&gt;HttpOnly Cookie&lt;/strong&gt; แทน เพื่อป้องกัน XSS Attack&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;problems&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;🐛 Part 4: ปัญหาที่พบบ่อย&lt;/h2&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;ปัญหาที่ 1: CORS Error ยังติดอยู่แม้ตั้งค่าแล้ว&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;สาเหตุที่พบบ่อย: Spring Security Intercept ก่อนที่ CORS Config จะทำงาน แก้ด้วยการเพิ่มใน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;SecurityConfig&lt;/code&gt;:&lt;/p&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;Java&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;an&quot; style=&quot;box-sizing: border-box; color: #fbbf24; margin: 0px; padding: 0px;&quot;&gt;@Bean&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;public&lt;/span&gt; SecurityFilterChain &lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;filterChain&lt;/span&gt;(HttpSecurity http) &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;throws&lt;/span&gt; Exception { http .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;cors&lt;/span&gt;(cors -&amp;gt; cors.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;configurationSource&lt;/span&gt;(&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;corsConfigurationSource&lt;/span&gt;())) .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;csrf&lt;/span&gt;(csrf -&amp;gt; csrf.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;disable&lt;/span&gt;()) &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #64748b; margin: 0px; padding: 0px;&quot;&gt;// ... rest of config&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #93c5fd; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; http.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;build&lt;/span&gt;(); }&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;ปัญหาที่ 2: OPTIONS Request ถูก Block&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;Browser ส่ง Preflight Request (&lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;OPTIONS&lt;/code&gt;) ก่อนทุก Cross-Origin Request ต้องให้ Spring ผ่าน &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;OPTIONS&lt;/code&gt; โดยไม่ต้อง Auth:&lt;/p&gt;&lt;pre style=&quot;background: rgb(15, 23, 42); border-radius: 10px; box-sizing: border-box; color: #2d2d2d; font-size: 17px; margin: 20px 0px 28px; overflow-x: auto; padding: 24px 28px; position: relative;&quot;&gt;&lt;span class=&quot;lang-tag&quot; style=&quot;box-sizing: border-box; color: #64748b; font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px; position: absolute; right: 16px; text-transform: uppercase; top: 10px;&quot;&gt;Java&lt;/span&gt;&lt;code style=&quot;background: none; border-color: currentcolor; border-image: initial; border-radius: 4px; border-style: none; border-width: medium; box-sizing: border-box; color: #e2e8f0; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;.&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;authorizeHttpRequests&lt;/span&gt;(auth -&amp;gt; auth .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;requestMatchers&lt;/span&gt;(HttpMethod.OPTIONS, &lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/**&quot;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;permitAll&lt;/span&gt;() .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;requestMatchers&lt;/span&gt;(&lt;span class=&quot;st&quot; style=&quot;box-sizing: border-box; color: #86efac; margin: 0px; padding: 0px;&quot;&gt;&quot;/api/auth/**&quot;&lt;/span&gt;).&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;permitAll&lt;/span&gt;() .&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;anyRequest&lt;/span&gt;().&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #7dd3fc; margin: 0px; padding: 0px;&quot;&gt;authenticated&lt;/span&gt;() )&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;background-color: white; box-sizing: border-box; color: #2e7dbe; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 19px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;ปัญหาที่ 3: JSON Parse Error&lt;/h3&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;ตรวจสอบว่า Controller ส่ง &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;Content-Type: application/json&lt;/code&gt; กลับมาด้วย ถ้าใช้ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;@RestController&lt;/code&gt; จะทำให้อัตโนมัติแล้ว แต่ถ้าใช้ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;@Controller&lt;/code&gt; ต้องเพิ่ม &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;@ResponseBody&lt;/code&gt; หรือใช้ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;ResponseEntity&lt;/code&gt;&lt;/p&gt;&lt;div class=&quot;tip&quot; style=&quot;background: rgb(240, 253, 244); border-left: 4px solid rgb(34, 197, 94); border-radius: 0px 8px 8px 0px; box-sizing: border-box; color: #14532d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 20px 0px; padding: 14px 18px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #16a34a; margin: 0px; padding: 0px;&quot;&gt;✅ เคล็ดลับ:&lt;/strong&gt; เปิด Browser DevTools → Network Tab → ดู Request/Response Headers ก่อนเสมอ จะเห็นสาเหตุของ Error ได้ชัดเจน&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: white; border-color: rgb(226, 232, 240) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 44px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;checklist&quot; style=&quot;background-color: white; border-bottom: 2px solid rgb(46, 125, 190); box-sizing: border-box; color: #1a3c5e; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 24px; margin: 48px 0px 16px; padding: 0px 0px 10px;&quot;&gt;✅ Checklist ก่อน Deploy&lt;/h2&gt;&lt;table class=&quot;checklist&quot; style=&quot;background-color: white; border-collapse: collapse; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 15px; margin: 24px 0px; padding: 0px; width: 740px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;background: rgb(26, 60, 94); box-sizing: border-box; color: white; margin: 0px; padding: 12px 16px; text-align: left;&quot;&gt;รายการ&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 60, 94); box-sizing: border-box; color: white; margin: 0px; padding: 12px 16px; text-align: center; width: 100px;&quot;&gt;สถานะ&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;CORS ตั้งค่า &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;allowedOrigins&lt;/code&gt; ถูก Domain&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 251, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;ไม่มี CORS &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;*&lt;/code&gt; กับ &lt;code style=&quot;background: rgb(240, 244, 248); border-radius: 4px; border: 1px solid rgb(226, 232, 240); box-sizing: border-box; color: #c0392b; font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 14px; margin: 0px; padding: 2px 7px;&quot;&gt;allowCredentials(true)&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;OPTIONS Request ผ่านได้โดยไม่ต้อง Auth&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 251, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;JWT Secret ยาวพอ (256 bit ขึ้นไป)&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;Error Handling ใน JS ครบทุก Case&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(248, 251, 255); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;ไม่ Expose Sensitive Data ใน Response&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px;&quot;&gt;HTTPS ใน Production&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(226, 232, 240); box-sizing: border-box; margin: 0px; padding: 11px 16px; text-align: center;&quot;&gt;&lt;span class=&quot;badge-check&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 20px; box-sizing: border-box; color: #713f12; font-size: 12px; font-weight: 600; margin: 0px; padding: 3px 10px;&quot;&gt;ตรวจสอบ&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 18px; padding: 0px;&quot;&gt;Vanilla JS + Spring Boot เป็น Stack ที่ Lightweight และเข้าใจง่าย เหมาะสำหรับระบบขนาดกลางที่ไม่ต้องการ Complexity ของ Frontend Framework เพียงแค่เข้าใจ CORS, Fetch API และ JWT ก็พร้อม Deploy ได้เลย&lt;/p&gt;&lt;div class=&quot;tags&quot; style=&quot;background-color: white; box-sizing: border-box; color: #2d2d2d; display: flex; flex-wrap: wrap; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; gap: 8px; margin: 44px 0px 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#SpringBoot&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#Java&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#VanillaJS&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#REST API&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#CORS&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#JWT&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(239, 246, 255); border-radius: 20px; border: 1px solid rgb(191, 219, 254); box-sizing: border-box; color: #1d4ed8; font-size: 13px; margin: 0px; padding: 5px 13px;&quot;&gt;#WebDev&lt;/span&gt;&lt;/div&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/3559716973291210109/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/spring-boot-api-vanilla-htmlcssjs.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3559716973291210109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/3559716973291210109'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/spring-boot-api-vanilla-htmlcssjs.html' title='เชื่อมต่อ Spring Boot API กับ Vanilla HTML/CSS/JS Frontend'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEi81OT58ETFE2AemXa4Lf7vhm2IJA09NWGWB88MOhME4iVjMdVhVwo-u2BxDcPVGsPNxSCEFc03u1CTioFy66zz217nJojQclRcQXc2UUZu1JhH7ARm39OSJEamJCbNiVGQ4lpMk2xjpIG8bTZG-1SOapwmfXLmh-Tenxh8P_aiYA2nQ6-Zf-iRFR5X8Ak=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-8384518333018085474</id><published>2026-06-10T05:00:00.000+07:00</published><updated>2026-06-10T05:00:00.125+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Vibe Coding"/><title type='text'>หยุดเขียน CRUD ซ้ำๆ: Vibe Coding เปลี่ยน PHP Dev ยังไง</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiKEfE84DfG-Un_99gN_0pPDYubqm-MevBNZC9e9ARSePVjmljwDmgOXlsSRT2jgVnMZZI-Ew_fzYnD8F2Rl8PivFjVV1g0xVVOQkxHRLZilsutAyZYYlHzNQlpUPEyMt4mCS48I5V9z3d6Pr8pOxE6XOGDvvek1g6l_UgEQTyn9h962ON7i0tEfk81voc&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiKEfE84DfG-Un_99gN_0pPDYubqm-MevBNZC9e9ARSePVjmljwDmgOXlsSRT2jgVnMZZI-Ew_fzYnD8F2Rl8PivFjVV1g0xVVOQkxHRLZilsutAyZYYlHzNQlpUPEyMt4mCS48I5V9z3d6Pr8pOxE6XOGDvvek1g6l_UgEQTyn9h962ON7i0tEfk81voc&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;hero&quot; style=&quot;background: linear-gradient(135deg, rgb(234, 241, 251) 0%, rgb(240, 246, 255) 50%, rgb(234, 241, 251) 100%) rgb(246, 248, 250); border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 16px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 48px; overflow: hidden; padding: 48px 40px; position: relative;&quot;&gt;&lt;div class=&quot;hero-tag&quot; style=&quot;background: rgba(88, 166, 255, 0.15); border-radius: 20px; border: 1px solid rgba(88, 166, 255, 0.3); box-sizing: border-box; color: #0969da; display: inline-block; font-size: 13px; font-weight: 600; letter-spacing: 0.5px; margin: 0px 0px 20px; padding: 4px 14px; text-transform: uppercase;&quot;&gt;🤖 Vibe Coding Series · EP.1&lt;/div&gt;&lt;h1 style=&quot;-webkit-text-fill-color: transparent; background: linear-gradient(90deg, rgb(31, 35, 40) 60%, rgb(9, 105, 218) 100%) 0% 0% / auto repeat scroll padding-box text rgba(0, 0, 0, 0); box-sizing: border-box; font-size: clamp(26px, 5vw, 38px); line-height: 1.3; margin: 0px 0px 16px; padding: 0px;&quot;&gt;หยุดเขียน CRUD ซ้ำๆ:&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;Vibe Coding เปลี่ยน PHP Dev ยังไง&lt;/h1&gt;&lt;p class=&quot;hero-sub&quot; style=&quot;box-sizing: border-box; color: #57606a; font-size: 16px; margin: 0px 0px 16px; max-width: 600px; padding: 0px;&quot;&gt;เมื่อ AI กลายเป็น pair programmer และ framework กลายเป็น rendering engine — นักพัฒนา PHP ยุคใหม่ต้องปรับตัวอย่างไร&lt;/p&gt;&lt;div class=&quot;hero-meta&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 20px; margin: 24px 0px 0px; padding: 0px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; color: #57606a; font-size: 13px; margin: 0px; padding: 0px;&quot;&gt;📅 &lt;strong style=&quot;box-sizing: border-box; color: #1a7f37; margin: 0px; padding: 0px;&quot;&gt;June 2025&lt;/strong&gt;&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; color: #57606a; font-size: 13px; margin: 0px; padding: 0px;&quot;&gt;⏱ อ่าน &lt;strong style=&quot;box-sizing: border-box; color: #1a7f37; margin: 0px; padding: 0px;&quot;&gt;~8 นาที&lt;/strong&gt;&lt;/span&gt;&lt;span style=&quot;box-sizing: border-box; color: #57606a; font-size: 13px; margin: 0px; padding: 0px;&quot;&gt;🎯 &lt;strong style=&quot;box-sizing: border-box; color: #1a7f37; margin: 0px; padding: 0px;&quot;&gt;PHP / CI4 / Laravel&lt;/strong&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;😩 ปัญหาที่ PHP Dev ทุกคนเจอ: CRUD วนซ้ำไม่รู้จบ&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ถ้าคุณเคยสร้างระบบ admin panel, ERP, หรือระบบบริหารงานองค์กร คุณคงรู้ดีว่ามันเป็นยังไง — &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Controller ก็โครงสร้างเดิม, Model ก็ query เดิม, View ก็ตาราง + form เดิมๆ&lt;/strong&gt; เปลี่ยนแค่ชื่อ module&lt;/p&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Carlos García นักพัฒนาชาวสเปนที่ทำงานในศูนย์วิจัยมหาวิทยาลัย พบว่าตัวเองใช้เวลางาน &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;80% ไปกับ boilerplate code&lt;/strong&gt; ที่ซ้ำซาก และมีแค่ 20% ที่เป็น business logic จริงๆ ปัญหานี้ไม่ใช่แค่เรื่องน่าเบื่อ แต่มันทำให้ codebase บวม, maintain ยาก, และเปลืองเวลาที่ควรจะไปพัฒนา feature ใหม่ๆ&lt;/p&gt;&lt;div class=&quot;callout warn&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(208, 215, 222) rgb(208, 215, 222) rgb(208, 215, 222) rgb(154, 103, 0); border-image: none 100% / 1 / 0 stretch; border-radius: 0px 8px 8px 0px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;div class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #9a6700; font-size: 13px; font-weight: 700; letter-spacing: 0.8px; margin: 0px 0px 8px; padding: 0px; text-transform: uppercase;&quot;&gt;💡 คุณเจอแบบนี้ไหม?&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 0px;&quot;&gt;สร้าง module ใหม่ทีนึง → copy Controller เดิม → แก้ชื่อ table → ปรับ form fields → นั่งแก้ View อีก 2-3 ไฟล์ → ทำซ้ำแบบนี้ทุก module จนครบ 20 module&lt;/p&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;วันนี้เราจะมาดูว่า &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Vibe Coding&lt;/strong&gt; — แนวคิดการเขียนโค้ดยุคใหม่ที่ใช้ AI เป็น pair programmer — มันทำงานยังไง และ PHP developer อย่างเราจะนำมาใช้กับ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/strong&gt; และ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/strong&gt; ได้อย่างไรบ้าง&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;🎵 Vibe Coding คืออะไร?&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Vibe Coding&lt;/strong&gt; คือ paradigm การพัฒนาซอฟต์แวร์ที่นักพัฒนาทำหน้าที่เป็น &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;architect และ director&lt;/em&gt; แทนที่จะเป็น typist ที่นั่งพิมพ์โค้ดทุกบรรทัดด้วยตัวเอง คุณ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;บอก&quot; AI ว่าต้องการอะไร&lt;/strong&gt; แล้วให้ AI + framework จัดการส่วนที่ซ้ำซากแทน&lt;/p&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;แนวคิดหลักคือการ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;shift จาก &quot;how to code it&quot;&lt;/strong&gt; (จะเขียนโค้ดยังไง) ไปเป็น &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;what to build&quot;&lt;/strong&gt; (จะสร้างอะไร) — เหมือนกับที่สถาปนิกวาด blueprint แล้วให้ช่างก่อสร้างทำตาม แทนที่จะแบกปูนขึ้นนั่งร้านเอง&lt;/p&gt;&lt;div class=&quot;callout success&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(208, 215, 222) rgb(208, 215, 222) rgb(208, 215, 222) rgb(26, 127, 55); border-image: none 100% / 1 / 0 stretch; border-radius: 0px 8px 8px 0px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;div class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #1a7f37; font-size: 13px; font-weight: 700; letter-spacing: 0.8px; margin: 0px 0px 8px; padding: 0px; text-transform: uppercase;&quot;&gt;✅ Vibe Coding ในทางปฏิบัติ&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 0px;&quot;&gt;แทนที่จะเขียน Controller + Model + 5 Views สำหรับ module เดียว — คุณแค่ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;เขียน configuration array 1 ชุด&lt;/strong&gt; แล้วให้ framework render ทุกอย่างให้อัตโนมัติ&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;🏗️ ตัวอย่างจริง: Framework ที่สร้างจาก Vibe Coding Philosophy&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Carlos ได้สร้าง &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Ragnos&lt;/strong&gt; — open-source framework ที่วางอยู่บน CodeIgniter 4 — โดยใช้แนวคิด &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Configuration over Programming&lt;/em&gt; แทนที่จะเขียน controller/model/view แยกกัน คุณแค่ define &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Data Dictionary&lt;/strong&gt; เป็น PHP array ชุดเดียว แล้ว framework จะ generate ทุกอย่างให้&lt;/p&gt;&lt;h3 style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #0969da; font-family: Sarabun, sans-serif; font-size: 18px; margin: 32px 0px 12px; padding: 0px;&quot;&gt;ตัวอย่าง: สร้าง Module จัดการผู้ใช้งาน&lt;/h3&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(24, 24, 37); border-bottom: 1px solid rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-lang&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;PHP · Data Dictionary (Ragnos / CI4)&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// แทนที่จะเขียน Controller + Model + View แยกกัน&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เราแค่ define config array ชุดนี้ชุดเดียว&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$config&lt;/span&gt; = [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;จัดการผู้ใช้งาน&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;table&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;users&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;pk&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;id&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;fields&#39;&lt;/span&gt; =&amp;gt; [ [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;username&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;label&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;ชื่อผู้ใช้&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;text&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;rules&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;required|min_length[3]&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;in_list&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;, ], [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;label&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;อีเมล&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;email&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;rules&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;required|valid_email&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;in_list&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;, ], [ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;name&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;label&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;สิทธิ์ใช้งาน&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;type&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;select&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;options&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;admin&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;Admin&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;staff&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;Staff&#39;&lt;/span&gt;], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;roles&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;admin&#39;&lt;/span&gt;], &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// เฉพาะ admin เท่านั้นที่เห็น field นี้&lt;/span&gt; ], ], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;actions&#39;&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;create&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;edit&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;delete&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;export_excel&#39;&lt;/span&gt;], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;per_page&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;num&quot; style=&quot;box-sizing: border-box; color: #89b4fa; margin: 0px; padding: 0px;&quot;&gt;25&lt;/span&gt;, ]; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Framework จะ auto-generate:&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Data table + pagination&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Add/Edit form พร้อม CSRF + validation&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Export Excel/CSV&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ SQL injection protection&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Role-based field visibility&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;สังเกตว่า &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ไม่มีโค้ด HTML เลยแม้แต่บรรทัดเดียว&lt;/strong&gt; — framework อ่าน config แล้ว render ทุกอย่างให้เอง และนี่แหละคือสิ่งที่ทำให้ Vibe Coding กับ AI ทำงานด้วยกันได้ดีมาก เพราะ AI สามารถ generate PHP array ได้แม่นยำ ไม่ต้องกังวลเรื่อง HTML structure&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;🔄 Vibe Coding Workflow สำหรับ PHP Dev&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ไม่ว่าจะใช้ CI4, Laravel, หรือ framework อะไรก็ตาม workflow ของ Vibe Coding มักจะเป็นแบบนี้:&lt;/p&gt;&lt;ul class=&quot;steps&quot; style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; list-style: none; margin: 24px 0px; padding: 0px;&quot;&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 16px; margin: 0px 0px 20px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgba(88, 166, 255, 0.15); border-radius: 50%; border: 1px solid rgba(88, 166, 255, 0.3); box-sizing: border-box; color: #0969da; display: flex; flex-shrink: 0; font-size: 13px; font-weight: 700; height: 32px; justify-content: center; margin: 0px; padding: 0px; width: 32px;&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; flex: 1 1 0%; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-title&quot; style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px 0px 4px; padding: 0px;&quot;&gt;🎯 กำหนด Spec ให้ชัด (Architect Mode)&lt;/div&gt;&lt;div class=&quot;step-desc&quot; style=&quot;box-sizing: border-box; color: #57606a; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;ระบุ module ที่ต้องการ, fields ที่จำเป็น, business rules, และ permissions ก่อน — ยิ่ง spec ชัด ยิ่ง AI generate ได้แม่น&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 16px; margin: 0px 0px 20px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgba(88, 166, 255, 0.15); border-radius: 50%; border: 1px solid rgba(88, 166, 255, 0.3); box-sizing: border-box; color: #0969da; display: flex; flex-shrink: 0; font-size: 13px; font-weight: 700; height: 32px; justify-content: center; margin: 0px; padding: 0px; width: 32px;&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; flex: 1 1 0%; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-title&quot; style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px 0px 4px; padding: 0px;&quot;&gt;🤖 Prompt AI ให้ generate โครงสร้าง&lt;/div&gt;&lt;div class=&quot;step-desc&quot; style=&quot;box-sizing: border-box; color: #57606a; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;ใช้ AI สร้าง config array, migration file, หรือ Blade component ให้ แทนที่จะพิมพ์เอง — ทบทวนและปรับแก้เท่าที่จำเป็น&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 16px; margin: 0px 0px 20px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgba(88, 166, 255, 0.15); border-radius: 50%; border: 1px solid rgba(88, 166, 255, 0.3); box-sizing: border-box; color: #0969da; display: flex; flex-shrink: 0; font-size: 13px; font-weight: 700; height: 32px; justify-content: center; margin: 0px; padding: 0px; width: 32px;&quot;&gt;3&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; flex: 1 1 0%; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-title&quot; style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px 0px 4px; padding: 0px;&quot;&gt;⚙️ ให้ Framework Render&lt;/div&gt;&lt;div class=&quot;step-desc&quot; style=&quot;box-sizing: border-box; color: #57606a; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;วาง config ที่ได้ลงใน controller หรือ service layer แล้วให้ framework จัดการ rendering, validation, และ security&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; box-sizing: border-box; display: flex; gap: 16px; margin: 0px 0px 20px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-num&quot; style=&quot;align-items: center; background: rgba(88, 166, 255, 0.15); border-radius: 50%; border: 1px solid rgba(88, 166, 255, 0.3); box-sizing: border-box; color: #0969da; display: flex; flex-shrink: 0; font-size: 13px; font-weight: 700; height: 32px; justify-content: center; margin: 0px; padding: 0px; width: 32px;&quot;&gt;4&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; flex: 1 1 0%; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-title&quot; style=&quot;box-sizing: border-box; font-weight: 600; margin: 0px 0px 4px; padding: 0px;&quot;&gt;🔍 Review + Test&lt;/div&gt;&lt;div class=&quot;step-desc&quot; style=&quot;box-sizing: border-box; color: #57606a; font-size: 15px; margin: 0px; padding: 0px;&quot;&gt;คุณทำหน้าที่ reviewer — ตรวจ logic, ดู edge cases, เทสต์ security แทนที่จะนั่งพิมพ์โค้ด&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;⚡ Vibe Coding กับ Laravel: ตัวอย่าง Blade Component&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ใน Laravel แนวคิดเดียวกันนี้ทำได้ผ่าน &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Blade Components&lt;/strong&gt; + &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Service Classes&lt;/strong&gt; — แทนที่จะเขียน blade template ซ้ำๆ คุณสร้าง reusable component แล้ว AI ช่วย generate การเรียกใช้:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(24, 24, 37); border-bottom: 1px solid rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-lang&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;Blade · Laravel Reusable Data Table Component&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;{{-- resources/views/components/data-table.blade.php --}}&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@props&lt;/span&gt;([ &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;columns&#39;&lt;/span&gt; =&amp;gt; [], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;rows&#39;&lt;/span&gt; =&amp;gt; [], &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;title&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;ข้อมูล&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;actions&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;, ]) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;card shadow-sm&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;card-header d-flex justify-content-between&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;h5&lt;/span&gt;&amp;gt;{{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$title&lt;/span&gt; }}&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;h5&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;{{ route(request()-&amp;gt;route()-&amp;gt;getName() . &#39;.create&#39;) }}&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;btn btn-primary btn-sm&quot;&lt;/span&gt;&amp;gt;+ เพิ่มข้อมูล&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;div&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;table table-hover mb-0&quot;&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;thead&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@foreach&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$columns&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$col&lt;/span&gt;) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;th&lt;/span&gt;&amp;gt;{{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$col&lt;/span&gt;[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;label&#39;&lt;/span&gt;] }}&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;th&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@endforeach&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@if&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$actions&lt;/span&gt;) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;th&lt;/span&gt;&amp;gt;จัดการ&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;th&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@endif&lt;/span&gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;thead&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tbody&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@forelse&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$rows&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$row&lt;/span&gt;) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@foreach&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$columns&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$col&lt;/span&gt;) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt;&amp;gt;{{ &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$row&lt;/span&gt;-&amp;gt;{&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$col&lt;/span&gt;[&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&#39;field&#39;&lt;/span&gt;]} }}&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@endforeach&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@if&lt;/span&gt; (&lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;$actions&lt;/span&gt;) &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;btn btn-sm btn-outline-primary&quot;&lt;/span&gt;&amp;gt;แก้ไข&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt;&amp;gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;btn btn-sm btn-outline-danger&quot;&lt;/span&gt;&amp;gt;ลบ&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;a&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@endif&lt;/span&gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@empty&lt;/span&gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt;&amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;colspan&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;99&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;text-center text-muted&quot;&lt;/span&gt;&amp;gt;ไม่พบข้อมูล&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;td&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tr&lt;/span&gt;&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;box-sizing: border-box; color: #f38ba8; margin: 0px; padding: 0px;&quot;&gt;@endforelse&lt;/span&gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;tbody&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;table&lt;/span&gt;&amp;gt; &amp;lt;/&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;เมื่อมี component แล้ว การ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;เรียกใช้ใน View&lt;/strong&gt; กลายเป็นเรื่องง่ายมาก และนี่คือส่วนที่ AI ช่วย generate ได้เร็วมาก:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(24, 24, 37); border-bottom: 1px solid rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-lang&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;Blade · เรียกใช้ Component ใน View&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;{{-- ใช้ใน products/index.blade.php --}}&lt;/span&gt; &amp;lt;&lt;span class=&quot;fn&quot; style=&quot;box-sizing: border-box; color: #cba6f7; margin: 0px; padding: 0px;&quot;&gt;x-data-table&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;title&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;รายการสินค้า&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;:columns&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;[ [&#39;field&#39; =&amp;gt; &#39;name&#39;, &#39;label&#39; =&amp;gt; &#39;ชื่อสินค้า&#39;], [&#39;field&#39; =&amp;gt; &#39;price&#39;, &#39;label&#39; =&amp;gt; &#39;ราคา (บาท)&#39;], [&#39;field&#39; =&amp;gt; &#39;stock&#39;, &#39;label&#39; =&amp;gt; &#39;คงเหลือ&#39;], ]&quot;&lt;/span&gt; &lt;span class=&quot;arr&quot; style=&quot;box-sizing: border-box; color: #a6e3a1; margin: 0px; padding: 0px;&quot;&gt;:rows&lt;/span&gt;=&lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;$products&quot;&lt;/span&gt; /&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;📊 เปรียบเทียบ: Traditional Coding vs Vibe Coding&lt;/h2&gt;&lt;div class=&quot;table-wrap&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222); border-image: none 100% / 1 / 0 stretch; border-radius: 10px; border-style: solid; border-width: 1px; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 28px 0px; overflow-x: auto; padding: 0px;&quot;&gt;&lt;table style=&quot;border-collapse: collapse; font-size: 15px; margin: 0px; padding: 0px; width: 818px;&quot;&gt;&lt;thead style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(240, 242, 245); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; color: #57606a; font-size: 13px; letter-spacing: 0.5px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; color: #57606a; font-size: 13px; letter-spacing: 0.5px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;Traditional Coding&lt;/th&gt;&lt;th style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; color: #57606a; font-size: 13px; letter-spacing: 0.5px; margin: 0px; padding: 14px 16px; text-align: left; text-transform: uppercase;&quot;&gt;Vibe Coding + AI&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;เวลาสร้าง Module ใหม่&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;1–3 วัน (ต้องเขียน C+M+V ทุกไฟล์)&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgba(63, 185, 80, 0.15); border-radius: 12px; box-sizing: border-box; color: #1a7f37; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;30 วินาที – 30 นาที&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โค้ดที่ต้องเขียนเอง&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;~80% boilerplate, 20% business logic&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgba(88, 166, 255, 0.15); border-radius: 12px; box-sizing: border-box; color: #0969da; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;~20% config, 80% business logic&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ความเสี่ยงด้าน Security&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgba(247, 129, 102, 0.2); border-radius: 12px; box-sizing: border-box; color: #cf222e; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;สูง&lt;/span&gt; — ต้อง sanitize เอง ทุก input&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgba(63, 185, 80, 0.15); border-radius: 12px; box-sizing: border-box; color: #1a7f37; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;ต่ำ&lt;/span&gt; — framework จัดการ CSRF/XSS/SQLi&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ความสามารถของ AI&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ช่วยได้จำกัด — HTML + logic ปนกัน&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-purple&quot; style=&quot;background: rgba(188, 140, 255, 0.15); border-radius: 12px; box-sizing: border-box; color: #8250df; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;สูงมาก&lt;/span&gt; — AI generate array/config แม่น&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Maintainability&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ยาก — view กระจายหลายไฟล์&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgba(63, 185, 80, 0.15); border-radius: 12px; box-sizing: border-box; color: #1a7f37; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;ง่าย&lt;/span&gt; — แก้ config ที่เดียว&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom: 1px solid rgb(208, 215, 222); box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Role ของ Developer&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;Coder (พิมพ์โค้ดทุกบรรทัด)&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-blue&quot; style=&quot;background: rgba(88, 166, 255, 0.15); border-radius: 12px; box-sizing: border-box; color: #0969da; display: inline-block; font-size: 12px; font-weight: 600; margin: 0px; padding: 2px 10px;&quot;&gt;Architect + Reviewer&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;border-bottom-color: currentcolor; border-bottom-style: none; border-bottom-width: medium; box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Onboarding ทีมใหม่&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;ต้องรู้ codebase ลึก&lt;/td&gt;&lt;td style=&quot;box-sizing: border-box; margin: 0px; padding: 13px 16px; vertical-align: top;&quot;&gt;อ่าน config array เข้าใจทันที&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;💡 เทคนิค Prompt สำหรับ PHP Dev ที่ได้ผลจริง&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;การ Vibe Coding จะได้ผลดีแค่ไหน ขึ้นอยู่กับคุณภาพของ prompt เป็นหลัก นี่คือ pattern ที่ใช้ได้ดีกับงาน PHP:&lt;/p&gt;&lt;div class=&quot;code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;code-header&quot; style=&quot;align-items: center; background: rgb(24, 24, 37); border-bottom: 1px solid rgb(49, 50, 68); box-sizing: border-box; display: flex; gap: 8px; margin: 0px; padding: 10px 16px;&quot;&gt;&lt;div class=&quot;dot dot-r&quot; style=&quot;background: rgb(255, 95, 86); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-y&quot; style=&quot;background: rgb(255, 189, 46); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;dot dot-g&quot; style=&quot;background: rgb(39, 201, 63); border-radius: 50%; box-sizing: border-box; height: 12px; margin: 0px; padding: 0px; width: 12px;&quot;&gt;&lt;/div&gt;&lt;span class=&quot;code-lang&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 12px; margin: 0px 0px 0px auto; padding: 0px;&quot;&gt;Prompt Template · สำหรับ AI&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #cdd6f4; font-family: &amp;quot;Fira Code&amp;quot;, monospace; font-size: 13.5px; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 20px;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ❌ Prompt แย่ — ไม่ชัดเจน&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;สร้าง CRUD สินค้าให้หน่อย&quot;&lt;/span&gt; &lt;span class=&quot;cm&quot; style=&quot;box-sizing: border-box; color: #6c7086; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// ✅ Prompt ดี — ระบุ context + constraint + format&lt;/span&gt; &lt;span class=&quot;str&quot; style=&quot;box-sizing: border-box; color: #89dceb; margin: 0px; padding: 0px;&quot;&gt;&quot;สร้าง Laravel Controller สำหรับ module จัดการสินค้า โดยมี fields: name (string), price (decimal), stock (int), category_id (FK) - ใช้ Form Request validation - ใช้ Repository Pattern - return JSON response สำหรับ API - ใส่ PHPDoc ทุก method - Laravel 11, PHP 8.2&quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;callout&quot; style=&quot;background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255); border-color: rgb(208, 215, 222) rgb(208, 215, 222) rgb(208, 215, 222) rgb(9, 105, 218); border-image: none 100% / 1 / 0 stretch; border-radius: 0px 8px 8px 0px; border-style: solid; border-width: 1px 1px 1px 4px; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 24px 0px; padding: 18px 22px;&quot;&gt;&lt;div class=&quot;callout-title&quot; style=&quot;box-sizing: border-box; color: #0969da; font-size: 13px; font-weight: 700; letter-spacing: 0.8px; margin: 0px 0px 8px; padding: 0px; text-transform: uppercase;&quot;&gt;🔑 หลัก 3 ข้อของ Prompt ที่ดี&lt;/div&gt;&lt;p style=&quot;box-sizing: border-box; font-size: 15.5px; margin: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Context&lt;/strong&gt; — บอก framework, version, และ architecture pattern ที่ใช้ &amp;nbsp;|&amp;nbsp;&amp;nbsp;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Constraint&lt;/strong&gt; — ระบุข้อจำกัด เช่น &quot;ห้าม raw query&quot;, &quot;ต้องมี type hint&quot; &amp;nbsp;|&amp;nbsp;&amp;nbsp;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Output Format&lt;/strong&gt; — บอกว่าต้องการ array, class, หรือ blade component&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;background-color: #f6f8fa; border-color: rgb(208, 215, 222) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; box-sizing: border-box; font-family: Sarabun, sans-serif; font-size: 17px; margin: 40px 0px; padding: 0px;&quot; /&gt;&lt;h2 style=&quot;background-color: #f6f8fa; border-left: 3px solid rgb(9, 105, 218); box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 22px; line-height: 1.4; margin: 48px 0px 16px; padding: 0px 0px 0px 14px;&quot;&gt;🏁 สรุป: Developer ยุคใหม่คือ Architect ไม่ใช่ Typist&lt;/h2&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;Vibe Coding ไม่ได้แปลว่า &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&quot;ให้ AI เขียนโค้ดทั้งหมดแล้วไม่ต้องคิดอะไร&quot;&lt;/em&gt; — มันหมายความว่าเราเปลี่ยน role ตัวเองจาก &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;คนพิมพ์โค้ด&lt;/strong&gt; ไปเป็น &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;คนออกแบบระบบ&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;สำหรับ PHP developer ที่ทำงานกับ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CodeIgniter 4&lt;/strong&gt; หรือ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Laravel&lt;/strong&gt; การนำ Vibe Coding มาใช้หมายถึง:&lt;/p&gt;&lt;ul style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; line-height: 2.2; margin: 0px 0px 16px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ลงทุนเวลาสร้าง &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;reusable components / config-driven modules&lt;/strong&gt; ให้ครบก่อน&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ใช้ AI generate &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;structure code&lt;/strong&gt; (config arrays, migrations, form requests) ที่ซ้ำซาก&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;โฟกัสเวลาของคุณไปกับ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;business logic, security review, และ architecture decisions&lt;/strong&gt;&lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ทดสอบและ review ผลลัพธ์จาก AI เสมอ — อย่าเชื่อ 100% โดยไม่ตรวจ&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-color: #f6f8fa; box-sizing: border-box; color: #1f2328; font-family: Sarabun, sans-serif; font-size: 17px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;ผลลัพธ์ที่ได้คือ — &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ระบบที่ deliver เร็วขึ้น, code ที่ maintainable มากขึ้น, และ developer ที่มีเวลาคิด creative solution&lt;/strong&gt; แทนที่จะนั่ง copy-paste boilerplate ซ้ำๆ ทุกวัน&lt;/p&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/8384518333018085474/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/crud-vibe-coding-php-dev.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8384518333018085474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8384518333018085474'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/crud-vibe-coding-php-dev.html' title='หยุดเขียน CRUD ซ้ำๆ: Vibe Coding เปลี่ยน PHP Dev ยังไง'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiKEfE84DfG-Un_99gN_0pPDYubqm-MevBNZC9e9ARSePVjmljwDmgOXlsSRT2jgVnMZZI-Ew_fzYnD8F2Rl8PivFjVV1g0xVVOQkxHRLZilsutAyZYYlHzNQlpUPEyMt4mCS48I5V9z3d6Pr8pOxE6XOGDvvek1g6l_UgEQTyn9h962ON7i0tEfk81voc=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-5470870222155918070</id><published>2026-06-09T16:30:00.000+07:00</published><updated>2026-06-09T16:30:00.112+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CodeIgniter"/><category scheme="http://www.blogger.com/atom/ns#" term="Laravel"/><title type='text'>Laravel vs CodeIgniter เลือกอันไหนดี?</title><content type='html'> &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh8WVm6OtUYzRKOw2HozeIT2jfLKwvggES6s6vEXsJCL97o5hHb_flTS1Jj3dT5O985q0EtNkpuo0OnBSA31CJRfXH18vRQDHB8ok4W7XzntvXWhfvr8S7lA1ZQ2wr18A-M9tOGKfwOs5GhX9JtK9SLWRPQXeAHEaEVyhACBpUZMFXyozG_2QxVMyKCOsQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh8WVm6OtUYzRKOw2HozeIT2jfLKwvggES6s6vEXsJCL97o5hHb_flTS1Jj3dT5O985q0EtNkpuo0OnBSA31CJRfXH18vRQDHB8ok4W7XzntvXWhfvr8S7lA1ZQ2wr18A-M9tOGKfwOs5GhX9JtK9SLWRPQXeAHEaEVyhACBpUZMFXyozG_2QxVMyKCOsQ&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt; &lt;div class=&quot;pma-hero&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(240, 244, 255) 0%, rgb(250, 245, 255) 60%, rgb(240, 253, 244) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 12px; border: 1px solid rgb(209, 213, 219); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; margin: 2rem 0px; overflow: hidden; padding: 2.5rem 2rem; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;pma-hero-badge&quot; style=&quot;background: rgba(124, 58, 237, 0.1); border-radius: 999px; border: 1px solid rgba(124, 58, 237, 0.35); color: #6d28d9; display: inline-block; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.08em; margin-bottom: 1rem; padding: 0.3rem 0.9rem; text-transform: uppercase;&quot;&gt;PHP Framework Showdown 2025&lt;/div&gt;&lt;h1 style=&quot;color: #111827; font-size: clamp(1.6rem, 4vw, 2.4rem); line-height: 1.3; margin: 0px 0px 0.8rem;&quot;&gt;&lt;span style=&quot;color: #7c3aed;&quot;&gt;Laravel&lt;/span&gt; vs &lt;span class=&quot;ci&quot; style=&quot;color: #059669;&quot;&gt;CodeIgniter&lt;/span&gt;&lt;br /&gt;เลือกอันไหนดี?&lt;/h1&gt;&lt;p style=&quot;color: #374151; font-size: 1rem; margin: 0px 0px 1rem;&quot;&gt;คู่มือฉบับสมบูรณ์สำหรับนักพัฒนาไทยที่อยากสร้าง Web App ด้วย PHP&lt;/p&gt;&lt;/div&gt;&lt;div style=&quot;color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px;&quot;&gt;&lt;span class=&quot;pma-tag&quot; style=&quot;background: rgb(243, 240, 255); border-radius: 4px; border: 1px solid rgb(221, 214, 254); color: #6d28d9; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-bottom: 0.35rem; margin-right: 0.35rem; padding: 0.2rem 0.65rem;&quot;&gt;Laravel&lt;/span&gt; &lt;span class=&quot;pma-tag&quot; style=&quot;background: rgb(243, 240, 255); border-radius: 4px; border: 1px solid rgb(221, 214, 254); color: #6d28d9; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-bottom: 0.35rem; margin-right: 0.35rem; padding: 0.2rem 0.65rem;&quot;&gt;CodeIgniter 4&lt;/span&gt; &lt;span class=&quot;pma-tag&quot; style=&quot;background: rgb(243, 240, 255); border-radius: 4px; border: 1px solid rgb(221, 214, 254); color: #6d28d9; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-bottom: 0.35rem; margin-right: 0.35rem; padding: 0.2rem 0.65rem;&quot;&gt;PHP&lt;/span&gt; &lt;span class=&quot;pma-tag&quot; style=&quot;background: rgb(243, 240, 255); border-radius: 4px; border: 1px solid rgb(221, 214, 254); color: #6d28d9; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-bottom: 0.35rem; margin-right: 0.35rem; padding: 0.2rem 0.65rem;&quot;&gt;MVC&lt;/span&gt; &lt;span class=&quot;pma-tag&quot; style=&quot;background: rgb(243, 240, 255); border-radius: 4px; border: 1px solid rgb(221, 214, 254); color: #6d28d9; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-bottom: 0.35rem; margin-right: 0.35rem; padding: 0.2rem 0.65rem;&quot;&gt;Backend&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;บทนำ: ทำไมต้องเลือกให้ถูกตัว&lt;/h2&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span face=&quot;Sarabun, sans-serif&quot; style=&quot;color: #374151; font-size: 16.8px; font-weight: 400; text-align: start;&quot;&gt;สำหรับนักพัฒนา PHP ที่กำลังเริ่มต้นสร้าง Web Application คำถามที่หลีกเลี่ยงไม่ได้คือ&lt;/span&gt;&lt;span face=&quot;Sarabun, sans-serif&quot; style=&quot;color: #374151; font-size: 16.8px; font-weight: 400; text-align: start;&quot;&gt; &lt;/span&gt;&lt;strong style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; text-align: start;&quot;&gt;&quot;ควรเริ่มด้วย Laravel หรือ CodeIgniter?&quot;&lt;/strong&gt;&lt;span face=&quot;Sarabun, sans-serif&quot; style=&quot;color: #374151; font-size: 16.8px; font-weight: 400; text-align: start;&quot;&gt; &lt;/span&gt;&lt;span face=&quot;Sarabun, sans-serif&quot; style=&quot;color: #374151; font-size: 16.8px; font-weight: 400; text-align: start;&quot;&gt;ทั้งสองเฟรมเวิร์กต่างมีชุมชนขนาดใหญ่ ใช้งาน production จริงมาหลายปี และรองรับ pattern MVC เหมือนกัน แต่แนวคิด ความซับซ้อน และกลุ่มเป้าหมายของโปรเจกต์กลับแตกต่างกันอย่างมีนัยสำคัญ&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;บทความนี้จะพาคุณเปรียบเทียบทั้งคู่แบบตรงไปตรงมา พร้อม code ตัวอย่างจริง ตารางเปรียบเทียบ และข้อสรุปว่าโปรเจกต์แบบไหนเหมาะกับเฟรมเวิร์กไหน&lt;/p&gt;&lt;div class=&quot;pma-callout&quot; style=&quot;background: rgb(245, 243, 255); border-color: rgb(221, 214, 254) rgb(221, 214, 254) rgb(221, 214, 254) rgb(124, 58, 237); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; color: #374151; font-family: Sarabun, sans-serif; font-size: 0.97rem; font-weight: 400; margin: 1.5rem 0px; padding: 1rem 1.25rem; text-align: start;&quot;&gt;&lt;strong style=&quot;color: #6d28d9;&quot;&gt;เป้าหมายบทความ:&lt;/strong&gt; ผู้อ่านที่ยังไม่เคยใช้เฟรมเวิร์ก PHP มาก่อน หรือเคยใช้ CodeIgniter 3 แล้วอยากรู้ว่าควร migrate ไป CI4 หรือโดดไป Laravel เลย&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;ทำความรู้จัก: Laravel และ CodeIgniter คืออะไร?&lt;/h2&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;🔴 Laravel&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;Laravel สร้างโดย &lt;strong&gt;Taylor Otwell&lt;/strong&gt; ปี 2011 โดยใช้ Symfony components เป็นรากฐาน ออกแบบมาสำหรับแอปพลิเคชันขนาดกลาง-ใหญ่ ที่ต้องการ feature ครบครัน เช่น ORM (Eloquent), Queue, Event, Broadcast, Authentication สำเร็จรูป, และ Blade templating engine ที่ทรงพลัง&lt;/p&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;🟢 CodeIgniter 4&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;CodeIgniter พัฒนาโดย EllisLab ตั้งแต่ปี 2006 และปัจจุบันดูแลโดย &lt;strong&gt;BCITstc&lt;/strong&gt; เวอร์ชัน 4 ที่ rewrite ใหม่ทั้งหมด เน้นความเบา เรียนรู้ง่าย bootstrap เร็ว และเหมาะกับโปรเจกต์ขนาดเล็ก-กลาง ที่ต้องการ overhead น้อย&lt;/p&gt;&lt;hr class=&quot;pma-hr&quot; style=&quot;border-color: rgb(229, 231, 235) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 2rem 0px; text-align: start;&quot; /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;ตารางเปรียบเทียบ: Laravel vs CodeIgniter 4&lt;/h2&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-table-wrap&quot; style=&quot;color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow-x: auto; text-align: start;&quot;&gt;&lt;table class=&quot;pma-table&quot; style=&quot;border-collapse: collapse; font-size: 0.93rem; width: 860px;&quot;&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(243, 240, 255); border-bottom: 2px solid rgb(221, 214, 254); color: #6d28d9; padding: 0.75rem 1rem; text-align: left; white-space: nowrap;&quot;&gt;หัวข้อ&lt;/th&gt;&lt;th style=&quot;background: rgb(243, 240, 255); border-bottom: 2px solid rgb(221, 214, 254); color: #6d28d9; padding: 0.75rem 1rem; text-align: left; white-space: nowrap;&quot;&gt;Laravel&lt;/th&gt;&lt;th style=&quot;background: rgb(243, 240, 255); border-bottom: 2px solid rgb(221, 214, 254); color: #6d28d9; padding: 0.75rem 1rem; text-align: left; white-space: nowrap;&quot;&gt;CodeIgniter 4&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;ความยาก (Learning Curve)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-warn&quot; style=&quot;background: rgb(254, 249, 195); border-radius: 4px; border: 1px solid rgb(253, 230, 138); color: #854d0e; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;ปานกลาง–สูง&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;ต่ำ–ปานกลาง&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;ดี (พร้อม caching)&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;เร็วกว่า (lightweight)&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;ORM&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;Eloquent (ทรงพลัง)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;Query Builder / Model เบา&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;Templating Engine&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;Blade (มี directive เยอะ)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;PHP native / Parser class&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;CLI Tool&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;Artisan (ครบมาก)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;Spark (พื้นฐาน)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;Built-in Auth&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;Laravel Breeze / Jetstream&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;Shield (add-on)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;Community &amp;amp; Package&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;ใหญ่มาก (Packagist)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;เล็กกว่า แต่เพียงพอ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;Hosting requirement&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;PHP 8.1+, Composer&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;PHP 7.4+, เกือบทุก host&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;strong&gt;เหมาะกับโปรเจกต์&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;กลาง–ใหญ่, SaaS, API&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(243, 244, 246); color: #374151; padding: 0.65rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge-good&quot; style=&quot;background: rgb(220, 252, 231); border-radius: 4px; border: 1px solid rgb(187, 247, 208); color: #166534; font-size: 0.8rem; font-weight: 600; padding: 0.15rem 0.5rem;&quot;&gt;เล็ก–กลาง, ราชการ, Intranet&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr class=&quot;pma-hr&quot; style=&quot;border-color: rgb(229, 231, 235) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 2rem 0px; text-align: start;&quot; /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;เปรียบเทียบ Code จริง: Routing&lt;/h2&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;เริ่มจากสิ่งพื้นฐานที่สุด — การกำหนด Route&lt;/p&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;Laravel — &lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;routes/web.php&lt;/code&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;routes/web.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ── Laravel: Route พื้นฐาน ──────────────────────────&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products&#39;&lt;/span&gt;, [&lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;index&#39;&lt;/span&gt;]); &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products&#39;&lt;/span&gt;, [&lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;store&#39;&lt;/span&gt;]); &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products/{id}&#39;&lt;/span&gt;, [&lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;update&#39;&lt;/span&gt;]); &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;delete&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products/{id}&#39;&lt;/span&gt;, [&lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;destroy&#39;&lt;/span&gt;]); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// หรือใช้ Resource route แทนทั้ง 4 บรรทัดข้างบน&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Route&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;resource&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;products&#39;&lt;/span&gt;, &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductController&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;CodeIgniter 4 — &lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;app/Config/Routes.php&lt;/code&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;app/Config/Routes.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ── CodeIgniter 4: Route พื้นฐาน ─────────────────────&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;ProductController::index&#39;&lt;/span&gt;); &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;ProductController::store&#39;&lt;/span&gt;); &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products/(:num)&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;ProductController::update/$1&#39;&lt;/span&gt;); &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;delete&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;/products/(:num)&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;ProductController::destroy/$1&#39;&lt;/span&gt;); &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// หรือใช้ presenter (resource-style)&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;resource&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;products&#39;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pma-callout&quot; style=&quot;background: rgb(245, 243, 255); border-color: rgb(221, 214, 254) rgb(221, 214, 254) rgb(221, 214, 254) rgb(124, 58, 237); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; color: #374151; font-family: Sarabun, sans-serif; font-size: 0.97rem; font-weight: 400; margin: 1.5rem 0px; padding: 1rem 1.25rem; text-align: start;&quot;&gt;&lt;strong style=&quot;color: #6d28d9;&quot;&gt;💡 สังเกต:&lt;/strong&gt; Syntax ของทั้งคู่คล้ายกันมาก ต่างกันแค่ Laravel ใช้ Facade (&lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;Route::&lt;/code&gt;) ส่วน CI4 ใช้ object (&lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;$routes-&amp;gt;&lt;/code&gt;) และ parameter capture ใช้ &lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;{id}&lt;/code&gt; vs &lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;(:num)&lt;/code&gt;&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;เปรียบเทียบ Code จริง: Database / ORM&lt;/h2&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;Laravel — Eloquent ORM&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;app/Models/Product.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;App\Models&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Product&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Model&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$fillable&lt;/span&gt; = [&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;name&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;price&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;stock&#39;&lt;/span&gt;]; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// Relationship: สินค้า belongs to หมวดหมู่&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;category&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;belongsTo&lt;/span&gt;(&lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Category&lt;/span&gt;::&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt;); } } &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ── การใช้งานใน Controller ───────────────────────────&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$products&lt;/span&gt; = &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Product&lt;/span&gt;::&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;category&#39;&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;price&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;&amp;gt;&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;100&lt;/span&gt;)-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;get&lt;/span&gt;();&lt;/pre&gt;&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;CodeIgniter 4 — Model + Query Builder&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;app/Models/ProductModel.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;App\Models&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;CodeIgniter\Model&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;ProductModel&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;cls&quot; style=&quot;color: #fab387;&quot;&gt;Model&lt;/span&gt; { &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$table&lt;/span&gt; = &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;products&#39;&lt;/span&gt;; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$allowedFields&lt;/span&gt; = [&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;name&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;price&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;stock&#39;&lt;/span&gt;]; &lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;// ดึงสินค้าที่ราคา &amp;gt; 100 พร้อม join หมวดหมู่&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;getWithCategory&lt;/span&gt;() { &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;select&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;products.*, categories.name AS cat_name&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;join&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;categories&#39;&lt;/span&gt;, &lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;categories.id = products.category_id&#39;&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;products.price &amp;gt;&#39;&lt;/span&gt;, &lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;100&lt;/span&gt;) -&amp;gt;&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;findAll&lt;/span&gt;(); } }&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;pma-callout&quot; style=&quot;background: rgb(245, 243, 255); border-color: rgb(221, 214, 254) rgb(221, 214, 254) rgb(221, 214, 254) rgb(124, 58, 237); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; color: #374151; font-family: Sarabun, sans-serif; font-size: 0.97rem; font-weight: 400; margin: 1.5rem 0px; padding: 1rem 1.25rem; text-align: start;&quot;&gt;&lt;strong style=&quot;color: #6d28d9;&quot;&gt;💡 ความต่าง:&lt;/strong&gt; Eloquent ของ Laravel ใช้ Relationship (&lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;belongsTo&lt;/code&gt;, &lt;code style=&quot;background: rgb(243, 240, 255); border-radius: 4px; color: #5b21b6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.85em; padding: 0.1rem 0.35rem;&quot;&gt;hasMany&lt;/code&gt;) แบบ OOP เต็มรูปแบบ ทำให้ query ซับซ้อนเขียนได้หรูหรากว่า แต่ CI4 ใช้ Query Builder ที่ใกล้เคียง SQL ดั้งเดิม เหมาะกับคนที่ถนัด SQL&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;เปรียบเทียบ Template Engine&lt;/h2&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;Laravel — Blade Template&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;resources/views/products/index.blade.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;{{-- Blade directive สะอาดกว่า PHP native มาก --}}&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@extends&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;layouts.app&#39;&lt;/span&gt;) &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@section&lt;/span&gt;(&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;content&#39;&lt;/span&gt;) &amp;lt;h1&amp;gt;รายการสินค้า&amp;lt;/h1&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@forelse&lt;/span&gt; (&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$products&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;) &amp;lt;p&amp;gt;{{ &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;-&amp;gt;name }} — {{ &lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;number_format&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;-&amp;gt;price) }} บาท&amp;lt;/p&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@empty&lt;/span&gt; &amp;lt;p&amp;gt;ไม่มีสินค้า&amp;lt;/p&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@endforelse&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;@endsection&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 1.15rem; margin: 1.8rem 0px 0.6rem;&quot;&gt;CodeIgniter 4 — PHP Native View&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-code-wrap&quot; style=&quot;background: rgb(30, 30, 46); border-radius: 10px; border: 1px solid rgb(49, 50, 68); color: #1f2328; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 1.5rem 0px; overflow: hidden; text-align: start;&quot;&gt;&lt;div class=&quot;pma-code-bar&quot; style=&quot;align-items: center; background: rgb(40, 40, 56); display: flex; gap: 0.5rem; padding: 0.55rem 1rem;&quot;&gt;&lt;span class=&quot;dot-r&quot; style=&quot;background: rgb(255, 95, 87); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-y&quot; style=&quot;background: rgb(254, 188, 46); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;dot-g&quot; style=&quot;background: rgb(40, 200, 64); border-radius: 50%; display: inline-block; height: 12px; width: 12px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;pma-filename&quot; style=&quot;background: none; border-radius: 0px; color: #6c7086; display: inline-block; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.78rem; height: auto; margin-left: auto; width: auto;&quot;&gt;app/Views/products/index.php&lt;/span&gt;&lt;/div&gt;&lt;pre style=&quot;color: #cdd6f4; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 0.88rem; line-height: 1.7; margin: 0px; overflow-x: auto; padding: 1.2rem 1.4rem;&quot;&gt;&lt;span class=&quot;cm&quot; style=&quot;color: #6c7086; font-style: italic;&quot;&gt;&amp;lt;?php /* CI4 ใช้ PHP ตรงๆ หรือ Parser class ก็ได้ */ ?&amp;gt;&lt;/span&gt; &amp;lt;h1&amp;gt;รายการสินค้า&amp;lt;/h1&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php if&lt;/span&gt; (!&lt;span class=&quot;fn&quot; style=&quot;color: #cba6f7;&quot;&gt;empty&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$products&lt;/span&gt;)) : &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php foreach&lt;/span&gt; (&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$products&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;) : &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;?&amp;gt;&lt;/span&gt; &amp;lt;p&amp;gt;&lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?= esc&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;[&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;name&#39;&lt;/span&gt;]) &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;?&amp;gt;&lt;/span&gt; — &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?= number_format&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #89dceb;&quot;&gt;$product&lt;/span&gt;[&lt;span class=&quot;str&quot; style=&quot;color: #a6e3a1;&quot;&gt;&#39;price&#39;&lt;/span&gt;]) &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;?&amp;gt;&lt;/span&gt; บาท&amp;lt;/p&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php endforeach; ?&amp;gt;&lt;/span&gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php else : ?&amp;gt;&lt;/span&gt; &amp;lt;p&amp;gt;ไม่มีสินค้า&amp;lt;/p&amp;gt; &lt;span class=&quot;kw&quot; style=&quot;color: #f38ba8;&quot;&gt;&amp;lt;?php endif; ?&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr class=&quot;pma-hr&quot; style=&quot;border-color: rgb(229, 231, 235) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 2rem 0px; text-align: start;&quot; /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;เลือกอันไหน? — คำตอบตรงๆ&lt;/h2&gt;&lt;h4 style=&quot;color: #a21caf; font-size: 1rem; margin: 0px 0px 0.5rem;&quot;&gt;🔴 เลือก Laravel เมื่อ…&lt;/h4&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-verdict&quot; style=&quot;color: #1f2328; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; gap: 1rem; margin: 1.5rem 0px; text-align: start;&quot;&gt;&lt;div class=&quot;pma-verdict-card vc-laravel&quot; style=&quot;background: rgb(249, 250, 251); border-color: rgb(232, 121, 249) rgb(229, 231, 235) rgb(229, 231, 235); border-image: initial; border-radius: 10px; border-style: solid; border-width: 3px 1px 1px; flex: 1 1 0%; min-width: 200px; padding: 1.1rem 1.25rem;&quot;&gt;&lt;p style=&quot;color: #6b7280; font-size: 0.9rem; margin: 0px;&quot;&gt;— สร้าง SaaS หรือ Multi-tenant app&lt;br /&gt;— ต้องการ API backend สำหรับ React/Vue/Next.js&lt;br /&gt;— โปรเจกต์มี team และต้องการ structure ชัดเจน&lt;br /&gt;— ต้องการ Queue, Job, Event, Notification สำเร็จรูป&lt;br /&gt;— ระยะยาว และต้องการ ecosystem ที่ใหญ่&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h4 style=&quot;color: #065f46; font-size: 1rem; margin: 0px 0px 0.5rem;&quot;&gt;🟢 เลือก CodeIgniter 4 เมื่อ…&lt;/h4&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;div class=&quot;pma-verdict&quot; style=&quot;color: #1f2328; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; gap: 1rem; margin: 1.5rem 0px; text-align: start;&quot;&gt;&lt;div class=&quot;pma-verdict-card vc-ci&quot; style=&quot;background: rgb(249, 250, 251); border-color: rgb(52, 211, 153) rgb(229, 231, 235) rgb(229, 231, 235); border-image: initial; border-radius: 10px; border-style: solid; border-width: 3px 1px 1px; flex: 1 1 0%; min-width: 200px; padding: 1.1rem 1.25rem;&quot;&gt;&lt;p style=&quot;color: #6b7280; font-size: 0.9rem; margin: 0px;&quot;&gt;— โปรเจกต์ราชการ/องค์กร ที่ shared hosting จำกัด&lt;br /&gt;— ต้องการ bootstrap เร็ว ทีมขนาดเล็ก&lt;br /&gt;— Migrate มาจาก CI3 หรือ CI2&lt;br /&gt;— ระบบ Intranet, POS, หรือ Back-office เรียบง่าย&lt;br /&gt;— Server spec ต่ำ ต้องการ footprint น้อย&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;pma-callout&quot; style=&quot;background: rgb(245, 243, 255); border-color: rgb(221, 214, 254) rgb(221, 214, 254) rgb(221, 214, 254) rgb(124, 58, 237); border-image: initial; border-radius: 8px; border-style: solid; border-width: 1px 1px 1px 4px; color: #374151; font-family: Sarabun, sans-serif; font-size: 0.97rem; font-weight: 400; margin: 1.5rem 0px; padding: 1rem 1.25rem; text-align: start;&quot;&gt;&lt;strong style=&quot;color: #6d28d9;&quot;&gt;⚠️ ข้อควรระวัง:&lt;/strong&gt; อย่าเลือกตาม &quot;กระแส&quot; — Laravel ได้รับความนิยมสูงกว่า แต่ CodeIgniter ยังมี active community และตอบโจทย์งานจริงในไทยได้ดีมาก โดยเฉพาะระบบราชการและ Intranet ที่ hosting มีข้อจำกัด&lt;/div&gt;&lt;hr class=&quot;pma-hr&quot; style=&quot;border-color: rgb(229, 231, 235) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 2rem 0px; text-align: start;&quot; /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(124, 58, 237); color: #111827; font-family: Sarabun, sans-serif; font-size: 1.45rem; margin: 2.5rem 0px 1rem; padding-left: 0.8rem;&quot;&gt;บทสรุป&lt;/h2&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;ทั้ง Laravel และ CodeIgniter 4 ต่างเป็นเฟรมเวิร์กที่ดี ใช้งานได้จริง และมี community รองรับ ความต่างอยู่ที่ &lt;strong&gt;โฟกัส&lt;/strong&gt; — Laravel โฟกัสที่ &lt;em&gt;ความสามารถและ ecosystem&lt;/em&gt; ที่ครบครัน ส่วน CodeIgniter 4 โฟกัสที่ &lt;em&gt;ความเบาและเรียนรู้ง่าย&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;หากคุณเพิ่งเริ่มต้น PHP และมีเวลาเรียนรู้ — &lt;strong style=&quot;color: #a21caf;&quot;&gt;Laravel&lt;/strong&gt; คือการลงทุนที่คุ้มในระยะยาว เพราะ job market ต้องการสูงกว่า แต่ถ้าคุณต้องการ deliver งานเร็ว งบน้อย หรือดูแลระบบองค์กรอยู่แล้ว — &lt;strong style=&quot;color: #065f46;&quot;&gt;CodeIgniter 4&lt;/strong&gt; เป็นตัวเลือกที่ตรงจุดและเชื่อถือได้&lt;/p&gt;&lt;p style=&quot;color: #374151; font-family: Sarabun, sans-serif; font-size: 16.8px; font-weight: 400; margin: 0px 0px 1rem; text-align: start;&quot;&gt;ในที่สุด เฟรมเวิร์กที่ดีที่สุดคือเฟรมเวิร์กที่ &lt;strong style=&quot;color: #6d28d9;&quot;&gt;ทีมของคุณใช้ได้ดีที่สุด&lt;/strong&gt; ไม่ใช่ที่มี star บน GitHub มากที่สุด&lt;/p&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;&lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/5470870222155918070/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-vs-codeigniter.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/5470870222155918070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/5470870222155918070'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/laravel-vs-codeigniter.html' title='Laravel vs CodeIgniter เลือกอันไหนดี?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEh8WVm6OtUYzRKOw2HozeIT2jfLKwvggES6s6vEXsJCL97o5hHb_flTS1Jj3dT5O985q0EtNkpuo0OnBSA31CJRfXH18vRQDHB8ok4W7XzntvXWhfvr8S7lA1ZQ2wr18A-M9tOGKfwOs5GhX9JtK9SLWRPQXeAHEaEVyhACBpUZMFXyozG_2QxVMyKCOsQ=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-4633920941976974567</id><published>2026-06-09T11:30:00.000+07:00</published><updated>2026-06-09T11:30:00.114+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Claude Code"/><title type='text'>คู่มือการใช้งาน Claude Code ให้ได้ผลจริง</title><content type='html'>&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjR_AovDdV-9bqLNFN_oC3TWG-kEKbx9Lcom2WPURNp6gil_WKuXxywkbkyaCBrn2AZyLJjqpW1TSv0e9PI8LTc-Wb78Gks2NWyZDyAxVC_E9Wu18pcePjTmag1UQ1ibZIA1qnYfea_gFmHhIgy23lIBIm-f3aeuuQ_DUbVd4UN0JRU08yqTwjIBIz58j4&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1536&quot; data-original-width=&quot;2752&quot; height=&quot;356&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjR_AovDdV-9bqLNFN_oC3TWG-kEKbx9Lcom2WPURNp6gil_WKuXxywkbkyaCBrn2AZyLJjqpW1TSv0e9PI8LTc-Wb78Gks2NWyZDyAxVC_E9Wu18pcePjTmag1UQ1ibZIA1qnYfea_gFmHhIgy23lIBIm-f3aeuuQ_DUbVd4UN0JRU08yqTwjIBIz58j4=w640-h356&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;topband&quot; style=&quot;align-items: end; background: rgb(26, 39, 68); box-sizing: border-box; color: #1a1612; display: grid; font-family: Sarabun, sans-serif; gap: 24px; grid-template-columns: 1fr auto; margin: 0px; padding: 40px 48px 36px;&quot;&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;topband-title&quot; style=&quot;box-sizing: border-box; color: rgba(255, 255, 255, 0.45); font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 13px; letter-spacing: 2px; margin: 0px 0px 10px; padding: 0px; text-transform: uppercase;&quot;&gt;คู่มือการใช้งาน · Claude Code&lt;/div&gt;&lt;h1 style=&quot;box-sizing: border-box; color: white; font-size: clamp(26px, 4vw, 40px); line-height: 1.2; margin: 0px; padding: 0px;&quot;&gt;ใช้ Claude Code&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;ให้ได้ผลจริง&lt;/h1&gt;&lt;p class=&quot;topband-desc&quot; style=&quot;box-sizing: border-box; color: rgba(255, 255, 255, 0.55); font-size: 14px; line-height: 1.8; margin: 10px 0px 0px; max-width: 440px; padding: 0px;&quot;&gt;Claude Code คือ AI ที่ทำงานใน Terminal ได้โดยตรง — อ่านไฟล์ แก้โค้ด รันคำสั่ง ได้เลย โดยไม่ต้องก๊อปวางเอง คู่มือนี้รวมทุกอย่างที่ต้องรู้ไว้ในหน้าเดียว&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;topband-stats&quot; style=&quot;align-items: flex-end; box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;stat&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; text-align: right;&quot;&gt;&lt;div class=&quot;stat-num&quot; style=&quot;box-sizing: border-box; color: #7eb8e8; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 28px; font-weight: 600; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;8&lt;/div&gt;&lt;div class=&quot;stat-label&quot; style=&quot;box-sizing: border-box; color: rgba(255, 255, 255, 0.35); font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px;&quot;&gt;เทคนิคหลัก&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;stat&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; text-align: right;&quot;&gt;&lt;div class=&quot;stat-num&quot; style=&quot;box-sizing: border-box; color: #7eb8e8; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 28px; font-weight: 600; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;3&lt;/div&gt;&lt;div class=&quot;stat-label&quot; style=&quot;box-sizing: border-box; color: rgba(255, 255, 255, 0.35); font-size: 11px; letter-spacing: 1px; margin: 0px; padding: 0px;&quot;&gt;กฎสำคัญ&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;what&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-bottom: 1px solid rgb(224, 219, 208); box-sizing: border-box; color: #1a1612; display: grid; font-family: Sarabun, sans-serif; gap: 20px; grid-template-columns: auto 1fr; margin: 0px; padding: 28px 48px;&quot;&gt;&lt;div class=&quot;what-icon&quot; style=&quot;box-sizing: border-box; font-size: 36px; line-height: 1; margin: 0px; padding: 0px;&quot;&gt;💻&lt;/div&gt;&lt;div class=&quot;what-text&quot; style=&quot;box-sizing: border-box; color: #3a3530; font-size: 15px; line-height: 1.85; margin: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; color: #1a2744; margin: 0px; padding: 0px;&quot;&gt;Claude Code ≠ Chatbot ในเว็บ&lt;/strong&gt; — มันทำงานอยู่ในคอมของคุณโดยตรงผ่าน Terminal สั่งให้อ่านไฟล์ได้ แก้โค้ดได้ รันคำสั่งได้ ผลที่ได้คือ &quot;ของจริงในโปรเจกต์&quot; ไม่ใช่แค่ข้อความ ติดตั้งผ่าน &lt;strong style=&quot;box-sizing: border-box; color: #1a2744; margin: 0px; padding: 0px;&quot;&gt;VS Code Extension&lt;/strong&gt; → ล็อกอิน → ใช้ได้เลย&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;body&quot; style=&quot;box-sizing: border-box; color: #1a1612; display: grid; font-family: Sarabun, sans-serif; gap: 32px 40px; grid-template-columns: 1fr 1fr; margin: 0px; padding: 40px 48px;&quot;&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;ก่อนเริ่มโปรเจกต์ใหม่&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;↓&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;รัน /init ก่อนเสมอ&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;Claude จะสแกนโปรเจกต์และสร้างไฟล์ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;CLAUDE.md&lt;/strong&gt; — เป็นเหมือน &quot;โน้ตย่อของโปรเจกต์&quot; ที่ Claude อ่านทุกครั้งที่เปิด Session ไม่ต้องอธิบายซ้ำ&lt;/div&gt;&lt;div class=&quot;cmd&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: #7eb8e8; display: inline-block; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 11px; margin: 5px 0px 0px; padding: 1px 8px;&quot;&gt;/init&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;📝&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;เขียน CLAUDE.md ให้กระชับ&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;บอกแค่ที่จำเป็น — โปรเจกต์ทำอะไร, ไฟล์อยู่ที่ไหน, ข้อกำหนดพิเศษ ไม่เกิน 100–200 บรรทัด ยิ่งยาวยิ่งช้า&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;02&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;เลือก Model ให้ตรงงาน&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;model-rows&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 8px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;model-row&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(224, 219, 208); box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 80px 1fr 80px; margin: 0px; padding: 12px 14px;&quot;&gt;&lt;div class=&quot;model-name&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Opus&lt;/div&gt;&lt;div class=&quot;model-use&quot; style=&quot;box-sizing: border-box; color: #3a3530; font-size: 12.5px; line-height: 1.6; margin: 0px; padding: 0px;&quot;&gt;งานคิดซับซ้อน วิเคราะห์ลึก โปรเจกต์ใหญ่&lt;/div&gt;&lt;div class=&quot;pill pill-h&quot; style=&quot;background: rgb(253, 236, 234); border-radius: 20px; box-sizing: border-box; color: #c0392b; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 8px; text-align: center;&quot;&gt;ราคาสูง&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;model-row&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(224, 219, 208); box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 80px 1fr 80px; margin: 0px; padding: 12px 14px;&quot;&gt;&lt;div class=&quot;model-name&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Sonnet&lt;/div&gt;&lt;div class=&quot;model-use&quot; style=&quot;box-sizing: border-box; color: #3a3530; font-size: 12.5px; line-height: 1.6; margin: 0px; padding: 0px;&quot;&gt;งานทั่วไปทุกวัน — &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;แนะนำใช้เป็นหลัก&lt;/strong&gt;&lt;/div&gt;&lt;div class=&quot;pill pill-m&quot; style=&quot;background: rgb(234, 242, 251); border-radius: 20px; box-sizing: border-box; color: #1a5e94; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 8px; text-align: center;&quot;&gt;คุ้มค่า&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;model-row&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(224, 219, 208); box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 80px 1fr 80px; margin: 0px; padding: 12px 14px;&quot;&gt;&lt;div class=&quot;model-name&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 12px; font-weight: 600; margin: 0px; padding: 0px;&quot;&gt;Haiku&lt;/div&gt;&lt;div class=&quot;model-use&quot; style=&quot;box-sizing: border-box; color: #3a3530; font-size: 12.5px; line-height: 1.6; margin: 0px; padding: 0px;&quot;&gt;งานเบา คำถามสั้น หรืองาน batch ปริมาณมาก&lt;/div&gt;&lt;div class=&quot;pill pill-l&quot; style=&quot;background: rgb(234, 250, 246); border-radius: 20px; box-sizing: border-box; color: #1a7a5c; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; letter-spacing: 0.5px; margin: 0px; padding: 3px 8px; text-align: center;&quot;&gt;ถูกสุด&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;divider&quot; style=&quot;background: rgb(232, 224, 208); box-sizing: border-box; grid-column: 1 / -1; height: 1px; margin: 0px; padding: 0px;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;เปิด Plan Mode ก่อนสั่งทำงาน&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;🗺&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;กด Shift + Tab&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;Claude จะแสดงแผนการทำงานก่อน — ตรวจสอบให้ถูกต้อง แล้วค่อยกดยืนยัน ลดโอกาสที่งานจะออกมาผิดทิศโดยไม่รู้ตัว&lt;/div&gt;&lt;div class=&quot;cmd&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: #7eb8e8; display: inline-block; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 11px; margin: 5px 0px 0px; padding: 1px 8px;&quot;&gt;Shift + Tab → ดูแผน → ยืนยัน&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;04&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;ล้าง Context หลังจบแต่ละงาน&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;🧹&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;พิมพ์ /clear ทุกครั้ง&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;AI มีพื้นที่จำจำกัด ถ้าสะสมข้อมูลมากเกินไป คุณภาพงานจะตก และโอกาสผิดพลาดสูงขึ้นมาก ทำเป็นนิสัยหลังจบงานแต่ละชิ้น&lt;/div&gt;&lt;div class=&quot;cmd&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: #7eb8e8; display: inline-block; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 11px; margin: 5px 0px 0px; padding: 1px 8px;&quot;&gt;/clear&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;05&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;บันทึก Slash Commands ไว้ใช้ซ้ำ&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;⚡&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;งานซ้ำ ๆ → บันทึกเป็นคำสั่ง&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;เช่น สร้าง &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;/commit-message&lt;/strong&gt; ไว้ให้ Claude เช็กไฟล์ที่เปลี่ยนแปลงและเขียน Commit message ให้เองอัตโนมัติ แค่พิมพ์ชื่อคำสั่งสั้น ๆ แล้วกดยืนยัน&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;สร้าง Skill ไว้ใช้ข้ามโปรเจกต์&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;steps&quot; style=&quot;box-sizing: border-box; display: flex; flex-direction: column; gap: 10px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;📦&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;Skill = ไฟล์ขั้นตอนที่นำกลับมาใช้ได้&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;เขียนขั้นตอนในไฟล์ Markdown เช่น วิธี Code Review หรือวิธี Refactor — Claude เรียกใช้ได้เองเมื่อเหมาะสม และแชร์ให้ทีมใช้ได้ด้วย&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;step&quot; style=&quot;background: rgb(247, 244, 238); border-left: 3px solid rgb(216, 208, 192); border-radius: 6px; box-sizing: border-box; display: grid; gap: 12px; grid-template-columns: 28px 1fr; margin: 0px; padding: 12px 14px; transition: border-color 0.2s;&quot;&gt;&lt;div class=&quot;step-dot&quot; style=&quot;align-items: center; background: rgb(26, 39, 68); border-radius: 50%; box-sizing: border-box; color: #7eb8e8; display: flex; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; font-weight: 600; height: 28px; justify-content: center; margin: 2px 0px 0px; padding: 0px; width: 28px;&quot;&gt;≠&lt;/div&gt;&lt;div class=&quot;step-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;step-name&quot; style=&quot;box-sizing: border-box; font-size: 13.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;Skill vs Slash Command&lt;/div&gt;&lt;div class=&quot;step-detail&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Skill&lt;/strong&gt; — Claude เรียกใช้เองได้อัตโนมัติ&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;&lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;Slash Command&lt;/strong&gt; — ผู้ใช้ต้องพิมพ์เรียกเอง&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;full&quot; style=&quot;box-sizing: border-box; grid-column: 1 / -1; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;07&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;ต่อ MCP Servers — ทำงานทุกอย่างจากที่เดียว&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;mcp-list&quot; style=&quot;box-sizing: border-box; display: flex; flex-wrap: wrap; gap: 8px; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;mcp-chip&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(208, 200, 184); box-sizing: border-box; color: #3a3530; display: flex; font-size: 12.5px; gap: 7px; margin: 0px; padding: 8px 14px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;&quot;&gt;🐙&lt;/span&gt;GitHub — จัดการ Repo / PR / Issues&lt;/div&gt;&lt;div class=&quot;mcp-chip&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(208, 200, 184); box-sizing: border-box; color: #3a3530; display: flex; font-size: 12.5px; gap: 7px; margin: 0px; padding: 8px 14px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;&quot;&gt;📚&lt;/span&gt;Context7 — ดึง Docs Library ล่าสุด&lt;/div&gt;&lt;div class=&quot;mcp-chip&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(208, 200, 184); box-sizing: border-box; color: #3a3530; display: flex; font-size: 12.5px; gap: 7px; margin: 0px; padding: 8px 14px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;&quot;&gt;📧&lt;/span&gt;Email — อ่าน/เขียนอีเมลใน Terminal&lt;/div&gt;&lt;div class=&quot;mcp-chip&quot; style=&quot;align-items: center; background: rgb(247, 244, 238); border-radius: 6px; border: 1px solid rgb(208, 200, 184); box-sizing: border-box; color: #3a3530; display: flex; font-size: 12.5px; gap: 7px; margin: 0px; padding: 8px 14px;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-size: 16px; margin: 0px; padding: 0px;&quot;&gt;📊&lt;/span&gt;Google Sheets — อ่าน/เขียน Spreadsheet&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;mcp-note&quot; style=&quot;box-sizing: border-box; color: #6a6058; font-size: 13px; line-height: 1.75; margin: 12px 0px 0px; padding: 0px;&quot;&gt;MCP (Model Context Protocol) คือสะพานเชื่อม Claude Code กับแอปภายนอก ทำให้ไม่ต้องสลับหน้าต่างไปมา — ทุกอย่างอยู่ใน Session เดียว&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;full&quot; style=&quot;box-sizing: border-box; grid-column: 1 / -1; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;08&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;ลำดับการทำงานที่ควรใช้เสมอ&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;wf-track&quot; style=&quot;border-radius: 6px; border: 1px solid rgb(216, 208, 192); box-sizing: border-box; display: grid; gap: 0px; grid-template-columns: repeat(4, 1fr); margin: 4px 0px 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;wf-node&quot; style=&quot;background: rgb(247, 244, 238); border-right: 1px solid rgb(216, 208, 192); box-sizing: border-box; margin: 0px; padding: 16px 12px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;wf-n&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 9px; letter-spacing: 1.5px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;STEP 1&lt;/div&gt;&lt;div class=&quot;wf-icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;🗺️&lt;/div&gt;&lt;div class=&quot;wf-label&quot; style=&quot;box-sizing: border-box; font-size: 12.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;วางแผน&lt;/div&gt;&lt;div class=&quot;wf-sub&quot; style=&quot;box-sizing: border-box; color: #7a7068; font-size: 11px; line-height: 1.5; margin: 0px; padding: 0px;&quot;&gt;เปิด Plan Mode ตรวจสอบแผนก่อน&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wf-node&quot; style=&quot;background: rgb(247, 244, 238); border-right: 1px solid rgb(216, 208, 192); box-sizing: border-box; margin: 0px; padding: 16px 12px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;wf-n&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 9px; letter-spacing: 1.5px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;STEP 2&lt;/div&gt;&lt;div class=&quot;wf-icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;⚙️&lt;/div&gt;&lt;div class=&quot;wf-label&quot; style=&quot;box-sizing: border-box; font-size: 12.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;สั่งทำงาน&lt;/div&gt;&lt;div class=&quot;wf-sub&quot; style=&quot;box-sizing: border-box; color: #7a7068; font-size: 11px; line-height: 1.5; margin: 0px; padding: 0px;&quot;&gt;ทีละงาน ไม่โยนทั้งก้อน&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wf-node&quot; style=&quot;background: rgb(247, 244, 238); border-right: 1px solid rgb(216, 208, 192); box-sizing: border-box; margin: 0px; padding: 16px 12px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;wf-n&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 9px; letter-spacing: 1.5px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;STEP 3&lt;/div&gt;&lt;div class=&quot;wf-icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;🔍&lt;/div&gt;&lt;div class=&quot;wf-label&quot; style=&quot;box-sizing: border-box; font-size: 12.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;ตรวจสอบ&lt;/div&gt;&lt;div class=&quot;wf-sub&quot; style=&quot;box-sizing: border-box; color: #7a7068; font-size: 11px; line-height: 1.5; margin: 0px; padding: 0px;&quot;&gt;ดูผลเองทุกครั้ง อย่าเชื่อแค่คำว่า &quot;เสร็จ&quot;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wf-node&quot; style=&quot;background: rgb(247, 244, 238); border-right-color: currentcolor; border-right-style: none; border-right-width: medium; box-sizing: border-box; margin: 0px; padding: 16px 12px; position: relative; text-align: center;&quot;&gt;&lt;div class=&quot;wf-n&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 9px; letter-spacing: 1.5px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;STEP 4&lt;/div&gt;&lt;div class=&quot;wf-icon&quot; style=&quot;box-sizing: border-box; font-size: 20px; margin: 0px 0px 6px; padding: 0px;&quot;&gt;🧹&lt;/div&gt;&lt;div class=&quot;wf-label&quot; style=&quot;box-sizing: border-box; font-size: 12.5px; font-weight: 700; margin: 0px 0px 3px; padding: 0px;&quot;&gt;Clear&lt;/div&gt;&lt;div class=&quot;wf-sub&quot; style=&quot;box-sizing: border-box; color: #7a7068; font-size: 11px; line-height: 1.5; margin: 0px; padding: 0px;&quot;&gt;/clear แล้วเริ่มงานชิ้นถัดไป&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;wf-warn&quot; style=&quot;background: rgb(253, 246, 232); border-radius: 5px; border: 1px solid rgb(232, 216, 154); box-sizing: border-box; color: #7a5a1a; font-size: 12.5px; line-height: 1.7; margin: 12px 0px 0px; padding: 10px 14px;&quot;&gt;⚠️ &lt;strong style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;ระวัง:&lt;/strong&gt; Claude อาจรายงานว่า &quot;ทำเสร็จแล้ว&quot; ทั้งที่ยังไม่ได้ทำอะไร — ตรวจสอบผลงานจริงด้วยตาตัวเองทุกครั้ง&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;full&quot; style=&quot;box-sizing: border-box; grid-column: 1 / -1; margin: 0px; padding: 0px;&quot;&gt;&lt;div class=&quot;sh&quot; style=&quot;align-items: center; box-sizing: border-box; display: flex; gap: 10px; margin: 0px 0px 16px; padding: 0px;&quot;&gt;&lt;span class=&quot;sh-num&quot; style=&quot;background: rgb(26, 39, 68); border-radius: 3px; box-sizing: border-box; color: white; flex-shrink: 0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; margin: 0px; padding: 3px 8px;&quot;&gt;★&lt;/span&gt;&lt;span class=&quot;sh-title&quot; style=&quot;box-sizing: border-box; font-size: 15px; font-weight: 700; margin: 0px; padding: 0px;&quot;&gt;3 กฎที่ใช้กับ AI Agent ทุกตัว ไม่ใช่แค่ Claude Code&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;rules&quot; style=&quot;border-radius: 6px; border: 2px solid rgb(26, 39, 68); box-sizing: border-box; display: grid; gap: 0px; grid-template-columns: repeat(3, 1fr); margin: 0px; overflow: hidden; padding: 0px;&quot;&gt;&lt;div class=&quot;rule&quot; style=&quot;border-right: 1px solid rgb(216, 208, 192); box-sizing: border-box; margin: 0px; padding: 22px 20px;&quot;&gt;&lt;div class=&quot;rule-num&quot; style=&quot;box-sizing: border-box; color: #d8d0c0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 22px; font-weight: 600; line-height: 1; margin: 0px 0px 10px; padding: 0px;&quot;&gt;01&lt;/div&gt;&lt;div class=&quot;rule-title&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-size: 14px; font-weight: 700; margin: 0px 0px 8px; padding: 0px;&quot;&gt;บอกให้ชัด อย่าให้เดา&lt;/div&gt;&lt;div class=&quot;rule-body&quot; style=&quot;box-sizing: border-box; color: #5a5048; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;บอก &lt;em style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot;&gt;สิ่งที่ต้องการ + บริบท + ตัวอย่างผลที่อยากได้&lt;/em&gt; ยิ่งละเอียด ยิ่งได้งานตรง ถ้าปล่อยให้ AI เดาเองมักได้ผลที่ใช้ไม่ได้&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rule&quot; style=&quot;border-right: 1px solid rgb(216, 208, 192); box-sizing: border-box; margin: 0px; padding: 22px 20px;&quot;&gt;&lt;div class=&quot;rule-num&quot; style=&quot;box-sizing: border-box; color: #d8d0c0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 22px; font-weight: 600; line-height: 1; margin: 0px 0px 10px; padding: 0px;&quot;&gt;02&lt;/div&gt;&lt;div class=&quot;rule-title&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-size: 14px; font-weight: 700; margin: 0px 0px 8px; padding: 0px;&quot;&gt;แบ่งงานเป็นชิ้นเล็ก ๆ&lt;/div&gt;&lt;div class=&quot;rule-body&quot; style=&quot;box-sizing: border-box; color: #5a5048; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;โยนงานทั้งก้อนมักทำให้ผลออกมาพัง แบ่งเป็นชิ้นย่อย ทำทีละชิ้น ถ้ามีปัญหาจะได้รู้ว่าติดตรงไหน&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rule&quot; style=&quot;border-right-color: currentcolor; border-right-style: none; border-right-width: medium; box-sizing: border-box; margin: 0px; padding: 22px 20px;&quot;&gt;&lt;div class=&quot;rule-num&quot; style=&quot;box-sizing: border-box; color: #d8d0c0; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 22px; font-weight: 600; line-height: 1; margin: 0px 0px 10px; padding: 0px;&quot;&gt;03&lt;/div&gt;&lt;div class=&quot;rule-title&quot; style=&quot;box-sizing: border-box; color: #1a2744; font-size: 14px; font-weight: 700; margin: 0px 0px 8px; padding: 0px;&quot;&gt;คนต้องตรวจสอบเสมอ&lt;/div&gt;&lt;div class=&quot;rule-body&quot; style=&quot;box-sizing: border-box; color: #5a5048; font-size: 12.5px; line-height: 1.75; margin: 0px; padding: 0px;&quot;&gt;อย่าปล่อยให้ AI ทำและตรวจสอบเองครบวงจร ผู้ใช้ต้องเป็นคนดูผลลัพธ์และตัดสินใจขั้นสุดท้ายเสมอ&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;footer&quot; style=&quot;align-items: center; border-top: 2px solid rgb(26, 39, 68); box-sizing: border-box; color: #1a1612; display: flex; flex-wrap: wrap; font-family: Sarabun, sans-serif; gap: 8px; justify-content: space-between; margin: 0px 48px; padding: 18px 0px 40px;&quot;&gt;&lt;div class=&quot;footer-l&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-family: &amp;quot;IBM Plex Mono&amp;quot;, monospace; font-size: 10px; letter-spacing: 1px; line-height: 1.7; margin: 0px; padding: 0px;&quot;&gt;CLAUDE CODE · claude.ai/code&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px;&quot; /&gt;Anthropic&lt;/div&gt;&lt;div class=&quot;footer-r&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-size: 12px; margin: 0px; padding: 0px;&quot;&gt;ติดตั้งผ่าน VS Code Extension · รองรับ MCP Servers&lt;/div&gt;&lt;div class=&quot;footer-r&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-size: 12px; margin: 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;footer-r&quot; style=&quot;box-sizing: border-box; color: #b0a898; font-size: 12px; margin: 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/4633920941976974567/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/claude-code.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/4633920941976974567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/4633920941976974567'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/claude-code.html' title='คู่มือการใช้งาน Claude Code ให้ได้ผลจริง'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjR_AovDdV-9bqLNFN_oC3TWG-kEKbx9Lcom2WPURNp6gil_WKuXxywkbkyaCBrn2AZyLJjqpW1TSv0e9PI8LTc-Wb78Gks2NWyZDyAxVC_E9Wu18pcePjTmag1UQ1ibZIA1qnYfea_gFmHhIgy23lIBIm-f3aeuuQ_DUbVd4UN0JRU08yqTwjIBIz58j4=s72-w640-h356-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-9057504843669396202</id><published>2026-06-09T07:30:00.000+07:00</published><updated>2026-06-09T07:30:00.109+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CodeIgniter 4"/><title type='text'>Debug CI4 ยังไงให้ได้ผล? เมื่อ Log เพียงอย่างเดียวไม่พอ — แนะนำ DEX</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;/div&gt; &lt;div&gt;&lt;p class=&quot;meta&quot; style=&quot;color: #5f5e5a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 0.85rem; margin: 0px 0px 2rem;&quot;&gt;📅 June 2025 &amp;nbsp;·&amp;nbsp; 🏷️ CodeIgniter 4, PHP, Debugging, DEX, Laravel &amp;nbsp;·&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;h1 style=&quot;color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 2rem; line-height: 1.4; margin-bottom: 0.5rem;&quot;&gt;Debug CI4 ยังไงให้ได้ผล?&lt;br /&gt;เมื่อ Log เพียงอย่างเดียวไม่พอ — แนะนำ &lt;span style=&quot;color: #0f6e56;&quot;&gt;DEX&lt;/span&gt;&lt;/h1&gt;&lt;div class=&quot;tag-list&quot; style=&quot;color: #2c2c2a; display: flex; flex-wrap: wrap; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; gap: 8px; margin: 1rem 0px 2rem;&quot;&gt;&lt;span class=&quot;tag-chip&quot; style=&quot;background: rgb(237, 247, 243); border-radius: 50px; border: 1px solid rgb(159, 225, 203); color: #085041; font-size: 0.8rem; padding: 3px 12px;&quot;&gt;CodeIgniter 4&lt;/span&gt;&lt;span class=&quot;tag-chip&quot; style=&quot;background: rgb(237, 247, 243); border-radius: 50px; border: 1px solid rgb(159, 225, 203); color: #085041; font-size: 0.8rem; padding: 3px 12px;&quot;&gt;PHP Debugging&lt;/span&gt;&lt;span class=&quot;tag-chip&quot; style=&quot;background: rgb(237, 247, 243); border-radius: 50px; border: 1px solid rgb(159, 225, 203); color: #085041; font-size: 0.8rem; padding: 3px 12px;&quot;&gt;DEX&lt;/span&gt;&lt;span class=&quot;tag-chip&quot; style=&quot;background: rgb(237, 247, 243); border-radius: 50px; border: 1px solid rgb(159, 225, 203); color: #085041; font-size: 0.8rem; padding: 3px 12px;&quot;&gt;Laravel&lt;/span&gt;&lt;span class=&quot;tag-chip&quot; style=&quot;background: rgb(237, 247, 243); border-radius: 50px; border: 1px solid rgb(159, 225, 203); color: #085041; font-size: 0.8rem; padding: 3px 12px;&quot;&gt;Web Development&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;intro-box&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: linear-gradient(135deg, rgb(225, 245, 238) 0%, rgb(237, 247, 243) 100%); background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 12px; border: 1px solid rgb(159, 225, 203); color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 1.5rem 0px 2rem; padding: 1.5rem 1.75rem;&quot;&gt;&lt;p style=&quot;color: #085041; font-size: 1.05rem; margin: 0px;&quot;&gt;เคยเจอ error แปลกๆ ใน production แล้วเปิด log ขึ้นมาดู แต่รู้สึกว่า &quot;มันบอกแค่นี้เองเหรอ?&quot; ไม่รู้ว่า request ทำอะไรไปก่อนจะ fail ไม่รู้ว่า query ไหนรันไปบ้าง ไม่รู้ว่า bug นี้เคยเกิดแล้วหรือเปล่า — บทความนี้มีคำตอบให้ครับ&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiO-AvZK6y71ppQZyC5Dr8laeK8ZFf2ao40TROhqFGhsy5ONKFmMiiBfVF88-86RzpRU0OPbXW6zkGeHFgxocg9ApgmQ53zN_So9vPubzds704-5VP1HmiLUQxljHups_k5yEJxoKfp3NZ4Wt_7I8-u3RpGM-iDj6FatjnyrlC53e_Q6LtCKHDkYnDFiA4&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1536&quot; data-original-width=&quot;2752&quot; height=&quot;357&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiO-AvZK6y71ppQZyC5Dr8laeK8ZFf2ao40TROhqFGhsy5ONKFmMiiBfVF88-86RzpRU0OPbXW6zkGeHFgxocg9ApgmQ53zN_So9vPubzds704-5VP1HmiLUQxljHups_k5yEJxoKfp3NZ4Wt_7I8-u3RpGM-iDj6FatjnyrlC53e_Q6LtCKHDkYnDFiA4&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🔍 ปัญหาที่นักพัฒนา CI4 ทุกคนเจอ&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;ถ้าคุณเคยทำงานกับ &lt;strong&gt;CodeIgniter 4 (CI4)&lt;/strong&gt; มาสักพัก คุณคงรู้ดีว่า การ debug แอปพลิเคชันจริงๆ นั้น ไม่ง่ายอย่างที่คิด โดยเฉพาะเมื่อ application ขึ้น production ไปแล้ว&lt;/p&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;สิ่งที่เรามักเห็นใน log file มักมีหน้าตาแบบนี้:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// log ที่เห็นใน application/logs/&lt;/span&gt; &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;ERROR - 2025-06-09 14:32:11 --&amp;gt; Call to a member function getResult() on bool&lt;/span&gt; &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;ERROR - 2025-06-09 15:01:44 --&amp;gt; Trying to access array offset on value of type null&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;Log บอกได้ว่า error เกิด &lt;em&gt;ที่ไหน&lt;/em&gt; แต่มันไม่บอกว่า:&lt;/p&gt;&lt;ul style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px;&quot;&gt;&lt;li&gt;Controller method ไหนที่รับ request นั้น?&lt;/li&gt;&lt;li&gt;Database query อะไรรันไปก่อนหน้า?&lt;/li&gt;&lt;li&gt;Error เกิดใน service, model, หรือ API call?&lt;/li&gt;&lt;li&gt;Bug นี้เคยถูก fix แล้วและ &lt;em&gt;กลับมาใหม่&lt;/em&gt; หรือเปล่า?&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;ข้อสุดท้ายนี่เจ็บปวดที่สุดครับ บางครั้งเรา fix bug ไปแล้ว แต่สัปดาห์ต่อมามันกลับมา แล้วเราก็เริ่ม debug ใหม่ราวกับว่ามันเป็น bug ใหม่ — ทั้งที่จริงๆ มันคือ &lt;strong&gt;regression&lt;/strong&gt;&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🛠️ DEX คืออะไร?&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;&lt;strong&gt;DEX&lt;/strong&gt; คือ open-source issue tracking tool ที่สร้างขึ้นมาเพื่อ CodeIgniter 4 โดยเฉพาะ มันไม่ได้แค่ดักจับ error แต่มันบันทึก &lt;strong&gt;context รอบๆ request&lt;/strong&gt; ทั้งหมดให้คุณด้วย เพื่อให้คุณเข้าใจได้ว่า:&lt;/p&gt;&lt;ul class=&quot;step-list&quot; style=&quot;color: #2c2c2a; counter-reset: step 0; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; list-style: none; margin: 1rem 0px 1.75rem; padding: 0px;&quot;&gt;&lt;li style=&quot;align-items: flex-start; counter-increment: step 1; display: flex; gap: 1rem; margin-bottom: 1rem;&quot;&gt;&lt;p style=&quot;margin: 0px;&quot;&gt;แอปทำ&lt;em&gt;อะไร&lt;/em&gt;ก่อนที่มันจะพัง&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; counter-increment: step 1; display: flex; gap: 1rem; margin-bottom: 1rem;&quot;&gt;&lt;p style=&quot;margin: 0px;&quot;&gt;issue นี้เป็น &lt;em&gt;ใหม่, ignored, resolved&lt;/em&gt; หรือ &lt;em&gt;regressed&lt;/em&gt;?&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; counter-increment: step 1; display: flex; gap: 1rem; margin-bottom: 1rem;&quot;&gt;&lt;p style=&quot;margin: 0px;&quot;&gt;request lifecycle เป็นยังไงแบบ timeline&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;align-items: flex-start; counter-increment: step 1; display: flex; gap: 1rem; margin-bottom: 1rem;&quot;&gt;&lt;p style=&quot;margin: 0px;&quot;&gt;มี slow query หรือ failed query ก่อน error ไหม?&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;tip-box&quot; style=&quot;background: rgb(250, 238, 218); border-left: 4px solid rgb(239, 159, 39); border-radius: 0px 8px 8px 0px; color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 1.5rem 0px; padding: 1rem 1.25rem;&quot;&gt;&lt;strong style=&quot;color: #633806;&quot;&gt;💡 ตัวอย่างจริง:&lt;/strong&gt;&lt;p style=&quot;color: #4a2e08; font-size: 0.95rem; margin: 0px;&quot;&gt;ลูกค้าแจ้งว่า checkout ล้มเหลว — Log บอกว่ามี exception แต่คำถามคือ: cart โหลดสำเร็จไหม? payment provider ถูกเรียกไหม? error เกิดก่อนหรือหลัง payment? DEX ตอบคำถามพวกนี้ได้ทั้งหมด&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;⚙️ ติดตั้ง DEX ใน CI4 Project&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;การติดตั้ง DEX ทำได้ผ่าน Composer เหมือน package ทั่วไปครับ:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;# ติดตั้งผ่าน Composer&lt;/span&gt; composer require sarutobi/dex&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;จากนั้น run migration เพื่อสร้าง table ในฐานข้อมูล:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;# Run migration&lt;/span&gt; php spark migrate --all&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;แล้วก็เพิ่ม DEX filter เข้าไปใน &lt;code style=&quot;background: rgb(237, 247, 243); border-radius: 4px; color: #0f6e56; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: 0.88em; padding: 2px 6px;&quot;&gt;app/Config/Filters.php&lt;/code&gt;:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Sarutobi\Dex\Filters\DexFilter&lt;/span&gt;; &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน $globals หรือ $filters ตาม route ที่ต้องการ track&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$globals&lt;/span&gt; = [ &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;before&#39;&lt;/span&gt; =&amp;gt; [ &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;DexFilter&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, ], ];&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;เพียงเท่านี้ DEX ก็จะเริ่มจับ request ทุกอันของคุณแล้ว&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;📊 เปรียบเทียบ: Log อย่างเดียว VS ใช้ DEX&lt;/h2&gt;&lt;table style=&quot;border-collapse: collapse; color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 0.93rem; margin: 1.5rem 0px 2rem; width: 719px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(15, 110, 86); color: white;&quot;&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;สิ่งที่ต้องการรู้&lt;/th&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;Log ไฟล์อย่างเดียว&lt;/th&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;ใช้ DEX&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Error message พร้อม stack trace&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Controller / Method ที่รับ request&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗ ไม่มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Database queries ที่รันก่อน error&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗ ไม่มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Request lifecycle timeline&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗ ไม่มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;สถานะ issue (new / resolved / regressed)&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗ ไม่มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;ค้นหาและจัดการ issue แบบมี workflow&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-amber&quot; style=&quot;background: rgb(250, 199, 117); border-radius: 50px; color: #633806; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;ยาก&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ มี UI ให้&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;ตรวจจับ regression&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗ ไม่มี&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ แจ้งเตือนได้&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Self-hosted ไม่ต้องพึ่ง third-party SaaS&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ ได้&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓ ได้&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🐛 วิธี Debug CI4 เบื้องต้น (ก่อนใช้ DEX)&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;ก่อนจะพูดถึง DEX เพิ่มเติม มาทบทวนเทคนิค debug พื้นฐานใน CI4 กันก่อนครับ สำหรับมือใหม่ที่เพิ่งเริ่มต้น&lt;/p&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;1. เปิด Display Errors ใน Development&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน app/Config/Boot/development.php&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;ini_set&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;display_errors&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;1&#39;&lt;/span&gt;); &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;error_reporting&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;E_ALL&lt;/span&gt;);&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;warn-box&quot; style=&quot;background: rgb(252, 235, 235); border-left: 4px solid rgb(226, 75, 74); border-radius: 0px 8px 8px 0px; color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 1.5rem 0px; padding: 1rem 1.25rem;&quot;&gt;&lt;p style=&quot;color: #501313; font-size: 0.95rem; margin: 0px;&quot;&gt;⚠️ &lt;strong&gt;สำคัญ:&lt;/strong&gt; อย่าเปิด &lt;code style=&quot;background: rgb(237, 247, 243); border-radius: 4px; color: #0f6e56; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: 0.88em; padding: 2px 6px;&quot;&gt;display_errors&lt;/code&gt; ใน production เด็ดขาดครับ เพราะจะทำให้ข้อมูล internal ของระบบโชว์ให้ผู้ใช้เห็นได้&lt;/p&gt;&lt;/div&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;2. ใช้ var_dump() และ die() สำหรับ Quick Debug&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน Controller&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;checkout&lt;/span&gt;() { &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$cart&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;cartModel&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;getCart&lt;/span&gt;(&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;session&lt;/span&gt;()-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;user_id&#39;&lt;/span&gt;)); &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// Debug ชั่วคราว — ดูว่า cart มีข้อมูลอะไรบ้าง&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;var_dump&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$cart&lt;/span&gt;); &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;die&lt;/span&gt;(); &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ... โค้ดที่เหลือ&lt;/span&gt; }&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;3. ใช้ log_message() สำหรับ Production Debug&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// บันทึก log พร้อม context&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;log_message&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;error&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;Checkout failed for user_id: &#39;&lt;/span&gt; . &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$userId&lt;/span&gt;); &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;log_message&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;debug&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;Cart data: &#39;&lt;/span&gt; . &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;json_encode&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$cart&lt;/span&gt;)); &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;log_message&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;info&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;Payment attempt at: &#39;&lt;/span&gt; . &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;date&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;Y-m-d H:i:s&#39;&lt;/span&gt;));&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;4. ใช้ CI4 Debug Toolbar&lt;/h3&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;CI4 มี built-in Debug Toolbar ที่เปิดใช้ได้ใน development mode ใน &lt;code style=&quot;background: rgb(237, 247, 243); border-radius: 4px; color: #0f6e56; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: 0.88em; padding: 2px 6px;&quot;&gt;app/Config/Toolbar.php&lt;/code&gt;:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน app/Config/Toolbar.php&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$collectors&lt;/span&gt; = [ &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Timers&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Database&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ดู queries ที่รัน&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Logs&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Views&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Cache&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Files&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Routes&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Events&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;, ];&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;Toolbar นี้จะโชว์ข้อมูลที่ bottom bar ของหน้า web ในขณะ develop ซึ่งมีประโยชน์มากสำหรับดู query time และ route ที่ match&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🔄 Workflow การ Debug ด้วย DEX&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;เมื่อ DEX ติดตั้งแล้ว workflow การ debug จะเปลี่ยนไปอย่างชัดเจนครับ แทนที่จะเปิด log file แล้วค้นหาเองแบบ manual คุณจะได้ทำงานแบบนี้:&lt;/p&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// DEX จะ capture exception โดยอัตโนมัติผ่าน Exception Handler&lt;/span&gt; &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน app/Config/Exceptions.php เพิ่ม:&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;Sarutobi\Dex\Handlers\DexExceptionHandler&lt;/span&gt;; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$handler&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;DexExceptionHandler&lt;/span&gt;::&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;class&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;จากนั้น DEX จะบันทึก issue พร้อมกับ context ครบ ได้แก่:&lt;/p&gt;&lt;ul style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px;&quot;&gt;&lt;li&gt;&lt;strong&gt;Request method, URI, headers&lt;/strong&gt; — รู้ว่า request มาจากไหน&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Database queries timeline&lt;/strong&gt; — เห็นว่า query ไหนช้าหรือ fail&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Issue status tracking&lt;/strong&gt; — &lt;span class=&quot;badge badge-teal&quot; style=&quot;background: rgb(159, 225, 203); border-radius: 50px; color: #085041; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;badge badge-amber&quot; style=&quot;background: rgb(250, 199, 117); border-radius: 50px; color: #633806; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;ignored&lt;/span&gt; &lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;resolved&lt;/span&gt; &lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;regressed&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Occurrence count&lt;/strong&gt; — bug นี้เกิดกี่ครั้งแล้ว&lt;/li&gt;&lt;/ul&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🔴 สำหรับผู้ใช้ Laravel: มี Tool ที่ใกล้เคียงกันอยู่&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;ถ้าคุณทำงานกับ &lt;strong&gt;Laravel&lt;/strong&gt; มากกว่า CI4 ระบบ ecosystem ของ Laravel มี tool สำหรับ debug ที่ครบครันอยู่แล้วครับ ลองเปรียบเทียบดู:&lt;/p&gt;&lt;table style=&quot;border-collapse: collapse; color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 0.93rem; margin: 1.5rem 0px 2rem; width: 719px;&quot;&gt;&lt;thead&gt;&lt;tr style=&quot;background: rgb(15, 110, 86); color: white;&quot;&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;Feature&lt;/th&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;DEX (CI4)&lt;/th&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;Laravel Telescope&lt;/th&gt;&lt;th style=&quot;padding: 0.7rem 1rem; text-align: left;&quot;&gt;Laravel Debugbar&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Request lifecycle&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Issue status tracking&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-amber&quot; style=&quot;background: rgb(250, 199, 117); border-radius: 50px; color: #633806; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;จำกัด&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Regression detection&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-red&quot; style=&quot;background: rgb(247, 193, 193); border-radius: 50px; color: #791f1f; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✗&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Production-ready&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-amber&quot; style=&quot;background: rgb(250, 199, 117); border-radius: 50px; color: #633806; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;Dev only&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(255, 255, 255);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Self-hosted&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;&lt;span class=&quot;badge badge-green&quot; style=&quot;background: rgb(192, 221, 151); border-radius: 50px; color: #27500a; display: inline-block; font-size: 0.78rem; font-weight: 600; margin-right: 4px; padding: 2px 10px;&quot;&gt;✓&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;background: rgb(237, 247, 243);&quot;&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Framework&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;CI4&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Laravel&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(200, 232, 216); padding: 0.6rem 1rem; vertical-align: top;&quot;&gt;Laravel&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;จะเห็นว่า DEX มีจุดเด่นที่ issue status tracking และ regression detection ซึ่ง Telescope ยังทำได้ไม่เต็มที่ครับ&lt;/p&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;✅ Best Practices การ Debug PHP/CI4 อย่างมืออาชีพ&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;นอกจากการใช้ tool แล้ว วิธีคิดและวิธีเขียนโค้ดก็สำคัญมากครับ ขอแนะนำแนวทางปฏิบัติที่ดีที่สุดไว้ดังนี้:&lt;/p&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;1. แยก Logic ออกจาก Controller ให้ชัดเจน&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ❌ ไม่ดี — Controller ทำทุกอย่าง debug ยาก&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;createOrder&lt;/span&gt;() { &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$data&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;request-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;getPost&lt;/span&gt;(); &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$db&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;db_connect&lt;/span&gt;(); &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$db&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&quot;INSERT INTO orders ...&quot;&lt;/span&gt;); &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ส่ง email, update stock, log ทุกอย่างอยู่ใน method เดียว&lt;/span&gt; } &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ✓ ดี — แยก concern ออกจากกัน trace ได้ง่าย&lt;/span&gt; &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;public function&lt;/span&gt; &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;createOrder&lt;/span&gt;() { &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$data&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;request-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;getPost&lt;/span&gt;(); &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$order&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;orderService-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;create&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$data&lt;/span&gt;); &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;respond&lt;/span&gt;([&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;order_id&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$order&lt;/span&gt;-&amp;gt;id]); }&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;2. ใส่ Try-Catch พร้อม Context ที่มีความหมาย&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;try&lt;/span&gt; { &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$result&lt;/span&gt; = &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$this&lt;/span&gt;-&amp;gt;paymentGateway-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;charge&lt;/span&gt;(&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$amount&lt;/span&gt;, &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$card&lt;/span&gt;); } &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;\Exception&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$e&lt;/span&gt;) { &lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;log_message&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;error&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;Payment failed&#39;&lt;/span&gt;, [ &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;user_id&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$userId&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;amount&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$amount&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;error&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$e&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;getMessage&lt;/span&gt;(), &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;trace&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$e&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;getTraceAsString&lt;/span&gt;(), ]); &lt;span class=&quot;keyword&quot; style=&quot;color: #85dab4;&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$e&lt;/span&gt;; &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// re-throw ให้ DEX จับได้&lt;/span&gt; }&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&quot;color: #3b3b38; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.15rem; margin-bottom: 0.5rem; margin-top: 1.75rem;&quot;&gt;3. ตั้งชื่อ Route ให้สื่อความหมาย&lt;/h3&gt;&lt;pre style=&quot;background: rgb(30, 42, 36); border-radius: 10px; border: 1px solid rgb(45, 64, 55); color: #c8f0df; font-size: 0.88rem; line-height: 1.7; margin: 1.25rem 0px 1.75rem; overflow-x: auto; padding: 1.25rem 1.5rem;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 4px; color: inherit; font-family: &amp;quot;JetBrains Mono&amp;quot;, &amp;quot;Fira Code&amp;quot;, Consolas, monospace; font-size: inherit; padding: 0px;&quot;&gt;&lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ใน app/Config/Routes.php&lt;/span&gt; &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;checkout/process&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;CheckoutController::process&#39;&lt;/span&gt;, [ &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;as&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;checkout.process&#39;&lt;/span&gt; &lt;span class=&quot;comment&quot; style=&quot;color: #6a8f7a; font-style: italic;&quot;&gt;// ชื่อ route ช่วยให้ DEX log อ่านง่าย&lt;/span&gt; ]); &lt;span class=&quot;var&quot; style=&quot;color: #e8c87a;&quot;&gt;$routes&lt;/span&gt;-&amp;gt;&lt;span class=&quot;func&quot; style=&quot;color: #78c8f0;&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;order/(:num)/status&#39;&lt;/span&gt;, &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;OrderController::status/$1&#39;&lt;/span&gt;, [ &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;as&#39;&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot; style=&quot;color: #fac775;&quot;&gt;&#39;order.status&#39;&lt;/span&gt; ]);&lt;/code&gt;&lt;/pre&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(93, 202, 165); color: #1a1a18; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 2.5rem; padding-left: 0.75rem;&quot;&gt;🎯 สรุป&lt;/h2&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;การ debug application จริงๆ ใน production ต้องการมากกว่าแค่การเปิดดู log file ครับ เราต้องการ &lt;strong&gt;workflow&lt;/strong&gt; ที่ช่วยให้เราเห็นภาพรวมของ request ทั้งหมด ไม่ใช่แค่ error message เพียงบรรทัดเดียว&lt;/p&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;&lt;strong&gt;DEX&lt;/strong&gt; ถูกสร้างมาเพื่อเติมช่องว่างตรงนี้ใน ecosystem ของ CodeIgniter 4 โดยเฉพาะ — ไม่ได้พยายามเป็น APM ขนาดใหญ่ แต่มุ่งเน้นที่การทำสิ่งหนึ่งสิ่งเดียวให้ดี นั่นคือ: &lt;em&gt;บอกว่า CI4 request ของคุณทำอะไร ที่ไหน และทำไมมันถึงพัง&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;สำหรับนักพัฒนาที่ทำงานกับ business application ที่ใช้ CI4 มานานหลายปี DEX ช่วยให้การ debug กลายเป็น workflow ที่มีระเบียบ แทนที่จะเป็นการ &quot;เดาเอา&quot; จาก log ที่กระจัดกระจาย&lt;/p&gt;&lt;p style=&quot;color: #2c2c2a; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 0px 0px 1.1rem;&quot;&gt;ส่วนนักพัฒนา Laravel ก็ไม่ต้องน้อยใจ เพราะมี Telescope และ Debugbar รองรับอยู่แล้ว แต่ถ้าวันไหนต้องย้ายมาทำ CI4 บ้าง ลอง DEX ดูครับ — คุ้มค่าแน่นอน&lt;/p&gt;&lt;div class=&quot;cta-box&quot; style=&quot;background: rgb(15, 110, 86); border-radius: 14px; color: #e1f5ee; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 3rem 0px 1.5rem; padding: 2rem; text-align: center;&quot;&gt;&lt;h2 style=&quot;border-left-color: currentcolor; border-left-style: none; border-left-width: medium; color: #9fe1cb; font-size: 1.45rem; margin-bottom: 0.75rem; margin-top: 0px; padding-left: 0px;&quot;&gt;🚀 พร้อมจะ Debug อย่างมืออาชีพแล้วหรือยัง?&lt;/h2&gt;&lt;p style=&quot;color: #c8f0df; margin: 0px 0px 1.25rem;&quot;&gt;ลอง DEX ใน CI4 project ของคุณวันนี้ หรือถ้ายังไม่มี project ลองเริ่มจาก Hello World ก็ได้ครับ — ขอแค่เริ่ม!&lt;/p&gt;&lt;a class=&quot;cta-btn&quot; href=&quot;https://dev.to/sarutobi87/debugging-codeigniter-apps-from-logs-alone-was-not-enough-so-i-built-dex-3gph&quot; style=&quot;background: rgb(93, 202, 165); border-radius: 50px; color: #04342c; display: inline-block; font-size: 1rem; font-weight: 700; margin: 0.3rem 0.4rem; padding: 0.7rem 2rem; text-decoration: none; transition: background 0.2s;&quot; target=&quot;_blank&quot;&gt;📖 อ่านบทความต้นฉบับ DEX&lt;/a&gt; &lt;a class=&quot;cta-btn secondary&quot; href=&quot;https://codeigniter.com/user_guide/index.html&quot; style=&quot;background: transparent; border-radius: 50px; border: 2px solid rgb(93, 202, 165); color: #9fe1cb; display: inline-block; font-size: 1rem; font-weight: 700; margin: 0.3rem 0.4rem; padding: 0.7rem 2rem; text-decoration: none; transition: background 0.2s;&quot; target=&quot;_blank&quot;&gt;📚 CI4 Official Docs&lt;/a&gt;&lt;p style=&quot;color: #9fe1cb; font-size: 0.9rem; margin: 1.25rem 0px;&quot;&gt;💬 มีคำถามหรืออยากแชร์ประสบการณ์ debug? ฝากไว้ใน comment ด้านล่างได้เลยครับ&lt;/p&gt;&lt;/div&gt;&lt;hr class=&quot;divider&quot; style=&quot;border-color: rgb(200, 232, 216) currentcolor currentcolor; border-image: initial; border-style: solid none none; border-width: 1px medium medium; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 17px; margin: 2.5rem 0px;&quot; /&gt;&lt;p style=&quot;color: #888780; font-family: Sarabun, &amp;quot;Noto Sans Thai&amp;quot;, sans-serif; font-size: 0.82rem; margin: 0px 0px 1.1rem; text-align: center;&quot;&gt;บทความนี้เขียนขึ้นจาก source: &lt;a href=&quot;https://dev.to/sarutobi87/debugging-codeigniter-apps-from-logs-alone-was-not-enough-so-i-built-dex-3gph&quot; style=&quot;color: #0f6e56;&quot;&gt;DEX on dev.to&lt;/a&gt; · &lt;a href=&quot;https://stackoverflow.com/questions/13562950/debugging-in-codeigniter-and-mvc&quot; style=&quot;color: #0f6e56;&quot;&gt;Stack Overflow CI Debug&lt;/a&gt; · &lt;a href=&quot;https://gist.github.com/samkeen/1142213&quot; style=&quot;color: #0f6e56;&quot;&gt;GitHub Gist: Testing CI Apps&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/9057504843669396202/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/debug-ci4-log-dex.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/9057504843669396202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/9057504843669396202'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/debug-ci4-log-dex.html' title='Debug CI4 ยังไงให้ได้ผล? เมื่อ Log เพียงอย่างเดียวไม่พอ — แนะนำ DEX'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiO-AvZK6y71ppQZyC5Dr8laeK8ZFf2ao40TROhqFGhsy5ONKFmMiiBfVF88-86RzpRU0OPbXW6zkGeHFgxocg9ApgmQ53zN_So9vPubzds704-5VP1HmiLUQxljHups_k5yEJxoKfp3NZ4Wt_7I8-u3RpGM-iDj6FatjnyrlC53e_Q6LtCKHDkYnDFiA4=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2142305340755025784.post-8831198723624950411</id><published>2026-06-08T21:13:48.344+07:00</published><updated>2026-06-08T21:17:31.070+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Microservices"/><title type='text'>PHP Microservices Without Frameworks: สร้าง Microservices ด้วย Native PHP</title><content type='html'>&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMKaOGkvZfW0mD8NtnUUaIZoRObi2v5ZR8sQ-ihaJfJLtsrgeuvtj2zkG9UmlybsyCE1q2TznhmECVO3NgwYrZ5anBAkm3DzGHBcd2Fi0CM7h8KPS9beoY6G6L3XmZ_7gJqHb0J4ON5UtObwxwpGdVWbG5erFJ9heGCrYdV0aDRpFw1BH8nPcQN525xHs/s1672/fe971fbd-f1f6-4c0f-9ca3-d56bb8a040b0.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;941&quot; data-original-width=&quot;1672&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMKaOGkvZfW0mD8NtnUUaIZoRObi2v5ZR8sQ-ihaJfJLtsrgeuvtj2zkG9UmlybsyCE1q2TznhmECVO3NgwYrZ5anBAkm3DzGHBcd2Fi0CM7h8KPS9beoY6G6L3XmZ_7gJqHb0J4ON5UtObwxwpGdVWbG5erFJ9heGCrYdV0aDRpFw1BH8nPcQN525xHs/w640-h360/fe971fbd-f1f6-4c0f-9ca3-d56bb8a040b0.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;ในยุคที่แอปพลิเคชันมีความซับซ้อนมากขึ้นเรื่อยๆ &lt;strong&gt;Microservices Architecture&lt;/strong&gt; ได้กลายมาเป็นหนึ่งในแนวทางที่นักพัฒนาหลายคนเลือกใช้ บทความนี้จะพาไปทำความเข้าใจว่าเราสามารถสร้าง Microservices ด้วย &lt;strong&gt;PHP แบบ Native&lt;/strong&gt; โดยไม่ต้องพึ่งพา Framework ขนาดใหญ่ได้อย่างไร&lt;/p&gt;&lt;div class=&quot;info-box&quot; style=&quot;background: rgb(239, 246, 255); border-left: 4px solid rgb(59, 130, 246); border-radius: 0px 8px 8px 0px; margin: 1.5em 0px; padding: 1em 1.2em;&quot;&gt;&lt;strong style=&quot;color: #1d4ed8;&quot;&gt;📌 บทความนี้เหมาะสำหรับ:&lt;/strong&gt; นักพัฒนา PHP ที่ต้องการทำความเข้าใจแนวคิด Microservices และอยากลองนำไปใช้งานจริงโดยเริ่มจาก PHP พื้นฐาน&lt;/div&gt;&lt;h2&gt;Microservices คืออะไร?&lt;/h2&gt;&lt;p&gt;Microservices Architecture คือรูปแบบการออกแบบซอฟต์แวร์ที่แบ่งแอปพลิเคชันออกเป็น &lt;strong&gt;บริการขนาดเล็กหลายๆ ตัว&lt;/strong&gt; แต่ละตัวทำงานอิสระและสื่อสารกันผ่านเครือข่าย ตรงกันข้ามกับ Monolithic Architecture ที่ใส่ทุกอย่างไว้ในโค้ดเบสเดียวกัน&lt;/p&gt;&lt;table class=&quot;arch-table&quot; style=&quot;border-collapse: collapse; color: black; font-size: 0.95em; margin: 1.5em 0px; width: 903px;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th style=&quot;background: rgb(26, 86, 219); color: white; padding: 10px 14px; text-align: left;&quot;&gt;คุณสมบัติ&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 86, 219); color: white; padding: 10px 14px; text-align: left;&quot;&gt;Monolithic&lt;/th&gt;&lt;th style=&quot;background: rgb(26, 86, 219); color: white; padding: 10px 14px; text-align: left;&quot;&gt;Microservices&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;การ Deploy&lt;/td&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;Deploy ทั้งระบบพร้อมกัน&lt;/td&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;Deploy แยกอิสระแต่ละ Service&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;การ Scale&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;Scale ทั้งระบบ&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;Scale เฉพาะ Service ที่ต้องการ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;เทคโนโลยี&lt;/td&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;Stack เดียวทั้งระบบ&lt;/td&gt;&lt;td style=&quot;background: rgb(249, 250, 251); border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;แต่ละ Service เลือก Stack เองได้&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;ความซับซ้อน&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;โค้ดซับซ้อนขึ้นเมื่อระบบใหญ่&lt;/td&gt;&lt;td style=&quot;border-bottom: 1px solid rgb(229, 231, 235); padding: 9px 14px;&quot;&gt;ซับซ้อนด้าน Infrastructure&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2&gt;หลักการออกแบบ Microservices ด้วย PHP&lt;/h2&gt;&lt;p&gt;เมื่อออกแบบ Microservices ด้วย PHP Native มีหลักการสำคัญ 3 ข้อที่ควรคำนึงถึง:&lt;/p&gt;&lt;h3&gt;1. Single Responsibility — หนึ่ง Service หนึ่งหน้าที่&lt;/h3&gt;&lt;p&gt;แต่ละ Microservice ควรรับผิดชอบเพียง &lt;strong&gt;Domain เดียว&lt;/strong&gt; เช่น:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;UserService&lt;/code&gt; — จัดการข้อมูลผู้ใช้และการลงทะเบียน&lt;/li&gt;&lt;li&gt;&lt;code&gt;AuthService&lt;/code&gt; — ดูแลการ Authentication และ Token&lt;/li&gt;&lt;li&gt;&lt;code&gt;ProductService&lt;/code&gt; — จัดการแคตตาล็อกสินค้า&lt;/li&gt;&lt;li&gt;&lt;code&gt;OrderService&lt;/code&gt; — ประมวลผลคำสั่งซื้อ&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;2. Independent Deployment — Deploy แยกกันได้&lt;/h3&gt;&lt;p&gt;แต่ละ Service ควรมี Repository และสภาพแวดล้อมเป็นของตัวเอง สามารถอัปเดตหรือ Deploy ได้โดยไม่กระทบ Service อื่น&lt;/p&gt;&lt;h3&gt;3. Network Communication — สื่อสารผ่านเครือข่าย&lt;/h3&gt;&lt;p&gt;Services สื่อสารกันได้หลายรูปแบบ:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;HTTP/REST API&lt;/strong&gt; — ง่ายที่สุด เหมาะสำหรับเริ่มต้น&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Message Queue&lt;/strong&gt; (RabbitMQ, Redis) — เหมาะกับงาน Async&lt;/li&gt;&lt;li&gt;&lt;strong&gt;gRPC&lt;/strong&gt; — ประสิทธิภาพสูง รองรับ Binary Protocol&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;โครงสร้างโปรเจกต์&lt;/h2&gt;&lt;p&gt;ตัวอย่างโครงสร้างโฟลเดอร์สำหรับแต่ละ Microservice:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;services/ ├── user-service/ │ ├── src/ │ │ ├── Controllers/ │ │ ├── Models/ │ │ └── Services/ │ ├── public/ │ │ └── index.php │ ├── composer.json │ └── Dockerfile ├── auth-service/ │ ├── src/ │ ├── public/ │ └── Dockerfile └── product-service/ ├── src/ ├── public/ └── Dockerfile&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;ตัวอย่างโค้ด: HTTP Communication ใน PHP&lt;/h2&gt;&lt;p&gt;วิธีง่ายที่สุดในการสื่อสารระหว่าง Services คือการใช้ &lt;code&gt;file_get_contents()&lt;/code&gt; หรือ cURL:&lt;/p&gt;&lt;h3&gt;แบบที่ 1: ใช้ file_get_contents&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?php // ดึงข้อมูลผู้ใช้จาก UserService $url = &#39;http://user-service.local/api/users/1&#39;; $response = file_get_contents($url); $user = json_decode($response, true); echo &quot;ชื่อผู้ใช้: &quot; . $user[&#39;name&#39;]; &lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;แบบที่ 2: ใช้ cURL (แนะนำ — ควบคุมได้มากกว่า)&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?php function callService(string $url, string $method = &#39;GET&#39;, array $data = []): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER =&amp;gt; true, CURLOPT_TIMEOUT =&amp;gt; 10, CURLOPT_HTTPHEADER =&amp;gt; [ &#39;Content-Type: application/json&#39;, &#39;Accept: application/json&#39;, ], ]); if ($method === &#39;POST&#39;) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($response === false || $httpCode &amp;gt;= 400) { throw new RuntimeException(&quot;Service call failed: HTTP $httpCode&quot;); } return json_decode($response, true); } // ตัวอย่างการใช้งาน try { // เรียก AuthService เพื่อ Login $authResult = callService( &#39;http://auth-service.local/api/login&#39;, &#39;POST&#39;, [&#39;email&#39; =&amp;gt; &#39;user@example.com&#39;, &#39;password&#39; =&amp;gt; &#39;secret&#39;] ); $token = $authResult[&#39;token&#39;]; echo &quot;Login สำเร็จ! Token: $token&quot;; // เรียก UserService ดึงข้อมูล $user = callService(&#39;http://user-service.local/api/users/1&#39;); echo &quot;ชื่อ: &quot; . $user[&#39;name&#39;]; } catch (RuntimeException $e) { echo &quot;เกิดข้อผิดพลาด: &quot; . $e-&amp;gt;getMessage(); } &lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;ตัวอย่าง: สร้าง Simple UserService&lt;/h2&gt;&lt;p&gt;ตัวอย่าง UserService แบบ Native PHP ที่พร้อมใช้งาน:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?php // user-service/public/index.php header(&#39;Content-Type: application/json&#39;); $method = $_SERVER[&#39;REQUEST_METHOD&#39;]; $path = parse_url($_SERVER[&#39;REQUEST_URI&#39;], PHP_URL_PATH); // Routing แบบ Simple if ($method === &#39;GET&#39; &amp;amp;&amp;amp; preg_match(&#39;#^/api/users/(\d+)$#&#39;, $path, $m)) { echo json_encode(getUser((int)$m[1])); } elseif ($method === &#39;GET&#39; &amp;amp;&amp;amp; $path === &#39;/api/users&#39;) { echo json_encode(getAllUsers()); } elseif ($method === &#39;POST&#39; &amp;amp;&amp;amp; $path === &#39;/api/users&#39;) { $body = json_decode(file_get_contents(&#39;php://input&#39;), true); echo json_encode(createUser($body)); } else { http_response_code(404); echo json_encode([&#39;error&#39; =&amp;gt; &#39;Not Found&#39;]); } // ฟังก์ชันจำลองฐานข้อมูล function getUser(int $id): array { $users = [ 1 =&amp;gt; [&#39;id&#39; =&amp;gt; 1, &#39;name&#39; =&amp;gt; &#39;สมชาย ใจดี&#39;, &#39;email&#39; =&amp;gt; &#39;somchai@example.com&#39;], 2 =&amp;gt; [&#39;id&#39; =&amp;gt; 2, &#39;name&#39; =&amp;gt; &#39;สมหญิง รักเรียน&#39;, &#39;email&#39; =&amp;gt; &#39;somying@example.com&#39;], ]; return $users[$id] ?? [&#39;error&#39; =&amp;gt; &#39;User not found&#39;]; } function getAllUsers(): array { return [&#39;data&#39; =&amp;gt; [getUser(1), getUser(2)]]; } function createUser(array $data): array { // บันทึกลง DB จริงๆ ในโปรเจกต์จริง return [&#39;success&#39; =&amp;gt; true, &#39;id&#39; =&amp;gt; rand(100, 999), &#39;data&#39; =&amp;gt; $data]; } &lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;การใช้งาน Message Queue (Async)&lt;/h2&gt;&lt;p&gt;สำหรับงานที่ไม่ต้องรอผลทันที เช่น ส่ง Email หรือประมวลผล Order แนะนำให้ใช้ &lt;strong&gt;Message Queue&lt;/strong&gt; ร่วมกับ Redis หรือ RabbitMQ:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?php // Producer: OrderService ส่งข้อความไปยัง Queue $redis = new Redis(); $redis-&amp;gt;connect(&#39;redis&#39;, 6379); $orderEvent = json_encode([ &#39;event&#39; =&amp;gt; &#39;order.created&#39;, &#39;order_id&#39; =&amp;gt; 1234, &#39;user_id&#39; =&amp;gt; 56, &#39;total&#39; =&amp;gt; 1500.00, &#39;created_at&#39; =&amp;gt; date(&#39;c&#39;), ]); $redis-&amp;gt;rPush(&#39;order_events&#39;, $orderEvent); echo &quot;Order event ส่งเข้า Queue เรียบร้อย&quot;; &lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;?php // Consumer: EmailService รับข้อความจาก Queue (รัน background worker) $redis = new Redis(); $redis-&amp;gt;connect(&#39;redis&#39;, 6379); echo &quot;EmailService Worker เริ่มทำงาน...\n&quot;; while (true) { $message = $redis-&amp;gt;blPop([&#39;order_events&#39;], 5); // รอ 5 วิ if ($message) { $event = json_decode($message[1], true); if ($event[&#39;event&#39;] === &#39;order.created&#39;) { sendOrderConfirmationEmail($event[&#39;user_id&#39;], $event[&#39;order_id&#39;]); echo &quot;ส่ง Email ยืนยัน Order #{$event[&#39;order_id&#39;]} แล้ว\n&quot;; } } } function sendOrderConfirmationEmail(int $userId, int $orderId): void { // Logic ส่ง Email จริงๆ echo &quot;Email ถึง User #$userId สำหรับ Order #$orderId\n&quot;; } &lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Docker Compose สำหรับรัน Microservices&lt;/h2&gt;&lt;p&gt;ใช้ Docker Compose จัดการ Services หลายตัวพร้อมกัน:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;version: &#39;3.8&#39; services: user-service: build: ./services/user-service ports: - &quot;8001:80&quot; environment: DB_HOST: user-db DB_NAME: users_db auth-service: build: ./services/auth-service ports: - &quot;8002:80&quot; environment: JWT_SECRET: your-secret-key product-service: build: ./services/product-service ports: - &quot;8003:80&quot; redis: image: redis:alpine ports: - &quot;6379:6379&quot; user-db: image: mysql:8 environment: MYSQL_DATABASE: users_db MYSQL_ROOT_PASSWORD: secret&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;tip-box&quot; style=&quot;background: rgb(240, 253, 244); border-left: 4px solid rgb(34, 197, 94); border-radius: 0px 8px 8px 0px; margin: 1.5em 0px; padding: 1em 1.2em;&quot;&gt;&lt;strong style=&quot;color: #15803d;&quot;&gt;💡 เคล็ดลับ:&lt;/strong&gt; ในโปรเจกต์จริง ควรเพิ่ม &lt;strong style=&quot;color: #15803d;&quot;&gt;API Gateway&lt;/strong&gt; ด้านหน้าเพื่อจัดการ Routing, Authentication, Rate Limiting และ Load Balancing ให้กับ Services ทั้งหมด แนะนำ &lt;strong style=&quot;color: #15803d;&quot;&gt;Nginx&lt;/strong&gt; หรือ &lt;strong style=&quot;color: #15803d;&quot;&gt;Traefik&lt;/strong&gt;&lt;/div&gt;&lt;h2&gt;ข้อดีและข้อเสียของแนวทางนี้&lt;/h2&gt;&lt;h3&gt;✅ ข้อดี&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;ไม่มี Framework Overhead — เร็วและเบา&lt;/li&gt;&lt;li&gt;เข้าใจได้ง่าย เพราะเป็น PHP พื้นฐาน&lt;/li&gt;&lt;li&gt;แต่ละ Service สามารถใช้ PHP Version ต่างกันได้&lt;/li&gt;&lt;li&gt;Scale เฉพาะ Service ที่ Load สูงได้&lt;/li&gt;&lt;li&gt;Team แยกกันพัฒนาได้โดยไม่ Conflict&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;❌ ข้อเสีย&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;ต้องเขียน Boilerplate เยอะกว่า Framework&lt;/li&gt;&lt;li&gt;ซับซ้อนด้าน Infrastructure และ DevOps&lt;/li&gt;&lt;li&gt;Network Latency เพิ่มขึ้นจากการ Call ระหว่าง Services&lt;/li&gt;&lt;li&gt;Debugging ยากขึ้น ต้องการ Distributed Tracing&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;สรุป&lt;/h2&gt;&lt;p&gt;การสร้าง Microservices ด้วย Native PHP เป็นไปได้อย่างสมบูรณ์แบบ โดยใช้เพียง cURL, JSON, และ HTTP Standards ที่มีอยู่แล้วใน PHP โดยไม่จำเป็นต้องพึ่งพา Framework ขนาดใหญ่ อย่างไรก็ตาม ควรพิจารณาให้ดีก่อนว่าโปรเจกต์ของคุณมีความซับซ้อนพอที่จะได้ประโยชน์จาก Microservices จริงหรือไม่ เพราะสำหรับโปรเจกต์ขนาดกลาง &lt;strong&gt;Monolithic ที่ออกแบบดีๆ ก็ยังเป็นทางเลือกที่ดี&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot;tag-list&quot; style=&quot;display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2em;&quot;&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#PHP&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#Microservices&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#WebDevelopment&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#Docker&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#BackendDevelopment&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#SoftwareArchitecture&lt;/span&gt;&lt;span class=&quot;tag&quot; style=&quot;background: rgb(224, 231, 255); border-radius: 20px; color: #3730a3; font-size: 0.85em; padding: 4px 12px;&quot;&gt;#NativePHP&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt; &lt;br /&gt; &lt;br /&gt; &lt;h3 style=&quot;text-align: center;&quot;&gt; &lt;span style=&quot;color: #674ea7;&quot;&gt;PHP&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #e06666;&quot;&gt;CI&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #c27ba0;&quot;&gt;MANIA&lt;/span&gt;&lt;span style=&quot;color: #d5a6bd;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #674ea7;&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;color: orange;&quot;&gt;PHP Code Generator&amp;nbsp;&lt;/span&gt;&lt;/h3&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;b&gt;&lt;span style=&quot;color: magenta;&quot;&gt;โปรแกรมช่วยสร้างโค้ด &lt;/span&gt;&lt;span style=&quot;color: #274e13;&quot;&gt;&quot;ลดเวลาการเขียนโปรแกรม&quot;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt; &lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;366&quot; data-original-width=&quot;640&quot; height=&quot;229&quot; src=&quot;https://1.bp.blogspot.com/-TUNSpxlni24/YBS8d0gXdTI/AAAAAAAANB0/WNHrNHDIetAk7jFsYdPeOfxIbqk-ymAnACLcBGAsYHQ/w400-h229/php-code-generator.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt; &lt;span style=&quot;color: blue; font-weight: bold;&quot;&gt;ราคาสุดคุ้ม&lt;/span&gt;&lt;span style=&quot;color: #38761d; font-weight: bold;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;&lt;span style=&quot;color: blue;&quot;&gt;&lt;a href=&quot;http://www.phpcodemania.com&quot; target=&quot;_blank&quot;&gt;http://www.phpcodemania.com&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;div style=&quot;text-align: center;&quot;&gt; &lt;br /&gt;&lt;/div&gt; </content><link rel='replies' type='application/atom+xml' href='http://blog.phpcodemania.com/feeds/8831198723624950411/comments/default' title='ส่งความคิดเห็น'/><link rel='replies' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-microservices-without-frameworks.html#comment-form' title='0 ความคิดเห็น'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8831198723624950411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2142305340755025784/posts/default/8831198723624950411'/><link rel='alternate' type='text/html' href='http://blog.phpcodemania.com/2026/06/php-microservices-without-frameworks.html' title='PHP Microservices Without Frameworks: สร้าง Microservices ด้วย Native PHP'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMKaOGkvZfW0mD8NtnUUaIZoRObi2v5ZR8sQ-ihaJfJLtsrgeuvtj2zkG9UmlybsyCE1q2TznhmECVO3NgwYrZ5anBAkm3DzGHBcd2Fi0CM7h8KPS9beoY6G6L3XmZ_7gJqHb0J4ON5UtObwxwpGdVWbG5erFJ9heGCrYdV0aDRpFw1BH8nPcQN525xHs/s72-w640-h360-c/fe971fbd-f1f6-4c0f-9ca3-d56bb8a040b0.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>