Migration và Seeder

Khi bắt đầu bài viết này mình mặc định bạn đã cài đặt và chạy được Laravel rồi nên mình sẽ không hướng dẫn lại quá trình cài đặt. Còn nếu bạn chưa cài đặt thì bạn có thể truy cập vào document trên trang chính thức của Laravel và làm theo hướng dẫn.

Mở đầu

Chắc hẳn khi bắt tay vào code một project công việc đầu tiên bạn cần làm là tạo cho mình cơ sở dữ liệu cùng với một số dữ liệu mẫu để phục vụ cho quá trình phát triển chức năng. Đối với PHP thông thường, bạn phải truy cập vào CSDL thông qua PHPMyAdmin, Workbench (nếu bạn sử dụng MySQl) để tạo CSDL, tạo các bảng và thêm dữ liệu mẫu bằng giao diện hoặc bằng việc gõ lệnh SQL. Tuy nhiên cách làm này có thể nói là khá thủ công và sẽ phát sinh nhiều vấn đề nhất là khi bạn làm việc teamwork với các thành viên khác. Để giải quyết những vấn đề phát sinh đó, Laravel giới thiệu đến người sử dụng hai tính năng là MigrationSeeder.

Migration

Migration theo như trong document chính thức của Laravel giới thiệu nó giống như một hệ thống quản lý phiên bản giống như Git nhưng dành cho cơ sở dữ liệu của bạn. Migration cho phép bạn định nghĩa các bảng trong CSDL, định nghĩa nội dung các bảng cũng như cập nhật thay đổi các bảng đó hoàn toàn bằng PHP. Đồng thời các thao tác với CSDL này còn có thể sử dụng trên các loại CSDL khác nhau như MySQL, SQL Server, Postgres, ... mà không cần phải chỉnh sửa lại code theo CSDL sử dụng.

1. Các file migration

  • Mặc định khi bạn tạo mới project Laravel sẽ có sẵn một thư mục dành cho các file migration là folder database/migrations. Toàn bộ các file migration bạn tạo ra trong quá trình làm việc sẽ được lưu trữ ở đây. Các file migration này đơn giản chỉ là các file PHP có nhiệm vụ định nghĩa cấu trúc các bảng cho CSDL của bạn.

  • Còn đây là nội dung bên trong 1 file migration

2. Cách tạo một file migration

  • Để tạo một file migration, ta sử dụng cú pháp sau trên terminal (command line):
$ php artisan make:migration <file-name> --create=<table-name>
  • Lệnh này sẽ tạo ra một file migration mới có tên dưới dạng <timestamp>_<file-name>.php. Bên trong đó sẽ tạo sẵn cho bạn cấu trúc để định nghĩa nội dung một bảng có tên giống với <table-name> mà bạn chọn ở trên.

  • Từ đó bạn có thể dễ dàng định nghĩa các cột trong bảng của mình như sau: Tạm thời bạn chưa cần quan tầm đến hàm up bọc bên ngoài đó

  • Như các bạn đã thấy, chúng ta có thể dễ dàng định nghĩa các cột trong bảng của mình thông qua cú pháp mà Laravel cung cấp. Bạn chỉ cần định nghĩa kiểu dữ liệu thông qua các hàmLaravel cung cấp đi kèm đó là tên cột cùng một số chọn lựa khác như cột đó có giá trị defaul là gì, có thể để null không,...

  • Ngoài ra bạn cũng có thể định nghĩa quan hệ giữa các bảng với nhau:

  • Đoạn code trên đơn giản định nghĩa một khóa ngoại có tên là users_id liên kết với cột id trong bảng users và cột đó có dạng interger

  • Ngoài việc tạo mới bản, ta cũng có thể tạo file migration mới nhằm chỉnh sửa lại bảng bằng cú pháp tương tự như khi tạo mới file migration để tạo bảng

$ php artisan make:migration <file-name> --table=<table-name>
  • Sẽ tạo cho ta file migration mới có nhiệm vụ để cập nhật nội dung cho bảng đã được tạo trước đó

Để chạy được hàm change() bạn cần cài thêm package tên là doctrine/dbal

  • Nếu bạn để ý kĩ, khi tạo mới bảng thì sẽ thực hiện hàm có tên Schema::create còn khi cập nhật bảng sẽ dùng hàm Schema::table. Để xem được hết các hafmg mà Laravel cung cấp cho bạn khi cập nhật chỉnh sửa hay xóa cột trong bảng bạn có thế tìm kiếm ở đây.
  • Bằng việc sử dụng migration, khi bạn tạo mới hay chỉnh sửa CSDL thì thay vì bạn phải sửa thủ công trong CSDL sau đó lại báo lại với các thành viên khác và hướng dẫn họ sửa theo bạn thì bạn chỉ cân đưa họ file migration có chứa chỉnh sửa mà bạn viết để các thành viên chạy lên và các thay đổi hoàn toàn được đồng bộ giữa mọi người.

