Skip to content

Eloquent: Bắt đầu (Getting Started)

Giới thiệu (Introduction)

Laravel bao gồm Eloquent, một object-relational mapper (ORM) giúp tương tác với cơ sở dữ liệu trở nên thú vị. Khi sử dụng Eloquent, mỗi bảng trong database sẽ có một "Model" tương ứng dùng để tương tác với bảng đó. Ngoài việc truy vấn bản ghi, Eloquent model còn cho phép bạn thêm (insert), cập nhật (update) và xóa (delete) bản ghi.

Trước khi bắt đầu, hãy đảm bảo bạn đã cấu hình kết nối database trong file config/database.php. Để biết thêm chi tiết, xem tài liệu cấu hình database.

Tạo Model Class (Generating Model Classes)

Để bắt đầu, hãy tạo một Eloquent model. Model thường nằm trong thư mục app/Models và kế thừa class Illuminate\Database\Eloquent\Model. Bạn có thể sử dụng lệnh Artisan make:model để tạo model mới:

bash
php artisan make:model Flight

Nếu bạn muốn tạo database migration kèm theo model, sử dụng tùy chọn --migration hoặc -m:

bash
php artisan make:model Flight --migration

Bạn có thể tạo nhiều loại class khác nhau khi tạo model, như factory, seeder, policy, controller, và form request. Các tùy chọn có thể kết hợp:

bash
# Tạo model và FlightFactory class...
php artisan make:model Flight --factory
php artisan make:model Flight -f

# Tạo model và FlightSeeder class...
php artisan make:model Flight --seed
php artisan make:model Flight -s

# Tạo model và FlightController class...
php artisan make:model Flight --controller
php artisan make:model Flight -c

# Tạo model, FlightController resource class, và form request classes...
php artisan make:model Flight --controller --resource --requests
php artisan make:model Flight -crR

# Tạo model và FlightPolicy class...
php artisan make:model Flight --policy

# Tạo model và migration, factory, seeder, controller...
php artisan make:model Flight -mfsc

# Tạo tất cả: model, migration, factory, seeder, policy, controller, form requests...
php artisan make:model Flight --all
php artisan make:model Flight -a

# Tạo pivot model...
php artisan make:model Member --pivot
php artisan make:model Member -p

Kiểm tra Model (Inspecting Models)

Đôi khi khó xác định tất cả thuộc tính (attributes) và relationships của model chỉ bằng cách đọc code. Thay vào đó, thử lệnh model:show để xem tổng quan:

bash
php artisan model:show Flight

Quy ước Eloquent Model (Eloquent Model Conventions)

Model được tạo bởi lệnh make:model sẽ nằm trong thư mục app/Models. Hãy xem một model cơ bản:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    // ...
}

Tên bảng (Table Names)

Theo quy ước, tên class ở dạng "snake case" số nhiều sẽ được dùng làm tên bảng, trừ khi chỉ định tên khác. Ví dụ: model Flight sẽ lưu vào bảng flights, model AirTrafficController vào bảng air_traffic_controllers.

Nếu bảng tương ứng không tuân theo quy ước này, bạn có thể chỉ định tên bảng bằng attribute Table:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;

#[Table('my_flights')]
class Flight extends Model
{
    // ...
}

Khóa chính (Primary Keys)

Eloquent giả định rằng mỗi bảng có cột khóa chính tên là id. Nếu cần, bạn có thể chỉ định cột khóa chính khác bằng tham số key trên attribute Table:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;

#[Table(key: 'flight_id')]
class Flight extends Model
{
    // ...
}

Ngoài ra, Eloquent giả định khóa chính là số nguyên tự tăng (auto-incrementing integer). Nếu muốn sử dụng khóa chính không tự tăng hoặc không phải số, hãy chỉ định keyTypeincrementing:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;

#[Table(key: 'uuid', keyType: 'string', incrementing: false)]
class Flight extends Model
{
    // ...
}

Khóa chính "Composite"

