Quay lại
Class based model factories trong Laravel 8

Model factories trong Laravel là một cách tuyệt vời để seeding một số dữ liệu fake vào cơ sở dữ liệu cho mục đích test mà mình đã thảo luận trong bài viết này. Mặc dù việc triển khai trước đó rất tuyệt vời, nhưng Laravel 8 đã mang đến cho cácModel factories một cuộc đại tu lớn và nó làm cho chúng thậm chí còn tốt hơn!

Model factories của Laravel 8 là class-based. Có nghĩa là, giờ đây bạn sẽ có nhiều quyền kiểm soát hơn đối với những thứ không thể thực hiện được trong các phiên bản trước.

Để so sánh, trước Laravel 8, Model factories không có gì khác ngoài các tệp PHP thông thường. Chẳng hạn, nếu chúng ta có một BookFactory cho Book model nó sẽ giống như này.

<?php

use App\Book;
use Illuminate\Support\Str;
use Faker\Generator as Faker;

$factory->define(Book::class, function (Faker $faker) {
    $type = ['fiction', 'nonfiction'];

    return [
        'name' => $faker->word,
        'author' => $faker->name,
        'type' => $type[rand(0, (count($type)-1))]
    ];
});

Như bạn có thể thấy, không có bất kỳ class involved tham gia vào việc này. Và cú pháp cũng khá khó nhớ với tất cả các Closures và các biến “magic” như $factory.

Laravel 8 đã cố gắng giải quyết vấn đề này. Hãy xem làm thế nào.

Class based model factories

Tóm lại, các Model factories không chỉ đơn giản là các tệp PHP nữa. Bây giờ chúng là các lớp PHP chính thức đi kèm với một số tính năng bổ sung.

Vì vậy, nếu bạn tạo một factorie mới cho model Book bằng lệnh Artisan sau,

$ php artisan make:factory BookFactory --model=Book

..nó sẽ tạo một tệp BookFactory.php trong database/factories giống như này.

<?php

namespace Database\Factories;

use App\Models\Book;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class BookFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Book::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            //
        ];
    }
}

Như bạn có thể thấy, BookFactory là một class mở rộng dựa vào factory class trong Laravel’s và định nghĩa một thuộc tính model và phương thức definition .

Phương thức definition là nơi bạn trả về cần tập giá trị thuộc tính mặc định sẽ được áp dụng khi tạo model bằng cách sử dụng factory.

Vì vậy, nếu chúng ta muốn điền vào model Book bằng cách sử dụng factory, chúng ta có thể xác định phương thức định nghĩa như sau.

public function definition()
{
    return [
        'title' => $this->faker->name,
        'author' => $this->faker->name,
        'published' => 1
    ];
}

Sử dụng các factories

Sau khi BookFactory được tạo, nó đã sẵn sàng để sử dụng. Chẳng hạn, chúng ta có thể sử dụng nó trong class database/seeders/DatabaseSeeder.php như sau.

<?php

namespace Database\Seeders;

use App\Models\Book;
use App\Models\User;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        Book::factory(5)->create();
    }
}

Lưu ý, bây giờ bạn có thể trực tiếp sử dụng factory trên model instance (App\Models\Book trong trường hợp này) bởi vì khi bạn tạo một model bằng cách sử dụng lệnh php artisan make:model Book Artisan trong Laravel 8, nó sẽ tạo ra model mà bao gồm trait HasFactory mới. Vì vậy, model Book của chúng ta trông giống như sau.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;
}

Về cơ bản, trait HasFactory này trả về một factory instance mới cho model và nhờ đó chúng ta có thể trực tiếp sử dụng instance trên các model.

Bây giờ, bạn có thể tạo cơ sở dữ liệu bằng cách sử dụng lệnh php artisan db:seed và nó sẽ tạo cơ sở dữ liệu với năm bản ghi mới trong bảng Book.

Sử dụng các factories ở nơi khác trong code của bạn

Do việc triển khai các factories dựa trên file-based, nên không thể sử dụng các factories trong code ngoài các seeders. Nhưng vì chúng bây giờ dựa trên class, bạn có thể sử dụng chúng để tạo các factories ở nơi khác trong code (có thể trong testing) như này.

use App\Models\Book;

$book = Book::factory()->make();

// Use model in tests...

Điều này sẽ tạo một model instance trong suốt quá trình testing của bạn.

Thao tác này sẽ khởi tạo bảng books với một bản ghi có thể được sử dụng làm phiên bản mẫu trong suốt quá trình testing  của bạn.

Bạn có thể tạo một collection bằng cách sử dụng phương thức count như này.

$books = Book::factory()->count(5)->make();

// Use model in tests...

Bạn cũng có thể sử dụng phương thức create thay vì phương thức make sẽ tạo một bản ghi trong cơ sở dữ liệu bằng cách sử dụng phương thức Eloquent’s save như sau.

use App\Models\Book;

$book = Book::factory()->create();

// Use model in tests...

Overriding attributes 

Tận dụng lợi thế của các class-based factories này, giờ đây bạn có thể định nghĩa nhiều phương thức hơn trong class cho nhiều thứ khác. Chẳng hạn, giờ đây bạn có thể ghi đè một số thuộc tính của factories bằng phương thức state của factories.

 

Vì vậy, trong ví dụ của chúng ta, nếu mình muốn thay đổi giá trị của published thành 0, chúng ta có thể làm như này.

public function notpublished()
{
    return $this->state([
        'published' => 0,
    ]);
}

Bây giờ, khi tôi tạo một factory mới bằng cách đính kèm notpublished, nó sẽ tạo một Book model instance với published là 0 như này.

$book = Book::factory()->notpublished()->make();

Ngoài ra, bạn có thể sử dụng phương thức state trực tiếp trên factory như sau.

$book = Book::factory()->state([
    'published' => 0,
])->make();

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday