บทช่วยสอน Laravel สำหรับผู้เริ่มต้น

Laravel คืออะไร?

Laravel เป็นเฟรมเวิร์ก MVC เว็บแบบโอเพ่นซอร์สสำหรับ PHP Laravel เป็นเฟรมเวิร์กที่แข็งแกร่งที่ช่วยให้การพัฒนาเว็บแอปพลิเคชัน PHP เป็นเรื่องง่าย พร้อมฟีเจอร์ต่างๆ เช่น ระบบบรรจุภัณฑ์แบบโมดูลาร์พร้อมตัวจัดการการพึ่งพาเฉพาะ การเข้าถึงฐานข้อมูลเชิงสัมพันธ์ และยูทิลิตี้อื่นๆ สำหรับการปรับใช้และบำรุงรักษาแอปพลิเคชัน

Laravel ถูกสร้างขึ้นโดย Taylor Otwell นับตั้งแต่เปิดตัวครั้งแรกในเดือนมิถุนายน 2011 (เวอร์ชัน 1) ก็ได้รับความนิยมมากขึ้นเรื่อยๆ ในภาคส่วนเฟรมเวิร์ก PHP ของอุตสาหกรรมการพัฒนาเว็บ ความนิยมมากมายนี้สามารถนำมาประกอบกับคุณสมบัติที่คำนึงถึงนักพัฒนาจำนวนมากที่มาพร้อมกับสต็อก

ทำไมต้องลาราเวล?

ประมาณปี 2000 มากที่สุด รหัส PHP เป็นขั้นตอนและสามารถพบได้ในรูปแบบของ "สคริปต์" ที่จะมีรหัสสปาเก็ตตี้ยุ่งเหยิง แม้แต่หน้าที่ง่ายที่สุดก็ไม่มี แยกความกังวลดังนั้นจึงค่อนข้างง่ายสำหรับแอปพลิเคชันที่จะเติบโตอย่างรวดเร็วจนกลายเป็นฝันร้ายในการบำรุงรักษา โลกต้องการบางสิ่งที่ดีกว่า...เข้าสู่ PHP เวอร์ชัน 5 และเฟรมเวิร์ก PHP ที่หลากหลาย โดยพยายามนำเสนอความละเอียดที่จำเป็นมากและโซลูชั่นที่ดีกว่าสำหรับข้อกังวลต่างๆ ของเว็บแอปพลิเคชัน

ตั้งแต่นั้นมา เราได้เห็นเฟรมเวิร์กจำนวนมากที่เปิดตัวออกมา ซึ่งจะช่วยปูทางให้กับเฟรมเวิร์กยอดนิยมที่มีอยู่และใช้งานอยู่ในปัจจุบัน ในปัจจุบัน เฟรมเวิร์กสามอันดับแรก (ในความเห็นของเรา) คือ Zend Framework, Symfony และแน่นอนว่า Laravel ถึงแม้ว่าเฟรมเวิร์กเหล่านี้ทั้งหมดจะสร้างขึ้นบนหลักการที่คล้ายคลึงกันและมุ่งเน้นไปที่การแก้ไขปัญหาทั่วไป (โดยพื้นฐาน) เดียวกัน แต่ความแตกต่างที่สำคัญอยู่ที่การใช้งาน เฟรมเวิร์กเหล่านี้แต่ละเฟรมเวิร์กมีลักษณะเฉพาะของตนเองในการแก้ปัญหา เมื่อคุณดูโค้ดที่สร้างขึ้นโดยเฟรมเวิร์กเหล่านี้ คุณจะเห็นว่ามีเส้นแบ่งที่ชัดเจนระหว่างเฟรมเวิร์กเหล่านี้ ในความคิดเห็นที่ไม่โอ้อวดของเรา เฟรมเวิร์ก Laravel ดีที่สุด

เรียนรู้เพิ่มเติมเกี่ยวกับ ความแตกต่างระหว่าง Laravel และ CodeIgniter

วิธีดาวน์โหลดและติดตั้ง Laravel ด้วย Composer

หมายเหตุ ถือว่าคุณมีสำเนาของ PHP ติดตั้งอยู่ในระบบภายในเครื่องของคุณแล้ว ถ้าไม่คุณสามารถอ่านวิธีการติดตั้งได้ Good Farm Animal Welfare Awards

Composer เป็นทั้งตัวจัดการแพ็กเกจและการอ้างอิง เมื่อต้องการติดตั้ง ให้เปิดเทอร์มินัลแล้ว cd เข้าไปในไดเร็กทอรีใหม่ รันคำสั่งนี้:

curl -Ss getcomposer.org/installer | php

ผลลัพธ์ของคำสั่งนี้จะมีลักษณะดังนี้:

ดาวน์โหลดและติดตั้ง Laravel ด้วย Composer

หมายเหตุ หากต้องการคำแนะนำเพิ่มเติมเกี่ยวกับการตั้งค่า Laravel โปรดดูเอกสารประกอบของ Laravel Good Farm Animal Welfare Awards.

คุณจะเห็นว่ามีการดาวน์โหลดและคอมไพล์สคริปต์ composer.phar ซึ่งเป็นสคริปต์ที่เราใช้ในการติดตั้ง Laravel แม้ว่าจะมีหลายวิธีในการตั้งค่าแอปพลิเคชัน Laravel ใหม่ แต่เราจะทำผ่านสคริปต์ composer ของ Laravel หากต้องการติดตั้งสคริปต์นี้ ให้รัน:

composer global require laravel/installer

ซึ่งจะมีลักษณะดังนี้:

ดาวน์โหลดและติดตั้ง Laravel ด้วย Composer

ขั้นตอนนี้จะดาวน์โหลดและติดตั้งไฟล์เฟรมเวิร์กทั้งหมด รวมถึงไฟล์ที่ต้องพึ่งพาทั้งหมด แพ็กเกจต่างๆ จะถูกบันทึกไว้ในไดเร็กทอรีของผู้จำหน่าย เมื่อดาวน์โหลดและติดตั้งเสร็จแล้ว ก็ง่ายเพียงใช้คำสั่งต่อไปนี้:

laravel new uploadApp

คุณจะเห็นผลลัพธ์ประมาณนี้:

ดาวน์โหลดและติดตั้ง Laravel ด้วย Composer