Eloquent yêu cầu mỗi model phải có ít nhất một "ID" định danh duy nhất làm khóa chính. Eloquent không hỗ trợ khóa chính "composite". Tuy nhiên, bạn có thể thêm các index unique nhiều cột ngoài khóa chính.

Khóa UUID và ULID (UUID and ULID Keys)

Thay vì dùng số nguyên tự tăng, bạn có thể chọn UUID làm khóa chính. UUID là chuỗi ký tự alpha-numeric dài 36 ký tự, độc nhất toàn cầu.

Để sử dụng UUID, dùng trait Illuminate\Database\Eloquent\Concerns\HasUuids:

php
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasUuids;

    // ...
}

$article = Article::create(['title' => 'Traveling to Europe']);

$article->id; // "8f8e8478-9035-4d23-b9a7-62f4d2612ce5"

Mặc định, trait HasUuids sẽ tạo UUID "có thứ tự" (ordered), hiệu quả hơn cho việc lập index database.

Bạn có thể tùy chỉnh UUID bằng method newUniqueId và chỉ định cột nhận UUID qua uniqueIds:

php
use Ramsey\Uuid\Uuid;

/**
 * Tạo UUID mới cho model.
 */
public function newUniqueId(): string
{
    return (string) Uuid::uuid4();
}

/**
 * Các cột nhận định danh duy nhất.
 *
 * @return array<int, string>
 */
public function uniqueIds(): array
{
    return ['id', 'discount_code'];
}

Nếu muốn, bạn có thể sử dụng ULID thay vì UUID. ULID tương tự UUID nhưng chỉ dài 26 ký tự và có thể sắp xếp từ vựng. Sử dụng trait Illuminate\Database\Eloquent\Concerns\HasUlids:

php
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasUlids;

    // ...
}

$article = Article::create(['title' => 'Traveling to Asia']);

$article->id; // "01gd4d3tgrrfqeda94gdbtdk5c"

Dấu thời gian (Timestamps)

Mặc định, Eloquent mong đợi hai cột created_atupdated_at tồn tại trong bảng. Eloquent sẽ tự động thiết lập giá trị này khi model được tạo hoặc cập nhật. Để tắt:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;

#[Table(timestamps: false)]
class Flight extends Model
{
    // ...
}

Nếu cần tùy chỉnh định dạng timestamp, sử dụng tham số dateFormat:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;

#[Table(dateFormat: 'U')]
class Flight extends Model
{
    // ...
}

Để tùy chỉnh tên cột timestamp, định nghĩa hằng số CREATED_ATUPDATED_AT:

php
<?php

class Flight extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'updated_date';
}

Nếu muốn thực hiện thao tác model mà không cập nhật updated_at:

php
Model::withoutTimestamps(fn () => $post->increment('reads'));

Kết nối Database (Database Connections)

Mặc định, tất cả Eloquent model sử dụng kết nối database mặc định. Nếu muốn chỉ định kết nối khác, sử dụng attribute Connection:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Connection;
use Illuminate\Database\Eloquent\Model;

#[Connection('mysql')]
class Flight extends Model
{
    // ...
}

Giá trị thuộc tính mặc định (Default Attribute Values)

Mặc định, model instance mới sẽ không chứa giá trị thuộc tính. Để định nghĩa giá trị mặc định, gán property $attributes:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    /**
     * Giá trị mặc định cho các thuộc tính.
     *
     * @var array
     */
    protected $attributes = [
        'options' => '[]',
        'delayed' => false,
    ];
}

Cấu hình Eloquent Strictness

Laravel cung cấp các phương thức để cấu hình hành vi "strictness" của Eloquent.

Phương thức preventLazyLoading nhận tham số boolean để ngăn lazy loading. Thường gọi trong method boot của AppServiceProvider:

php
use Illuminate\Database\Eloquent\Model;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Model::preventLazyLoading(! $this->app->isProduction());
}

Bạn cũng có thể yêu cầu Laravel throw exception khi gán thuộc tính không fillable:

php
Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());

Truy vấn Model (Retrieving Models)

