Hiểu về sole() Query Builder Method trong Laravel
sole()
là một phương thức query builder được giới thiệu ở Laravel 8.23, phương thức này trả về một single record
và Object của sole()
có relation giống như first()
method . Trước sole() luôn là một điều kiện where
Sử dụng Sole khi nào?
Sole được sử dụng khi bạn cần một single record
từ query và query đó cũng matching với duy nhất một record. Lợi ích của việc này là khi bạn mong muốn câu truy vấn của bạn luôn luôn có duy nhất một bản ghi, không hơn không kém record. Nếu câu query của bạn trả về ít hơn hoặc nhiều hơn 1 bản ghi thì nó sẽ bắn ra lỗi Laravel throws exception.
Để hiểu rõ hơn điều này chúng ta cùng tìm hiểu Case Study đưới đây. Tôi sẽ chia ra ba trường hợp như sau
- Chỉ có 1 bản ghi matching với câu query
- Không có bản ghi nào matching
- Có nhiều hơn 1 bản ghi matching
Quick Demo
Trước tiên, bạn tạo một project Laravel với câu lệnh Composer
sau
composer create-project laravel/laravel sole-demo
cd sole-demo
Tiếp theo, tạo một model Book
và migration
tương ứng
php artisan make:model -m Book
Cuối cùng bạn mở file migration lên và định nghĩa column cho bảng books
như sau
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBooksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('summary');
$table->dateTime('published_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('books');
}
}
Trong Book model khai báo thêm thuộc tính $guarded
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
use HasFactory;
protected $guarded = [];
}
Ok, mọi thứ đã xong. Bây giờ bạn chạy migration để tạo bảng
php artisan migrate:fresh
Để bắt đầu với sole()
chúng ta sử dụng Tinker để tạo mới 1 record và thực hiện query với bảng books
bằng cách chạy lệnh này lên
php artisan tinker
Sau đó chạy lệnh này để thêm mới 1 record vào bảng books
Book::create([
'title' => 'War of the Worlds',
'summary' => 'Example summary'
]);
Bảng books đã có dữ liệu, chúng ta sẽ thử first()
và get()
method với câu query sau xem điều gì sẽ sảy ra .
Với get() method
Book::where('title', 'like', '%War%')->get();
Kết quả:
Illuminate\Database\Eloquent\Collection {#4264
all: [
App\Models\Book {#4209
id: 1,
title: "War of the Worlds",
summary: "Example summary",
published_at: null,
created_at: "2021-01-21 22:14:29",
updated_at: "2021-01-21 22:14:29",
},
],
}
Với first() method
Book::where('title', 'like', '%War%')->first();
Kết quả:
App\Models\Book {#4210
id: 1,
title: "War of the Worlds",
summary: "Example summary",
published_at: null,
created_at: "2021-01-21 22:14:29",
updated_at: "2021-01-21 22:14:29",
}
Cả get() và first() đều là những phương thức phổ biến trong Laravel, nhìn vào kết quả sẽ không có gì đặc biệt ở đây cả.
Với sole() method
Book::where('title', 'like', '%War%')->sole();
Kết quả:
App\Models\Book {#3647
id: 1,
title: "War of the Worlds",
summary: "Example summary",
published_at: null,
created_at: "2021-01-21 22:14:29",
updated_at: "2021-01-21 22:14:29",
}
Kết quả cũng không khác gì sử dụng first()
đúng không? Vậy sole() khác biệt ở chỗ nào? Chúng ta tiếp tục insert thêm bản ghi thứ 2 vào bảng books
nhé
Book::create([
'title' => 'War and Peace',
'summary' => 'Example summary'
]);
Lúc này trong books đã có 2 bản ghi và câu query này sẽ trả về 2 record vì điều kiện là like
Book::where('title', 'like', '%War%')->get()
Chúng ta thay thế get()
thành sole()
như sau
Book::where('title', 'like', '%The War')->sole();
Kết quả: Các bạn sẽ nhìn thấy lỗi này
Illuminate\Database\MultipleRecordsFoundException
Lý do là sole()
chỉ được thực hiện khi câu query trên trả về 1 bản ghi matching, nhưng vì điều kiện là like nên chúng ta có 2 bản ghi được trả về dẫn đến khi dùng sole()
sẽ bị lỗi
Hy vọng qua bài này các bạn có cái nhìn rõ hơn về sole() method trong Laravel!
Thanks!