Composer กำลังติดตั้งแพ็กเกจทั้งหมดที่ Laravel ต้องการเพื่อรัน อาจใช้เวลาสักครู่ โปรดอดทนรอ เมื่อติดตั้งเสร็จแล้ว ให้รันคำสั่ง ls -al เพื่อดูว่ามีการติดตั้งอะไรไว้บ้าง

นี่คือรายละเอียดโดยย่อของไดเร็กทอรีในแอปพลิเคชัน Laravel ทั่วไป:

  • แอป/ : นี่คือโฟลเดอร์ต้นทางที่มีโค้ดแอปพลิเคชันของเราอยู่ ตัวควบคุม นโยบาย และโมเดลทั้งหมดอยู่ในโฟลเดอร์นี้
  • บูตสแตรป/ : เก็บสคริปต์เริ่มต้นของแอปพลิเคชันและไฟล์แผนผังคลาสบางไฟล์
  • กำหนดค่า/ : เก็บไฟล์การกำหนดค่าของแอป โดยทั่วไปสิ่งเหล่านี้จะไม่ได้รับการแก้ไขโดยตรง แต่อาศัยค่าที่ตั้งค่าไว้ในไฟล์ .env (สภาพแวดล้อม) ที่รูทของแอปแทน
  • ฐานข้อมูล/ : จัดเก็บไฟล์ฐานข้อมูลรวมถึงการโยกย้าย เมล็ดพันธุ์พืช และโรงงานทดสอบ
  • สาธารณะ/ : โฟลเดอร์ที่เข้าถึงได้แบบสาธารณะซึ่งมีเนื้อหาที่คอมไพล์แล้วและแน่นอนว่าเป็นไฟล์ index.php
  • ทรัพยากร/ : ประกอบด้วยเนื้อหาส่วนหน้า เช่น ไฟล์จาวาสคริปต์ ไฟล์ภาษา ไฟล์ CSS/SASS และเทมเพลตทั้งหมดที่ใช้ในแอปพลิเคชัน (เรียกว่าเทมเพลตเบลด)
  • เส้นทาง/ : เส้นทางทั้งหมดในแอปพลิเคชันอยู่ที่นี่ มี "ขอบเขต" ของเส้นทางที่แตกต่างกันเล็กน้อย แต่สิ่งที่เราจะเน้นคือไฟล์ web.php
  • พื้นที่จัดเก็บ/ : ไฟล์แคชชั่วคราวทั้งหมดที่ใช้โดยแอปพลิเคชัน ไฟล์เซสชัน สคริปต์มุมมองที่คอมไพล์ และไฟล์บันทึก
  • การทดสอบ/ : มีไฟล์ทดสอบสำหรับแอปพลิเคชัน เช่น การทดสอบหน่วยและการทดสอบการทำงาน
  • ผู้ขาย/ : แพ็คเกจการอ้างอิงทั้งหมดติดตั้งพร้อมกับ composer

ตอนนี้ เรามาสร้างแอปที่เหลือและรันด้วยคำสั่งพิเศษของช่างฝีมือกัน (เพื่อไม่ต้องยุ่งยากกับการติดตั้งและกำหนดค่าเว็บเซิร์ฟเวอร์ เช่น Apache หรือ nginx) ไฟล์ .env มีค่าการกำหนดค่าทั้งหมดที่ไฟล์ในไดเร็กทอรี /config ใช้เพื่อกำหนดค่าแอปพลิเคชัน ภายในนั้นคุณจะสังเกตเห็นว่าค่าการกำหนดค่าสำหรับพารามิเตอร์ต่างๆ ที่ใช้โดยภายในของแอปพลิเคชัน

การออกแบบแอปพลิเคชัน: ความต้องการของเราลดลงอย่างรวดเร็ว

ในบทช่วยสอน Laravel ออนไลน์นี้ เราจะสร้างแอปพลิเคชันที่เรียบง่ายซึ่งจะทำเพียงสองสิ่งเท่านั้น:

  1. จัดการการอัพโหลดไฟล์จากเว็บฟอร์ม
  2. การแสดงไฟล์ที่อัพโหลดก่อนหน้านี้ในหน้าอื่น

สำหรับโปรเจ็กต์นี้ แอปพลิเคชันของเราจะเขียนได้อย่างเดียว ซึ่งหมายความว่าผู้ใช้สามารถเขียนได้เฉพาะไฟล์และดูรายการไฟล์ที่พวกเขาอัปโหลดเท่านั้น แอปพลิเคชั่นนี้เป็นพื้นฐานอย่างยิ่ง แต่ควรทำหน้าที่เป็นแนวปฏิบัติที่ดีสำหรับคุณในการเริ่มสร้างทักษะและความรู้ Laravel ของคุณ โปรดทราบว่าเพื่อความกระชับ ฉันได้ยกเว้นการสร้างแบบจำลองฐานข้อมูล การย้ายข้อมูล และการรับรองความถูกต้องใดๆ แต่ในแอปพลิเคชันในโลกแห่งความเป็นจริง สิ่งเหล่านี้คือสิ่งเพิ่มเติมที่คุณจะต้องพิจารณา

นี่คือรายการส่วนประกอบที่เราจะต้องมีเพื่อให้แอปพลิเคชันทำงานได้ตามที่คาดไว้:

  • A เส้นทาง ที่จะทำให้โลกภายนอก (อินเตอร์เน็ต) สามารถใช้งานแอพพลิเคชั่นได้พร้อมทั้งระบุจุดปลายทางที่จะชี้ตำแหน่งตรรกะในการบันทึกไฟล์ที่อัพโหลดอยู่
  • A ตัวควบคุม ที่จัดการคำขอกระแสตอบรับ
  • A เทมเพลต ที่จะใช้แสดงรายการไฟล์ที่อัพโหลดก่อนหน้านี้และแบบฟอร์มการอัพโหลดจริงนั้นเอง
  • A ขอ ที่คอนโทรลเลอร์จะใช้เพื่อตรวจสอบความถูกต้องของข้อมูลที่ส่งมาจากเว็บฟอร์ม

เส้นทางคืออะไร?