Sau khi tạo model và bảng database tương ứng, bạn có thể bắt đầu truy vấn dữ liệu. Mỗi Eloquent model hoạt động như một query builder mạnh mẽ. Sử dụng method all để lấy tất cả bản ghi:

php
use App\Models\Flight;

foreach (Flight::all() as $flight) {
    echo $flight->name;
}

Xây dựng truy vấn (Building Queries)

Method all trả về tất cả kết quả. Vì mỗi Eloquent model là query builder, bạn có thể thêm điều kiện rồi gọi get:

php
$flights = Flight::where('active', 1)
    ->orderBy('name')
    ->limit(10)
    ->get();

GỢI Ý

Vì Eloquent model là query builder, bạn nên xem tất cả các phương thức của query builder. Bạn có thể sử dụng bất kỳ phương thức nào khi viết Eloquent query.

Làm mới Model (Refreshing Models)

Nếu đã có instance model từ database, bạn có thể "làm mới" bằng method freshrefresh:

  • fresh — truy vấn lại model từ database, instance hiện tại không bị ảnh hưởng:
php
$flight = Flight::where('number', 'FR 900')->first();

$freshFlight = $flight->fresh();
  • refresh — nạp lại dữ liệu mới từ database vào instance hiện tại, bao gồm cả relationships:
php
$flight = Flight::where('number', 'FR 900')->first();

$flight->number = 'FR 456';

$flight->refresh();

$flight->number; // "FR 900"

Collections

Method allget của Eloquent trả về instance Illuminate\Database\Eloquent\Collection, cung cấp nhiều phương thức hữu ích để xử lý kết quả. Xem tài liệu Eloquent Collections.

Chia nhỏ kết quả (Chunking Results)

Ứng dụng có thể hết bộ nhớ nếu load hàng nghìn bản ghi. Sử dụng method chunk để xử lý từng nhóm:

php
use App\Models\Flight;
use Illuminate\Database\Eloquent\Collection;

Flight::chunk(200, function (Collection $flights) {
    foreach ($flights as $flight) {
        // ...
    }
});

Chunking sử dụng Lazy Collections

Method lazy tương tự chunk nhưng trả về LazyCollection, cho phép tương tác như một stream đơn:

php
use App\Models\Flight;

foreach (Flight::lazy() as $flight) {
    // ...
}

Con trỏ (Cursors)

Method cursor cho phép duyệt qua kết quả bằng cursor, chỉ thực thi một query duy nhất:

php
use App\Models\Flight;

foreach (Flight::where('destination', 'Zurich')->cursor() as $flight) {
    // ...
}

LƯU Ý

cursor chỉ giữ một Eloquent model trong bộ nhớ tại mỗi thời điểm, nhưng không thể eager load relationships. Sử dụng lazy nếu cần eager load.

Truy vấn Model đơn / Aggregates

Ngoài truy vấn tất cả bản ghi, bạn có thể lấy một bản ghi đơn bằng find, first, hoặc firstWhere:

php
use App\Models\Flight;

// Tìm model theo khóa chính...
$flight = Flight::find(1);

// Lấy model đầu tiên khớp với điều kiện...
$flight = Flight::where('active', 1)->first();

// Cách viết thay thế...
$flight = Flight::firstWhere('active', 1);

Các method findOrfirstOr trả về model hoặc thực thi closure nếu không tìm thấy:

php
$flight = Flight::findOr(1, function () {
    // ...
});

$flight = Flight::where('legs', '>', 3)->firstOr(function () {
    // ...
});

Exceptions khi không tìm thấy (Not Found Exceptions)

Method findOrFailfirstOrFail sẽ throw Illuminate\Database\Eloquent\ModelNotFoundException nếu không tìm thấy kết quả. Nếu exception không được bắt, response HTTP 404 sẽ tự động gửi về client:

php
$flight = Flight::findOrFail(1);

$flight = Flight::where('legs', '>', 3)->firstOrFail();