3. Chạy file migration

  • Sau khi đã định nghĩa xong cấu trúc cũng như quan hệ giữa các bảng với nhau trong CSDL, bạn gõ lệnh:
$ php artisan migrate

và đây là kết quả chúng ta thu được sau khi chạy lệnh Các file migration sẽ lần lượt được chạy theo thứ tự bạn tạo cho đến hết nếu không có lỗi gì.

  • Để tiến hành biến những bảng trong file migration bạn đã tạo thành các bảng trong CSDL mà bạn kết nối tới. Lưu ý để chạy lệnh này bạn cần chỉnh sửa phần khai báo CSDL trong file .env và đảm bảo các bảng có sử dụng quan hệ khóa ngoại được tạo sau các bảng cha của nó. Đây là kết quả khi chúng ta mở CSDL bằng Workbench lên xem: Ngoài các các bảng mà chúng ta tạo từ file migration, có thể thấy xuất hiện thêm một bảng tên là migrations, đây chính là bảng dùng để quản lý các phiên bản cho CSDL của bạn cho mỗi lần chạy lệnh, nó bao gồm 1 cột id, 1 cột chứa tên file và cuối cùng là cột batch chứa lần chạy lệnh migrate mà file đó được thực hiện

Như ví dụ trên 4 hàng đầu tiên thể hiện file migration được chạy ở lần thứ nhất, dòng thứ 5 là thể hiện file migration được tạo và chạy sau 4 file đó nên nó có batch là 2. Các file tiếp theo được thêm vào khi chạy lệnh sẽ lần lượt là 3, 4, ...

  • Như trong hình ở trên mình cung cấp về nội dung file migration sẽ có hai hàm là function up()function down(). Với function down() sẽ là các lệnh dùng để đảo ngược những định nghĩa hay chỉnh sửa trong function up(). Đối với thao tác tạo mới bảng thì mặc định function down() của các bạn sẽ là xóa bảng đó đi, còn trong trường hợp bạn chỉnh sửa bảng thì bạn cần tự thêm code vào function down() này để nó chạy ngược lại với function up().
  • Sở dĩ bạn cần định nghĩa function down() là vì ngoài lệnh php artisan migrate, Laravel còn cung cấp cho chúng ta các lệnh khác là:
$ php artisan migrate:rollback

Với lệnh này, toàn bộ file có batch mới nhất trong bảng migration sẽ được thực hiện function down của nó hay chính xác hơn là đảo ngược lại thay đổi mà nó tạo ra cho CSDL. Nếu bạn không định nghĩa nội dung cho function down thì mặc dù trong bảng migration đã rollback file migration đó nhưng thực chất nó vẫn tồn tại trong CSDL hay nói cách khác lệnh rollback là vô dụng. Ngoài việc rollback từng batch một, bạn có thể tiến hành rollback nhiều batch cùng lúc bằng lệnh:

$ php artisan migrate:rollback --step=n

Với n là số lượng batch bạn muộn rollback. Ví dụ bạn đang có các batch cho các lần migrate khác nhau là 1, 2, 3, 4, 5. Khi chạy lệnh trên với n = 2 thì trong migration sẽ chỉ còn lại batch 1, 2, 3. Cuối cùng, nếu bạn muốn rollback toàn bộ thì sẽ dùng lệnh sau:

$ php artisan migrate:reset

Lệnh trên sẽ rollback toàn bộ CSDL của bạn hay đúng hơn là chạy toàn bộ function down() trong các file migration của bạn. Cuối cùng chúng ta có lệnh:

$ php artisan migrate:refresh

Lệnh này nhằm rollback toàn bộ CSDL đồng thời chạy lại luôn toàn bộ các file migrate của bạn.

Seeder

Sau khi đã đã có CSDL, việc tiếp theo bạn có thể cần làm đó là thêm một số dữ liệu mẫu trước khi bắt đầu thực hiện việc code các tính năng. Như đã nói trên việc các bạn thêm dữ liệu mẫu thủ công tốn rất nhiều công sức và nếu làm viêc team bạn lại mất công export thành file .sql và đưa cho thành viên khác của team nếu không mỗi thành viên lại phải tự tạo dữ liệu thì lại càng mất thời gian. Để giải quyết vấn đề này, Seedẻr cung cấp cho bạn các phương thức đơn giản để tạo ra dữ liệu mẫu bạn cần cho việc phát triển các tính năng.

