
Ở phần trước các bạn đã được tiếp xúc cơ bản với Eloquent Model and MVC. Trong bài viết này, chúng ta cùng tìm hiểu thêm về Factories nhé!
Factories trong Laravel giúp tạo ra các mô hình (model) và các bản ghi trong cơ sở dữ liệu một cách dễ dàng và tự động, giúp việc kiểm thử và phát triển trở nên thuận tiện hơn.
Tạo Factory
Để tạo một factory, bạn có thể sử dụng lệnh artisan make:factory
. Ví dụ, để tạo một factory cho mô hình User
, bạn có thể chạy lệnh:
php artisan make:factory UserFactory
Lệnh này sẽ tạo một file factory trong thư mục database/factories
.
Định Nghĩa Factory
Trong file factory mới tạo, bạn sẽ định nghĩa các giá trị mặc định cho các thuộc tính của mô hình. Ví dụ:
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => bcrypt('password'), // password mặc định
'remember_token' => Str::random(10),
];
}
}
Sử Dụng Factory
Sau khi đã định nghĩa xong factory, bạn có thể sử dụng nó để tạo ra các bản ghi trong cơ sở dữ liệu. Bạn có thể sử dụng phương thức create
để lưu bản ghi vào cơ sở dữ liệu hoặc make
để chỉ tạo ra đối tượng mà không lưu.
// Tạo một người dùng và lưu vào cơ sở dữ liệu
$user = User::factory()->create();
// Tạo một đối tượng người dùng nhưng không lưu vào cơ sở dữ liệu
$user = User::factory()->make();
Bạn cũng có thể tạo nhiều bản ghi cùng lúc bằng cách truyền vào số lượng cần tạo:
// Tạo 5 người dùng và lưu vào cơ sở dữ liệu
$users = User::factory()->count(5)->create();
Sử Dụng Factory Với Seeder
Factories rất hữu ích khi sử dụng kết hợp với seeders để tạo dữ liệu mẫu cho ứng dụng:
use Illuminate\Database\Seeder;
use App\Models\User;
class DatabaseSeeder extends Seeder
{
public function run()
{
// Tạo 50 người dùng
User::factory()->count(50)->create();
}
}
Chạy lệnh seeder:
php artisan db:seed
# Model and Factory Discovery Conventions
Trong Laravel, các model và factory được kết nối với nhau qua các quy tắc phát hiện (discovery conventions). Khi bạn sử dụng trait Illuminate\Database\Eloquent\Factories\HasFactory
trong mô hình của bạn, Laravel sẽ tự động tìm và sử dụng factory phù hợp theo các quy tắc sau:
-
Tự Động Phát Hiện Factory:
- Laravel sẽ tìm kiếm một factory trong namespace
Database\Factories
mà có tên lớp (class name) khớp với tên mô hình (model name) và kết thúc bằngFactory
. - Ví dụ, nếu bạn có mô hình
Flight
, Laravel sẽ tìm kiếm một factory có tênFlightFactory
trong namespaceDatabase\Factories
.
- Laravel sẽ tìm kiếm một factory trong namespace
-
Xác Định Factory Cụ Thể:
- Nếu bạn muốn xác định factory cho mô hình của bạn theo cách cụ thể hơn hoặc nếu tên và namespace của factory không tuân theo quy tắc tự động, bạn có thể ghi đè phương thức
newFactory
trên mô hình của mình để trả về instance của factory tương ứng.
- Nếu bạn muốn xác định factory cho mô hình của bạn theo cách cụ thể hơn hoặc nếu tên và namespace của factory không tuân theo quy tắc tự động, bạn có thể ghi đè phương thức
Ví Dụ
Giả sử bạn có mô hình Flight
và factory tương ứng FlightFactory
:
-
Tạo Mô Hình và Factory:
- Mô hình
Flight
:
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Flight extends Model { use HasFactory; // Bạn có thể tùy chỉnh phương thức newFactory nếu cần protected static function newFactory() { return \Database\Factories\FlightFactory::new(); } }
- Factory
FlightFactory
:
namespace Database\Factories; use App\Models\Flight; use Illuminate\Database\Eloquent\Factories\Factory; class FlightFactory extends Factory { /** * Tên của mô hình mà factory tương ứng. * * @var class-string<\Illuminate\Database\Eloquent\Model> */ protected $model = Flight::class; /** * Định nghĩa các thuộc tính mẫu cho mô hình. * * @return array */ public function definition() { return [ 'flight_number' => $this->faker->unique()->word, 'departure' => $this->faker->dateTime, 'arrival' => $this->faker->dateTime, ]; } }
- Mô hình
- Sử Dụng Factory Trong Seeder:
Khi bạn sử dụng factory trong seeder, bạn có thể dễ dàng tạo dữ liệu mẫu:
use Illuminate\Database\Seeder; use App\Models\Flight; class DatabaseSeeder extends Seeder { public function run() { // Tạo 10 bản ghi flight Flight::factory()->count(10)->create(); } }
- Chạy Seeder:
php artisan db:seed
# Factory States
Factory states trong Laravel cho phép bạn định nghĩa các trạng thái (states) khác nhau để áp dụng các thay đổi cụ thể cho các mô hình khi tạo dữ liệu mẫu. Điều này rất hữu ích khi bạn muốn có các biến thể của mô hình với các thuộc tính khác nhau mà không cần phải viết nhiều factory khác nhau.
Cách Định Nghĩa và Sử Dụng Các Trạng Thái Trong Factory
-
Định Nghĩa Trạng Thái:
Bạn có thể định nghĩa trạng thái trong factory bằng cách sử dụng phương thức
state
. Phương thức này nhận một closure mà sẽ nhận các thuộc tính gốc của factory và trả về các thuộc tính đã được thay đổi.Ví dụ:
Giả sử bạn có một factory cho mô hình
User
và bạn muốn định nghĩa một trạng tháisuspended
để thay đổi thuộc tínhaccount_status
thànhsuspended
:namespace Database\Factories; use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; class UserFactory extends Factory { /** * Tên của mô hình mà factory tương ứng. * * @var class-string<\Illuminate\Database\Eloquent\Model> */ protected $model = User::class; /** * Định nghĩa các thuộc tính mẫu cho mô hình. * * @return array */ public function definition() { return [ 'name' => $this->faker->name, 'email' => $this->faker->unique()->safeEmail, 'password' => bcrypt('password'), 'account_status' => 'active', // Giá trị mặc định ]; } /** * Chỉ định rằng người dùng bị tạm ngưng. * * @return \Illuminate\Database\Eloquent\Factories\Factory */ public function suspended(): Factory { return $this->state(function (array $attributes) { return [ 'account_status' => 'suspended', ]; }); } }
-
Sử Dụng Các Trạng Thái:
Khi bạn muốn sử dụng một trạng thái cụ thể khi tạo dữ liệu mẫu, bạn có thể gọi phương thức trạng thái đó trước khi gọi
create()
hoặcmake()
.Ví dụ:
// Tạo một người dùng với trạng thái bị tạm ngưng $suspendedUser = User::factory()->suspended()->create(); // Tạo một người dùng với trạng thái mặc định $activeUser = User::factory()->create();
-
Trạng Thái "Trashed":
Nếu mô hình Eloquent của bạn hỗ trợ xóa mềm (soft deletes), bạn có thể sử dụng trạng thái
trashed
được tích hợp sẵn để chỉ định rằng mô hình đã bị "xóa mềm".Ví dụ:
Trạng tháiuse App\Models\User; // Tạo một người dùng đã bị xóa mềm $trashedUser = User::factory()->trashed()->create();
trashed
tự động có sẵn cho tất cả các factory mà mô hình hỗ trợ xóa mềm. Bạn không cần phải định nghĩa trạng thái này trong factory của mình.
# Tạo Mô Hình Sử Dụng Factory
Khi bạn đã định nghĩa các factory, bạn có thể sử dụng phương thức factory
tĩnh được cung cấp bởi trait Illuminate\Database\Eloquent\Factories\HasFactory
trong các mô hình của bạn để khởi tạo các phiên bản factory cho mô hình đó. Dưới đây là hướng dẫn chi tiết về cách tạo mô hình sử dụng factory.
Khởi Tạo Mô Hình
-
Tạo Mô Hình Mà Không Lưu Vào Cơ Sở Dữ Liệu:
Để tạo các mô hình mà không lưu vào cơ sở dữ liệu, bạn có thể sử dụng phương thức
make
:use App\Models\User; $user = User::factory()->make();
Phương thức này tạo ra một đối tượng
User
mới nhưng không lưu vào cơ sở dữ liệu. -
Tạo Một Bộ Sưu Tập Các Mô Hình:
Bạn có thể tạo một số lượng mô hình nhất định bằng cách sử dụng phương thức
count
:$users = User::factory()->count(3)->make();
Lệnh trên tạo ra ba đối tượng
User
mà không lưu chúng vào cơ sở dữ liệu.
Áp Dụng Trạng Thái
Bạn có thể áp dụng các trạng thái khác nhau cho các mô hình. Nếu bạn muốn áp dụng nhiều trạng thái cho các mô hình, bạn chỉ cần gọi các phương thức trạng thái trực tiếp:
$users = User::factory()->count(5)->suspended()->make();
Trong ví dụ này, năm đối tượng User
được tạo ra với trạng thái bị tạm ngưng.
Ghi Đè Thuộc Tính
Nếu bạn muốn ghi đè một số giá trị mặc định của mô hình, bạn có thể truyền một mảng các giá trị vào phương thức make
. Chỉ những thuộc tính được chỉ định mới bị thay đổi, trong khi các thuộc tính khác vẫn giữ giá trị mặc định:
$user = User::factory()->make([
'name' => 'Abigail Otwell',
]);
Ngoài ra, bạn có thể sử dụng phương thức state
để thực hiện việc ghi đè thuộc tính trực tiếp:
$user = User::factory()->state([
'name' => 'Abigail Otwell',
])->make();
Lưu ý rằng việc tạo mô hình bằng factory tự động tắt bảo vệ gán hàng loạt (mass assignment).
Lưu Mô Hình Vào Cơ Sở Dữ Liệu
Phương thức create
không chỉ khởi tạo mô hình mà còn lưu nó vào cơ sở dữ liệu:
use App\Models\User;
// Tạo một đối tượng User và lưu vào cơ sở dữ liệu...
$user = User::factory()->create();
// Tạo ba đối tượng User và lưu vào cơ sở dữ liệu...
$users = User::factory()->count(3)->create();
Bạn có thể ghi đè các thuộc tính mặc định của factory bằng cách truyền một mảng các thuộc tính vào phương thức create
:
$user = User::factory()->create([
'name' => 'Abigail',
]);
Sequences
Đôi khi bạn muốn luân phiên giá trị của một thuộc tính mô hình cho mỗi mô hình được tạo. Bạn có thể thực hiện điều này bằng cách định nghĩa một chuỗi (sequence) trong factory. Ví dụ, bạn có thể muốn luân phiên giá trị của thuộc tính admin
giữa Y và N:
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
['admin' => 'Y'],
['admin' => 'N'],
))
->create();
Trong ví dụ này, năm đối tượng User
sẽ có giá trị admin
là Y và năm đối tượng sẽ có giá trị là N.
Nếu cần, bạn có thể sử dụng một closure làm giá trị chuỗi. Closure sẽ được gọi mỗi khi chuỗi cần một giá trị mới:
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
fn (Sequence $sequence) => ['role' => UserRoles::all()->random()],
))
->create();
Trong closure của chuỗi, bạn có thể truy cập các thuộc tính $index
hoặc $count
trên đối tượng chuỗi được chèn vào closure. Thuộc tính $index
chứa số lần lặp qua chuỗi cho đến thời điểm đó, trong khi thuộc tính $count
chứa tổng số lần chuỗi sẽ được gọi:
$users = User::factory()
->count(10)
->sequence(fn (Sequence $sequence) => ['name' => 'Name '.$sequence->index])
->create();
Để tiện lợi, bạn cũng có thể áp dụng chuỗi bằng phương thức sequence
, phương thức này thực hiện gọi phương thức state
nội bộ. Phương thức sequence
chấp nhận một closure hoặc các mảng thuộc tính được chuỗi hóa:
$users = User::factory()
->count(2)
->sequence(
['name' => 'First User'],
['name' => 'Second User'],
)
->create();
# Factory Relationships
Trong Laravel, bạn có thể xây dựng các mối quan hệ giữa các mô hình bằng cách sử dụng các phương thức factory. Dưới đây là cách bạn có thể sử dụng factories để tạo các mối quan hệ hasMany
và belongsTo
giữa các mô hình.
Quan Hệ "Has Many"
Khi một mô hình có nhiều mối quan hệ với một mô hình khác, ví dụ như một User
có nhiều Post
, bạn có thể sử dụng phương thức has
của factory để tạo các mô hình liên quan.
-
Tạo Mô Hình Có Quan Hệ
Has Many
Giả sử bạn có mô hình
User
vàPost
, và mô hìnhUser
định nghĩa một mối quan hệhasMany
vớiPost
. Để tạo một người dùng với ba bài viết, bạn có thể sử dụng phương thứchas
như sau:use App\Models\Post; use App\Models\User; $user = User::factory() ->has(Post::factory()->count(3)) ->create();
Laravel sẽ tự động giả định rằng mô hình
User
có một phương thứcposts
để định nghĩa mối quan hệhasMany
. Nếu cần, bạn có thể chỉ định tên của mối quan hệ:$user = User::factory() ->has(Post::factory()->count(3), 'posts') ->create();
-
Sử Dụng Các Phương Thức "Ma Thuật"
Để tiện lợi, bạn có thể sử dụng các phương thức mối quan hệ "ma thuật" của factory. Ví dụ, phương thức sau sẽ tự động xác định rằng các mô hình liên quan nên được tạo thông qua phương thức
posts
trên mô hìnhUser
:$user = User::factory() ->hasPosts(3) ->create();
Bạn cũng có thể ghi đè thuộc tính cho các mô hình liên quan:
$user = User::factory() ->hasPosts(3, [ 'published' => false, ]) ->create();
Và bạn có thể sử dụng closure nếu trạng thái cần truy cập vào mô hình cha:
$user = User::factory() ->hasPosts(3, function (array $attributes, User $user) { return ['user_type' => $user->type]; }) ->create();
Quan Hệ "Belongs To"
Bây giờ, hãy khám phá cách xây dựng các mối quan hệ ngược lại, tức là khi một mô hình thuộc về một mô hình khác. Bạn có thể sử dụng phương thức for
để định nghĩa mô hình cha mà các mô hình do factory tạo ra thuộc về.
-
Tạo Các Mô Hình Thuộc Về Một Mô Hình Cha
Để tạo ba bài viết thuộc về một người dùng duy nhất, bạn có thể làm như sau:
use App\Models\Post; use App\Models\User; $posts = Post::factory() ->count(3) ->for(User::factory()->state([ 'name' => 'Jessica Archer', ])) ->create();
Nếu bạn đã có một đối tượng mô hình cha và muốn liên kết với các mô hình bạn đang tạo, bạn có thể truyền đối tượng mô hình vào phương thức
for
:$user = User::factory()->create(); $posts = Post::factory() ->count(3) ->for($user) ->create();
-
Sử Dụng Các Phương Thức "Ma Thuật"
Để tiện lợi, bạn cũng có thể sử dụng các phương thức mối quan hệ "ma thuật" của factory để định nghĩa quan hệ
belongsTo
. Ví dụ, phương thức sau sẽ tự động xác định rằng các bài viết nên thuộc về mối quan hệuser
trên mô hìnhPost
:$posts = Post::factory() ->count(3) ->forUser([ 'name' => 'Jessica Archer', ]) ->create();
Tóm Tắt
Quan Hệ "Has Many": Sử dụng phương thức
has
để tạo các mô hình liên quan với mối quan hệhasMany
. Bạn có thể áp dụng trạng thái và sử dụng các phương thức "ma thuật" để dễ dàng định nghĩa mối quan hệ.Quan Hệ "Belongs To": Sử dụng phương thức
for
để xác định mô hình cha mà các mô hình do factory tạo ra thuộc về. Bạn cũng có thể sử dụng các phương thức "ma thuật" để đơn giản hóa việc định nghĩa quan hệ.Các tính năng này giúp bạn dễ dàng tạo dữ liệu mẫu cho việc kiểm thử và phát triển ứng dụng với các mối quan hệ giữa các mô hình.
Ở bài tiếp theo, chúng ta sẽ cùng khám phá các Relationships và các vấn đề liên quan đến Factories nhé
Danh mục
Bài viết liên quan

Quản Lý Thời Gian Tự Động Trong Eloquent
Author: | ADMIN |
---|

Các Mối Quan Hệ Trong Eloquent
Author: | ADMIN |
---|

Basic Eloquent Model and MVC
Author: | ADMIN |
---|

Eager Loading
Author: | ADMIN |
---|
Bài viết khác

Blade Basics
Author: | ADMIN |
---|

9 Mẹo Hữu Ích Khi Sử Dụng Blade Trong Laravel
Author: | ADMIN |
---|

Hiển thị giá trị trong Blade
Author: | ADMIN |
---|