การใช้ Eloquent ORM ใน Laravel
ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการสร้าง API Resources ใน Laravel ซึ่งช่วยให้เราแปลงข้อมูลจาก Model ให้เป็น JSON response ได้อย่างสวยงามและเป็นระเบียบ ในบทนี้ เราจะมาเรียนรู้เกี่ยวกับ Eloquent ORM ซึ่งเป็นเครื่องมือสำคัญในการจัดการฐานข้อมูลใน Laravel
Eloquent คืออะไร?
Eloquent ORM (Object-Relational Mapper) คือเครื่องมือที่ช่วยให้เราทำงานกับฐานข้อมูลได้ง่ายขึ้น โดยไม่ต้องเขียน SQL query ที่ซับซ้อน Eloquent จะแปลงข้อมูลจากฐานข้อมูลให้อยู่ในรูปแบบของ Object ซึ่งเราสามารถจัดการได้ด้วย PHP code ที่เราคุ้นเคย
ทำไมต้องใช้ Eloquent?
- ลดความซับซ้อน: Eloquent ช่วยลดความซับซ้อนในการเขียน SQL query โดยเฉพาะอย่างยิ่ง query ที่มีความซับซ้อน เช่น การ join ตาราง หรือการใช้ aggregate functions
- เพิ่มความสามารถในการอ่านโค้ด: การใช้ Eloquent ทำให้โค้ดของเราอ่านง่ายขึ้น เพราะเราสามารถเข้าใจความหมายของ query ได้จากชื่อ method และ property ของ Object
- ป้องกัน SQL Injection: Eloquent จะทำการ escape ข้อมูลที่เราส่งไปให้ฐานข้อมูลโดยอัตโนมัติ ทำให้เราไม่ต้องกังวลเรื่อง SQL Injection
- ความสะดวกในการบำรุงรักษา: เมื่อโครงสร้างฐานข้อมูลมีการเปลี่ยนแปลง การใช้ Eloquent จะช่วยให้เราปรับแก้โค้ดได้ง่ายขึ้น เพราะเราสามารถแก้ไข Model ได้โดยไม่ต้องแก้ไขทุก query ที่เกี่ยวข้อง
Trade-offs ของการใช้ Eloquent:
- Performance: Eloquent อาจมี performance ที่ต่ำกว่าการเขียน SQL query โดยตรง โดยเฉพาะอย่างยิ่งในกรณีที่ query มีความซับซ้อนมาก อย่างไรก็ตาม ในกรณีส่วนใหญ่ ความแตกต่างของ performance จะไม่มากนัก
- ความยืดหยุ่น: Eloquent อาจมีความยืดหยุ่นน้อยกว่าการเขียน SQL query โดยตรง ในกรณีที่เราต้องการ query ที่มีความซับซ้อนมาก อาจจำเป็นต้องใช้ raw SQL query แทน
การสร้าง Model
ในการใช้ Eloquent เราจะต้องสร้าง Model ขึ้นมาก่อน Model คือ Class ที่ represent ตารางในฐานข้อมูลของเรา ใน Laravel เราสามารถสร้าง Model ได้ด้วย Artisan command:
php artisan make:model Post
คำสั่งนี้จะสร้างไฟล์ Model ชื่อ Post.php ใน directory app/Models (หรือ app ใน Laravel เวอร์ชั่นเก่า) ภายในไฟล์นี้ เราสามารถกำหนดคุณสมบัติของ Model ได้ เช่น ชื่อตาราง ชื่อ primary key และชื่อ column อื่นๆ
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// ชื่อตาราง (ถ้าไม่กำหนด Laravel จะใช้ชื่อ class ในรูปแบบ snake_case พหูพจน์ เช่น posts)
protected $table = 'posts';
// Primary key (ถ้าไม่กำหนด Laravel จะใช้ 'id' โดยอัตโนมัติ)
protected $primaryKey = 'id';
// กำหนดว่า timestamps (created_at และ updated_at) จะถูกใช้งานหรือไม่
public $timestamps = true;
// กำหนด fillable attributes (attributes ที่สามารถกำหนดค่าได้)
protected $fillable = ['title', 'content', 'author_id'];
// กำหนด guarded attributes (attributes ที่ไม่สามารถกำหนดค่าได้)
protected $guarded = ['id'];
}
คำอธิบาย:
$table: กำหนดชื่อตารางในฐานข้อมูลที่ Model นี้จะเชื่อมต่อด้วย หากไม่ได้กำหนด Laravel จะแปลงชื่อ Model เป็น snake_case พหูพจน์ เช่น `Post` จะกลายเป็น `posts`$primaryKey: กำหนดชื่อ primary key ของตาราง หากไม่ได้กำหนด Laravel จะใช้ `id` เป็นค่าเริ่มต้น$timestamps: กำหนดว่า Laravel จะจัดการ timestamps (created_atและupdated_at) ให้หรือไม่ หากตั้งค่าเป็น `true` Laravel จะอัปเดต timestamps เหล่านี้โดยอัตโนมัติเมื่อมีการสร้างหรือแก้ไขข้อมูล$fillable: กำหนด attributes ที่สามารถกำหนดค่าได้ผ่าน mass assignment (เช่น การใช้Post::create()) การกำหนด$fillableเป็นการป้องกัน mass assignment vulnerability$guarded: กำหนด attributes ที่ไม่สามารถกำหนดค่าได้ผ่าน mass assignment ปกติแล้วเราจะใช้$guardedแทน$fillableถ้าเราต้องการป้องกัน attributes เพียงไม่กี่ตัว
แนวปฏิบัติที่ดี:
- ควรตั้งชื่อ Model ให้สอดคล้องกับชื่อตารางในฐานข้อมูล
- ควรใช้
$fillableหรือ$guardedเพื่อป้องกัน mass assignment vulnerability
การ Query ข้อมูล
เมื่อเราสร้าง Model แล้ว เราสามารถใช้ Eloquent ในการ query ข้อมูลจากฐานข้อมูลได้ ตัวอย่างเช่น:
use App\Models\Post;
// ดึงข้อมูลทั้งหมดจากตาราง posts
$posts = Post::all();
// ดึงข้อมูล post ที่มี id เท่ากับ 1
$post = Post::find(1);
// ดึงข้อมูล post ที่มี title เท่ากับ "Hello World"
$post = Post::where('title', 'Hello World')->first();
// ดึงข้อมูล post ทั้งหมดที่มี author_id เท่ากับ 1
$posts = Post::where('author_id', 1)->get();
// ดึงข้อมูล post ทั้งหมดที่มี author_id เท่ากับ 1 และ status เท่ากับ "published"
$posts = Post::where('author_id', 1)
->where('status', 'published')
->get();
// ดึงข้อมูล post ทั้งหมดที่เรียงตาม created_at จากมากไปน้อย
$posts = Post::orderBy('created_at', 'desc')->get();
// ดึงข้อมูล post 5 รายการแรก
$posts = Post::take(5)->get();
// ดึงข้อมูล post โดยใช้ pagination (แบ่งหน้า)
$posts = Post::paginate(10);
คำอธิบาย:
all(): ดึงข้อมูลทั้งหมดจากตารางfind($id): ดึงข้อมูลที่มี primary key เท่ากับ$idwhere($column, $value): เพิ่มเงื่อนไขในการ query โดย$columnคือชื่อ column และ$valueคือค่าที่ต้องการfirst(): ดึงข้อมูลรายการแรกที่ตรงกับเงื่อนไขget(): ดึงข้อมูลทั้งหมดที่ตรงกับเงื่อนไขorderBy($column, $direction): เรียงลำดับข้อมูลตาม$columnโดย$directionสามารถเป็น'asc'(ascending) หรือ'desc'(descending)take($limit): จำกัดจำนวนข้อมูลที่ดึงมาpaginate($perPage): แบ่งข้อมูลออกเป็นหน้าๆ โดยแต่ละหน้ามี$perPageรายการ
Chaining Methods:
Eloquent ช่วยให้เราสามารถ chain methods ได้ ซึ่งทำให้ query ของเราอ่านง่ายและกระชับขึ้น ตัวอย่างเช่น:
$posts = Post::where('author_id', 1)
->where('status', 'published')
->orderBy('created_at', 'desc')
->take(5)
->get();
Query นี้จะดึงข้อมูล post ทั้งหมดที่มี author_id เท่ากับ 1 และ status เท่ากับ "published" เรียงตาม created_at จากมากไปน้อย และดึงมาเพียง 5 รายการแรก
การใช้ Operators อื่นๆ ใน where:
นอกจาก = แล้ว เรายังสามารถใช้ operators อื่นๆ ใน where ได้ เช่น:
$posts = Post::where('views', '>', 100)->get(); // views มากกว่า 100
$posts = Post::where('created_at', '<', now()->subDays(7))->get(); // สร้างก่อน 7 วันที่แล้ว
$posts = Post::whereIn('author_id', [1, 2, 3])->get(); // author_id อยู่ใน [1, 2, 3]
ข้อควรระวัง:
- ควรใช้
findOrFail($id)แทนfind($id)หากต้องการให้ Laravel throw exception เมื่อไม่พบข้อมูล - ควรใช้
firstOrFail()แทนfirst()หากต้องการให้ Laravel throw exception เมื่อไม่พบข้อมูล
ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับการเพิ่ม แก้ไข และลบข้อมูลในฐานข้อมูลโดยใช้ Eloquent