1. Các file seeder

  • Trong một project Laravel các file seeder được lưu trong thư mục database/seeds, Nghĩ là khi bạn tạo mới một file seeder thì nó sẽ được lưu hết vào đây. Các file seeder này có nhiệm vụ thêm dữ liệu mẫu vào trong CSDL của bạn sau khi tạo.

  • Ban đầu thư mục này sẽ chưa một file tên là DatabaseSeeder.php, đây chính là file gốc được chạy khi ta thực hiện lệnh thêm dữ liệu (sẽ được nói ở dưới). Các file seeder nói chung chỉ có duy nhất một function là run(), hàm này sẽ dùng để thêm dữ liệu vào CSDL. Nội dung file DatabaseSeeder.php:

  • Ở trên chính là dữ liệu mẫu mà chúng ta muốn thêm được vào CSDL, tuy nhiên nó vẫn khác là thủ công vì ta vẫn phải gõ tay dữ liệu và thông thường ta sẽ không thêm trực tiếp dữ liệu cho bảng trực tiếp trong file DatabaseSeeder.php như thế này mà thay vào đó ta sẽ tạo các file seeder cho từng bảng rồi gọi nó trong file DatabaseSeeder.php, cụ thể khi áp dụng cách này file của chúng ta sẽ như sau:

Lưu ý dữ liệu thêm vào CSDL cần được sắp xếp theo đúng thứ tự phù hợp như nếu sử dụng khóa ngoại thì bảng cha cần được chạy trước Lúc này ta sẽ sử dụng hàm call để gọi đến các class Seeder khác dùng cho từng bảng trong CSDL, nội dung các class Seeder này cũng giống như nội dung class DatabaseSeeder.php ở ảnh trước kia. Ví dụ class UserTableSeeder: Để thêm đồng thời nhiều giữ liệu, ta có thể sử dụng truyền vào nhiều mảng cho hàm insert, tuy nhiên nếu bạn muốn dữ liệu độc đáo hơn và có nhiều lựa chọn hơn cho các dạng email, ngày sinh, tên, đoạn văn thì bạn nên dùng 1 package có sẵn trong Laravel tên là Faker.

2. Tạo các file seeder

  • Để tạo các file seeder cho các bảng, ta dùng lệnh:
$ php artisan make:seeder <seeder-class-name>

Sau khi thực hiện lệnh trên sẽ tạo cho ta 1 file và 1 class trong file đó giống với tên mà ta đã đặt ở trên. Bên trong class này cũng có một function run() rỗng đợi để được chúng ta định nghĩa, giả sử ta tạo dữ liệu mẫu cho bảng users cùng với 3 cột là name, email, password và muốn tạo 10 bản ghi thì file seeder của chúng ta lúc này sẽ như sau: Ở đây ta đang dùng Faker để tạo dữ liệu mẫu theo từng cột. Tuy nhiên nhìn vào cách làm trên, bạn sẽ thấy nếu muốn tạo dữ liệu nhiều hơn chả nhẽ ta sẽ đi copy đủ số lượng record ta muốn như 100, 1000. Để giải quyết vấn đề này, ta có thể sử dụng khái niệm tên là ModelFactory. Trong folder database ta sẽ thấy còn có một folder nữa là factories, bên trong folder này có 1 file tên là ModelFactory.php dùng để định nghĩa cấu trúc của dữ liệu mẫu mà ta muốn thêm vào CSDL theo từng bảng: Lưu ý để dùng được model factory thì trước đó ta cần tạo các Model cho các bảng trong CSDL Sau khi định nghĩa cấu trúc của một record nằm trong bảng users ứng với model User thì lúc này trong file UserTableSeeder.php ta có thể sửa lại thành như sau: Như bạn thấy, do chúng ta đã định nghĩa cấu trúc của 1 record cho model User bằng fatory nên ta chỉ đơn giản dùng cú pháp như trên đi kèm với số lượng bản ghi muốn tạo là xong. Ngắn gọn và hiệu quả hơn nhiều so với việc copy đủ số lượng record trong hàm insert 😄.

3. Chạy filder seeder

  • Để tiến hành chạy file seeder và thêm dữ liệu vào CSDL ta thực hiện lệnh sau:
$ php artisan db:seed

Lệnh trên sẽ tiến hành chạy nội dung file DatabaseSeeder.php theo hàm run được khai báo trong đó. Trong trường hợp bạn muốn chạy một file Seeder cụ thể thì ta thực hiện lệnh sau:

$ php artisan db:seed --class=UserTableSeeder

Sẽ chạy duy nhất file UserTableSeeder

Kết bài

Mong rằng qua bài viết này, bạn hiểu được phần nào về cách sử dụng cũng như điểm hay mà 2 tính năng migrationseeder trong Laravel. Hẹn gặp lại bạn trong các bài viết sau.