เส้นทางใน Laravel นั้นโดยพื้นฐานแล้วเป็นจุดสิ้นสุดที่ระบุโดย URI ซึ่งทำหน้าที่เป็น "ตัวชี้" ไปยังฟังก์ชันบางส่วนที่นำเสนอโดยแอปพลิเคชัน โดยทั่วไปแล้ว เส้นทางเพียงชี้ไปที่วิธีการบนตัวควบคุมและยังกำหนดว่าวิธี HTTP ใดที่สามารถโจมตี URI นั้นได้ เส้นทางไม่ได้หมายถึงวิธีการควบคุมเสมอไปเช่นกัน มันสามารถส่งผ่านการดำเนินการของแอปพลิเคชันไปยังการปิดที่กำหนดหรือฟังก์ชันที่ไม่ระบุชื่อได้เช่นกัน

ทำไมต้องใช้เส้นทาง?

เส้นทางจะถูกเก็บไว้ในไฟล์ภายใต้โฟลเดอร์ /routes ในไดเร็กทอรีรูทของโปรเจ็กต์ โดยค่าเริ่มต้นจะมีไฟล์ที่แตกต่างกันสองสามไฟล์ที่สอดคล้องกับ "ด้านต่างๆ" ของแอปพลิเคชัน ("ด้าน" มาจากวิธีการสถาปัตยกรรมแบบหกเหลี่ยม) ซึ่งได้แก่:

  • web.php เส้นทางที่ใช้ "เบราว์เซอร์" สาธารณะ สิ่งเหล่านี้เป็นเรื่องธรรมดาที่สุดและเป็นสิ่งที่เว็บเบราว์เซอร์โจมตี พวกเขาทำงานผ่านกลุ่มมิดเดิลแวร์ของเว็บและยังมีสิ่งอำนวยความสะดวกในการต่างๆ การป้องกันซีเอสอาร์เอฟ (ซึ่งช่วยป้องกันการโจมตีและการแฮ็กที่เป็นอันตรายตามแบบฟอร์ม) และโดยทั่วไปมีระดับ "สถานะ" (โดยที่ฉันหมายถึงพวกเขาใช้เซสชัน)
  • เส้นทาง api.php ที่สอดคล้องกับกลุ่ม API จึงมีการเปิดใช้งานมิดเดิลแวร์ API ตามค่าเริ่มต้น เส้นทางเหล่านี้ไม่มีสถานะและไม่มีเซสชันหรือหน่วยความจำคำขอข้าม (คำขอหนึ่งรายการไม่แชร์ข้อมูลหรือหน่วยความจำกับคำขออื่นใด โดยแต่ละคำขอถูกห่อหุ้มในตัวเอง)
  • console.php เส้นทางเหล่านี้สอดคล้องกับคำสั่งช่างฝีมือที่คุณสร้างขึ้นสำหรับแอปของคุณ
  • channel.php ลงทะเบียนเส้นทางสำหรับการออกอากาศกิจกรรม

ไฟล์สำคัญที่ต้องกังวลในขณะนี้คือไฟล์เฉพาะเบราว์เซอร์ web.php มีเส้นทางหนึ่งที่กำหนดไว้ตามค่าเริ่มต้นอยู่แล้ว ซึ่งเป็นเส้นทางที่คุณกดถูกเมื่อนำทางไปยังเว็บรูทของแอปพลิเคชันของคุณ (เว็บรูทอยู่ในไดเร็กทอรีสาธารณะ) เราต้องการเส้นทางที่แตกต่างกันสามเส้นทางเพื่อให้แอปพลิเคชันอัปโหลดของเราทำงานได้:

  • /upload นี่จะเป็น URI ของหน้าหลักที่แสดงเว็บฟอร์มของเราสำหรับการอัพโหลดไฟล์
  • /process นี่จะเป็นที่ที่แบบฟอร์มอยู่ที่ /upload URI โพสต์ข้อมูลที่ส่งแบบฟอร์มไปที่ ("การกระทำของแบบฟอร์ม")
  • /list นี่จะแสดงรายการไฟล์ทั้งหมดที่อัพโหลดไปยังไซต์

หมายเหตุ จุดสิ้นสุด /list อาจไม่จำเป็นหากเราต้องการใส่ตรรกะทั้งหมดสำหรับการแสดงแบบฟอร์มการอัปโหลดและรายการไฟล์ในหน้าเดียว อย่างไรก็ตาม เราแยกพวกมันไว้ต่างหากในตอนนี้เพื่อเพิ่มเรื่องเล็กน้อยให้กับหัวข้อที่มีอยู่ .