Truy vấn hoặc Tạo Model (Retrieving or Creating Models)

Method firstOrCreate tìm bản ghi khớp với thuộc tính. Nếu không tìm thấy, sẽ tạo bản ghi mới:

php
use App\Models\Flight;

// Tìm theo name, hoặc tạo mới...
$flight = Flight::firstOrCreate([
    'name' => 'London to Paris'
]);

// Tìm theo name, hoặc tạo với thuộc tính bổ sung...
$flight = Flight::firstOrCreate(
    ['name' => 'London to Paris'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

Method firstOrNew tương tự nhưng chỉ tạo instance mới mà không lưu vào database:

php
$flight = Flight::firstOrNew([
    'name' => 'London to Paris'
]);

$flight = Flight::firstOrNew(
    ['name' => 'Tokyo to Sydney'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

Truy vấn Aggregates

Bạn có thể sử dụng các method aggregate như count, sum, max, v.v.:

php
$count = Flight::where('active', 1)->count();

$max = Flight::where('active', 1)->max('price');

Thêm và Cập nhật Model (Inserting and Updating Models)

Thêm bản ghi (Inserts)

Để thêm bản ghi mới, tạo instance model, gán thuộc tính, rồi gọi save:

php
<?php

namespace App\Http\Controllers;

use App\Models\Flight;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class FlightController extends Controller
{
    /**
     * Lưu chuyến bay mới vào database.
     */
    public function store(Request $request): RedirectResponse
    {
        $flight = new Flight;

        $flight->name = $request->name;

        $flight->save();

        return redirect('/flights');
    }
}

Cập nhật (Updates)

Method save cũng được dùng để cập nhật model đã tồn tại. Eloquent sẽ tự động phát hành câu lệnh UPDATE:

php
use App\Models\Flight;

$flight = Flight::find(1);

$flight->name = 'Paris to London';

$flight->save();

Cập nhật hàng loạt (Mass Updates)

Cập nhật nhiều bản ghi cùng lúc bằng query:

php
Flight::where('active', 1)
    ->where('destination', 'San Diego')
    ->update(['delayed' => 1]);

LƯU Ý

Khi cập nhật hàng loạt, các event saving, saved, updating, updated sẽ không được phát cho các model bị ảnh hưởng.

Mass Assignment

Bạn có thể sử dụng method create để lưu model mới bằng một câu lệnh PHP:

php
use App\Models\Flight;

$flight = Flight::create([
    'name' => 'London to Paris',
]);

Trước khi sử dụng create, bạn cần chỉ định attribute Fillable hoặc Guarded trên model class. Tất cả Eloquent model được bảo vệ khỏi lỗ hổng mass assignment theo mặc định.

Lỗ hổng mass assignment xảy ra khi user gửi trường HTTP không mong đợi thay đổi cột mà bạn không dự kiến. Ví dụ, user gửi tham số is_admin qua HTTP request.

Để xác định thuộc tính nào được mass assignable, sử dụng attribute Fillable:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Model;

#[Fillable(['name'])]
class Flight extends Model
{
    // ...
}

Nếu đã có model instance, sử dụng fill để gán thuộc tính:

php
$flight->fill(['name' => 'Amsterdam to Frankfurt']);

Mass Assignment và cột JSON

Khi gán cột JSON, khóa mass assignable cần được chỉ định trong Fillable. Laravel không hỗ trợ cập nhật thuộc tính JSON lồng nhau khi dùng Guarded:

php
use Illuminate\Database\Eloquent\Attributes\Fillable;

#[Fillable(['options->enabled'])]
class Flight extends Model
{
    // ...
}

Cho phép Mass Assignment

Nếu muốn tất cả thuộc tính đều mass assignable, sử dụng attribute Guarded với mảng rỗng:

php
use Illuminate\Database\Eloquent\Attributes\Guarded;

#[Guarded([])]
class Flight extends Model
{
    // ...
}

Upserts

Method upsert thêm bản ghi không tồn tại và cập nhật bản ghi đã tồn tại bằng một thao tác nguyên tử (atomic):

php
Flight::upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], uniqueBy: ['departure', 'destination'], update: ['price']);
  • Tham số 1: Mảng các bản ghi cần thêm/cập nhật.
  • uniqueBy: Các cột xác định bản ghi duy nhất.
  • update: Các cột cần cập nhật nếu bản ghi khớp.

Xóa Model (Deleting Models)

Gọi method delete trên model instance:

php
use App\Models\Flight;

$flight = Flight::find(1);

$flight->delete();

Xóa model theo khóa chính

Sử dụng destroy để xóa mà không cần truy vấn trước:

php
Flight::destroy(1);

Flight::destroy(1, 2, 3);

Flight::destroy([1, 2, 3]);

Flight::destroy(collect([1, 2, 3]));

Nếu sử dụng soft delete, dùng forceDestroy để xóa vĩnh viễn:

php
Flight::forceDestroy(1);

GHI CHÚ

Method destroy load từng model riêng lẻ và gọi delete, đảm bảo event deletingdeleted được phát cho từng model.

Xóa bằng truy vấn (Deleting Models Using Queries)

php
$deleted = Flight::where('active', 0)->delete();

LƯU Ý

Khi xóa hàng loạt (mass delete), event deletingdeleted không được phát cho các model bị xóa.

Xóa mềm (Soft Deleting)

Ngoài việc xóa vĩnh viễn, Eloquent cung cấp "soft delete" — đánh dấu model là đã xóa mà không thực sự xóa khỏi database. Khi model bị soft delete, cột deleted_at được thiết lập.

Để bật soft delete, sử dụng trait Illuminate\Database\Eloquent\SoftDeletes:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Flight extends Model
{
    use SoftDeletes;
}

Bạn cũng cần thêm cột deleted_at vào bảng database qua migration:

php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('flights', function (Blueprint $table) {
    $table->softDeletes();
});

Giờ đây khi gọi delete, cột deleted_at sẽ được thiết lập thay vì xóa thật. Để kiểm tra model có bị soft delete:

php
if ($flight->trashed()) {
    // ...
}

Truy vấn model Soft Deleted

Bao gồm model đã xóa mềm:

php
$flights = Flight::withTrashed()
    ->where('account_id', 1)
    ->get();

Chỉ lấy model đã xóa mềm:

php
$flights = Flight::onlyTrashed()
    ->where('airline_id', 1)
    ->get();

Khôi phục model đã xóa mềm:

php
$flight->restore();

Xóa vĩnh viễn:

php
$flight->forceDelete();

Dọn dẹp Model (Pruning Models)

Đôi khi bạn muốn xóa định kỳ các model không còn cần thiết. Để làm điều này, thêm trait Illuminate\Database\Eloquent\Prunable hoặc MassPrunable vào model:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;

class Flight extends Model
{
    use Prunable;

    /**
     * Lấy query scope xác định model cần dọn dẹp.
     */
    public function prunable(): Builder
    {
        return static::where('created_at', '<=', now()->subMonth());
    }
}

Sau đó, đăng ký lệnh model:prune trong Artisan schedule:

php
use Illuminate\Support\Facades\Schedule;

Schedule::command('model:prune')->daily();

Nhân bản Model (Replicating Models)

Tạo bản sao chưa lưu của model bằng method replicate:

php
use App\Models\Address;

$shipping = Address::create([
    'type' => 'shipping',
    'line_1' => '123 Example Street',
    'city' => 'Victorville',
    'state' => 'CA',
    'postcode' => '90001',
]);

$billing = $shipping->replicate()->fill([
    'type' => 'billing'
]);

$billing->save();

Để loại trừ thuộc tính khi nhân bản, truyền mảng vào replicate:

php
$flight = $flight->replicate([
    'last_flown',
    'last_pilot_id'
]);

Phạm vi truy vấn (Query Scopes)

Global Scopes

Global scope cho phép thêm điều kiện vào tất cả query của model. Tạo class implement Illuminate\Database\Eloquent\Scope:

php
<?php

namespace App\Models\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class AncientScope implements Scope
{
    /**
     * Áp dụng scope vào query builder.
     */
    public function apply(Builder $builder, Model $model): void
    {
        $builder->where('created_at', '<', now()->subYears(2000));
    }
}

Gán global scope cho model bằng attribute ScopedBy:

php
<?php

namespace App\Models;

use App\Models\Scopes\AncientScope;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
use Illuminate\Database\Eloquent\Model;

#[ScopedBy(AncientScope::class)]
class User extends Model
{
    // ...
}

Để bỏ global scope khỏi query:

php
User::withoutGlobalScope(AncientScope::class)->get();

// Bỏ tất cả global scopes
User::withoutGlobalScopes()->get();

Local Scopes

Local scope cho phép định nghĩa các tập điều kiện thường dùng để tái sử dụng. Sử dụng attribute Scope trên method:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    #[Scope]
    public function popular(Builder $query): void
    {
        $query->where('votes', '>', 100);
    }

    #[Scope]
    public function active(Builder $query): void
    {
        $query->where('active', 1);
    }
}

Sử dụng local scope:

php
$flights = Flight::popular()->active()->orderBy('created_at')->get();

Kết hợp nhiều scope bằng or:

php
$flights = Flight::popular()->orWhere(function (Builder $query) {
    $query->active();
})->get();

Thuộc tính đang chờ (Pending Attributes)

Khi bạn muốn model mới tạo trong scope tự động có thuộc tính của scope đó, sử dụng method withAttributes:

php
#[Scope]
public function ofType(Builder $query, string $type): void
{
    $query->withAttributes(['type' => $type]);
}

So sánh Model (Comparing Models)

Sử dụng method isisNot để kiểm tra hai model có cùng khóa chính, bảng và kết nối database hay không:

php
if ($post->is($anotherPost)) {
    // ...
}

if ($post->isNot($anotherPost)) {
    // ...
}

Các method này cũng khả dụng cho các relationship belongsTo, hasOne, morphTo, morphOne:

php
if ($post->author()->is($user)) {
    // ...
}

Sự kiện (Events)

Eloquent model phát ra nhiều event tại các thời điểm trong vòng đời: retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, trashed, forceDeleting, forceDeleted, restoring, restored, replicating.

  • Event có hậu tố -ing được phát trước khi thay đổi được lưu.
  • Event có hậu tố -ed được phát sau khi thay đổi được lưu.

Để khai báo event, định nghĩa property $dispatchesEvents:

php
<?php

namespace App\Models;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * Map event cho model.
     *
     * @var array<string, string>
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}

