Soft Deletes
Author: | ADMIN |
---|
Trong bài viết này, chúng ta sẽ tìm hiểu về một tính năng rất hữu ích trong Laravel - Soft Deletes
Trong Laravel, "Soft Deletes" là một tính năng giúp bạn có thể xóa bản ghi mà không thực sự xóa nó khỏi cơ sở dữ liệu. Thay vào đó, bản ghi sẽ được đánh dấu là đã bị xóa bằng cách thiết lập một trường deleted_at
với thời gian xóa. Bản ghi vẫn tồn tại trong cơ sở dữ liệu nhưng sẽ không được hiển thị trong các truy vấn mặc định.
Cách sử dụng Soft Deletes trong Laravel
-
Thêm Soft Deletes vào Model: Đầu tiên, bạn cần thêm
SoftDeletes
trait vào model của mình.use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Post extends Model { use SoftDeletes; // Các thuộc tính khác của model protected $dates = ['deleted_at']; }
- Thêm cột
deleted_at
vào bảng: Bạn cần phải thêm một cộtdeleted_at
vào bảng tương ứng với model của bạn để lưu trữ thời gian xóa. Bạn có thể làm điều này bằng cách tạo một migration:php artisan make:migration add_deleted_at_to_posts_table --table=posts
Trong file migration:
Schema::table('posts', function (Blueprint $table) { $table->softDeletes(); // Thêm cột deleted_at });
Sau đó, chạy lệnh migrate:
php artisan migrate
-
Sử dụng Soft Deletes trong truy vấn:
-
Để xóa mềm một bản ghi, sử dụng phương thức
delete()
:$post = Post::find(1); $post->delete();
- Để khôi phục một bản ghi đã xóa mềm, sử dụng phương thức
restore()
:
$post = Post::withTrashed()->find(1); $post->restore();
- Để xóa cứng (xóa vĩnh viễn) một bản ghi đã xóa mềm, sử dụng phương thức
forceDelete()
:
$post->forceDelete();
- Để lấy tất cả các bản ghi, bao gồm cả những bản ghi đã bị xóa mềm, sử dụng phương thức
withTrashed()
:
$posts = Post::withTrashed()->get();
- Để chỉ lấy các bản ghi đã bị xóa mềm, sử dụng phương thức
onlyTrashed()
:
$trashedPosts = Post::onlyTrashed()->get();
-
Lợi ích của Soft Deletes
- Khôi phục dữ liệu: Cho phép bạn khôi phục lại các bản ghi đã bị xóa.
- An toàn: Tránh xóa nhầm dữ liệu, đặc biệt là khi cần duyệt lại hoặc kiểm toán dữ liệu đã bị xóa.
Eloquent Collections
Author: | ADMIN |
---|
Eloquent Collections trong Laravel là một tính năng mạnh mẽ cho phép bạn làm việc với tập hợp các model được truy vấn từ cơ sở dữ liệu. Mỗi khi bạn thực hiện một truy vấn Eloquent, kết quả trả về thường là một đối tượng của Illuminate\Database\Eloquent\Collection
. Các Eloquent Collection mở rộng từ Laravel Collection, cung cấp các phương thức hữu ích để thao tác và xử lý dữ liệu một cách dễ dàng.
1. Tổng quan về Eloquent Collections
Khi bạn truy xuất nhiều bản ghi từ cơ sở dữ liệu bằng Eloquent, Laravel sẽ trả về một Collection chứa các model. Ví dụ:
$users = User::all();
Biến $users
ở đây sẽ là một instance của Illuminate\Database\Eloquent\Collection
, chứa tất cả các đối tượng User
trong cơ sở dữ liệu.
Eloquent Collections cung cấp các phương thức mạnh mẽ cho phép bạn duyệt qua, lọc, sắp xếp, và biến đổi các tập hợp model mà không cần phải viết mã phức tạp.
2. Phương thức phổ biến trong Eloquent Collections
append
Phương thức
append
cho phép bạn thêm các thuộc tính ảo vào một collection. Các thuộc tính này không có trong cơ sở dữ liệu nhưng được định nghĩa trong model thông qua Accessors.Ví dụ:
$users = User::all()->append('full_name');
Ở đây,
full_name
là một accessor được định nghĩa trong modelUser
. Thuộc tính này sẽ được thêm vào mỗi model trong collection.-
contains
Phương thức
contains
kiểm tra xem collection có chứa một phần tử cụ thể không. Bạn có thể kiểm tra bằng cách so sánh giá trị thuộc tính hoặc kiểm tra đối tượng model.Ví dụ:
$containsUser = $users->contains('id', 1); $containsUser = $users->contains($someUser);
Phương thức này trả về
true
nếu collection chứa phần tử, ngược lại trả vềfalse
. -
diff
Phương thức
diff
so sánh hai collection và trả về phần tử có trong collection hiện tại nhưng không có trong collection so sánh.Ví dụ:
$users1 = User::where('status', 'active')->get(); $users2 = User::where('status', 'inactive')->get(); $diff = $users1->diff($users2);
Kết quả là các phần tử có trong
$users1
nhưng không có trong$users2
. -
except
Phương thức
except
tạo một collection mới bằng cách loại bỏ các phần tử có khóa hoặc chỉ số cụ thể.Ví dụ:
$users = User::all(); $usersExceptFirst = $users->except([0]);
Kết quả là một collection mới không chứa phần tử tại chỉ số
0
. -
find
Phương thức
find
tìm kiếm phần tử trong collection dựa trên giá trị của khóa chính.Ví dụ:
$user = $users->find(1);
Phương thức này trả về model có ID là
1
, hoặcnull
nếu không tìm thấy. -
6.
fresh
Phương thức
fresh
tải lại model từ cơ sở dữ liệu, cập nhật các thuộc tính của model với giá trị mới nhất.Ví dụ:
$user = User::find(1); $user->name = 'New Name'; $user->fresh();
Sau khi gọi
fresh()
, các thuộc tính của model sẽ được làm mới từ cơ sở dữ liệu. -
intersect
Phương thức
intersect
trả về phần giao nhau của hai collection.Ví dụ:
$users1 = User::where('status', 'active')->get(); $users2 = User::where('status', 'inactive')->get(); $intersect = $users1->intersect($users2);
Kết quả là các phần tử có trong cả
$users1
và$users2
. -
load
Phương thức
load
eager load các quan hệ cho collection của các model.Ví dụ:
$users = User::all()->load('posts');
Phương thức này sẽ tải trước quan hệ
posts
cho tất cả người dùng trong collection. -
loadMissing
Phương thức
loadMissing
tương tự nhưload
, nhưng chỉ tải các quan hệ còn thiếu, không tải lại các quan hệ đã được tải trước đó.Ví dụ:
$users = User::with('posts')->get(); $users->loadMissing('comments');
comments
chỉ được tải nếu chưa được tải từ trước đó. -
modelKeys
Phương thức
modelKeys
trả về một collection chứa các khóa chính của các model trong collection.Ví dụ:
$keys = $users->modelKeys();
Kết quả là một mảng các ID của các người dùng trong collection.
-
makeVisible
Phương thức
makeVisible
thêm các thuộc tính ẩn vào collection, làm cho chúng có thể truy cập được.Ví dụ:
$users = User::all()->makeVisible(['secret_field']);
secret_field
sẽ được thêm vào thuộc tính của model trong collection. -
makeHidden
Phương thức
makeHidden
ẩn các thuộc tính khỏi collection.Ví dụ:
$users = User::all()->makeHidden(['secret_field']);
secret_field
sẽ bị ẩn và không còn có thể truy cập được. -
only
Phương thức
only
tạo một collection mới chỉ với các phần tử có khóa cụ thể.Ví dụ:
$users = User::all()->only(['id', 'name']);
Kết quả là một collection mới chỉ chứa các trường
id
vàname
. -
setVisible
Phương thức
setVisible
thiết lập các thuộc tính của model mà bạn muốn hiển thị trong collection.Ví dụ:
$users = User::all()->setVisible(['name', 'email']);
Chỉ các thuộc tính
name
vàemail
sẽ được hiển thị trong collection. -
setHidden
Phương thức
setHidden
thiết lập các thuộc tính của model mà bạn muốn ẩn trong collection.Ví dụ:
$users = User::all()->setHidden(['password']);
Thuộc tính
password
sẽ bị ẩn và không được hiển thị. -
toQuery
Phương thức
toQuery
trả về một query builder cho collection.Ví dụ:
$query = User::all()->toQuery();
$query
là một instance củaIlluminate\Database\Eloquent\Builder
và có thể tiếp tục được sử dụng để thực hiện các truy vấn. -
unique
Phương thức
unique
loại bỏ các phần tử trùng lặp trong collection dựa trên một thuộc tính hoặc một hàm callback.Ví dụ:
$uniqueUsers = $users->unique('email');
Kết quả là một collection mới chỉ chứa các người dùng có email duy nhất.
Ngoài ra, bạn có thể tham khảo thêm các method khác tại đây
Eloquent Accessors and Mutators
Author: | ADMIN |
---|
Eloquent Accessors và Mutators là các phương thức trong Eloquent của Laravel cho phép bạn điều chỉnh cách dữ liệu được lấy ra hoặc lưu vào cơ sở dữ liệu. Đây là một tính năng mạnh mẽ giúp bạn dễ dàng thao tác và định dạng dữ liệu mà không cần thay đổi logic truy vấn.
1. Accessors (Bộ lấy dữ liệu)
Accessors cho phép bạn thay đổi giá trị của một thuộc tính trước khi trả về nó cho ứng dụng. Điều này giúp bạn có thể định dạng dữ liệu theo cách mong muốn mỗi khi truy vấn model.
Cách sử dụng:
Bạn định nghĩa một accessor bằng cách tạo một phương thức trong model với tên theo cú pháp get{Attribute}Attribute
, trong đó {Attribute}
là tên của thuộc tính bạn muốn định dạng.
Ví dụ:
Giả sử bạn có một model User
với thuộc tính first_name
và last_name
. Bạn muốn kết hợp chúng thành một thuộc tính full_name
khi lấy dữ liệu từ model:
class User extends Model
{
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}
}
Bây giờ, bạn có thể truy cập thuộc tính full_name
như thể nó là một cột trong bảng:
$user = User::find(1);
echo $user->full_name; // John Doe
Laravel sẽ tự động gọi phương thức getFullNameAttribute()
mỗi khi bạn truy cập vào thuộc tính full_name
.
2. Mutators (Bộ chỉnh sửa dữ liệu)
Mutators cho phép bạn thay đổi giá trị của một thuộc tính trước khi lưu nó vào cơ sở dữ liệu. Điều này rất hữu ích khi bạn muốn đảm bảo dữ liệu luôn được lưu theo định dạng nhất định.
Cách sử dụng:
Bạn định nghĩa một mutator bằng cách tạo một phương thức trong model với tên theo cú pháp set{Attribute}Attribute
, trong đó {Attribute}
là tên của thuộc tính bạn muốn thay đổi.
Ví dụ:
Giả sử bạn muốn đảm bảo rằng tất cả các tên người dùng (username
) được lưu vào cơ sở dữ liệu đều ở dạng chữ thường:
class User extends Model
{
public function setUsernameAttribute($value)
{
$this->attributes['username'] = strtolower($value);
}
}
Khi bạn gán giá trị cho thuộc tính username
, Laravel sẽ tự động gọi phương thức setUsernameAttribute()
:
$user = new User;
$user->username = 'JohnDoe';
$user->save();
// username được lưu dưới dạng 'johndoe'
3. Tùy chỉnh thuộc tính với Accessors và Mutators
Bạn có thể sử dụng cả Accessors và Mutators để tạo ra các thuộc tính tuỳ chỉnh không tồn tại trong cơ sở dữ liệu. Đây là cách bạn có thể thao tác với dữ liệu mà không ảnh hưởng đến các cột thực tế trong bảng.
Ví dụ:
Giả sử bạn có một cột birthdate
lưu trữ ngày sinh của người dùng. Bạn muốn tạo một thuộc tính age
để tính toán tuổi từ ngày sinh:
class User extends Model
{
public function getAgeAttribute()
{
return \Carbon\Carbon::parse($this->birthdate)->age;
}
}
Bây giờ, bạn có thể truy cập thuộc tính age
một cách dễ dàng:
$user = User::find(1);
echo $user->age; // 30
4. Lợi ích của Accessors và Mutators
- Tăng tính dễ đọc của mã nguồn: Accessors và Mutators giúp mã của bạn trở nên dễ đọc hơn bằng cách đóng gói logic xử lý dữ liệu vào trong model.
- Đảm bảo tính nhất quán của dữ liệu: Bằng cách sử dụng Mutators, bạn có thể đảm bảo rằng dữ liệu luôn được lưu vào cơ sở dữ liệu theo một định dạng chuẩn xác.
- Tính linh hoạt: Accessors cho phép bạn định dạng dữ liệu theo nhu cầu mà không cần phải thay đổi cấu trúc cơ sở dữ liệu.
5. Các trường hợp sử dụng phổ biến
-
Accessors thường được sử dụng để định dạng dữ liệu khi truy xuất, ví dụ như định dạng ngày tháng, kết hợp nhiều cột thành một, hoặc chuyển đổi mã sang định dạng hiển thị.
-
Mutators thường được sử dụng để xử lý dữ liệu trước khi lưu vào cơ sở dữ liệu, ví dụ như chuyển văn bản sang chữ thường, mã hóa mật khẩu, hoặc định dạng số điện thoại.
Kết luận
Eloquent Accessors và Mutators là công cụ mạnh mẽ trong Laravel giúp bạn quản lý và thao tác dữ liệu một cách dễ dàng và linh hoạt. Bằng cách sử dụng các phương thức này, bạn có thể đảm bảo rằng dữ liệu được định dạng và lưu trữ một cách nhất quán, đồng thời giữ cho mã nguồn của bạn trở nên dễ đọc và dễ bảo trì hơn.
Polymorphic Relationships
Author: | ADMIN |
---|
Polymorphic Relationships là một tính năng mạnh mẽ trong Eloquent của Laravel cho phép một model có thể liên kết với nhiều model khác nhau bằng cách sử dụng một bảng quan hệ duy nhất. Đây là mối quan hệ đặc biệt thường được sử dụng khi một thực thể có thể thuộc về nhiều loại thực thể khác nhau.
1. One-to-One Polymorphic Relationships
One-to-One Polymorphic Relationships cho phép một model có thể liên kết với một model khác trong mối quan hệ một-một, nhưng với khả năng liên kết với nhiều loại model khác nhau. Ví dụ, bạn có thể có một bảng image
chứa các hình ảnh cho cả người dùng (users) và bài viết (posts). Một hình ảnh có thể thuộc về một bài viết hoặc một người dùng.
Ví dụ:
-
Cấu trúc cơ sở dữ liệu:
Đầu tiên, bạn cần tạo các bảng
users
,posts
, vàimages
. Bảngimages
sẽ chứa hai cột đặc biệt làimageable_id
vàimageable_type
để xác định model mà hình ảnh thuộc về.Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->timestamps(); }); Schema::create('images', function (Blueprint $table) { $table->id(); $table->string('url'); $table->morphs('imageable'); $table->timestamps(); });
Ở đây,
morphs('imageable')
sẽ tạo hai cộtimageable_id
vàimageable_type
. -
Định nghĩa quan hệ trong model:
- Trong model
Image
, bạn sẽ định nghĩa phương thứcimageable
để chỉ ra rằng hình ảnh này có thể thuộc về nhiều loại model khác nhau:class Image extends Model { public function imageable() { return $this->morphTo(); } }
- Trong model
User
vàPost
, bạn sẽ định nghĩa một phương thứcimage
để chỉ ra rằng người dùng và bài viết có thể có một hình ảnh:class User extends Model { public function image() { return $this->morphOne(Image::class, 'imageable'); } } class Post extends Model { public function image() { return $this->morphOne(Image::class, 'imageable'); } }
- Trong model
-
Sử dụng One-to-One Polymorphic Relationship:
Bạn có thể thêm và lấy hình ảnh cho người dùng và bài viết như sau:
$user = User::find(1); $image = new Image(['url' => 'user_image.jpg']); $user->image()->save($image); $post = Post::find(1); $image = new Image(['url' => 'post_image.jpg']); $post->image()->save($image);
Để lấy hình ảnh của một người dùng hoặc bài viết:
$userImage = $user->image; $postImage = $post->image;
2. One-to-Many Polymorphic Relationships
One-to-Many Polymorphic Relationships cho phép một model có thể liên kết với nhiều model khác nhau. Ví dụ điển hình là một bảng comments
có thể chứa các bình luận cho cả bài viết (posts) và video (videos). Cả hai model Post
và Video
có thể chia sẻ cùng một bảng comments
.
Ví dụ:
-
Cấu trúc cơ sở dữ liệu:
Bạn cần có các bảng
posts
,videos
, vàcomments
. Bảngcomments
sẽ chứa hai cột đặc biệt làcommentable_id
vàcommentable_type
để theo dõi ID và loại model mà nó liên kết.Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->timestamps(); }); Schema::create('videos', function (Blueprint $table) { $table->id(); $table->string('title'); $table->timestamps(); }); Schema::create('comments', function (Blueprint $table) { $table->id(); $table->text('body'); $table->morphs('commentable'); $table->timestamps(); });
Ở đây,
morphs('commentable')
là một shortcut để tạo hai cộtcommentable_id
vàcommentable_type
. -
Định nghĩa quan hệ trong model:
- Trong model
Comment
, bạn sẽ định nghĩa một phương thứccommentable
để chỉ ra rằng comment này có thể thuộc về nhiều model khác nhau:
class Comment extends Model { public function commentable() { return $this->morphTo(); } }
- Trong model
Post
vàVideo
, bạn sẽ định nghĩa một phương thứccomments
để chỉ ra rằng các bài viết và video có thể có nhiều comment:
class Post extends Model { public function comments() { return $this->morphMany(Comment::class, 'commentable'); } } class Video extends Model { public function comments() { return $this->morphMany(Comment::class, 'commentable'); } }
- Trong model
-
Sử dụng Polymorphic Relationship:
Bạn có thể thêm và lấy các bình luận cho các bài viết và video như sau:
$post = Post::find(1); $comment = new Comment(['body' => 'Great post!']); $post->comments()->save($comment); $video = Video::find(1); $comment = new Comment(['body' => 'Nice video!']); $video->comments()->save($comment);
Để lấy tất cả các bình luận cho một bài viết hoặc video:
$postComments = $post->comments; $videoComments = $video->comments;
3. Many-to-Many Polymorphic Relationships
Many-to-Many Polymorphic Relationships cho phép một model có thể có mối quan hệ nhiều-nhiều với nhiều model khác nhau. Ví dụ, một bảng tags
có thể được liên kết với cả posts
và videos
.
Ví dụ:
-
Cấu trúc cơ sở dữ liệu:
Bạn cần có các bảng
posts
,videos
,tags
, vàtaggables
. Bảngtaggables
sẽ chứa hai cộttaggable_id
vàtaggable_type
để xác định loại thực thể mà nó liên kết (bài viết hoặc video).Schema::create('tags', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); Schema::create('taggables', function (Blueprint $table) { $table->morphs('taggable'); $table->foreignId('tag_id')->constrained(); $table->timestamps(); });
-
Định nghĩa quan hệ trong model:
- Trong model
Tag
, bạn sẽ định nghĩa phương thứctaggables
để chỉ ra rằng tag này có thể thuộc về nhiều loại model khác nhau:class Tag extends Model { public function taggables() { return $this->morphedByMany(Post::class, 'taggable'); } }
- Trong model
Post
vàVideo
, bạn sẽ định nghĩa một phương thứctags
để chỉ ra rằng bài viết và video có thể có nhiều tag:class Post extends Model { public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } } class Video extends Model { public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } }
- Trong model
-
Sử dụng Many-to-Many Polymorphic Relationship:
Bạn có thể thêm và lấy các tag cho bài viết và video như sau:
$post = Post::find(1); $tag = Tag::find(1); $post->tags()->attach($tag); $video = Video::find(1); $video->tags()->attach($tag);
Để lấy tất cả các tag cho một bài viết hoặc video:
$postTags = $post->tags; $videoTags = $video->tags;
4. Lợi ích của Polymorphic Relationships
- Tính linh hoạt: Bạn có thể thiết kế cơ sở dữ liệu linh hoạt hơn, cho phép các thực thể khác nhau có thể chia sẻ cùng một bảng quan hệ.
- Tái sử dụng: Polymorphic Relationships giúp tránh lặp lại các bảng quan hệ không cần thiết, giảm phức tạp của cơ sở dữ liệu.
- Tiết kiệm thời gian: Bạn có thể quản lý nhiều loại dữ liệu mà không cần phải tạo ra quá nhiều bảng phụ thuộc, giúp tiết kiệm thời gian trong quá trình phát triển và bảo trì.
Kết luận
Polymorphic Relationships trong Laravel là một công cụ cực kỳ mạnh mẽ và linh hoạt giúp bạn quản lý các mối quan hệ phức tạp trong cơ sở dữ liệu. Việc hiểu rõ và tận dụng tính năng này sẽ giúp bạn tối ưu hóa cấu trúc dữ liệu và mã nguồn của mình, đồng thời làm cho quá trình phát triển ứng dụng trở nên dễ dàng hơn.
Eloquent Query Scopes
Author: | ADMIN |
---|
Eloquent Query Scopes là một tính năng mạnh mẽ trong Laravel, giúp bạn tái sử dụng các đoạn mã truy vấn một cách dễ dàng. Bằng cách định nghĩa các scope, bạn có thể gom nhóm các truy vấn phức tạp thành các phương thức có thể tái sử dụng trên nhiều nơi trong ứng dụng.
Tổng quan
1. Local Scopes (Phạm vi cục bộ)
Local scopes cho phép bạn định nghĩa một truy vấn cụ thể ngay trong model và có thể được gọi trực tiếp từ các truy vấn Eloquent. Một scope cục bộ được định nghĩa bằng cách tạo một phương thức trong model và bắt đầu tên phương thức bằng từ khoá scope
.
Ví dụ:
Giả sử bạn có một model User
và bạn muốn tạo một scope để lấy tất cả các người dùng đã kích hoạt:
class User extends Model
{
public function scopeActive($query)
{
return $query->where('active', 1);
}
}
Bạn có thể sử dụng scope này trong các truy vấn của mình như sau:
$activeUsers = User::active()->get();
Phương thức scopeActive
sẽ được gọi một cách tự động khi bạn sử dụng active()
trong truy vấn. Scope này giúp mã trở nên ngắn gọn, dễ đọc và có thể tái sử dụng nhiều lần.
2. Dynamic Scopes (Phạm vi động)
Dynamic scopes cho phép bạn truyền tham số vào các phương thức scope để tuỳ chỉnh truy vấn dựa trên tham số đó.
Ví dụ:
Nếu bạn muốn tạo một scope để lấy người dùng dựa trên độ tuổi:
class User extends Model
{
public function scopeOfAge($query, $age)
{
return $query->where('age', $age);
}
}
Bạn có thể sử dụng scope này như sau:
$users = User::ofAge(25)->get();
Scope ofAge
sẽ nhận một tham số $age
và trả về danh sách người dùng có độ tuổi tương ứng.
3. Global Scopes (Phạm vi toàn cục)
Global scopes được áp dụng tự động trên mọi truy vấn của một model. Chúng thường được sử dụng khi bạn muốn áp dụng một điều kiện chung cho tất cả các truy vấn liên quan đến model đó. Để tạo một global scope, bạn cần định nghĩa một class riêng biệt và implement interface Scope
.
Ví dụ:
Giả sử bạn muốn áp dụng một scope để chỉ lấy những người dùng đã kích hoạt trong tất cả các truy vấn liên quan đến model User
:
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class ActiveScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
return $builder->where('active', 1);
}
}
Sau đó, bạn thêm scope này vào trong model User
:
class User extends Model
{
protected static function booted()
{
static::addGlobalScope(new ActiveScope);
}
}
Bây giờ, mọi truy vấn liên quan đến model User
sẽ tự động thêm điều kiện where('active', 1)
.
4. Xoá Global Scopes
Nếu bạn muốn loại bỏ một global scope khỏi một truy vấn cụ thể, bạn có thể sử dụng phương thức withoutGlobalScope
.
Ví dụ:
$users = User::withoutGlobalScope(ActiveScope::class)->get();
Lệnh này sẽ loại bỏ scope ActiveScope
và trả về tất cả người dùng, kể cả những người dùng chưa kích hoạt.
Lợi ích của Eloquent Query Scopes
- Tái sử dụng: Các scope giúp bạn tránh lặp lại mã bằng cách gom nhóm các điều kiện truy vấn chung vào một nơi có thể tái sử dụng.
- Tăng tính rõ ràng: Sử dụng scopes giúp mã nguồn dễ đọc hơn và rõ ràng hơn, đặc biệt là khi truy vấn phức tạp.
- Dễ bảo trì: Khi cần thay đổi một điều kiện truy vấn, bạn chỉ cần thay đổi trong scope và tất cả các truy vấn khác sẽ tự động cập nhật theo.
Kết luận
Eloquent Query Scopes là một công cụ tuyệt vời giúp bạn tối ưu hoá và tổ chức mã nguồn của mình. Bằng cách sử dụng Local Scopes, Dynamic Scopes và Global Scopes, bạn có thể dễ dàng tái sử dụng các truy vấn phức tạp và giữ cho mã nguồn của mình ngắn gọn, dễ bảo trì.
Eloquent: Factories (P2)
Author: | ADMIN |
---|
Ở bài trước, chúng ta đã nắm sơ bộ về Eloquent Factories rồi, tiếp theo, chúng ta cùng tìm hiểu tiếp các Relationships trong Factories nhé.
# Many to Many Relationships
Laravel cung cấp nhiều cách để xây dựng và quản lý các mối quan hệ giữa các mô hình bằng cách sử dụng factories. Dưới đây là hướng dẫn chi tiết về các loại mối quan hệ khác nhau và cách sử dụng factories để tạo chúng.
1. Quan Hệ Many-to-Many
Khi hai mô hình có mối quan hệ nhiều-mối quan hệ, bạn có thể sử dụng phương thức hasAttached
của factory để liên kết chúng qua bảng pivot.
Tạo Mô Hình Với Mối Quan Hệ Many-to-Many
Giả sử bạn có mô hình User
và Role
, và bạn muốn tạo một người dùng với ba vai trò:
use App\Models\Role;
use App\Models\User;
$user = User::factory()
->hasAttached(
Role::factory()->count(3),
['active' => true] // Thuộc tính trên bảng pivot
)
->create();
Sử Dụng Closure Để Thay Đổi Trạng Thái
Nếu trạng thái cần truy cập mô hình liên quan, bạn có thể sử dụng closure:
$user = User::factory()
->hasAttached(
Role::factory()
->count(3)
->state(function (array $attributes, User $user) {
return ['name' => $user->name.' Role'];
}),
['active' => true]
)
->create();
Sử Dụng Các Mô Hình Hiện Có
Nếu bạn đã có các mô hình để liên kết, bạn có thể truyền chúng vào phương thức hasAttached
:
$roles = Role::factory()->count(3)->create();
$user = User::factory()
->count(3)
->hasAttached($roles, ['active' => true])
->create();
Sử Dụng Các Phương Thức "Magic"
Để tiện lợi, bạn có thể sử dụng phương thức "ma thuật" để tạo quan hệ nhiều-mối quan hệ:
$user = User::factory()
->hasRoles(1, [
'name' => 'Editor'
])
->create();
# Quan Hệ "Đa Hình" (Polymorphic Relationships)
Các quan hệ đa hình có thể được tạo bằng factories như các quan hệ bình thường.
Quan Hệ Morph Many
Nếu mô hình Post
có mối quan hệ morphMany
với mô hình Comment
:
use App\Models\Post;
$post = Post::factory()->hasComments(3)->create();
Morph To Relationships
Để tạo các quan hệ morphTo
, bạn không thể sử dụng các phương thức "ma thuật". Thay vào đó, bạn sử dụng phương thức for
:
$comments = Comment::factory()->count(3)->for(
Post::factory(), 'commentable'
)->create();
Quan Hệ "Many-to-Many" Đa Hình
Quan hệ nhiều-mối quan hệ đa hình có thể được tạo giống như các quan hệ nhiều-mối quan hệ không phải đa hình:
use App\Models\Tag;
use App\Models\Video;
$videos = Video::factory()
->hasAttached(
Tag::factory()->count(3),
['public' => true]
)
->create();
Bạn cũng có thể sử dụng phương thức "ma thuật":
$videos = Video::factory()
->hasTags(3, ['public' => true])
->create();
Định Nghĩa Quan Hệ Trong Factory
Để định nghĩa một mối quan hệ trong factory của mô hình, bạn thường gán một instance factory mới cho khóa ngoại của mối quan hệ.
Định Nghĩa Quan Hệ "Belongs To"
Ví dụ, nếu bạn muốn tạo một người dùng mới khi tạo một bài viết, bạn có thể làm như sau:
use App\Models\User;
/**
* Định nghĩa trạng thái mặc định của mô hình.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->title(),
'content' => fake()->paragraph(),
];
}
Sử Dụng Closure Để Định Nghĩa Trạng Thái
Nếu các cột của mối quan hệ phụ thuộc vào factory định nghĩa nó, bạn có thể gán một closure cho thuộc tính:
public function definition(): array
{
return [
'user_id' => User::factory(),
'user_type' => function (array $attributes) {
return User::find($attributes['user_id'])->type;
},
'title' => fake()->title(),
'content' => fake()->paragraph(),
];
}
Tái Sử Dụng Một Mô Hình Đã Tạo
Nếu bạn có các mô hình chia sẻ một mối quan hệ chung với một mô hình khác, bạn có thể sử dụng phương thức recycle
để đảm bảo một instance của mô hình liên quan được tái sử dụng cho tất cả các mối quan hệ được tạo bởi factory.
Tái Sử Dụng Một Mô Hình Để Liên Kết
Ví dụ, nếu bạn có các mô hình Airline
, Flight
, và Ticket
, và bạn muốn đảm bảo rằng cùng một hãng hàng không được sử dụng cho cả vé và chuyến bay, bạn có thể làm như sau:
Ticket::factory()
->recycle(Airline::factory()->create())
->create();
Tái Sử Dụng Một Bộ Sưu Tập Mô Hình
Bạn cũng có thể truyền một bộ sưu tập mô hình vào phương thức recycle
. Khi có bộ sưu tập, một mô hình ngẫu nhiên từ bộ sưu tập sẽ được chọn khi factory cần một mô hình loại đó:
$airlines = Airline::factory()->count(3)->create();
Ticket::factory()
->recycle($airlines)
->create();
Eloquent: Factories
Author: | ADMIN |
---|
Ở 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é
Middleware
Author: | ADMIN |
---|
Middleware cung cấp một cơ chế lọc các yêu cầu HTTP vào ứng dụng của bạn. Ví dụ, Laravel bao gồm một middleware kiểm tra người dùng của bạn có xác thực hay chưa. Nếu người dùng không xác thực, middleware sẽ chuyển hướng người dùng đến trang đăng nhập. Tuy nhiên, nếu người dùng đã xác thực, middleware sẽ cho phép yêu cầu tiếp tục vào ứng dụng.
Dưới đây là các bước để định nghĩa middleware trong Laravel:
1. Tạo Middleware
Để tạo middleware, bạn có thể sử dụng lệnh Artisan sau:
php artisan make:middleware CheckAge
Lệnh này sẽ tạo ra một lớp middleware mới tại app/Http/Middleware/CheckAge.php
. Trong lớp middleware này, bạn chỉ cần định nghĩa phương thức handle
.
2. Định nghĩa Middleware
Trong lớp middleware, bạn có thể viết logic để kiểm tra hoặc xử lý yêu cầu. Ví dụ, dưới đây là cách middleware kiểm tra độ tuổi của người dùng:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckAge
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
Trong ví dụ này, nếu độ tuổi của người dùng nhỏ hơn hoặc bằng 200, middleware sẽ chuyển hướng họ về trang chủ. Nếu không, yêu cầu sẽ tiếp tục được xử lý.
3. Đăng ký Middleware
Sau khi tạo middleware, bạn cần đăng ký nó trong ứng dụng. Có hai cách để đăng ký middleware: toàn cục và nhóm.
3.1. Middleware Global
Để đăng ký middleware toàn cục, bạn thêm nó vào thuộc tính $middleware
trong app/Http/Kernel.php
:
protected $middleware = [
// Other middleware
\App\Http\Middleware\CheckAge::class,
];
3.2. Middleware Groups
Để đăng ký middleware nhóm, bạn thêm nó vào thuộc tính $middlewareGroups
trong app/Http/Kernel.php
. Ví dụ, bạn có thể thêm middleware vào nhóm web
:
protected $middlewareGroups = [
'web' => [
// Other middleware
\App\Http\Middleware\CheckAge::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
3.3. Middleware Định Tuyến
Bạn có thể gán middleware cho các tuyến cụ thể bằng cách sử dụng phương thức middleware
trong file routes/web.php
hoặc routes/api.php
:
Route::get('admin/profile', function () {
// Only authenticated users may enter...
})->middleware('auth', 'check.age');
4. Middleware Tham Số
Middleware cũng có thể chấp nhận tham số. Ví dụ, bạn có thể tạo middleware để kiểm tra vai trò của người dùng:
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
Sau đó, bạn có thể gán middleware này cho một tuyến với tham số:
Route::put('post/{id}', function ($id) {
// Update the post...
})->middleware('role:editor');
# Middleware and Responses
Middleware có thể thực hiện các tác vụ trước hoặc sau khi chuyển tiếp yêu cầu vào sâu hơn trong ứng dụng. Ví dụ, middleware sau đây sẽ thực hiện một số tác vụ trước khi yêu cầu được xử lý bởi ứng dụng:
Ví dụ Middleware
Dưới đây là một ví dụ về middleware thực hiện một số tác vụ trước khi xử lý yêu cầu:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class BeforeMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// Thực hiện một số tác vụ trước khi yêu cầu được xử lý
// Ví dụ: kiểm tra điều kiện hoặc ghi log
if ($request->user() && $request->user()->isBlocked()) {
return response('Your account is blocked.', 403);
}
// Chuyển tiếp yêu cầu vào sâu hơn trong ứng dụng
return $next($request);
}
}
Thực hiện tác vụ sau khi xử lý yêu cầu
Middleware cũng có thể thực hiện các tác vụ sau khi yêu cầu đã được xử lý. Để làm điều này, bạn chỉ cần thêm logic sau khi gọi hàm $next($request)
:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class AfterMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// Xử lý yêu cầu
$response = $next($request);
// Thực hiện một số tác vụ sau khi yêu cầu đã được xử lý
// Ví dụ: thêm header vào phản hồi
$response->header('X-Header-One', 'Header Value');
return $response;
}
}
Trong ví dụ trên, middleware sẽ thêm một header vào phản hồi sau khi yêu cầu đã được xử lý bởi ứng dụng.
# Sorting Middleware
Trong Laravel, bạn có thể chỉ định thứ tự thực hiện của các middleware. Việc sắp xếp này có thể hữu ích khi bạn cần một middleware phải được thực thi trước hoặc sau một middleware khác. Laravel cung cấp một cách dễ dàng để sắp xếp thứ tự của các middleware thông qua thuộc tính $middlewarePriority
trong lớp App\Http\Kernel
.
Định nghĩa Thứ Tự Middleware
Để sắp xếp thứ tự thực hiện của middleware, bạn chỉ cần thêm thuộc tính $middlewarePriority
vào lớp App\Http\Kernel
và liệt kê các middleware theo thứ tự bạn muốn chúng được thực thi:
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
// Danh sách các middleware toàn cục
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
// Danh sách các middleware nhóm 'web'
],
'api' => [
// Danh sách các middleware nhóm 'api'
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
// Danh sách các route middleware
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
\App\Http\Middleware\FirstMiddleware::class,
\App\Http\Middleware\SecondMiddleware::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\AnotherMiddleware::class,
// Thêm các middleware khác theo thứ tự bạn muốn
];
}
Trong ví dụ trên, FirstMiddleware
sẽ được thực thi trước SecondMiddleware
, và AnotherMiddleware
sẽ được thực thi sau StartSession
và ShareErrorsFromSession
.
Ví Dụ Về Middleware
Dưới đây là ví dụ về hai middleware mà bạn muốn sắp xếp thứ tự thực hiện:
FirstMiddleware
:
<?php namespace App\Http\Middleware; use Closure; class FirstMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { // Logic của FirstMiddleware return $next($request); } }
SecondMiddleware
:
<?php namespace App\Http\Middleware; use Closure; class SecondMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { // Logic của SecondMiddleware return $next($request); } }
Kết Hợp Với Route
Sau khi định nghĩa thứ tự của middleware, bạn có thể gán chúng cho các tuyến hoặc nhóm tuyến trong tệp routes/web.php
hoặc routes/api.php
:
// routes/web.php
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', 'HomeController@index');
});
// Hoặc sử dụng trực tiếp trong các tuyến:
Route::get('/example', 'ExampleController@index')->middleware('first', 'second');
# Terminable Middleware
Trong Laravel, middleware có thể được chia thành hai loại chính: middleware thực thi trong quá trình xử lý yêu cầu và middleware thực thi sau khi phản hồi đã được gửi đến client. Middleware thuộc loại thứ hai được gọi là "terminable middleware".
Terminable middleware cho phép bạn thực hiện các công việc sau khi phản hồi đã được gửi về phía client, chẳng hạn như ghi log hoặc thực hiện các tác vụ tốn thời gian mà bạn không muốn làm chậm thời gian phản hồi của ứng dụng.
Tạo Middleware Terminable
Để tạo một terminable middleware, bạn cần tạo một middleware như bình thường và thêm phương thức terminate
vào lớp middleware đó. Phương thức terminate
sẽ được tự động gọi sau khi phản hồi đã được gửi về phía client.
- Tạo Middleware bằng Artisan:
php artisan make:middleware LogAfterRequest
- Định nghĩa Middleware với phương thức
terminate
:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class LogAfterRequest { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle(Request $request, Closure $next) { // Thực hiện các công việc trước khi xử lý yêu cầu return $next($request); } /** * Handle tasks after the response has been sent to the client. * * @param \Illuminate\Http\Request $request * @param \Symfony\Component\HttpFoundation\Response $response * @return void */ public function terminate(Request $request, Response $response) { // Thực hiện các công việc sau khi phản hồi đã được gửi đến client \Log::info('Request has been completed.'); } }
Đăng Ký Middleware
Bạn cần đăng ký middleware trong tệp app/Http/Kernel.php
để Laravel có thể nhận diện và sử dụng middleware đó:
- Thêm middleware vào thuộc tính
$middleware
hoặc$routeMiddleware
của lớpKernel
:
// app/Http/Kernel.php protected $middleware = [ // Các middleware khác \App\Http\Middleware\LogAfterRequest::class, ];
- Nếu bạn muốn middleware này chỉ áp dụng cho một số tuyến cụ thể, bạn có thể thêm vào thuộc tính
$routeMiddleware
:
// app/Http/Kernel.php protected $routeMiddleware = [ // Các route middleware khác 'log.after' => \App\Http\Middleware\LogAfterRequest::class, ];
- Sử dụng middleware trong tuyến của bạn:
// routes/web.php Route::get('/example', 'ExampleController@index')->middleware('log.after');
Kết Hợp với Các Tác Vụ Sau Phản Hồi
Bạn có thể sử dụng terminable middleware để thực hiện các tác vụ sau khi phản hồi đã được gửi đến client, chẳng hạn như:
- Ghi log các yêu cầu và phản hồi
- Gửi email
- Thực hiện các tác vụ bảo trì
- Đặt lại các kết nối hoặc phiên làm việc
Ví dụ, bạn có thể sử dụng phương thức terminate
để ghi lại log các thông tin về yêu cầu và phản hồi:
public function terminate(Request $request, Response $response)
{
\Log::info('Request URL: ' . $request->fullUrl());
\Log::info('Response Status: ' . $response->status());
}
Database: Seeding
Author: | ADMIN |
---|
Seeding trong Laravel là một cách để tự động thêm dữ liệu mẫu vào cơ sở dữ liệu của bạn. Điều này hữu ích khi bạn cần tạo ra dữ liệu thử nghiệm hoặc khởi tạo dữ liệu mặc định cho ứng dụng.
Tạo Seeder
Bạn có thể tạo một seeder mới bằng cách sử dụng lệnh Artisan:
php artisan make:seeder UsersTableSeeder
Lệnh này sẽ tạo một file seeder mới trong thư mục database/seeders
.
Định Nghĩa Seeder
Khi bạn mở file seeder, nó sẽ trông giống như sau:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Đoạn mã để chèn dữ liệu mẫu vào bảng users
}
}
Bạn có thể sử dụng phương thức DB::table
hoặc các phương thức của Eloquent để chèn dữ liệu vào bảng:
public function run()
{
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'@gmail.com',
'password' => bcrypt('password'),
]);
}
Hoặc sử dụng model Eloquent:
public function run()
{
\App\Models\User::create([
'name' => 'John Doe',
'email' => 'johndoe@example.com',
'password' => bcrypt('password'),
]);
}
Gọi Seeder
Sau khi định nghĩa seeder, bạn cần gọi nó trong lớp DatabaseSeeder
để nó được chạy khi bạn chạy lệnh seed:
// database/seeders/DatabaseSeeder.php
public function run()
{
$this->call(UsersTableSeeder::class);
}
Chạy Seeder
Bạn có thể chạy tất cả các seeder bằng lệnh Artisan:
php artisan db:seed
Hoặc chạy một seeder cụ thể:
php artisan db:seed --class=UsersTableSeeder
Tái Tạo Cơ Sở Dữ Liệu
Nếu bạn muốn làm mới cơ sở dữ liệu và chạy lại các seeder, bạn có thể sử dụng lệnh migrate:fresh
:
php artisan migrate:fresh --seed
Lệnh này sẽ xóa tất cả các bảng trong cơ sở dữ liệu của bạn và chạy lại tất cả các migration và seeder.
Tùy chọn --seeder có thể được sử dụng để chỉ định một seeder cụ thể để chạy:
php artisan migrate:fresh --seed --seeder=UserSeeder
Sử Dụng Factory trong Seeder
Laravel có thể tích hợp factory với seeder để tạo ra dữ liệu mẫu phong phú hơn. Ví dụ, bạn có thể sử dụng factory để tạo nhiều người dùng một cách dễ dàng:
public function run()
{
\App\Models\User::factory(10)->create();
}
Forcing Seeders to Run in Production
Khi làm việc với Laravel, bạn có thể muốn chạy seeder (tạo dữ liệu mẫu) ngay cả khi ứng dụng đang ở môi trường production. Điều này thường bị ngăn chặn để tránh nguy cơ làm hỏng dữ liệu thực tế. Tuy nhiên, đôi khi bạn vẫn cần phải chạy seeder trong môi trường production, và Laravel cung cấp cách để làm điều này một cách an toàn.
php artisan db:seed --force
Cờ --force
sẽ bỏ qua cảnh báo và cho phép seeder chạy ngay cả khi ứng dụng đang ở môi trường production.
Ví dụ Thực Tế
Giả sử bạn có một seeder gọi là DatabaseSeeder
và bạn muốn chạy nó trong môi trường production. Bạn chỉ cần chạy lệnh sau từ dòng lệnh:
php artisan db:seed --class=DatabaseSeeder --force
Lệnh trên sẽ thực hiện seeding dữ liệu từ DatabaseSeeder
vào cơ sở dữ liệu hiện tại, ngay cả khi ứng dụng đang ở môi trường production.
Chạy Seeder Cụ Thể
Nếu bạn chỉ muốn chạy một seeder cụ thể trong môi trường production, bạn có thể chỉ định seeder đó với cờ --class
cùng với --force
. Ví dụ:
php artisan db:seed --class=UsersTableSeeder --force
Điều này sẽ chỉ chạy seeder UsersTableSeeder
.
Sử Dụng Migrate với Seeder
Nếu bạn muốn chạy migration kèm theo seeder trong môi trường production, bạn có thể sử dụng lệnh migrate:fresh
hoặc migrate
cùng với cờ --seed
và --force
:
php artisan migrate:fresh --seed --force
// or
php artisan migrate --seed --force
Cả hai lệnh trên sẽ chạy migration để tạo lại hoặc cập nhật các bảng trong cơ sở dữ liệu và sau đó chạy seeder.
Hiển thị giá trị trong Blade
Author: | ADMIN |
---|
# Hiển Thị Biến Trong Blade
Trong Laravel Blade, việc hiển thị biến rất đơn giản và trực quan. Blade cung cấp cú pháp dễ đọc và sử dụng để nhúng các biến PHP vào trong HTML.
Cú Pháp Cơ Bản
Sử Dụng Cặp Dấu Ngoặc Nhanh {{ }}
Để hiển thị giá trị của một biến trong Blade, bạn chỉ cần sử dụng cặp dấu ngoặc nhanh {{ }}
.
Ví Dụ
Giả sử bạn có một biến $name
được truyền từ controller đến view:
public function show()
{
$name = 'John Doe';
return view('greeting', compact('name'));
}
Trong file view greeting.blade.php
, bạn có thể hiển thị giá trị của biến $name
như sau:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Greeting Page</title>
</head>
<body>
<h1>Hello, {{ $name }}!</h1>
</body>
</html>
Escape HTML Đầu Vào
Khi sử dụng cặp dấu ngoặc nhanh {{ }}
, Blade sẽ tự động escape (chuyển đổi các ký tự đặc biệt thành các thực thể HTML) để bảo vệ chống lại các cuộc tấn công XSS.
Ví Dụ
<?php $name = '<script>alert("XSS")</script>'; ?>
<h1>Hello, {{ $name }}!</h1>
Kết quả hiển thị sẽ là:
<h1>Hello, <script>alert("XSS")</script>!</h1>
Hiển Thị Biến Mà Không Escape HTML
Nếu bạn muốn hiển thị giá trị của biến mà không escape HTML, bạn có thể sử dụng cú pháp {!! !!}
.
<?php $name = '<strong>John Doe</strong>'; ?>
<h1>Hello, {!! $name !!}!</h1>
Kết quả hiển thị sẽ là:
<h1>Hello, <strong>John Doe</strong>!</h1>
Hiển Thị Các Giá Trị Mặc Định
Bạn có thể hiển thị các giá trị mặc định khi biến không tồn tại hoặc rỗng bằng cách sử dụng toán tử null coalescing ??
.
Ví Dụ
<h1>Hello, {{ $name ?? 'Guest' }}!</h1>
Nếu biến $name
không tồn tại hoặc có giá trị là null, chuỗi 'Guest'
sẽ được hiển thị.
Hiển Thị Mảng và Đối Tượng
Bạn có thể truy cập và hiển thị các phần tử của mảng hoặc thuộc tính của đối tượng một cách dễ dàng.
Ví Dụ Mảng
<?php $user = ['name' => 'John Doe', 'email' => 'john@example.com']; ?>
<h1>Name: {{ $user['name'] }}</h1>
<p>Email: {{ $user['email'] }}</p>
Ví Dụ Đối Tượng
<?php $user = (object) ['name' => 'John Doe', 'email' => 'john@example.com']; ?>
<h1>Name: {{ $user->name }}</h1>
<p>Email: {{ $user->email }}</p>
Tóm Tắt
- Cú pháp cơ bản: Sử dụng
{{ $variable }}
để hiển thị giá trị của biến và tự động escape HTML.- Không escape HTML: Sử dụng
{!! $variable !!}
để hiển thị giá trị của biến mà không escape HTML.- Giá trị mặc định: Sử dụng
{{ $variable ?? 'default' }}
để hiển thị giá trị mặc định khi biến không tồn tại hoặc rỗng.- Mảng và đối tượng: Truy cập và hiển thị các phần tử của mảng hoặc thuộc tính của đối tượng bằng cú pháp
{{ $array['key'] }}
và{{ $object->property }}
.Việc sử dụng các cú pháp này giúp bạn dễ dàng và an toàn khi hiển thị dữ liệu trong các view Blade của Laravel.
Database: Pagination
Author: | ADMIN |
---|
# Database: Pagination
Phân trang (pagination) là một kỹ thuật quan trọng để phân chia dữ liệu lớn thành các trang nhỏ hơn, giúp người dùng dễ dàng duyệt qua dữ liệu mà không phải tải toàn bộ dữ liệu cùng một lúc. Laravel cung cấp các phương pháp đơn giản để thực hiện phân trang với Eloquent và Query Builder.
1. Phân Trang Với Eloquent
Khi sử dụng Eloquent để truy vấn dữ liệu, bạn có thể sử dụng phương thức paginate
để phân trang kết quả. Ví dụ, giả sử bạn có một model Post
, bạn có thể phân trang các bài viết như sau:
// Lấy 10 bài viết mỗi trang
$posts = App\Models\Post::paginate(10);
// or
$users = DB::table('users')->paginate(10);
paginate($perPage)
: Phương thức này trả về một đối tượngLengthAwarePaginator
, chứa các bài viết cho trang hiện tại và thông tin phân trang.
Bạn có thể sử dụng biến $posts
trong view Blade để hiển thị dữ liệu và các liên kết phân trang:
@foreach ($posts as $post)
<div>{{ $post->title }}</div>
@endforeach
{{ $posts->links() }}
2. Phân Trang Tuỳ Chỉnh
Bạn có thể tùy chỉnh phân trang bằng cách thay đổi số lượng bản ghi trên mỗi trang hoặc thêm các tham số khác:
// Lấy 15 bản ghi mỗi trang và tùy chỉnh các tham số khác
$posts = App\Models\Post::paginate(15, ['*'], 'page', $currentPage);
$currentPage
: Bạn có thể chỉ định số trang hiện tại nếu cần thiết.
# Tùy Chỉnh URL Phân Trang
Laravel cho phép bạn tùy chỉnh URL phân trang để phù hợp với các yêu cầu hoặc cấu trúc URL của ứng dụng. Đây là các cách bạn có thể thực hiện việc này:
1. Tùy Chỉnh Tham Số URL
Bạn có thể tùy chỉnh các tham số của URL phân trang bằng cách sử dụng phương thức appends
để thêm các tham số bổ sung vào các liên kết phân trang. Ví dụ, nếu bạn muốn giữ lại các tham số truy vấn hiện tại trong URL phân trang:
$posts = App\Models\Post::paginate(10)->appends(['sort' => 'desc']);
appends($array)
: Thêm các tham số bổ sung vào URL phân trang.
Ví dụ trong view Blade:
@foreach ($posts as $post)
<div>{{ $post->title }}</div>
@endforeach
{{ $posts->appends(['sort' => 'desc'])->links() }}
2. Tùy Chỉnh Đường Dẫn Phân Trang
$users->withPath('/admin/users');
withPath('/admin/users')
: Phương thức này được sử dụng để tùy chỉnh đường dẫn phân trang. Thay vì sử dụng đường dẫn mặc định, bạn có thể chỉ định một đường dẫn khác cho các liên kết phân trang.
# Các Phương Thức Của Paginator
/ LengthAwarePaginator
Khi làm việc với phân trang trong Laravel, bạn sẽ thường xuyên sử dụng các phương thức của lớp Paginator
hoặc LengthAwarePaginator
. Dưới đây là các phương thức chính và cách sử dụng chúng:
$users = User::paginate(15);
// Số mục trên trang hiện tại
$count = $users->count();
// Số trang hiện tại
$currentPage = $users->currentPage();
// Số thứ tự của mục đầu tiên
$firstItem = $users->firstItem();
// Các tùy chọn phân trang
$options = $users->getOptions();
// Dãy URL từ trang 1 đến trang 5
$urls = $users->getUrlRange(1, 5);
// Kiểm tra có nhiều trang không
$hasPages = $users->hasPages();
// Kiểm tra có còn trang kế tiếp không
$hasMore = $users->hasMorePages();
// Các mục trên trang hiện tại
$items = $users->items();
// Số thứ tự của mục cuối cùng
$lastItem = $users->lastItem();
// Số trang cuối cùng
$lastPage = $users->lastPage();
// URL của trang kế tiếp
$nextPageUrl = $users->nextPageUrl();
// Kiểm tra có đang ở trang đầu tiên không
$onFirstPage = $users->onFirstPage();
// Số lượng mục trên mỗi trang
$perPage = $users->perPage();
// URL của trang trước đó
$previousPageUrl = $users->previousPageUrl();
// Tổng số mục
$total = $users->total();
// URL của trang số 2
$url = $users->url(2);
// Biến truy vấn để lưu trữ số trang
$pageName = $users->getPageName();
// Đặt tên biến truy vấn để lưu trữ số trang
$users->setPageName('page');
// Chuyển đổi từng mục để chỉ lấy tên người dùng return $user->name;
$transformedUsers = $users->through(function ($user) {
return $user->name;
});
# Các Phương Thức Của CursorPaginator
Method | Description |
$paginator->count()
|
Số mục trên trang hiện tại
|
$paginator->cursor()
|
Đối tượng con trỏ hiện tại
|
$paginator->getOptions()
|
Các tùy chọn phân trang
|
$paginator->hasPages()
|
Kiểm tra có nhiều trang không
|
$paginator->hasMorePages()
|
Kiểm tra có còn mục nào không
|
$paginator->getCursorName()
|
Biến truy vấn để lưu trữ con trỏ
|
$paginator->items()
|
Các mục trên trang hiện tại
|
$paginator->nextCursor()
|
Con trỏ cho tập hợp mục tiếp theo
|
$paginator->nextPageUrl()
|
URL của trang kế tiếp
|
$paginator->onFirstPage()
|
Kiểm tra có đang ở trang đầu tiên không
|
$paginator->onLastPage()
|
Kiểm tra có đang ở trang cuối cùng không
|
$paginator->perPage()
|
Số lượng mục trên mỗi trang
|
$paginator->previousCursor()
|
Con trỏ cho tập hợp mục trước đó
|
$paginator->previousPageUrl()
|
URL của trang trước đó
|
$paginator->setCursorName()
|
Đặt tên biến truy vấn để lưu trữ con trỏ
|
$paginator->url($cursor)
|
URL cho con trỏ cụ thể
|
File Uploads
Author: | ADMIN |
---|
# File Uploads
Trong ứng dụng web, một trong những trường hợp sử dụng phổ biến nhất để lưu trữ tệp là lưu trữ các tệp được người dùng tải lên như hình ảnh và tài liệu. Laravel làm cho việc lưu trữ các files được upload rất dễ dàng bằng cách sử dụng phương thức store với tệp đã được upload. Gọi phương thức store với đường dẫn mà bạn muốn lưu trữ tệp được tải lên:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UserAvatarController extends Controller
{
/**
* Update the avatar for the user.
*/
public function update(Request $request): string
{
$path = $request->file('avatar')->store('avatars');
return $path;
}
}
Có một số điều quan trọng cần lưu ý về ví dụ này. Lưu ý rằng chúng ta chỉ chỉ định tên thư mục, không phải tên tệp. Theo mặc định, phương thức store sẽ tạo ra một ID duy nhất để làm tên tệp. Phần mở rộng của tệp sẽ được xác định bằng cách kiểm tra loại MIME của tệp. Đường dẫn đến tệp sẽ được trả về bởi phương thức store để bạn có thể lưu trữ đường dẫn, bao gồm tên tệp được tạo ra, trong cơ sở dữ liệu của bạn. Bạn cũng có thể gọi phương thức putFile trên Storage facade để thực hiện cùng một hoạt động lưu trữ tệp như ví dụ trên:
$path = Storage::putFile('avatars', $request->file('avatar'));
# Chỉ định một tên tệp
Nếu bạn không muốn tự động gán tên tệp cho tệp đã lưu của mình, bạn có thể sử dụng phương thức storeAs
, nhận đường dẫn, tên tệp và ổ đĩa (tùy chọn) là đối số của nó:
$path = $request->file('avatar')->storeAs(
'avatars', $request->user()->id
);
Bạn cũng có thể sử dụng phương thức putFileAs
trên Storage facade, sẽ thực hiện cùng một hoạt động lưu trữ tập tin như ví dụ trên:
$path = Storage::putFileAs(
'avatars', $request->file('avatar'), $request->user()->id
);
# Chỉ định một ổ đĩa
Theo mặc định, phương thức lưu trữ của tệp tải lên này sẽ sử dụng ổ đĩa mặc định của bạn. Nếu bạn muốn chỉ định một ổ đĩa khác, hãy truyền tên ổ đĩa như là đối số thứ hai cho phương thức lưu trữ:
$path = $request->file('avatar')->store(
'avatars/'.$request->user()->id, 's3'
);
// or
$path = $request->file('avatar')->storeAs(
'avatars',
$request->user()->id,
's3'
);
# Thông tin file đã upload
// Lấy tên gốc của tập tin
$originalName = $file->getClientOriginalName();
// Lấy phần mở rộng của tập tin
$extension = $file->getClientOriginalExtension();
// Lấy kích thước của tập tin (đơn vị: byte)
$size = $file->getSize();
// Lấy MIME type của tập tin
$mimeType = $file->getMimeType();
// Lưu tập tin
$path = $file->store('uploads', 'public');
Tuy nhiên, hãy nhớ rằng các phương thức getClientOriginalName
và getClientOriginalExtension
được coi là không an toàn, vì tên tập tin và phần mở rộng có thể bị người dùng độc hại can thiệp. Vì lý do này, bạn nên thường chọn phương thức hashName và phần mở rộng để có được tên và phần mở rộng cho tệp tải lên cụ thể:
$file = $request->file('avatar');
$name = $file->hashName(); // Generate a unique, random name...
$extension = $file->extension(); // Determine the file's extension based on the file's MIME type...
# File Visibility
Trong tích hợp Flysystem của Laravel, "visibility" là một sự trừu tượng hóa của các quyền tập tin trên nhiều nền tảng khác nhau. Các tập tin có thể được khai báo là công khai (public) hoặc riêng tư (private). Khi một tập tin được khai báo là công khai, bạn đang chỉ định rằng tập tin đó thường nên được truy cập bởi những người khác. Ví dụ, khi sử dụng driver S3, bạn có thể lấy URL cho các tập tin công khai.
Thiết Lập Tính Năng Hiển Thị Tập Tin
Lưu Trữ Tập Tin Công Khai
Bạn có thể lưu trữ một tập tin và chỉ định nó là công khai như sau:
use Illuminate\Support\Facades\Storage;
$content = 'Nội dung của tập tin';
Storage::put('file.jpg', $content, 'public');
Nếu tập tin đã được lưu trữ, bạn có thể lấy và thiết lập tính năng hiển thị của nó thông qua các phương thức getVisibility
và setVisibility
.
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public');
Khi làm việc với các tập tin được tải lên, bạn có thể sử dụng các phương thức storePublicly
và storePubliclyAs
để lưu trữ tập tin với tính năng hiển thị công khai.
Phương Thức storePublicly
Phương thức storePublicly
sẽ lưu trữ tập tin được tải lên với tính năng hiển thị công khai.
$path = $request->file('avatar')->storePublicly('avatars', 's3');
Phương Thức storePubliclyAs
Phương thức storePubliclyAs
cho phép bạn chỉ định tên tập tin khi lưu trữ với tính năng hiển thị công khai.
$path = $request->file('avatar')->storePubliclyAs(
'avatars',
$request->user()->id,
's3'
);
Tập Tin Cục Bộ và Tính Năng Hiển Thị
Khi sử dụng driver cục bộ (local
), tính năng hiển thị công khai được dịch thành quyền 0755 cho thư mục và 0644 cho tập tin. Bạn có thể chỉnh sửa các phép ánh xạ quyền này trong tệp cấu hình filesystems
của ứng dụng của bạn.
Cấu Hình filesystems.php
Trong tệp config/filesystems.php
, bạn có thể cấu hình quyền truy cập cho driver cục bộ như sau:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
],
Giải Thích
- Driver:
local
là driver cục bộ mà Laravel cung cấp để lưu trữ tập tin trên hệ thống tệp cục bộ. - Root: Đường dẫn gốc nơi các tập tin sẽ được lưu trữ. Mặc định là
storage_path('app')
, nghĩa là thư mụcstorage/app
trong ứng dụng của bạn. - Permissions: Đây là nơi bạn có thể chỉ định quyền truy cập cho tập tin và thư mục dựa trên tính năng hiển thị của chúng.
- File:
public
(0644): Quyền truy cập công khai cho tập tin, cho phép chủ sở hữu có thể đọc và ghi, trong khi người dùng khác chỉ có thể đọc.private
(0600): Quyền truy cập riêng tư cho tập tin, chỉ cho phép chủ sở hữu có thể đọc và ghi.
- Dir:
public
(0755): Quyền truy cập công khai cho thư mục, cho phép chủ sở hữu có thể đọc, ghi và thực thi, trong khi người dùng khác chỉ có thể đọc và thực thi.private
(0700): Quyền truy cập riêng tư cho thư mục, chỉ cho phép chủ sở hữu có thể đọc, ghi và thực thi.
- File:
# Deleting Files
Trong Laravel, bạn có thể dễ dàng xóa các tập tin đã được lưu trữ bằng cách sử dụng các phương thức được cung cấp bởi Storage
facade. Dưới đây là các phương pháp phổ biến để xóa tập tin trong Laravel.
Xóa Tập Tin Đơn Lẻ
Để xóa một tập tin đơn lẻ, bạn có thể sử dụng phương thức delete
:
use Illuminate\Support\Facades\Storage;
Storage::delete('path/to/file.jpg');
Xóa Nhiều Tập Tin
Nếu bạn cần xóa nhiều tập tin cùng lúc, bạn có thể truyền một mảng các đường dẫn tập tin vào phương thức delete
:
use Illuminate\Support\Facades\Storage;
Storage::delete([
'path/to/file1.jpg',
'path/to/file2.jpg',
'path/to/file3.jpg'
]);
Kiểm Tra Tập Tin Trước Khi Xóa
Bạn có thể kiểm tra xem tập tin có tồn tại hay không trước khi xóa bằng cách sử dụng phương thức exists
:
use Illuminate\Support\Facades\Storage;
if (Storage::exists('path/to/file.jpg')) {
Storage::delete('path/to/file.jpg');
}
Xóa Tập Tin Cục Bộ
Nếu bạn đang làm việc với các tập tin cục bộ và muốn xóa chúng, bạn có thể sử dụng phương thức unlink
của PHP. Tuy nhiên, sử dụng Storage
facade của Laravel là cách tiếp cận tốt hơn vì nó trừu tượng hóa các chi tiết của hệ thống tập tin cơ bản:
use Illuminate\Support\Facades\Storage;
Storage::disk('local')->delete('path/to/file.jpg');
Xóa Thư Mục
Bạn có thể xóa cả một thư mục và tất cả các tập tin trong đó bằng phương thức deleteDirectory
:
use Illuminate\Support\Facades\Storage;
Storage::deleteDirectory('path/to/directory');
Lấy Tất Cả Các Tập Tin Trong Một Thư Mục
Để lấy danh sách tất cả các tập tin trong một thư mục, bạn có thể sử dụng phương thức files
của Storage
facade:
use Illuminate\Support\Facades\Storage;
$files = Storage::files('path/to/directory');
Phương thức này sẽ trả về một mảng chứa các đường dẫn của tất cả các tập tin trong thư mục được chỉ định.
Lấy Tất Cả Các Tập Tin Kể Cả Trong Các Thư Mục Con
Nếu bạn muốn lấy tất cả các tập tin bao gồm cả trong các thư mục con, bạn có thể sử dụng phương thức allFiles
:
use Illuminate\Support\Facades\Storage;
$allFiles = Storage::allFiles('path/to/directory');
Phương thức này sẽ trả về một mảng chứa các đường dẫn của tất cả các tập tin, kể cả trong các thư mục con của thư mục được chỉ định.
Lấy Tất Cả Các Thư Mục Con Trong Một Thư Mục
Để lấy danh sách tất cả các thư mục con trong một thư mục, bạn có thể sử dụng phương thức directories
:
use Illuminate\Support\Facades\Storage;
$directories = Storage::directories('path/to/directory');
Phương thức này sẽ trả về một mảng chứa các đường dẫn của tất cả các thư mục con trong thư mục được chỉ định.
Lấy Tất Cả Các Thư Mục Con Bao Gồm Cả Trong Các Thư Mục Con Khác
Nếu bạn muốn lấy tất cả các thư mục con bao gồm cả trong các thư mục con khác, bạn có thể sử dụng phương thức allDirectories
:
use Illuminate\Support\Facades\Storage;
$allDirectories = Storage::allDirectories('path/to/directory');
Phương thức này sẽ trả về một mảng chứa các đường dẫn của tất cả các thư mục con, kể cả trong các thư mục con khác của thư mục được chỉ định.
Tạo Một Thư Mục
Để tạo một thư mục mới, bạn có thể sử dụng phương thức makeDirectory
:
use Illuminate\Support\Facades\Storage;
Storage::makeDirectory('path/to/directory');
-----------------------------------------------------------------------------------------------------------------------------------------
# Example:
Trước khi bắt đầu, hãy chắc chắn rằng thư mục lưu trữ tập tin tải lên có quyền ghi. Thư mục mặc định là storage/app/public
.
Tạo symbolic link: Chạy lệnh sau để tạo một symbolic link từ public/storage
tới storage/app/public
:
php artisan storage:link
Tạo Form Để Tải Lên Tập Tin
Đầu tiên, bạn cần tạo một form để người dùng có thể chọn tập tin để tải lên.
Ví Dụ Form Trong Blade:
<form action="{{ route('upload') }}" method="POST" enctype="multipart/form-data">
@csrf
<div>
<label for="file">Choose file</label>
<input type="file" id="file" name="file">
@error('file')
<div class="error">{{ $message }}</div>
@enderror
</div>
<button type="submit">Upload</button>
</form>
Lưu ý rằng bạn cần sử dụng enctype="multipart/form-data"
trong thẻ <form>
để có thể tải lên tập tin.
Xử Lý Yêu Cầu Tải Lên Trong Controller
Tiếp theo, tạo một phương thức trong controller để xử lý việc tải lên tập tin.
Ví Dụ Trong Controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class FileUploadController extends Controller
{
public function upload(Request $request)
{
// Kiểm tra dữ liệu
$request->validate([
'file' => 'required|file|mimes:jpg,png,pdf|max:2048',
]);
// Lưu tập tin
if ($request->file('file')->isValid()) {
$path = $request->file('file')->store('uploads', 'public');
return back()->with('success', 'File uploaded successfully.')->with('file', $path);
}
return back()->with('error', 'There was an error uploading your file.');
}
}
Cấu Hình Route
Cuối cùng, cấu hình route để xử lý form upload.
Ví Dụ Trong web.php
:
use App\Http\Controllers\FileUploadController;
Route::get('/upload', function () {
return view('upload');
})->name('upload.form');
Route::post('/upload', [FileUploadController::class, 'upload'])->name('upload');