//inside routes/web.php
Route::get('/upload', 'UploadController@upload')->name('upload');
Route::get('/download, 'UploadController@download)->name(‘download');
Route::post('/process', 'UploadController@process')->name('process');
Route::get('/list', 'UploadController@list')->name('list');

ในบทช่วยสอนเฟรมเวิร์ก Laravel นี้ สำหรับแต่ละเส้นทางที่ต้องการ เราจะแสดงรายการอย่างชัดเจนในไฟล์เส้นทาง web.php โดยใช้หนึ่งในวิธีการร้องขอ HTTP เฉพาะที่มีอยู่ (get(), post(), put() , Delete() patch() หรือ options() ) หากต้องการดูรายละเอียดแต่ละรายการ โปรดตรวจสอบ นี้ ออก. สิ่งที่วิธีการเหล่านี้ทำคือระบุว่ากริยา HTTP ใดที่ได้รับอนุญาตให้เข้าถึงเส้นทางที่กำหนด หากคุณต้องการเส้นทางเพื่อให้สามารถยอมรับกริยา HTTP มากกว่าหนึ่งรายการ (ซึ่งอาจเป็นกรณีนี้หากคุณใช้หน้าเดียวเพื่อแสดงข้อมูลเริ่มต้นและโพสต์ข้อมูลแบบฟอร์มที่ส่ง) คุณสามารถใช้ Route::any( ) วิธี.

อาร์กิวเมนต์ที่สองสำหรับวิธี Route::get() และ Route::post() (และวิธีการใดๆ ที่เกี่ยวข้องกับกริยา HTTP อื่นๆ ในส่วน Route) คือชื่อของ Controller เฉพาะและวิธีการที่เก็บอยู่ภายใน Controller นั้นและจะถูกดำเนินการเมื่อถึงจุดสิ้นสุดของเส้นทางด้วยคำขอ HTTP ที่อนุญาต (GET, POST, PATCH เป็นต้น) เรากำลังใช้ UploadController สำหรับทั้งสามเส้นทางและได้ระบุไว้ในลักษณะต่อไปนี้:

เส้นทางคืออะไร

วิธีสุดท้ายที่เราเรียกใช้ในแต่ละเส้นทางคือฟังก์ชัน name() ซึ่งยอมรับสตริงเดี่ยวเป็นอาร์กิวเมนต์ และใช้เพื่อ "แท็ก" เส้นทางเฉพาะไม่มากก็น้อยโดยง่ายต่อการจดจำชื่อ (ในกรณีของเรา อัปโหลด ประมวลผล และรายการ) ฉันรู้ว่ามันดูเหมือนจะไม่มีคุณสมบัติที่ดีนักที่จะให้แต่ละเส้นทางมีชื่อของตัวเองเมื่อ URL นั้นตั้งชื่อเหมือนกันทุกประการ แต่จะมีประโยชน์มากเมื่อคุณมีเส้นทางเฉพาะเช่น /users/profile/dashboard/config ซึ่งจะง่ายกว่าที่จะจำว่าเป็นprofile-adminหรือuser-config

หมายเหตุเกี่ยวกับ Facades:

  • Facades จัดเตรียมอินเทอร์เฟซ "คงที่" ให้กับคลาสที่มีอยู่ในคอนเทนเนอร์บริการของแอปพลิเคชัน”
  • พวกมันมีไวยากรณ์ที่กระชับและน่าจดจำซึ่งช่วยให้คุณสามารถใช้ฟีเจอร์ของ Laravel ได้โดยไม่ต้องจำชื่อคลาสขนาดยาวที่ต้องฉีดหรือกำหนดค่าด้วยตนเอง

คำจำกัดความเส้นทางข้างต้นในบทช่วยสอนกรอบงาน Laravel นี้ เราใช้ส่วนหน้าของเส้นทางแทนการสร้างอินสแตนซ์ออบเจ็กต์ Illuminate/Routing/Router ใหม่ด้วยตนเอง และเรียกใช้วิธีการที่เกี่ยวข้องบนออบเจ็กต์นั้น เป็นเพียงทางลัดที่ช่วยประหยัดการพิมพ์ Facades ถูกใช้อย่างหนักตลอดทั้งกรอบงาน Laravel คุณสามารถและควรทำความคุ้นเคยให้มากขึ้น สามารถดูเอกสารสำหรับ Facades ได้ Good Farm Animal Welfare Awards.

ผู้ควบคุมคืออะไร?

ตัวควบคุมคือ "C" ในสถาปัตยกรรม "MVC" (Model-View-Controller) ซึ่งเป็นพื้นฐานของ Laravel งานของตัวควบคุมสามารถสรุปเป็นคำจำกัดความง่ายๆ ดังต่อไปนี้: ได้รับการร้องขอจากลูกค้าและส่งคืนการตอบกลับไปยังลูกค้า นี่คือคำจำกัดความแบบเปลือยเปล่าและเป็นข้อกำหนดขั้นต่ำของคอนโทรลเลอร์ที่กำหนดด้วย โดยทั่วไปสิ่งที่ทำระหว่างสองสิ่งนี้ถือเป็น "การกระทำ" ของคอนโทรลเลอร์ (หรือ "การใช้งานเส้นทาง") มันทำหน้าที่เป็นจุดที่สองของการเข้าสู่แอปพลิเคชัน (จุดแรกคือคำขอ) ไปยังไคลเอนต์ ซึ่งส่งเพย์โหลดคำขอ (ซึ่งเราจะไปถึงถัดไป) ไปยังแอปพลิเคชัน โดยคาดหวังการตอบสนองบางประเภท (ในรูปแบบของ หน้าความสำเร็จ การเปลี่ยนเส้นทาง หน้าข้อผิดพลาด หรือการตอบกลับ HTTP ประเภทอื่น ๆ)

คอนโทรลเลอร์ทำ (โดยพื้นฐาน) เช่นเดียวกับการกำหนดเส้นทางโดยมีฟังก์ชันที่ไม่ระบุตัวตนซึ่งตั้งค่าเป็น "การกระทำ" เมื่อเส้นทางนั้นถูกโจมตี ข้อแตกต่างก็คือตัวควบคุมสามารถแยกข้อกังวลได้ดีในขณะที่เส้นทางถูกกำหนดแบบอินไลน์กับคำจำกัดความ URL จริง ซึ่งโดยทั่วไปหมายความว่าเรากำลังเชื่อมโยง URI ที่กำหนดของเส้นทางเข้ากับการใช้งานของเส้นทาง หรือโค้ดที่ดำเนินการเมื่อเส้นทางนั้น ตี.

ตัวอย่างเช่น โค้ดสองชิ้นต่อไปนี้จะบรรลุผลเดียวกัน:

ตัวอย่างที่ 1: คำจำกัดความและการใช้งานของเส้นทางภายในการเรียกเมธอดเดียว (ในไฟล์เส้นทาง web.php)

//inside routes/web.php
<?php
Route::get('/hello-world', function(Request $request) {
   $name = $request->name;
   return response()->make("<h1>Hello World! This is ".$name, 200);
});

ตัวอย่างที่ 2: คำจำกัดความของเส้นทางอยู่ภายในเส้นทาง/web.php แต่การใช้งานนั้นอยู่ภายในคลาส /app/Http/Controllers/HelloWorldController

//inside routes/web.php
<?php

Route::get('/hello-world', 'HelloWorldController@index')->name('hello-world');

------------------------------------------------------------------------------------
//inside app/Http/Controllers/HelloWorldController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class HelloWorldController extends Controller
{
   public function index(Request $request)
   {
       $name = $request->name;
       return response()->make("<h1>Hello World! This is ".$name, 200);
   }
}

แม้ว่าตัวอย่าง Laravel #2 ดูเหมือนว่าจะใช้งานได้มากขึ้น (ซึ่งไม่ใช่ แค่โค้ดเพิ่มเติมนิดหน่อยเท่านั้น) ให้ลองพิจารณาประโยชน์ที่เราได้รับจากการใส่ตรรกะการดำเนินการของเราสำหรับเส้นทาง "สวัสดีโลก" ที่ให้มาภายในคอนโทรลเลอร์แทน ด้วยคำจำกัดความของเส้นทางเป็นฟังก์ชันโทรกลับ:

  1. ตรรกะของเราถูกแยกออกเป็นประเภทของตัวเองอย่างชัดเจน (แยกข้อกังวล)
  2. คอนโทรลเลอร์ของเราถูกตั้งค่าให้ขยายในภายหลังหากเราต้องการเพิ่มความสามารถเพิ่มเติมให้กับมัน... สมมติว่าเราต้องการเพิ่มฟีเจอร์ "ลาโลก"... ในกรณีนี้ เราจะเปลี่ยนชื่อคอนโทรลเลอร์เป็น "HelloController" ทั่วไปมากขึ้น จากนั้นกำหนดวิธีการแยกกันสองวิธี สวัสดี() และ ลาก่อน()- นอกจากนี้เรายังจะต้องกำหนดเส้นทางแยกกันสองเส้นทางที่แมป /สวัสดี และ / ลาก่อน URI ไปยังวิธีการที่เหมาะสมบนคอนโทรลเลอร์ นี่เป็นสิ่งที่พึงประสงค์เมื่อเปรียบเทียบกับการทำให้ไฟล์เส้นทางอ้วนขึ้นโดยแต่ละเส้นทางถูกกำหนดให้เป็นฟังก์ชันการโทรกลับ
  3. Laravel มีความสามารถในตัวในการแคชคำจำกัดความเส้นทางทั้งหมดในแอปพลิเคชัน เพื่อเร่งความเร็วเวลาที่ใช้ในการค้นหาเส้นทางที่กำหนด (เพิ่มประสิทธิภาพของแอปพลิเคชัน) อย่างไรก็ตาม คุณจะสามารถใช้ประโยชน์จากสิ่งนั้นได้ก็ต่อเมื่อเส้นทางที่คุณกำหนดทั้งหมดภายในแอปพลิเคชันได้รับการกำหนดค่าโดยใช้การแมปเฉพาะคอนโทรลเลอร์ (ดูตัวอย่าง #2 ด้านบน)

มารันคำสั่งนี้เพื่อสร้างคอนโทรลเลอร์ใหม่ให้เรา

// ...inside the project's root directory:
php artisan make:controller UploadController   

โดยพื้นฐานแล้ว สิ่งที่คำสั่งนี้ทำคือการสร้าง stub สำหรับคอนโทรลเลอร์ชื่อ “UploadController” ภายในไดเร็กทอรีคอนโทรลเลอร์หลักที่ /app/Http/Controllers/UploadController.php.อย่าลังเลที่จะเปิดไฟล์นั้นแล้วลองดู มันง่ายมากเพราะมันเป็นเพียงเวอร์ชันที่ไม่สมบูรณ์ของคอนโทรลเลอร์ พร้อมด้วยพาธเนมสเปซที่ถูกต้องและคลาสที่จำเป็นที่จะขยายออกมา

การสร้างคำขอ

ก่อนที่เราจะดำเนินการต่อในบทช่วยสอน PHP Laravel นี้และทำการเปลี่ยนแปลงเล็กน้อยกับสตับที่สร้างขึ้นโดย UploadController ฉันคิดว่ามันจะสมเหตุสมผลมากกว่าที่จะสร้างคลาสคำขอก่อน นี่เป็นเพราะว่าเมธอดตัวควบคุมที่จัดการคำขอจะต้องระบุประเภทของอ็อบเจกต์คำขอในลายเซ็นของมัน ซึ่งจะทำให้สามารถตรวจสอบข้อมูลแบบฟอร์มขาเข้าได้โดยอัตโนมัติ (ตามที่ระบุไว้ในเมธอด rules() เราจะพูดถึงเรื่องนี้เพิ่มเติมในภายหลัง…) ในตอนนี้ ให้ใช้คำสั่ง artisan อีกครั้งเพื่อสร้างสตับคำขอของเรา:

php artisan make:request UploadFileRequest

คำสั่งนี้จะสร้างไฟล์ชื่อ UploadFileRequest ภายใน app/Http/Requests/UploadFileRequest เปิด stub แล้วลองดู… คุณจะพบว่ามันง่ายมาก โดยมีเพียงสองวิธีคือ authorize() และกฎ

การสร้างตรรกะการตรวจสอบความถูกต้อง

มาแก้ไขต้นขั้วคำขอเพื่อให้ตรงกับความต้องการของแอปพลิเคชันของเรา แก้ไขไฟล์เพื่อให้มีลักษณะดังนี้:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UploadFileRequest extends FormRequest
{
   /**
    * Determine if the user is authorized to make this request.
    *
    * @return bool
    */
   public function authorize()
   {
       return true;
   }

   /**
    * Get the validation rules that apply to the request.
    *
    * @return array
    */
   public function rules()
   {
       return [
           'fileName' => 'required|string',
           'userFile' => 'required|file'
       ];
   }
}

มีการเปลี่ยนแปลงไม่มากนัก แต่สังเกตว่าตอนนี้การอนุญาต () วิธีการคืนค่าจริงแทนที่จะเป็นเท็จ วิธีนี้จะตัดสินใจว่าจะอนุญาตให้คำขอเข้าสู่แอปพลิเคชันหรือไม่ หากตั้งค่าเป็น False จะหยุดการร้องขอเข้าสู่ระบบ (ซึ่งโดยปกติจะเป็นวิธีการบนคอนโทรลเลอร์) นี่จะเป็นสถานที่ที่มีประโยชน์มากในการตรวจสอบการอนุญาตกับผู้ใช้หรือตรรกะอื่นใดที่อาจตัดสินว่าคำขอสามารถส่งต่อไปยังตัวควบคุมได้หรือไม่ สำหรับตอนนี้ เราเพิ่งกลับมาที่นี่เพื่ออนุญาตให้ทุกสิ่งใช้คำขอได้

อีกวิธีหนึ่งคือกฎ () คือจุดที่เวทย์มนตร์ทั้งหมดเข้ามามีบทบาทเกี่ยวกับการตรวจสอบความถูกต้อง แนวคิดนั้นง่ายมาก: ส่งคืนอาร์เรย์ที่มีชุดกฎในรูปแบบของ:

'formFieldName' => 'constraints this field has separated by pipe characters (|)'

มีข้อจำกัดการตรวจสอบที่แตกต่างกันมากมายที่ Laravel รองรับทันที สำหรับรายการทั้งหมด โปรดดูเอกสารออนไลน์ Good Farm Animal Welfare Awardsสำหรับแอปพลิเคชันอัปโหลดของเรา จะมีสองฟิลด์ที่ส่งผ่านคำขอ POST จากฟอร์มที่ส่วนหน้า พารามิเตอร์ fileName จะต้องรวมอยู่ในเนื้อหาของฟอร์ม (กล่าวคือ จำเป็น) และใช้เป็นชื่อไฟล์ที่เราจะจัดเก็บไฟล์ไว้ในที่จัดเก็บ (ซึ่งจะดำเนินการในตัวควบคุม เราจะพูดถึงเรื่องนี้ในภายหลัง) นอกจากนี้ เรายังระบุด้วยว่าชื่อไฟล์จะต้องเป็นสตริงโดยการเพิ่มอักขระท่อ (|) และคำว่า 'สตริง' ข้อจำกัดจะถูกคั่นด้วยท่อเสมอ ทำให้คุณสามารถระบุเกณฑ์เพิ่มเติมสำหรับฟิลด์ที่กำหนดในบรรทัดเดียวได้! ทรงพลังจริงๆ!

พารามิเตอร์ที่สอง userFile คือไฟล์จริงที่ผู้ใช้อัปโหลดจากแบบฟอร์มบนเว็บเพจ จำเป็นต้องมี UserFile และ ต้อง เป็นไฟล์. หมายเหตุ หากเราคาดหวังว่าไฟล์ที่อัปโหลดจะเป็นรูปภาพ เราจะใช้ข้อจำกัดของรูปภาพแทน ซึ่งจะจำกัดประเภทไฟล์ที่ยอมรับว่าเป็นหนึ่งในประเภทรูปภาพยอดนิยม (jpeg, PNG, bmp, gif หรือ svg) เนื่องจากเราต้องการอนุญาตให้ผู้ใช้สามารถอัปโหลดไฟล์ประเภทใดก็ได้ เราจึงจะยึดข้อจำกัดในการตรวจสอบความถูกต้องของไฟล์เอาไว้

นั่นคือทั้งหมดที่มีให้กับวัตถุคำขอ หน้าที่หลักคือเพียงรักษาชุดเกณฑ์ (ข้อจำกัด) ที่ยอมรับได้ ซึ่งพารามิเตอร์เนื้อหาของแบบฟอร์มต้องเป็นไปตามนั้นเพื่อดำเนินการในเชิงลึกในแอปพลิเคชัน สิ่งที่ควรทราบอีกประการหนึ่งคือต้องระบุทั้งสองฟิลด์นี้ (ไฟล์ผู้ใช้และชื่อไฟล์) ภายในโค้ด HTML ในรูปแบบของฟิลด์อินพุต (โดยมีชื่อฟิลด์ที่สอดคล้องกับชื่อภายในวัตถุคำขอ)

คุณอาจถามว่า: แน่ใจว่าสิ่งนี้กำหนดลักษณะของสิ่งที่คำขอแบบฟอร์มควรมี แต่การตรวจสอบข้อจำกัดเหล่านี้เกิดขึ้นจริงที่ไหน เราจะเข้าสู่เรื่องนั้นต่อไป

การปรับเปลี่ยนตัวควบคุม

เปิดแอป/Http/Controllers/UploadController และทำการเปลี่ยนแปลงดังต่อไปนี้:

<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use App\Http\Requests\UploadFileRequest; //our new request class
use Illuminate\Support\Facades\Storage; 

class UploadController extends Controller
{
   /**
    * This is the method that will simply list all the files uploaded by name and provide a
    * link to each one so they may be downloaded
    *
    * @param $request : A standard form request object
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function list(Request $request)
   {
       $uploads = Storage::allFiles('uploads');

       return view('list', ['files' => $uploads]);
   }

   /**
    * @param $file
    * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
    * @throws BindingResolutionException
    */
   public function download($file)
   {
       return response()->download(storage_path('app/'.$file));
   }

   /**
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function upload()
   {
       return view('upload');
   }

   /**
    * This method will handle the file uploads. Notice that the parameter's typehint
    * is the exact request class we generated in the last step. There is a reason for this!
    *
    * @param $request : The special form request for our upload application
    * @return array|\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null
    * @throws BindingResolutionException
    */
   public function store(UploadFileRequest $request)
   {
       //At this point, the parameters passed into the $request (from form) are
       //valid--they satisfy each of the conditions inside the rules() method

       $filename = $request->fileName;    //parameters have already been validated
       $file = $request->file('userFile'); //that we don't need any additional isset()

       $extension = $file->getClientOriginalExtension(); //grab the file extension
       $saveAs = $filename . "." . $extension; //filename to save file under

       $file->storeAs('uploads', $saveAs, 'local'); //save the file to local folder

       return response()->json(['success' => true]); //return a success message
   }
}

ดังนั้นจึงเป็นวิธีที่ค่อนข้างตรงไปตรงมาในการบันทึกไฟล์ที่อัพโหลดลงดิสก์ นี่คือรายละเอียดของวิธีการอัพโหลด () ด้านบน:

  • พิมพ์คำใบ้คลาสคำขอในวิธีการควบคุมที่กำลังทำหน้าที่ 'เนื้อสัตว์และมันฝรั่ง' เพื่อให้เราสามารถตรวจสอบข้อมูลที่เข้ามาได้โดยอัตโนมัติ
  • ดึงไฟล์ออกจากออบเจ็กต์คำขอ (ตรวจสอบแล้ว) ภายในวิธีการควบคุม (ในกรณีนี้ เราได้ตั้งชื่อไฟล์นั้นว่า upload() แต่อาจตั้งชื่อเป็นชื่อที่เป็นมาตรฐานมากขึ้น เช่น store() ก็ได้
  • คว้าชื่อไฟล์ออกจากคำขอ
  • สร้างชื่อไฟล์สุดท้ายที่จะใช้บันทึกไฟล์ไว้ข้างใต้ เมธอด getClientOriginalExtension() จะดึงนามสกุลดั้งเดิมของไฟล์ที่อัพโหลด
  • จัดเก็บไฟล์ไว้ในระบบไฟล์ในเครื่องโดยใช้เมธอด storeAs() โดยส่งผ่านพาธที่มีชื่อภายในไดเร็กทอรี /storage เป็นอาร์กิวเมนต์ที่ 1 และชื่อไฟล์ที่จะบันทึกไว้เป็นอาร์กิวเมนต์ที่สอง
  • ส่งคืนการตอบสนอง JSON ที่ระบุว่าคำขอสำเร็จ

เทมเพลตใบมีด

ชิ้นส่วนสำคัญชิ้นสุดท้ายของปริศนานี้คือเทมเพลตใบมีด ซึ่งจะเก็บ HTML, CSS และ javascript ทั้งหมดสำหรับแอปพลิเคชันง่ายๆ ของเรา นี่คือโค้ด ซึ่งเราจะอธิบายในภายหลัง

<body>
   <h1>Upload a file</h1>
   <form id="uploadForm" name="uploadForm" action="{{route('upload')}}" enctype="multipart/form-data">
       @csrf
       <label for="fileName">File Name:</label>
       <input type="text" name="fileName" id="fileName" required /><br />
       <label for="userFile">Select a File</label>
       <input type="file" name="userFile" id="userFile" required />
       <button type="submit" name="submit">Submit</button>
   </form>
   <h2 id="success" style="color:green;display:none">Successfully uploaded file</h2>
   <h2 id="error" style="color:red;display:none">Error Submitting File</h2>
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
   <script>
        $('#uploadForm').on('submit', function(e) {
            e.preventDefault();
            var form = $(this);
            var url = form.attr('action');
            $.ajax({
                url: url,
                type: "POST",
                data: new FormData(this),
                processData: false,
                contentType: false,
                dataType: "JSON",
                success: function(data) {
                    $("#fileName").val("");
                    $("#userFile").val("");
                }
            }).done(function() {
                $('#success').css('display', 'block');
                window.setTimeout(()=>($("#success").css('display', 'none')), 5000);
            }).fail(function() {
                $('#error').css('display', 'block');
                window.setTimeout(()=>($("#error").css('display', 'none')), 5000);
            });
        });
   </script>
</body>
</html>

นี่คือสิ่งที่เรา /ที่อัพโหลด หน้าดูเหมือนว่า:

เทมเพลตใบมีด

นี่คือตัวอย่างทั่วไปของไฟล์เบลดที่มีแบบฟอร์ม HTML และ javascript/jQuery สำหรับเพิ่มฟังก์ชันการทำงานแบบอะซิงโครนัส (เพื่อไม่ให้หน้ารีเฟรช) มีพื้นฐานดังนี้ แท็กที่ไม่มีแอตทริบิวต์เมธอด (ซึ่งฉันจะอธิบายในอีกไม่กี่วินาที) และมีแอตทริบิวต์การดำเนินการที่น่าสนใจพร้อมค่า {{route('file.upload')}} ใน blade นี่คือสิ่งที่เรียกว่า คำสั่ง ไดเรกทิฟเป็นเพียงชื่อเก๋ๆ ของฟังก์ชัน ซึ่งเป็นฟังก์ชันเฉพาะสำหรับเทมเพลตเบลดที่ดำเนินการต่างๆ ที่ใช้กันทั่วไปในการสร้างหน้าเว็บและแอปพลิเคชันเว็บ หากต้องการทำความเข้าใจเกี่ยวกับสิ่งเจ๋งๆ ทั้งหมดที่เบลดทำได้ ให้ตรวจสอบเอกสาร Good Farm Animal Welfare Awards- ในกรณีข้างต้น เรากำลังใช้คำสั่งเส้นทางเพื่อสร้าง URL สำหรับการส่งแบบฟอร์มของเรา

โปรดจำไว้ว่าเราได้กำหนดเส้นทางของเราไว้ก่อนหน้านี้ในแอปพลิเคชันภายในไฟล์ web.php โดยระบุชื่อที่ง่ายต่อการจดจำสำหรับแต่ละเส้นทาง คำสั่ง {{route()}} ยอมรับชื่อของเส้นทาง ค้นหาภายในรายการเส้นทางที่แคชไว้ภายใน และสร้าง URL แบบเต็มตามคำจำกัดความของเส้นทางนั้นในไฟล์ web.php สำหรับกรณีแรกนี้ เรากำลังระบุว่าเราต้องการให้แบบฟอร์มส่งข้อมูลที่ส่งมาไปยัง /process URL ของแอปพลิเคชันของเรา ซึ่งถูกกำหนดให้เป็น POST เส้นทาง

สิ่งประหลาดถัดไปที่คุณอาจสังเกตเห็นคือแท็ก @csrf ด้านล่างแท็กแบบฟอร์มเปิด ในเบลด แท็กนี้จะสร้างพารามิเตอร์ _token บนแบบฟอร์ม ซึ่งได้รับการตรวจสอบภายในแอปพลิเคชันก่อนที่จะอนุญาตให้ประมวลผลข้อมูลแบบฟอร์ม เพื่อให้แน่ใจว่าข้อมูลในแบบฟอร์มมีแหล่งที่มาที่ถูกต้อง และป้องกันการโจมตีการปลอมแปลงคำขอข้ามไซต์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ โปรดดูที่ เอกสาร.

หลังจากนี้ เราจะกำหนดฟอร์มของเราตามปกติ อย่างไรก็ตาม โปรดทราบว่าชื่อของพารามิเตอร์ฟอร์ม, userFile และ fileName ของเราคือ แน่นอนเหมือนกัน ตามที่กำหนดไว้ในวัตถุคำขอของเรา หากเราลืมใส่อินพุตสำหรับพารามิเตอร์ที่กำหนดซึ่งกำหนดไว้ในออบเจ็กต์คำขอ (หรือสะกดผิด) คำขอจะล้มเหลวและข้อผิดพลาดจะถูกส่งกลับ ป้องกันไม่ให้คำขอแบบฟอร์มดั้งเดิมกดปุ่มวิธีควบคุมที่ UploadController@ กระบวนการ .

ลองใช้เลยและส่งไฟล์บางไฟล์ไปยังแอปพลิเคชันโดยใช้แบบฟอร์มนี้ หลังจากนั้นให้นำทางไปยัง /รายการ เพื่อดูเนื้อหาของโฟลเดอร์อัปโหลด โดยมีไฟล์ที่คุณอัปโหลดแสดงอยู่ในตาราง:

เทมเพลตใบมีด

ภาพใหญ่

ลองย้อนกลับไปดูว่าเราได้ทำอะไรไปบ้างในบทช่วยสอน Laravel นี้

ไดอะแกรมนี้แสดงแอปพลิเคชันตามที่เป็นอยู่ในขณะนี้ (ไม่รวมรายละเอียดระดับสูง):

แผนภาพการสอน Laravel

คุณควรจำไว้ว่าออบเจ็กต์คำขอที่เราสร้างขึ้นเมื่อตอนต้นของบทช่วยสอน Laravel นี้ควรมีพารามิเตอร์เดียวกันที่กำหนดไว้ในวิธีการกฎเช่นเดียวกับที่อยู่ในแบบฟอร์มในเทมเพลตเบลด (หากไม่ได้อ่านหัวข้อ “การสร้างตรรกะการตรวจสอบความถูกต้องอีกครั้ง”) . ผู้ใช้ป้อนแบบฟอร์มในหน้าเว็บที่แสดงผลผ่านกลไกเทมเพลตเบลด (กระบวนการนี้อยู่ในระบบนำร่องอัตโนมัติ ดังนั้นเราจึงไม่จำเป็นต้องคิดเกี่ยวกับมัน) และส่งแบบฟอร์ม รหัส jQuery ของเทมเพลตที่ด้านล่างจะหยุดการส่งเริ่มต้น (ซึ่งจะเปลี่ยนเส้นทางไปยังหน้าแยกต่างหากโดยอัตโนมัติ) สร้างคำขอ ajax โหลดคำขอพร้อมข้อมูลแบบฟอร์มและอัปโหลดไฟล์ และส่งทั้งหมดไปยังเลเยอร์แรกของเรา ใบสมัคร: คำขอ

ออบเจ็กต์คำขอได้รับการเติมโดยการเชื่อมโยงพารามิเตอร์ภายในเมธอดกฎ () กับพารามิเตอร์แบบฟอร์มที่ส่ง จากนั้นตรวจสอบข้อมูลตามกฎที่ระบุแต่ละกฎ หากเป็นไปตามกฎทั้งหมด คำขอจะถูกส่งผ่านไปยังวิธีการควบคุมใดก็ตามที่สอดคล้องกับค่าที่กำหนดไว้ในไฟล์เส้นทาง web.php ในกรณีนี้ มันเป็นเมธอด process() ของ UploadController ที่ทำงานได้ เมื่อเรากดที่คอนโทรลเลอร์ เราก็รู้อยู่แล้วว่าคำขอนั้นผ่านการตรวจสอบแล้ว ดังนั้นเราจึงไม่ต้องทดสอบซ้ำว่าชื่อไฟล์ที่ระบุนั้น แท้จริงแล้วเป็นสตริงหรือพารามิเตอร์ userFile เก็บไฟล์บางประเภทไว้จริงหรือไม่… เราสามารถดำเนินการต่อได้ ปกติ.

จากนั้นวิธีการควบคุมจะดึงพารามิเตอร์ที่ผ่านการตรวจสอบแล้วออกจากออบเจ็กต์คำขอ สร้างชื่อไฟล์แบบเต็มโดยการเชื่อมพารามิเตอร์ที่ส่งใน fileName เข้ากับนามสกุลดั้งเดิมของ userFile เก็บไฟล์ไว้ในไดเร็กทอรีในแอปพลิเคชันของเรา จากนั้นส่งคืน JSON ที่เข้ารหัสอย่างง่าย การตอบสนองเพื่อยืนยันว่าคำขอสำเร็จ ตรรกะ jQuery ได้รับการตอบสนอง ซึ่งทำงานที่เกี่ยวข้องกับ UI อีกสองสามอย่าง เช่น การแสดงข้อความแสดงความสำเร็จ (หรือข้อผิดพลาด) เป็นเวลา 5 วินาที จากนั้นซ่อนข้อความนั้น ตลอดจนล้างรายการแบบฟอร์มก่อนหน้าออก...เพื่อให้ผู้ใช้ทราบ มั่นใจว่าคำขอสำเร็จและสามารถอัปโหลดไฟล์อื่นได้หากต้องการ

นอกจากนี้ ให้สังเกตในไดอะแกรมด้านบนว่าเส้นแบ่งระหว่างไคลเอนต์และเซิร์ฟเวอร์อยู่ตรงไหน แนวคิดนี้มีความสำคัญอย่างยิ่งที่คุณต้องเข้าใจ และจะช่วยให้คุณแก้ปัญหาและประเด็นต่างๆ ที่คุณอาจประสบในอนาคตได้ เช่น เมื่อต้องจัดการกับคำขอแบบอะซิงโครนัสหลายรายการที่อาจเกิดขึ้นในเวลาใดก็ตาม การแยกส่วนนี้เกิดขึ้นตรงขอบเขตของวัตถุคำขอ วัตถุคำขอสามารถคิดได้ว่าเป็น "เกตเวย์" ไปยังส่วนอื่นๆ ของแอปพลิเคชัน... วัตถุคำขอจะทำการตรวจสอบเบื้องต้นและลงทะเบียนค่าฟอร์มที่ส่งมาจากเว็บเบราว์เซอร์ หากค่าเหล่านี้ถูกต้อง ก็จะดำเนินการต่อไปยังตัวควบคุม ทุกอย่างก่อนหน้านั้นจะอยู่ที่ส่วนหน้า ("ไคลเอนต์" หมายความตามตัวอักษรว่า "อยู่ในคอมพิวเตอร์ของผู้ใช้") การตอบสนองจะถูกส่งกลับจากแอปพลิเคชันกลับไปยังฝั่งไคลเอนต์ ซึ่งโค้ด jQuery ของเราจะคอยรอการมาถึงอย่างอดทน และดำเนินการงาน UI ง่ายๆ สองสามอย่างเมื่อได้รับข้อมูล

เราได้ครอบคลุมคำถามที่พบบ่อยที่สำคัญเกือบ 90 รายการ คำถามสัมภาษณ์ที่เกี่ยวข้องกับ Laravel และ PHP สำหรับนักศึกษาใหม่และผู้มีประสบการณ์เพื่อให้ได้งานที่เหมาะสม