LƯU Ý

Khi thực hiện mass update hoặc delete, các event saved, updated, deleting, deleted không được phát vì model không thực sự được truy vấn.

Sử dụng Closures

Thay vì tạo event class, bạn có thể đăng ký closure cho các model event trong method booted:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected static function booted(): void
    {
        static::created(function (User $user) {
            // ...
        });
    }
}

Observers

Nếu bạn lắng nghe nhiều event trên model, sử dụng Observer class:

bash
php artisan make:observer UserObserver --model=User
php
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    /**
     * Xử lý event "created".
     */
    public function created(User $user): void
    {
        // ...
    }

    /**
     * Xử lý event "updated".
     */
    public function updated(User $user): void
    {
        // ...
    }
}

Đăng ký observer bằng attribute ObservedBy:

php
use App\Observers\UserObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;

#[ObservedBy(UserObserver::class)]
class User extends Authenticatable
{
    // ...
}

Tắt Event (Muting Events)

Sử dụng withoutEvents để tạm tắt tất cả event:

php
use App\Models\User;

$user = User::withoutEvents(function () {
    User::findOrFail(1)->delete();

    return User::find(2);
});

Lưu model mà không phát Event

Sử dụng saveQuietly để lưu mà không phát event:

php
$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();

Các method tương tự: deleteQuietly, forceDeleteQuietly, restoreQuietly.