Tìm hiểu Laravel từ số 0 (P3)
Ở phần 2 chúng ta đã đi đến mục tạo layout bằng blade. Và tiếp tục trong phần 3 này tôi sẽ nói về những mục sau : Setting môi trường DB Quản lý DB version bằng Migration Tạo ra Migration Tạo Model Sẽ có 2 files chúng ta cần quan tâm là . env config / database . php FIle ...
Ở phần 2 chúng ta đã đi đến mục tạo layout bằng blade. Và tiếp tục trong phần 3 này tôi sẽ nói về những mục sau :
- Setting môi trường DB
- Quản lý DB version bằng Migration
- Tạo ra Migration
- Tạo Model
Sẽ có 2 files chúng ta cần quan tâm là
.env config/database.php
FIle .env là nơi để chứa những thông tin có thể chúng ta sẽ thay đổi thiết lập theo từng môi trường như development, staging hay production.
DB_HOST=localhost DB_DATABASE=mydatabase DB_USERNAME=developer DB_PASSWORD=secret
Dựa vào giá trị key value được khai báo như trên chúng ta có thể thiết lập được value theo từng môi trường. Nếu trường hợp sử dụng git thì hãy loại bỏ khỏi đối tượng git quản lý bằng cách thêm .env vào file .gitignore
Còn config/database sẽ là nơi để thiết lập liên quan đến DB :
<?php return [ // .... 'default' => env('DB_CONNECTION', 'mysql'), 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'database' => storage_path('database.sqlite'), 'prefix' => ', ], 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', '), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => ', 'strict' => false, ], // .... ]; ];
Mảng connections định nghĩa những thông tin kết nối cần thiết theo từng loại DB. Trong Laravel có SQLite, MySQL, PostgreSQL, SQL Server. Ở phần khai báo mysql chúng ta thấy env(‘DB_HOST’, ‘localhost’), đây là nơi tham chiếu đến file .env. Đối số thứ nhất chỉ định key được định nghĩa trong file .env và lấy ra giá trị trong nó. Đối số thứ 2 là giá trị mặc định, nếu mà không có file .env hay khi key đang không được thiết lập thì sẽ sử dụng mặc định giá trị đó. Ở phần khai báo default => env(‘DB_CONNECTION’, ‘mysql’) thiết lập DB sẽ sử dụng trên Laravel.
Trong trường hợp trong file .env mà đã thiết lập DB_CONNECTION=sqlite thì cần phải tạo thủ công file database.sqlite.
$ touch storage/database.sqlite
Tiếp theo sẽ thực hiện xác nhận kết nối DB có ổn chưa. Ta sẽ dùng câu lệnh artisan migrate để tạo ra bảng user được chuẩn bị sẵn 1 cách mặc định
$ php artisan migrate
Sau đó thực thi lệnh artisan tinker để xác nhận
$ php artisan tinker Psy Shell v0.3.4 (PHP 5.6.2 — cli) by Justin Hilema >>>
Và ta sẽ thử tìm User
>>> AppUser::all()->toArray(); => [] >>>
Như trên là không có User nào nhưng cũng không có lỗi gì mà kết quả là một mảng trống nên cho thấy kết nối tới DB không có vấn đề gì.
Chúng ta sẽ thử dùng chức năng Migration để quản lý DB version :
- Chạy Migration và tạo bảng trong DB
- Rollback đưa DB trở về version cũ
- Nội dung có trong file Migration
Thiết lập môi trường DB
Đầu tiên ta sẽ tiến hành thiết lập môi trường DB, phần nội dung này như ở mục trên đã trình bày. Còn trong phần này ta sẽ chỉ định SQLite.
// .env ... DB_CONNECTION=sqlite ... // config/database.php ... 'default' => env('DB_CONNECTION', 'mysql'), ... 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'database' => storage_path('database.sqlite'), 'prefix' => ', ], ...
Như phần trên đã nói, ta sẽ tạo thủ công file
$ touch storage/database.sqlite
Thực thi Migration
Khi mà chúng ta tạo project Laravel thì sẽ có 2 files Migration sau được tạo.
database/ └── migrations ├── 2014_10_12_000000_create_users_table.php └── 2014_10_12_100000_create_password_resets_table.php
Lý do là do khi chúng ta tạo project thì có chức năng chứng thực user đã được bao gồm nên cần có 2 bảng dùng để tạo user và xác nhận việc cấp lại mật khẩu. Về chứng thực user thì chúng ta sẽ bàn sau, giờ hãy thử chạy :
$ php artisan migrate Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table
Để xác nhận xem bảng đã được tạo thành công chưa ta sẽ dùng câu lệnh sqlite3
$ sqlite3 storage/database.sqlite sqlite> .tables migrations password_resets users // vậy là đã có 3 bảng được tạo
Giờ hãy xem bên trong bảng migrations chứa những gì :
sqlite> select * from migrations; migration batch ------------------------------------ ---------- 2014_10_12_000000_create_users_table 1 2014_10_12_100000_create_password_re 1
Trong bảng này nó đã có bản ghi chưa thông tin về file migration đã được thực thi. Khi này nếu thử chạy lại thì sẽ không có gì được chạy cả và kết quả như sau :
$ php artisan migrate
Nothing to migrate.
Rollback Migration
Trong thực tế khi chạy xong lệnh đôi khi có vấn đề phát sinh hoặc chạy nhầm thì nhu cầu sẽ có thể là rollback lại DB. Như ở trên ta đã tạo ra bảng thì giờ hãy thử rollback lại bước đó :
$ php artisan migrate:rollback Rolled back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_000000_create_users_table
Một lần nữa nếu thử lại thì ta sẽ thấy không còn 2 bảng đó nữa và nội dung chứa trong bảng migrations cũng bị xoá đi :
$ sqlite3 storage/database.sqlite sqlite> .tables migrations sqlite> select * from migrations; sqlite>
Bên trong file Migration
<?php // database/migrations/2014_10_12_000000_create_users_table.php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateUsersTable extends Migration { public function up() { Schema::create('users', function(Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('password', 60); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::drop('users'); } }
Trong file này có định nghĩa class CreateUsersTable kế thừa class Migration, nhưng điểm quan trọng là hai hàm up() và down(). Trong hàm up() sẽ có nội dung xử lý version up khi mà thực thi Migration. Và hàm down() sẽ có nội dung ngược lại cho lúc rollback. Các bạn đọc nội dung trong hai hàm đó ở trên sẽ thấy 1 cái là tạo bảng users còn 1 cái sẽ xoá đi. Và nếu để ý bạn sẽ thấy cụm Schema:xxx, nó được gọi Schema Builder là nơi đang thao tác với DB trong thực tế :
Schema::create(‘table name’, Closure $$allback) – tạo bảng Schema::drop(‘table name’) – Xoá bảng
Để tìm hiểu kỹ hơn về nó bạn có thể xem tại đây.
Từ giờ chúng ta sẽ hướng đến việc tạo 1 blog đơn giản và đầu tiên sẽ là tạo bảng Articles.
Tạo Migration
Chúng ta sẽ dùng lệnh artisan make:migration để tạo ra file migration :
// Cú pháp : php artisan make:migration <tên migration> php artisan make:migration create_articles_table
File này sẽ được tạo ra trong folder database/migrations và để cho framwork biết được thứ tự thực thi của migration thì time stamp sẽ được gắn vào đầu file dạng như sau :
database/ └── migrations └── 2015_02_22_133752_create_articles_table.php
Khi mở file này ra thì nội dung sẽ như bên dưới :
<?php // 2015_02_22_133752_create_articles_table.php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateArticlesTable extends Migration { public function up() { // } public function down() { // } }
Trong đó có class CreateArticlesTable kế thừa class Migration và để ý sẽ thấy tên lớp được tạo ra theo tên của migration với cách đặt tên kiểu camel case. Và đươn nhiên nội dung 2 hàm up() và down() sẽ rỗng. Bởi vì chúng ta chưa chỉ định tham số gì khi tạo ra cả. Giờ hãy thử dùng tham số --create với tên bảng là articles (nhưng trước khi chạy hãy xoá file trống vừa được tạo trước đó đi).
php artisan make:migration create_articles_table --create=articles
Và khi xác nhận nội dung bạn sẽ thấy nó đã khác so với lần trước :
<?php // 2015_02_22_133821_create_articles_table.php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateArticlesTable extends Migration { public function up() { Schema::create('articles', function(Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } public function down() { Schema::drop('articles'); } }
Nhưng một bài blog thì ít nhất phải có tiêu đề và nội dung nên chúng ta cần thêm vào nội dung này.
<?php // 2015_02_22_133821_create_articles_table.php // ... public function up() { Schema::create('articles', function(Blueprint $table) { $table->increments('id'); $table->string('title'); // thêm $table->text('body'); // thêm $table->timestamps(); }); } // ... }
Ta sẽ chạy migration để xem nội dung trong bảng sẽ như nào :
// Chạy migration $ php artisan migrate // Migrated: 2015_02_22_150438_create_articles_table // chạy sqlite xem bảng đã được tạo ra chưa $ sqlite3 storage/database.sqlite sqlite> .tables // articles migrations password_resets users // xem cấu trúc bảng có theo đúng định nghĩa ở trong file migration không sqlite> .schema articles CREATE TABLE "articles" ( "id" integer not null primary key autoincrement, "title" varchar not null, "body" text not null, "created_at" datetime not null, "updated_at" datetime not null );
Thay đổi bảng
Chúng ta sẽ thêm vào bảng vừa tạo một trường mới là published_at. Để làm điều này chúng ta có hai cách, một là rollback lại rồi sửa file migration và sau đó chạy lại. Nhưng như thế sẽ không track back được những thay đổi của DB nên sẽ dùng đến cách thứ hai, đó là tạo ra file migration khác cho sự thay đổi này. Khi thay đổi chúng ta sẽ cần chỉ định tham số --table :
php artisan make:migration add_published_at_to_articles_table --table=articles
Tương tự như khi tạo bảng một file tương ứng sẽ được tạo ra và hàm up(), down() ở trạng thái trống.
<?php // 2015_02_22_153343_add_published_at_to_articles_table.php use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class AddPublishedAtToArticlesTable extends Migration { public function up() { Schema::table('articles', function(Blueprint $table) { // }); } public function down() { Schema::table('articles', function(Blueprint $table) { // }); } }
Điều khác chúng ta thấy ở đây là Schema Builder đã thay đổi theo tham số truyền vào - Schema:table, nó có nghĩa nội dung file migration này sẽ thay đổi cấu trúc của bảng. Giờ ta sẽ thêm vào nội dung thêm mới cột và xoá cột đó đi khi rollback tương ứng cho hai hàm up(), down() :
<?php // 2015_02_22_153343_add_published_at_to_articles_table.php // ... public function up() { Schema::table('articles', function(Blueprint $table) { $table->timestamp('published_at')->nullable(); }); } public function down() { Schema::table('articles', function(Blueprint $table) { $table->dropColumn('published_at'); }); } }
Đến đây việc thực hiện chạy file migration, xác nhận kết quả đều tương tự như khi ta tạo bảng nên tôi sẽ giản lược đi.
Việc tiếp chúng ta sẽ tiếp tục đến phần M - Model trong mô hình MVC, qua Model chúng ta sẽ thao tác đến dữ liệu trong DB. Ở trong Laravel thì chức năng xử lý object Model với DB được đặt tên là Eloquent. Những class mà kế thừa Eloquent và mở rộng logic chính là Model.
Chúng ta sẽ dùng artisan để tạo ra Model. Với tên bảng chúng ta đã tạo ra với số nhiều là Articles nhưng với tên Model thì bạn sẽ cần chú ý là đặt dạng số ít - Article.
php artisan make:model Article
Sau khi được tạo các Model sẽ được tìm thấy tại thư mục app
// Nơi chứa model app └── Article.php // Nội dung bên trong <?php namespace App; // app/Article.php use IlluminateDatabaseEloquentModel; class Article extends Model { // }
Như các bạn thấy nó chỉ là 1 class kế thừa lại lớp Model của Eloquent nhưng chỉ với như vậy là bạn đã có thể thao tác với bảng Articles được rồi. Chúng ta sẽ sử dụng tinker - là một công cụ để giao tiếp với ứng dụng Laravel. Nó rất hữu dụng khi muốn thử xem chương trình có hoạt động không.
// thực thi tinker
php artisan tinker
Từ giờ sẽ là những thao tác sử dụng tinker, hãy xem đoạn code sau :
// Tạo ra một bài blog (instance) mới trên bộ nhớ bằng cách sử dụng từ khoá new >>> $article = new AppArticle(); => {} // chuyển qua định dạng mảng nhưng hiện chưa có nội dung gì >>> $article->toArray(); => [] // Tạo ra các thông tin của bài blog bằng cách gán như dưới >>> >>> $article->title = 'I am a title of blog'; => "I am a title of blog" >>> >>> $article->body = 'And i am a content of above title'; => "And i am a content of above title" >>> >>> $article->published_at = CarbonCarbon::now(); => { date: "2017-01-03 07:36:28.000000", timezone_type: 3, timezone: "UTC" } // xem lại kết quả dạng mảng >>> >>> $article->toArray(); => [ "title" => "I am a title of blog", "body" => "And i am a content of above title", "published_at" => { date: "2017-01-03 07:36:28.000000", timezone_type: 3, timezone: "UTC" } ] // dùng hàm save() để lưu lại >>> >>> $article->save(); => true >>>
Như các bạn thấy là dù không có những phương thức getter, setter nhưng chúng ta vẫn có thể thiết lập được giá trị cho bài blog. Nhưng thực sự thì khi kế thừa Model của Eloquent là đã có dùng hàm set() sẵn rồi.
Khi có nhiều bài blog ta có thể xem tất cả bằng cách dùng hàm all() như sau
>>> AppArticle::all()->toArray() => [ [ "id" => "1", "title" => "I am a title of blog", "body" => "And i am a content of above title", "created_at" => "2017-01-03 07:36:58", "updated_at" => "2017-01-03 09:13:00", "published_at" => "2017-01-03 10:03:42" ] ] >>>
Trên đây là những thao tác cơ bản nhất với DB thông qua Model và cũng là kết thúc của phần 2. Ở phần sau, chúng ta sẽ đi sâu hơn 1 chút về Eloquent như lấy bản ghi theo id, ném ra ngoại lệ, chỉ định điều kiện tìm kiếm, cập nhật, xoá bỏ, rồi về Mass Assignment và Mutators ...
Nguồn : Laravel10.wordpress.com