Một số lệnh Artisan Make với các tham số

Một số lệnh Artisan Make với các tham số

01.08.2024
Author: ADMIN

Laravel cung cấp nhiều lệnh Artisan để tạo các thành phần khác nhau trong ứng dụng. Dưới đây là danh sách các lệnh make cùng với các tham số phổ biến mà bạn có thể sử dụng.

1. Make Controller

php artisan make:controller {name} [--resource] [--api] [--invokable] [--model[=MODEL]] [--parent] [--requests] [--singleton] [--force]
  • --resource: Controller sẽ chứa một phương thức cho mỗi hoạt động tài nguyên có sẵn - index(), create(), store(), show(), edit(), update(), destroy().
  • --api: Tương tự như -resource ở trên, nhưng chỉ tạo ra 5 phương thức: index(), store(), show(), update(), destroy(). Bởi vì các biểu mẫu tạo/sửa không cần thiết cho API.
  • --invokable: Tạo một controller với một phương thức __invoke duy nhất.
  • --model[=MODEL]: Tạo controller với mô hình được liên kết.
  • --requests: Tạo các lớp request form cho controller.

2. Make Model

php artisan make:model {name} [--migration] [--controller] [--resource] [--factory] [--seed] [--policy] [--all] [--pivot]
  • --migration: Tạo migration cho mô hình.
  • --controller: Tạo controller cho mô hình.
  • --resource: Tạo controller tài nguyên cho mô hình.
  • --factory: Tạo factory cho mô hình.
  • --seed: Tạo seeder cho mô hình.
  • --policy: Tạo policy cho mô hình.
  • --all: Tạo migration, factory, seeder, policy, và controller cho mô hình.
  • --pivot: Tạo mô hình pivot.

3. Make Migration

php artisan make:migration {name} [--create[=TABLE]] [--table[=TABLE]] [--path[=PATH]] [--realpath] [--fullpath]
  • --create[=TABLE]: Tạo migration cho bảng mới.
  • --table[=TABLE]: Tạo migration để cập nhật bảng hiện có.

4. Make Seeder

php artisan make:seeder {name}

5. Make Factory

php artisan make:factory {name} [--model[=MODEL]]
  • --model[=MODEL]: Liên kết factory với mô hình.

6. Make Middleware

php artisan make:middleware {name}

7. Make Request

php artisan make:request {name}

8. Make Event

php artisan make:event {name}

9. Make Listener

php artisan make:listener {name} [--event[=EVENT]]
  • --event[=EVENT]: Liên kết listener với sự kiện.

10. Make Job

php artisan make:job {name} [--sync]
  • --sync: Tạo job đồng bộ.

11. Make Notification

php artisan make:notification {name}

12. Make Mail

php artisan make:mail {name} [--markdown[=MARKDOWN]]
  • --markdown[=MARKDOWN]: Tạo email với template markdown.

13. Make Command

php artisan make:command {name} [--command[=COMMAND]]
  • --command[=COMMAND]: Tên của lệnh console.

14. Make Policy

php artisan make:policy {name} [--model[=MODEL]]
  • --model[=MODEL]: Liên kết policy với mô hình.

15. Make Provider

php artisan make:provider {name}

16. Make Test

php artisan make:test {name} [--unit] [--pest]
  • --unit: Tạo test đơn vị.
  • --pest: Tạo test Pest.

17. Make Rule

php artisan make:rule {name}

18. Make Observer

php artisan make:observer {name} [--model[=MODEL]]
  • --model[=MODEL]: Liên kết observer với mô hình.

19. Make Channel

php artisan make:channel {name}

20. Make Resource

php artisan make:resource {name}

Trên đây là một số command mà tôi hay sử dụng, ngoài các command này, bạn có thể sử dụng command php artisan list để liệt kê tất cả command artisan tính đến thời điểm hiện tại

Laravel Routing – 8 Advanced Tips

Laravel Routing – 8 Advanced Tips

01.08.2024
Author: ADMIN

# Laravel Routing – 8 Advanced Tips

Chúng ta tất cả đều sử dụng cú pháp đơn giản của Route::get() và Route::post(), nhưng trong các dự án lớn, nó trở nên phức tạp hơn nhiều. Bài viết này sẽ tổng hợp các mẹo khác nhau cho các tình huống khác nhau.

Tip 1. Route::get() BEFORE Route::resource()

Đối với Resource Controllers, đây là một trong những sai lầm phổ biến nhất, hãy xem ví dụ này:

Route::resource('photos', 'PhotoController');
Route::get('photos/popular', 'PhotoController@method');

Khi bạn định nghĩa một route resource, Laravel tự động tạo ra nhiều route cho các hành động CRUD (Create, Read, Update, Delete)

Điều này sẽ tạo ra các route như /photos, /photos/{id}, /photos/{id}/edit, và nhiều hơn nữa. Nếu bạn có một route thêm vào, ví dụ như /photos/popular, mà bạn định nghĩa sau route resource, thì có thể xảy ra xung đột. Điều này là do Laravel ưu tiên các route định nghĩa trước. Vì vậy, nếu bạn đặt route thêm vào sau route resource, nó có thể không hoạt động như mong muốn. Trong ví dụ này, route /photos/popular có thể bị route resource /photos/{id} chặn và sẽ được gán giá trị "popular" làm tham số {id}.

Vì vậy, cú pháp đúng phải là: 

// Đặt route bổ sung trước
Route::get('photos/popular', 'PhotoController@method');

// Sau đó định nghĩa route resource
Route::resource('photos', 'PhotoController');

Tip 2. Group in Another Group

Chúng ta có lẽ đều biết rằng có thể nhóm các route bằng Route::group() và gán các middleware/prefixes khác nhau cùng các tham số khác, như các route công khai và các route yêu cầu đăng nhập.

Nhưng nếu bạn cần một tập hợp các quy tắc nhất định cho các nhóm con của những nhóm đó thì sao?

Ví dụ điển hình: bạn cần các route công khai và các route yêu cầu đăng nhập, nhưng trong nhóm các route yêu cầu đăng nhập, bạn cần tách biệt quản trị viên khỏi người dùng thông thường.

Vì vậy, bạn có thể làm điều này:

// route công khai
Route::get('/', 'HomeController@index');

// Người dùng đã đăng nhập - với middleware "auth"
Route::group(['middleware' => ['auth']], function () {

    // /user/XXX: Bên cạnh "auth", nhóm này sẽ có middleware "simple_users"
    Route::group(['middleware' => ['simple_users'], 'prefix' => 'user'], function () {
        Route::resource('tasks', 'TaskController');
    });

    // /admin/XXX: Nhóm này sẽ không có "simple_users", nhưng sẽ có "auth" và "admins"
    Route::group(['middleware' => ['admins'], 'prefix' => 'admin'], function () {
        Route::resource('users', 'UserController');
    });
});

Tip 3. Route Parameter Validation – Multi-Language Example

Một trường hợp khá điển hình là sử dụng prefix cho các route của bạn theo ngôn ngữ địa phương, ví dụ như fr/blogen/article/333. Làm thế nào để chúng ta đảm bảo rằng hai chữ cái đầu tiên đó không được sử dụng cho mục đích khác ngoài ngôn ngữ?

Chúng ta có thể xác thực trực tiếp trong route bằng tham số "where":

Route::group(['prefix' => '{locale}', 'where' => ['locale' => '[a-zA-Z]{2}']], function () {
    Route::get('/', 'HomeController@index');
    Route::get('article/{id}', 'ArticleController@show');
});

Tip 4. Routing với Subdomain Động

Đây là một tính năng đến trực tiếp từ tài liệu chính thức của Laravel, nhưng ít được sử dụng nên mình muốn đề cập đến nó.

Nếu bạn có một subdomain động, như một subdomain khác nhau cho mỗi người dùng, nó cần trở thành một biến, đúng không? Laravel đã tự động làm điều đó cho bạn. Xem ví dụ:

Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        // Code xử lý
    });
});

Giải thích

  • Route::domain('{account}.myapp.com'): Định nghĩa một nhóm các route với một subdomain động {account}. Subdomain này sẽ được thay thế bằng giá trị cụ thể của từng người dùng.

  • group(function () { ... }): Định nghĩa một nhóm các route sẽ thuộc subdomain đã định nghĩa ở trên.

  • Route::get('user/{id}', function ($account, $id) { ... }): Định nghĩa một route trong nhóm này. Route này chấp nhận hai tham số: $account (giá trị của subdomain động) và $id (ID của người dùng).

Lưu ý:

  • {account} tự động được truyền như một tham số $account vào tất cả các phương thức controller bên trong nhóm route này. Vì vậy, bạn cần chấp nhận tham số này trong tất cả các phương thức controller, không quên điều này.

Ví dụ:

  • Subdomain: john.myapp.com
    • Route: john.myapp.com/user/123
    • Controller Method: function ($account, $id)
    • $account sẽ là john$id sẽ là 123.

Tip 5. Cẩn Thận với Route Model Binding Không Dùng Tiếng Anh

Đôi khi, URL cần chứa các từ không phải tiếng Anh. Ví dụ, bạn có một trang web tiếng Tây Ban Nha về sách và bạn muốn có URL như /libros cho danh sách sách, và sách cụ thể sẽ có URL như /libros/1, giống như một Resource Controller thông thường.

Nhưng trong cơ sở dữ liệu, tất cả các tên nên là tiếng Anh để "magic" của Laravel có thể hoạt động giữa dạng số ít và số nhiều, đúng không?

Vì vậy, nếu bạn tạo một model Book với migration và Controller, bạn có thể dùng lệnh sau:

php artisan make:model Book -mcr

Phím -mcr sẽ tạo một model và một resource controller. Trong Controller đó, bạn sẽ có như sau:

/**
 * Display the specified resource.
 *
 * @param  \App\Book  $book
 * @return \Illuminate\Http\Response
 */
public function show(Book $book)
{
    // ...
}

Nhưng trong routes/web.php, bạn sẽ có như sau:

Route::resource('libros', 'BookController');

Vấn đề là nó sẽ không hoạt động. Một vấn đề lớn hơn là nó sẽ không đưa ra bất kỳ lỗi nào, chỉ là biến $book sẽ rỗng, và bạn sẽ không hiểu tại sao.

Theo mô tả của Resource Controller chính thức, tên của biến phải giống với tham số ở dạng số ít:

// Thay vì
public function show(Book $book)
{
    // ...
}

// Bạn nên để
public function show(Book $libro)
{
    // ...
}

Nhưng, thành thật mà nói, trong các dự án không sử dụng tiếng Anh, tôi khuyên không nên sử dụng Route::resource và Route Model Binding. Quá nhiều "magic" không thể đoán trước, như cách Laravel sẽ "đoán" rằng dạng số ít của "libros" là "libro"?

Tip 6. API Routes – từ V1 đến V2

Hãy tưởng tượng bạn đang làm việc với dự án dựa trên API và cần phát hành phiên bản mới của API. Các endpoint cũ sẽ giữ nguyên tại api/[something], và đối với phiên bản mới, bạn sẽ sử dụng api/V2/[something].

Toàn bộ logic nằm trong app/Providers/RouteServiceProvider.php:

public function map()
{
    $this->mapApiRoutes();

    $this->mapWebRoutes();

    // ...
}

protected function mapWebRoutes()
{
    Route::middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));
}

protected function mapApiRoutes()
{
    Route::prefix('api')
        ->middleware('api')
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

Như bạn có thể thấy, các route API được đăng ký trong một hàm riêng với tiền tố api/.

Vì vậy, nếu bạn muốn tạo nhóm route V2, bạn có thể tạo một tệp riêng routes/api_v2.php và làm như sau:

public function map()
{
    // ... các hàm cũ

    $this->mapApiV2Routes();
}

// Và hàm mới
protected function mapApiV2Routes()
{
    Route::prefix('api/V2')
        ->middleware('api')
        ->namespace($this->namespace)
        ->group(base_path('routes/api_v2.php'));
}

Bằng cách này, các route cũ sẽ không bị phá vỡ, và bạn chỉ cần tạo một bộ route mới.

Tip 7. Giới Hạn Tốc Độ (Rate Limiting) – Tổng Thể và cho Khách/Người Dùng

Điều này cũng xuất phát từ tài liệu chính thức, nhưng với những chi tiết ít được biết đến hơn.

Giới Hạn Tốc Độ Tổng Thể

Đầu tiên, bạn có thể giới hạn một URL được gọi tối đa 60 lần mỗi phút, với throttle:60,1.

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Giới Hạn Tốc Độ Riêng cho Khách và Người Dùng Đã Đăng Nhập

Nhưng bạn có biết rằng bạn có thể làm điều này riêng biệt cho người dùng công khai và người dùng đã đăng nhập không?

// tối đa 10 yêu cầu mỗi phút cho khách và 60 cho người dùng đã đăng nhập
Route::middleware('throttle:10|60,1')->group(function () {
    //
});

Giới Hạn Tốc Độ cho Người Dùng Cụ Thể
Bạn cũng có thể có một trường cơ sở dữ liệu users.rate_limit và giới hạn số lượng yêu cầu cho người dùng cụ thể:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Tip 8. Route List and Route Caching

Xem Danh Sách Routes

Không phải tất cả chúng ta đều biết chính xác những routes nào ẩn dưới Route::resource(), hoặc dưới một số câu lệnh Route::group phức tạp hơn. Nhưng vào bất kỳ thời điểm nào, bạn có thể kiểm tra routes thực tế của mình bằng lệnh Artisan:

php artisan route:list

Lệnh này sẽ hiển thị một danh sách tất cả các routes hiện có trong ứng dụng của bạn, bao gồm tên route, phương thức HTTP, URL, tên controller và action tương ứng. Đây là một công cụ rất hữu ích để kiểm tra và gỡ lỗi cấu hình routes của bạn.

Sử Dụng Bộ Nhớ Đệm Routes

Bộ nhớ đệm routes (route caching) là một tính năng mạnh mẽ giúp cải thiện hiệu suất của ứng dụng bằng cách lưu trữ cấu hình routes trong bộ nhớ đệm. Tuy nhiên, khi bạn sử dụng bộ nhớ đệm routes, bạn cần nhớ xóa và tạo lại bộ nhớ đệm sau mỗi lần thay đổi cấu hình routes.

Để xóa bộ nhớ đệm routes:

php artisan route:clear

Sau đó, để tạo lại bộ nhớ đệm routes:

php artisan route:cache

Lệnh này sẽ lưu trữ cấu hình routes của bạn trong bộ nhớ đệm, giúp Laravel tải routes nhanh hơn trong các yêu cầu tiếp theo.

Database: Pagination

Database: Pagination

01.08.2024
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ượng LengthAwarePaginator, 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

File Uploads

01.08.2024
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 getVisibilitysetVisibility.

$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 storePubliclystorePubliclyAs để 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ục storage/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.

# 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');
Validation

Validation

01.08.2024
Author: ADMIN

# Laravel Validation

Laravel cung cấp một hệ thống kiểm tra dữ liệu mạnh mẽ và dễ sử dụng. Bạn có thể thực hiện kiểm tra dữ liệu (validation) trong các controller, form request, hoặc thậm chí là trực tiếp trong các model. Dưới đây là hướng dẫn cơ bản về cách sử dụng hệ thống kiểm tra dữ liệu của Laravel.

1. Validation trong Controller

Bạn có thể thực hiện kiểm tra dữ liệu trực tiếp trong các phương thức của controller bằng cách sử dụng phương thức validate:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // User::create($validatedData);

        return response('User created successfully.');
    }
}
  • name phải có giá trị và không được vượt quá 255 ký tự.
  • email phải là một địa chỉ email hợp lệ và duy nhất trong bảng users.
  • password phải có ít nhất 8 ký tự và được xác nhận (có một trường password_confirmation khớp với password).

2. Validation trong Form Request

Bạn có thể tách logic kiểm tra dữ liệu ra khỏi controller bằng cách sử dụng Form Request. Điều này giúp mã nguồn của bạn sạch hơn và dễ bảo trì hơn.

Tạo một Form Request:

php artisan make:request StoreUserRequest

Sử dụng Form Request:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ];
    }
}

Sử dụng Form Request trong Controller:

namespace App\Http\Controllers;

use App\Http\Requests\StoreUserRequest;

class UserController extends Controller
{
    public function store(StoreUserRequest $request)
    {
        $validatedData = $request->validated();

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // User::create($validatedData);

        return response('User created successfully.');
    }
}

3. Custom Messages

Bạn có thể tùy chỉnh các thông báo lỗi kiểm tra dữ liệu bằng cách sử dụng phương thức messages trong Form Request hoặc bằng cách truyền mảng thứ ba vào phương thức validate.

Tùy chỉnh thông báo lỗi trong Form Request:
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ];
    }

    public function messages()
    {
        return [
            'name.required' => 'Vui lòng nhập tên.',
            'email.required' => 'Vui lòng nhập địa chỉ email.',
            'email.email' => 'Địa chỉ email không hợp lệ.',
            'email.unique' => 'Địa chỉ email đã tồn tại.',
            'password.required' => 'Vui lòng nhập mật khẩu.',
            'password.min' => 'Mật khẩu phải có ít nhất 8 ký tự.',
            'password.confirmed' => 'Xác nhận mật khẩu không khớp.',
        ];
    }
}

Tùy chỉnh thông báo lỗi trong Controller:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ], [
            'name.required' => 'Vui lòng nhập tên.',
            'email.required' => 'Vui lòng nhập địa chỉ email.',
            'email.email' => 'Địa chỉ email không hợp lệ.',
            'email.unique' => 'Địa chỉ email đã tồn tại.',
            'password.required' => 'Vui lòng nhập mật khẩu.',
            'password.min' => 'Mật khẩu phải có ít nhất 8 ký tự.',
            'password.confirmed' => 'Xác nhận mật khẩu không khớp.',
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // User::create($validatedData);

        return response('User created successfully.');
    }
}

4. Custom Validation Rules

Bạn có thể tạo các quy tắc kiểm tra dữ liệu tùy chỉnh nếu cần.

Tạo Custom Validation Rule:
php artisan make:rule Uppercase

Sử dụng Custom Validation Rule:

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    public function passes($attribute, $value)
    {
        return strtoupper($value) === $value;
    }

    public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

Sử dụng Custom Validation Rule trong Controller hoặc Form Request:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Rules\Uppercase;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => ['required', 'max:255', new Uppercase],
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ];
    }
}

# ValidateWithBag

Trong Laravel, khi thực hiện kiểm tra dữ liệu (validation), đôi khi bạn muốn tách biệt các thông báo lỗi thành nhiều túi (bag) khác nhau. Điều này có thể hữu ích khi bạn có nhiều form trên cùng một trang và bạn muốn quản lý thông báo lỗi riêng biệt cho từng form. Laravel cung cấp phương thức validateWithBag để thực hiện điều này.

Sử dụng validateWithBag

Phương thức validateWithBag cho phép bạn chỉ định một túi lỗi cụ thể cho các lỗi kiểm tra dữ liệu. Đây là cách sử dụng cơ bản:

Controller:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $validatedData = $request->validateWithBag('storeUser', [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8|confirmed',
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // User::create($validatedData);

        return response('User created successfully.');
    }

    public function update(Request $request, $id)
    {
        $validatedData = $request->validateWithBag('updateUser', [
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users,email,' . $id,
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // User::find($id)->update($validatedData);

        return response('User updated successfully.');
    }
}

Trong ví dụ trên, phương thức validateWithBag được sử dụng với túi lỗi storeUser cho phương thức store và túi lỗi updateUser cho phương thức update.

Hiển thị lỗi trong Blade

Để hiển thị các thông báo lỗi cho từng túi lỗi riêng biệt trong Blade, bạn có thể sử dụng phương thức hasBaggetBag của đối tượng $errors.

Ví dụ trong Blade template:
<!-- Form tạo người dùng mới -->
<form action="{{ route('user.store') }}" method="POST">
    @csrf
    <div>
        <label for="name">Name</label>
        <input type="text" id="name" name="name">
        @if ($errors->storeUser->has('name'))
            <div>{{ $errors->storeUser->first('name') }}</div>
        @endif
    </div>
    <div>
        <label for="email">Email</label>
        <input type="email" id="email" name="email">
        @if ($errors->storeUser->has('email'))
            <div>{{ $errors->storeUser->first('email') }}</div>
        @endif
    </div>
    <div>
        <label for="password">Password</label>
        <input type="password" id="password" name="password">
        @if ($errors->storeUser->has('password'))
            <div>{{ $errors->storeUser->first('password') }}</div>
        @endif
    </div>
    <button type="submit">Create User</button>
</form>

<!-- Form cập nhật người dùng -->
<form action="{{ route('user.update', ['id' => 1]) }}" method="POST">
    @csrf
    @method('PUT')
    <div>
        <label for="name">Name</label>
        <input type="text" id="name" name="name">
        @if ($errors->updateUser->has('name'))
            <div>{{ $errors->updateUser->first('name') }}</div>
        @endif
    </div>
    <div>
        <label for="email">Email</label>
        <input type="email" id="email" name="email">
        @if ($errors->updateUser->has('email'))
            <div>{{ $errors->updateUser->first('email') }}</div>
        @endif
    </div>
    <button type="submit">Update User</button>
</form>

Trong ví dụ trên, các thông báo lỗi cho từng form được hiển thị riêng biệt dựa trên túi lỗi tương ứng (storeUserupdateUser).

Kết luận

Phương thức validateWithBag của Laravel giúp bạn dễ dàng tách biệt và quản lý các thông báo lỗi cho nhiều form trên cùng một trang. Bằng cách sử dụng túi lỗi riêng biệt, bạn có thể đảm bảo rằng mỗi form chỉ hiển thị các thông báo lỗi liên quan, giúp giao diện người dùng trở nên rõ ràng và dễ hiểu hơn.

# Dừng Lại Khi Gặp Lỗi Đầu Tiên

Trong Laravel, để dừng kiểm tra dữ liệu khi gặp lỗi đầu tiên, bạn có thể sử dụng quy tắc bail. Quy tắc này sẽ yêu cầu Laravel dừng quá trình kiểm tra dữ liệu đối với thuộc tính cụ thể ngay khi phát hiện ra lỗi đầu tiên.

Sử Dụng Quy Tắc bail

Bạn có thể gán quy tắc bail cho thuộc tính cần kiểm tra. Khi một thuộc tính có quy tắc bail và Laravel phát hiện ra lỗi đầu tiên trên thuộc tính đó, các quy tắc kiểm tra còn lại sẽ không được thực thi.

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

Ngoài ra, bạn có thể sử dụng method stopOnFirstFailure 

if ($validator->stopOnFirstFailure()->fails()) {
    // ...
}

# Lưu Ý Về Các Thuộc Tính Lồng Nhau

Trong Laravel, khi yêu cầu HTTP chứa dữ liệu trường "lồng nhau", bạn có thể chỉ định các trường này trong các quy tắc kiểm tra dữ liệu (validation rules) bằng cú pháp "dot". Ngoài ra, nếu tên trường của bạn chứa một dấu chấm thực sự, bạn có thể ngăn chặn việc này bị hiểu sai thành cú pháp "dot" bằng cách sử dụng dấu gạch chéo ngược để thoát khỏi dấu chấm.

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'author.name' => 'required',
            'author.description' => 'required',
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // Post::create($validatedData);

        return response('Post created successfully.');
    }
}
  • title là một trường thông thường với các quy tắc required, unique:posts, và max:255.
  • author.nameauthor.description là các thuộc tính lồng nhau trong trường author.

Tránh Nhầm Lẫn Với Tên Trường Chứa Dấu Chấm Thực Sự

Nếu tên trường của bạn chứa một dấu chấm thực sự, bạn có thể ngăn chặn việc này bị hiểu sai thành cú pháp "dot" bằng cách sử dụng dấu gạch chéo ngược để thoát khỏi dấu chấm. Điều này hữu ích khi bạn có các phiên bản hoặc các tên trường đặc biệt.

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class VersionController extends Controller
{
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'v1\.0' => 'required',
        ]);

        // Nếu dữ liệu hợp lệ, bạn có thể tiếp tục xử lý dữ liệu ở đây.
        // Version::create($validatedData);

        return response('Version created successfully.');
    }
}
  • title là một trường thông thường với các quy tắc required, unique:posts, và max:255.
  • v1\.0 là một tên trường chứa dấu chấm thực sự và được thoát bằng dấu gạch chéo ngược.

Tham khảo
# Available Validation Rules

# Tái Tạo Dữ Liệu Cho Form

Trong Laravel, việc tái tạo dữ liệu cho các form rất quan trọng để giữ lại thông tin đã nhập vào khi có lỗi xảy ra hoặc khi cần hiển thị lại dữ liệu đã lưu trước đó. Laravel cung cấp nhiều cách để thực hiện việc này một cách dễ dàng và hiệu quả.

Sử Dụng old() Helper

Khi một yêu cầu HTTP POST không thành công do lỗi kiểm tra dữ liệu, Laravel sẽ tự động chuyển hướng người dùng trở lại trang trước đó với dữ liệu cũ (old input) và các thông báo lỗi. Bạn có thể sử dụng helper old() để lấy lại dữ liệu này và hiển thị trong form.

<form action="{{ route('post.store') }}" method="POST">
    @csrf
    <div>
        <label for="title">Title</label>
        <input type="text" id="title" name="title" value="{{ old('title') }}">
        @error('title')
            <div class="error">{{ $message }}</div>
        @enderror
    </div>
    <div>
        <label for="content">Content</label>
        <textarea id="content" name="content">{{ old('content') }}</textarea>
        @error('content')
            <div class="error">{{ $message }}</div>
        @enderror
    </div>
    <button type="submit">Submit</button>
</form>

Trong ví dụ này, nếu kiểm tra dữ liệu không thành công, giá trị của các trường titlecontent sẽ được tái tạo lại trong form bằng cách sử dụng old('title')old('content').

Route Resource and Resourceful Controllers

Route Resource and Resourceful Controllers

01.08.2024
Author: ADMIN

# Resource Controllers

Resource Controllers trong Laravel cung cấp một cách thuận tiện để xử lý các hành động CRUD (Create, Read, Update, Delete) cho các tài nguyên của bạn. Khi bạn tạo một Resource Controller, Laravel sẽ tự động tạo ra các phương thức xử lý các hành động CRUD tiêu chuẩn. Điều này giúp bạn giảm bớt việc phải viết mã thủ công cho các hành động lặp đi lặp lại.

1. Tạo Resource Controller

Để tạo một Resource Controller, bạn sử dụng lệnh Artisan sau:

php artisan make:controller UserController --resource

Lệnh này sẽ tạo ra một controller mới tên là UserController với các phương thức mặc định cho các hành động CRUD. Đây là các phương thức được tạo ra:

  • index(): Hiển thị danh sách tài nguyên.
  • create(): Hiển thị form để tạo tài nguyên mới.
  • store(): Lưu trữ tài nguyên mới vào cơ sở dữ liệu.
  • show($id): Hiển thị chi tiết một tài nguyên cụ thể.
  • edit($id): Hiển thị form để chỉnh sửa một tài nguyên cụ thể.
  • update(Request $request, $id): Cập nhật tài nguyên cụ thể trong cơ sở dữ liệu.
  • destroy($id): Xóa một tài nguyên cụ thể khỏi cơ sở dữ liệu.

2. Route Resource

Để định tuyến đến Resource Controller, bạn có thể sử dụng phương thức Route::resource. Ví dụ:

use Illuminate\Support\Facades\Route;

Route::resource('users', UserController::class);

Lệnh này sẽ tự động tạo ra tất cả các tuyến đường cần thiết cho các hành động CRUD tương ứng với các phương thức trong UserController.

# Actions Handled by Resource Controllers

Verb URI Action Route Name
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy

# Tùy Chỉnh Hành Vi Khi Model Không Tồn Tại với Phương Thức missing

Thường thì, một phản hồi HTTP 404 sẽ được tạo ra nếu một resource model không được tìm thấy. Tuy nhiên, bạn có thể tùy chỉnh hành vi này bằng cách gọi phương thức missing khi xác định resource route của bạn. Phương thức missing chấp nhận một closure sẽ được gọi nếu một Model được ràng buộc một cách ngầm định không thể tìm thấy cho bất kỳ resource's routes nào:

use App\Http\Controllers\UserController;
use App\Models\User;
use Illuminate\Support\Facades\Route;

Route::resource('users', UserController::class)
    ->missing(function (Request $request) {
         return response()->view('errors.custom', [], 404);
});

Trong ví dụ trên, nếu một mô hình User không được tìm thấy khi truy cập bất kỳ tuyến đường tài nguyên nào của users, Laravel sẽ trả về một view tùy chỉnh errors.custom với mã trạng thái 404.

# Soft Deleted Models

Trong Laravel, tính năng Soft Deletes cho phép bạn "xóa" các bản ghi khỏi cơ sở dữ liệu mà không thực sự xóa chúng. Thay vì bị xóa, một bản ghi sẽ được đánh dấu là đã xóa bằng cách thiết lập giá trị của cột deleted_at thành thời điểm hiện tại. Điều này giúp bạn dễ dàng khôi phục các bản ghi đã bị xóa nếu cần thiết.

1. Thiết lập Soft Deletes cho một Model

Để sử dụng Soft Deletes, bạn cần làm theo các bước sau:

Thêm cột deleted_at vào bảng

Bạn có thể sử dụng migration để thêm cột deleted_at vào bảng của bạn:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddDeletedAtToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->softDeletes();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropSoftDeletes();
        });
    }
}
Sử dụng trait SoftDeletes trong model

Bạn cần thêm trait SoftDeletes vào model của bạn:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
    use SoftDeletes;

    protected $dates = ['deleted_at'];
}

2. Sử dụng Soft Deletes

Xóa mềm một bản ghi

Để xóa mềm một bản ghi, bạn chỉ cần gọi phương thức delete:

$user = User::find(1);
$user->delete();
Khôi phục một bản ghi đã bị xóa mềm

Bạn có thể khôi phục một bản ghi đã bị xóa mềm bằng phương thức restore:

$user = User::withTrashed()->find(1);
$user->restore();
Xóa vĩnh viễn một bản ghi

Để xóa vĩnh viễn một bản ghi, bạn có thể sử dụng phương thức forceDelete:

$user = User::withTrashed()->find(1);
$user->forceDelete();

3. Truy vấn với Soft Deletes

Lấy các bản ghi chưa bị xóa

Mặc định, các truy vấn Eloquent sẽ chỉ lấy các bản ghi chưa bị xóa:

$users = User::all();
Lấy tất cả các bản ghi, bao gồm cả bản ghi đã bị xóa

Bạn có thể sử dụng phương thức withTrashed để lấy tất cả các bản ghi, bao gồm cả những bản ghi đã bị xóa:

$users = User::withTrashed()->get();
Chỉ lấy các bản ghi đã bị xóa

Bạn có thể sử dụng phương thức onlyTrashed để chỉ lấy những bản ghi đã bị xóa mềm:

$users = User::onlyTrashed()->get();

4. Các phương thức bổ sung

Kiểm tra xem một bản ghi đã bị xóa hay chưa

Bạn có thể sử dụng phương thức trashed để kiểm tra xem một bản ghi đã bị xóa mềm hay chưa:

$user = User::withTrashed()->find(1);

if ($user->trashed()) {
    // Bản ghi đã bị xóa mềm
}

# Nested Resources

Nested Resources (tài nguyên lồng nhau) cho phép bạn định nghĩa các tuyến đường tài nguyên lồng nhau để biểu diễn mối quan hệ giữa các mô hình. Điều này thường được sử dụng khi một mô hình có mối quan hệ với một mô hình khác, ví dụ như PostComment.

1. Định Nghĩa Nested Resources

Bạn có thể định nghĩa các nested resources trong tệp định tuyến của mình (routes/web.php). Dưới đây là một ví dụ về cách định nghĩa nested resources cho PostComment:

use App\Http\Controllers\PostController;
use App\Http\Controllers\CommentController;
use Illuminate\Support\Facades\Route;

Route::resource('posts', PostController::class);

Route::resource('posts.comments', CommentController::class);

2. URL và Tên Định Tuyến cho Nested Resources

Khi bạn định nghĩa nested resources, Laravel sẽ tự động tạo ra các tuyến đường với các URL và tên định tuyến tương ứng.

Ví dụ URL và tên định tuyến:
  • GET /posts - posts.index
  • GET /posts/{post} - posts.show
  • GET /posts/{post}/comments - posts.comments.index
  • GET /posts/{post}/comments/{comment} - posts.comments.show

3. Sử Dụng Nested Resources trong Controller

Bạn có thể sử dụng nested resources trong controller của bạn để quản lý các hành động liên quan đến mô hình lồng nhau.

namespace App\Http\Controllers;

use App\Models\Post;
use App\Models\Comment;
use Illuminate\Http\Request;

class CommentController extends Controller
{
    public function index(Post $post)
    {
        $comments = $post->comments;
        return view('comments.index', compact('comments'));
    }

    public function show(Post $post, Comment $comment)
    {
        return view('comments.show', compact('post', 'comment'));
    }

    public function create(Post $post)
    {
        return view('comments.create', compact('post'));
    }

    public function store(Request $request, Post $post)
    {
        $validatedData = $request->validate([
            'body' => 'required|max:255',
        ]);

        $post->comments()->create($validatedData);

        return redirect()->route('posts.comments.index', $post);
    }

    public function edit(Post $post, Comment $comment)
    {
        return view('comments.edit', compact('post', 'comment'));
    }

    public function update(Request $request, Post $post, Comment $comment)
    {
        $validatedData = $request->validate([
            'body' => 'required|max:255',
        ]);

        $comment->update($validatedData);

        return redirect()->route('posts.comments.index', $post);
    }

    public function destroy(Post $post, Comment $comment)
    {
        $comment->delete();

        return redirect()->route('posts.comments.index', $post);
    }
}

4. Ràng Buộc Ngầm Định và Nested Resources

Laravel tự động ràng buộc các Model cho các nested resources. Khi bạn định nghĩa một nested resource, Laravel sẽ tự động ràng buộc các Model cha cho các tuyến đường con. Ví dụ, trong CommentController, mô hình Post sẽ tự động được ràng buộc trước khi mô hình Comment.

Nested resources cung cấp một cách rõ ràng và dễ dàng để quản lý mối quan hệ giữa các mô hình trong ứng dụng Laravel của bạn. Bằng cách sử dụng nested resources, bạn có thể tạo ra các tuyến đường và controller hành động cho các mô hình lồng nhau một cách trực quan và dễ dàng.

 

Ví dụ về các vấn đề truy vấn N+1

Ví dụ về các vấn đề truy vấn N+1

01.08.2024
Author: ADMIN

# Vấn Đề N+1 Query Trong Eloquent

Vấn đề N+1 query là một trong những vấn đề phổ biến mà các nhà phát triển gặp phải khi làm việc với ORM như Eloquent trong Laravel. Vấn đề này xảy ra khi ứng dụng của bạn thực hiện một lượng lớn các truy vấn nhỏ lặp đi lặp lại để lấy dữ liệu liên quan, thay vì chỉ thực hiện một vài truy vấn lớn hơn, dẫn đến giảm hiệu suất ứng dụng. Dưới đây là bốn ví dụ về vấn đề N+1 query và cách giải quyết chúng.

# Laravel Debugbar

Trước khi vào các ví dụ cụ thể, bạn nên cài đặt Laravel Debugbar để có thể kiểm tra  và debug các ứng dụng Laravel một cách dễ dàng. Debugbar hiển thị các thông tin chi tiết về các truy vấn cơ sở dữ liệu, các biến session, các yêu cầu HTTP và nhiều thông tin khác ngay trên giao diện của ứng dụng.

composer require barryvdh/laravel-debugbar --dev

Tiếp theo, bạn chỉ cần kích hoạt chế độ gỡ lỗi với biến APP_DEBUG=true trong file .env

// .env
APP_DEBUG=true 

Ví Dụ 1: Lấy Dữ Liệu Liên Quan Trong Vòng Lặp

Mã Gặp Vấn Đề N+1 Query:
$posts = Post::all();

foreach ($posts as $post) {
    echo $post->user->name;
}
Giải Thích:

Đoạn mã trên sẽ thực hiện một truy vấn để lấy tất cả các bài viết. Sau đó, nó sẽ thực hiện một truy vấn riêng lẻ cho mỗi bài viết để lấy thông tin người dùng liên quan, dẫn đến tổng cộng 1 + N truy vấn (N là số lượng bài viết).

Giải Quyết Sử Dụng Eager Loading:
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    echo $post->user->name;
}
Giải Thích:

Bằng cách sử dụng phương thức with, chúng ta chỉ thực hiện hai truy vấn: một truy vấn để lấy tất cả các bài viết và một truy vấn để lấy tất cả các người dùng liên quan.

Ví Dụ 2: Ký hiệu

Giả sử bạn có cùng mối quan hệ hasMany giữa tác giả và sách và bạn cần liệt kê các tác giả cùng số lượng sách của mỗi tác giả.

// Controller

public function index()
{
    $authors = Author::with('books')->get();
 
    return view('authors.index', compact('authors'));
}

Và sau đó, trong tệp Blade, bạn thực hiện một vòng lặp foreach cho bảng:

@foreach($authors as $author)
    <tr>
        <td>{{ $author->name }}</td>
        <td>{{ $author->books()->count() }}</td>
    </tr>
@endforeach

Mọi thứ trông có vẻ hợp lý, đúng không? Nhưng nhìn vào dữ liệu Debugbar bên dưới.

Chúng ta đang sử dụng eager loading, Author::with('books'), nhưng tại sao lại có nhiều truy vấn xảy ra như thế?

Bởi vì, trong Blade,  $author->books()->count() không load mối quan hệ từ bộ nhớ.

  • $author->books() có nghĩa là PHƯƠNG THỨC của mối quan hệ
  • $author->books có nghĩa là DỮ LIỆU được eager loaded vào bộ nhớ

Vậy, phương pháp liên kết sẽ truy vấn cơ sở dữ liệu cho mỗi tác giả. Nhưng nếu bạn tải dữ liệu mà không có dấu ngoặc "()", nó sẽ thành công sử dụng dữ liệu được eager loading:

Vì vậy, hãy chú ý đến chính xác những gì bạn đang sử dụng - phương pháp quan hệ hay dữ liệu.

Lưu ý rằng trong ví dụ cụ thể này có một giải pháp thậm chí còn tốt hơn. Nếu bạn chỉ cần dữ liệu tổng hợp được tính toán của mối quan hệ, mà không cần mô hình đầy đủ, thì bạn chỉ nên tải các tổng hợp, như withCount:

// Controller:
$authors = Author::withCount('books')->get();
 
// Blade:
{{ $author->books_count }}

Kết quả sẽ chỉ có MỘT truy vấn đến cơ sở dữ liệu, thậm chí không phải là hai truy vấn. Và bộ nhớ cũng sẽ không bị "polluted" với dữ liệu quan hệ, do đó cũng tiết kiệm được một số RAM.

Ví Dụ 3: Mối quan hệ "ẩn" trong Accessor

Hãy lấy một ví dụ tương tự: danh sách các tác giả, với cột cho biết tác giả có hoạt động hay không: "Có" hoặc "Không". Hoạt động đó được xác định bởi việc tác giả có ít nhất một cuốn sách hay không và được tính như một accessor bên trong mô hình Author.

// Controller:
public function index()
{
    $authors = Author::all();
 
    return view('authors.index', compact('authors'));
}

// Blade file
@foreach($authors as $author)
    <tr>
        <td>{{ $author->name }}</td>
        <td>{{ $author->is_active ? 'Yes' : 'No' }}</td>
    </tr>
@endforeach

"is_active" được định nghĩa trong model Eloquent:

use Illuminate\Database\Eloquent\Casts\Attribute;
 
class Author extends Model
{
    public function isActive(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->books->count() > 0,
        );
    }
}

Hãy xem Debugbar hiển thị những gì:

Đúng, chúng ta có thể giải quyết bằng  eager loading các sách trong Controller. Nhưng trong trường hợp này, lời khuyên chung của tôi là tránh sử dụng các mối quan hệ trong accessor . Bởi vì accessor thường được sử dụng khi hiển thị dữ liệu và trong tương lai, người khác có thể sử dụng accessor này trong một số tệp Blade khác và bạn sẽ không kiểm soát được Controller đó trông như thế nào.

Nói cách khác, Accessor được cho là một phương pháp có thể tái sử dụng để định dạng dữ liệu, do đó bạn không kiểm soát được khi nào/cách thức dữ liệu sẽ được tái sử dụng. Trong trường hợp hiện tại của bạn, bạn có thể tránh truy vấn N+1, nhưng trong tương lai, người khác có thể không nghĩ đến nó.

# Giải pháp tích hợp chống lại truy vấn N + 1
Add eloquent strict loading mode

Eager Loading

Eager Loading

01.08.2024
Author: ADMIN

# Eager Loading

Eager loading là một kỹ thuật trong Eloquent ORM của Laravel để giảm số lượng truy vấn đến cơ sở dữ liệu bằng cách tải các quan hệ của model ngay lập tức khi bạn truy vấn model chính. Điều này giúp cải thiện hiệu suất ứng dụng bằng cách tránh vấn đề N+1 queries, nơi bạn thực hiện nhiều truy vấn không cần thiết khi tải các quan hệ.

Ví Dụ: Eager Loading với Mối Quan Hệ Một-Nhiều

Giả sử bạn có một model Post và mỗi bài viết có nhiều Comment. Khi bạn muốn lấy tất cả các bài viết cùng với các bình luận của chúng, bạn có thể sử dụng eager loading để giảm số lượng truy vấn SQL.

Model và Cấu Trúc Bảng
  1. Model Post

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Post extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều với Comment.
         */
        public function comments()
        {
            return $this->hasMany(Comment::class);
        }
    }
    

     

  2. Model Comment
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Comment extends Model
    {
        /**
         * Thiết lập mối quan hệ nhiều-một với Post.
         */
        public function post()
        {
            return $this->belongsTo(Post::class);
        }
    }
    
  3. Cấu Trúc Bảng
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->timestamps();
    });
    
    Schema::create('comments', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('post_id');
        $table->text('content');
        $table->timestamps();
    
        $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
    });
    
  4. Sử Dụng Eager Loading
    4.1 Truy Vấn Bình Thường (Lazy Loading)
    // Lấy tất cả bài viết
    $posts = Post::all();
    
    // Truy xuất các bình luận của mỗi bài viết (N+1 queries)
    foreach ($posts as $post) {
        foreach ($post->comments as $comment) {
            // Xử lý bình luận
        }
    }
    

    4.2 Sử Dụng Eager Loading

    // Lấy tất cả bài viết cùng với các bình luận của chúng (1 query cho bài viết + 1 query cho bình luận)
    $posts = Post::with('comments')->get();
    
    // Truy xuất các bình luận của mỗi bài viết mà không thực hiện thêm truy vấn
    foreach ($posts as $post) {
        foreach ($post->comments as $comment) {
            // Xử lý bình luận
        }
    }
    
  5. Các Tùy Chọn Eager Loading

    5.1 Chỉ Định Các Quan Hệ Nâng Cao

    Bạn có thể eager load nhiều quan hệ hoặc nested quan hệ (quan hệ trong quan hệ) bằng cách chỉ định chúng trong phương thức with.

    // Eager load các quan hệ bình luận và user của mỗi bình luận
    $posts = Post::with('comments.user')->get();
    

    5.2 Sử Dụng withCount
    Bạn có thể sử dụng withCount để lấy số lượng các quan hệ mà không cần phải lấy dữ liệu chi tiết của quan hệ.

    // Lấy số lượng bình luận cho mỗi bài viết
    $posts = Post::withCount('comments')->get();
    
    foreach ($posts as $post) {
        echo $post->comments_count; // Số lượng bình luận
    }
    
    5.3 Eager Load Với Điều Kiện
    // Eager load bình luận với điều kiện chỉ lấy những bình luận mới nhất
    $posts = Post::with(['comments' => function ($query) {
        $query->where('created_at', '>', now()->subDays(7));
    }])->get();
    

# Nested Eager Loading morphTo Relationships

Khi làm việc với các mối quan hệ polymorphic trong Eloquent, bạn có thể cần thực hiện eager loading không chỉ cho các mối quan hệ polymorphic mà còn cho các mối quan hệ liên quan đến các model mà chúng liên kết đến. Đây được gọi là nested eager loading.

Mối Quan Hệ Polymorphic (morphTo) cho phép một model liên kết với nhiều model khác và không cần phải tạo nhiều cột khóa ngoại. Khi sử dụng eager loading với các mối quan hệ polymorphic, bạn có thể tải tất cả các dữ liệu cần thiết trong một truy vấn hiệu quả.

Ví Dụ: Nested Eager Loading với Mối Quan Hệ Polymorphic

Giả sử bạn có một hệ thống bình luận mà mỗi bình luận có thể thuộc về nhiều loại model khác nhau (như Post hoặc Video). Đồng thời, mỗi bình luận có thể được gán cho một người dùng (user). Dưới đây là cách bạn có thể thiết lập và thực hiện nested eager loading cho các mối quan hệ này.

Cấu Trúc và Model
  1. Model Comment

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Comment extends Model
    {
        /**
         * Thiết lập mối quan hệ polymorphic.
         */
        public function commentable()
        {
            return $this->morphTo();
        }
    
        /**
         * Thiết lập mối quan hệ nhiều-một với User.
         */
        public function user()
        {
            return $this->belongsTo(User::class);
        }
    }
    

     

  2. Model Post
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Post extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều polymorphic với Comment.
         */
        public function comments()
        {
            return $this->morphMany(Comment::class, 'commentable');
        }
    }
    
  3. Model Video
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Video extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều polymorphic với Comment.
         */
        public function comments()
        {
            return $this->morphMany(Comment::class, 'commentable');
        }
    }
    
  4. Model User
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class User extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều với Comment.
         */
        public function comments()
        {
            return $this->hasMany(Comment::class);
        }
    }
    
  5. Cấu Trúc Bảng
    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->unsignedBigInteger('commentable_id');
        $table->string('commentable_type');
        $table->unsignedBigInteger('user_id');
        $table->text('content');
        $table->timestamps();
    
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
    
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
    
  6. Thực Hiện Nested Eager Loading
    // Lấy tất cả các bài viết cùng với bình luận của chúng, bình luận có người dùng và video hoặc bài viết liên quan
    $posts = Post::with(['comments.user', 'comments.commentable'])->get();
    
    foreach ($posts as $post) {
        foreach ($post->comments as $comment) {
            echo $comment->content; // Nội dung bình luận
            echo $comment->user->name; // Tên người dùng bình luận
            echo $comment->commentable->title; // Tiêu đề của video hoặc bài viết liên quan
        }
    }
    

    Giải Thích:

    • Post::with(['comments.user', 'comments.commentable'])->get();: Phương thức with được sử dụng để eager load các quan hệ comments và trong comments, eager load user (người dùng bình luận) và commentable (model mà bình luận thuộc về, có thể là Post hoặc Video).
    • Trong ví dụ này, khi bạn truy xuất các bài viết và bình luận, tất cả các dữ liệu liên quan đến bình luận và người dùng bình luận, cùng với model liên quan của bình luận (có thể là bài viết hoặc video) sẽ được tải ngay lập tức, giúp giảm số lượng truy vấn đến cơ sở dữ liệu.
Các Mối Quan Hệ Trong Eloquent

Các Mối Quan Hệ Trong Eloquent

01.08.2024
Author: ADMIN

# Các Mối Quan Hệ Trong Eloquent

Eloquent cung cấp một hệ thống mạnh mẽ để quản lý các mối quan hệ giữa các mô hình trong cơ sở dữ liệu. Các mối quan hệ giúp bạn dễ dàng lấy dữ liệu liên quan từ các bảng khác nhau. Dưới đây là các loại mối quan hệ phổ biến trong Eloquent và cách sử dụng chúng:

1. Mối Quan Hệ Một-Một (One-to-One)

Một mối quan hệ một-một liên kết hai mô hình với nhau, với mỗi bản ghi trong bảng đầu tiên liên kết với một bản ghi trong bảng thứ hai.

Ví Dụ:

// Mô hình User
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}

// Mô hình Profile
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Cấu Trúc Bảng:

  • users table: id, name
  • profiles table: id, user_id, bio

2. Mối Quan Hệ Một-Nhiều (One-to-Many)

Một mối quan hệ một-nhiều cho phép một bản ghi trong bảng đầu tiên liên kết với nhiều bản ghi trong bảng thứ hai.

Ví Dụ:

// Mô hình Post
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

// Mô hình Comment
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

Cấu Trúc Bảng:

  • posts table: id, title
  • comments table: id, post_id, content

3. Mối Quan Hệ Nhiều-Nhiều (Many-to-Many)

Mối quan hệ nhiều-nhiều cho phép nhiều bản ghi trong bảng đầu tiên liên kết với nhiều bản ghi trong bảng thứ hai thông qua bảng trung gian.

Ví Dụ:

// Mô hình Student
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    public function courses()
    {
        return $this->belongsToMany(Course::class);
    }
}

// Mô hình Course
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Course extends Model
{
    public function students()
    {
        return $this->belongsToMany(Student::class);
    }
}

Cấu Trúc Bảng:

  • students table: id, name
  • courses table: id, title
  • course_student table: student_id, course_id

4. Mối Quan Hệ Một-Một (Polymorphic)

Mối quan hệ polymorphic cho phép một mô hình liên kết với nhiều mô hình khác theo cách linh hoạt.

Ví Dụ:

// Mô hình Comment
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

// Mô hình Post
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

// Mô hình Video
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

Cấu Trúc Bảng:

  • comments table: id, commentable_id, commentable_type, content
  • posts table: id, title
  • videos table: id, title

5. Mối Quan Hệ Một-Nhiều (Polymorphic)

 

Mối quan hệ một-nhiều polymorphic cho phép một mô hình liên kết với nhiều mô hình khác mà không cần phải tạo ra nhiều cột khóa ngoại. Điều này rất hữu ích khi bạn muốn một mô hình có thể liên kết với nhiều loại mô hình khác mà không cần tạo nhiều bảng trung gian.

Ví Dụ Cụ Thể

Giả sử bạn có một hệ thống mà người dùng có thể bình luận trên các bài viết (Post) và video (Video). Bạn có thể sử dụng mối quan hệ polymorphic để xử lý các bình luận mà không cần tạo bảng trung gian riêng cho mỗi loại mô hình.

Bước 1: Tạo Các Mô Hình và Cấu Trúc Bảng

  1. Tạo Model Comment
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Comment extends Model
    {
        /**
         * Thiết lập mối quan hệ polymorphic.
         */
        public function commentable()
        {
            return $this->morphTo();
        }
    }
    
  2. Tạo Model Post
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Post extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều polymorphic.
         */
        public function comments()
        {
            return $this->morphMany(Comment::class, 'commentable');
        }
    }
    
  3. Tạo Model Video
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Video extends Model
    {
        /**
         * Thiết lập mối quan hệ một-nhiều polymorphic.
         */
        public function comments()
        {
            return $this->morphMany(Comment::class, 'commentable');
        }
    }
    
  4. Tạo Cấu Trúc Bảng
    • Bảng comments

      Schema::create('comments', function (Blueprint $table) {
          $table->id();
          $table->text('content');
          $table->unsignedBigInteger('commentable_id');
          $table->string('commentable_type');
          $table->timestamps();
      });
      

       

      • commentable_id: ID của mô hình mà bình luận thuộc về.
      • commentable_type: Loại mô hình mà bình luận thuộc về (ví dụ: Post hoặc Video).
    • Bảng posts
      Schema::create('posts', function (Blueprint $table) {
          $table->id();
          $table->string('title');
          $table->timestamps();
      });
      
    • Bảng videos
      Schema::create('videos', function (Blueprint $table) {
          $table->id();
          $table->string('title');
          $table->timestamps();
      });
      

Bước 2: Sử Dụng Mối Quan Hệ

1. Thêm Bình Luận

use App\Models\Post;
use App\Models\Video;
use App\Models\Comment;

// Thêm bình luận cho một bài viết
$post = Post::find(1);
$post->comments()->create([
    'content' => 'Great post!',
]);

// Thêm bình luận cho một video
$video = Video::find(1);
$video->comments()->create([
    'content' => 'Amazing video!',
]);

2. Truy Xuất Bình Luận

// Truy xuất bình luận của một bài viết
$post = Post::find(1);
foreach ($post->comments as $comment) {
    echo $comment->content;
}

// Truy xuất bình luận của một video
$video = Video::find(1);
foreach ($video->comments as $comment) {
    echo $comment->content;
}

3. Lấy Mô Hình Từ Bình Luận

// Lấy mô hình mà bình luận thuộc về
$comment = Comment::find(1);
echo $comment->commentable_type; // Ví dụ: App\Models\Post hoặc App\Models\Video

6.Mối Quan Hệ Nhiều-Nhiều (Polymorphic)

Mối quan hệ nhiều-nhiều polymorphic cho phép một mô hình liên kết với nhiều mô hình khác và ngược lại thông qua một bảng trung gian duy nhất. Điều này cho phép mô hình liên kết với nhiều mô hình khác mà không cần phải tạo nhiều bảng trung gian riêng biệt.

Ví Dụ: Tagging trên Bài Viết và Video

Cấu Trúc và Mô Hình
  1. Tạo Mô Hình Tag

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Tag extends Model
    {
        /**
         * Thiết lập mối quan hệ nhiều-nhiều polymorphic.
         */
        public function taggable()
        {
            return $this->morphTo();
        }
    }
    
  2. Tạo Mô Hình Post
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Post extends Model
    {
        /**
         * Thiết lập mối quan hệ nhiều-nhiều polymorphic.
         */
        public function tags()
        {
            return $this->morphToMany(Tag::class, 'taggable');
        }
    }
    
  3. Tạo Mô Hình Video
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Video extends Model
    {
        /**
         * Thiết lập mối quan hệ nhiều-nhiều polymorphic.
         */
        public function tags()
        {
            return $this->morphToMany(Tag::class, 'taggable');
        }
    }
    
  4. Tạo Cấu Trúc Bảng
    Schema::create('tags', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
    
    Schema::create('taggables', function (Blueprint $table) {
        $table->unsignedBigInteger('tag_id');
        $table->unsignedBigInteger('taggable_id');
        $table->string('taggable_type');
        $table->timestamps();
    });
    
  5. Sử dụng
    // Thêm tag cho một bài viết
    $post = Post::find(1);
    $tag = Tag::find(1);
    $post->tags()->attach($tag);
    
    // Thêm tag cho một video
    $video = Video::find(1);
    $tag = Tag::find(2);
    $video->tags()->attach($tag);
    

Kết Luận

  • Một-Một (One-to-One): Liên kết mỗi bản ghi trong bảng đầu tiên với một bản ghi trong bảng thứ hai.
  • Một-Nhiều (One-to-Many): Liên kết một bản ghi trong bảng đầu tiên với nhiều bản ghi trong bảng thứ hai.
  • Nhiều-Nhiều (Many-to-Many): Liên kết nhiều bản ghi trong bảng đầu tiên với nhiều bản ghi trong bảng thứ hai thông qua bảng trung gian.
  • Polymorphic: Cho phép liên kết linh hoạt với nhiều mô hình khác.

Các mối quan hệ trong Eloquent giúp bạn dễ dàng quản lý và truy xuất dữ liệu liên quan trong ứng dụng của bạn, làm cho việc tương tác với cơ sở dữ liệu trở nên dễ dàng và trực quan hơn.

Quản Lý Thời Gian Tự Động Trong Eloquent

Quản Lý Thời Gian Tự Động Trong Eloquent

01.08.2024
Author: ADMIN

# Timestamps

Mặc định, Eloquent yêu cầu hai cột created_atupdated_at tồn tại trên bảng cơ sở dữ liệu tương ứng với mô hình của bạn. Eloquent sẽ tự động thiết lập giá trị cho các cột này khi mô hình được tạo mới hoặc cập nhật.

Tuy nhiên, nếu bạn không muốn Eloquent tự động quản lý các cột thời gian này, bạn có thể cấu hình mô hình của bạn để bỏ qua việc tự động cập nhật các cột created_atupdated_at. Để làm điều này, bạn cần định nghĩa thuộc tính $timestamps trên mô hình của bạn với giá trị false.

Ví Dụ Cụ Thể

Mô Hình Mặc Định Với Cột Thời Gian

Khi bạn tạo một mô hình Eloquent mà không cấu hình thuộc tính $timestamps, Eloquent sẽ tự động quản lý các cột thời gian:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Eloquent tự động quản lý created_at và updated_at
}

Bỏ Qua Quản Lý Thời Gian

Nếu bạn không muốn Eloquent tự động quản lý created_atupdated_at, bạn có thể cấu hình mô hình của bạn như sau:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Tắt quản lý created_at và updated_at
    public $timestamps = false;
}

# Tùy Chỉnh Định Dạng Thời Gian

Nếu bạn cần tùy chỉnh định dạng của các timestamp trên mô hình Eloquent của bạn, bạn có thể thiết lập thuộc tính $dateFormat trên mô hình. Thuộc tính này xác định cách các thuộc tính ngày tháng được lưu trữ trong cơ sở dữ liệu cũng như định dạng của chúng khi mô hình được chuyển đổi thành mảng hoặc JSON.

Ví Dụ Cụ Thể

Giả sử bạn muốn thay đổi định dạng ngày tháng từ mặc định (Y-m-d H:i:s) thành định dạng khác, chẳng hạn như d/m/Y H:i:s, bạn có thể thực hiện điều này bằng cách cấu hình thuộc tính $dateFormat trong mô hình của bạn.

Mô Hình Với Định Dạng Tùy Chỉnh

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Đặt định dạng ngày tháng tùy chỉnh
    protected $dateFormat = 'd/m/Y H:i:s';
}

Cách Hoạt Động

  • Lưu Trữ Trong Cơ Sở Dữ Liệu: Khi bạn lưu một mô hình vào cơ sở dữ liệu, Eloquent sẽ sử dụng định dạng d/m/Y H:i:s để lưu trữ giá trị thời gian vào các cột created_atupdated_at.
  • Chuyển Đổi Thành Mảng hoặc JSON: Khi bạn chuyển đổi mô hình thành mảng hoặc JSON, giá trị của các thuộc tính ngày tháng sẽ được định dạng theo cách bạn đã chỉ định trong thuộc tính $dateFormat.

# Tùy Chỉnh Tên Cột Thời Gian Trong Eloquent

Nếu bạn cần tùy chỉnh tên của các cột được sử dụng để lưu trữ timestamp (created_atupdated_at), bạn có thể định nghĩa các hằng số CREATED_ATUPDATED_AT trên mô hình của bạn. Điều này cho phép bạn thay đổi tên các cột mặc định mà Eloquent sử dụng để lưu trữ thời gian tạo và cập nhật.

Ví Dụ Cụ Thể

Giả sử bạn có các cột trong bảng cơ sở dữ liệu với tên là created_onupdated_on thay vì created_atupdated_at. Bạn có thể cấu hình mô hình của bạn như sau:

Mô Hình Với Tên Cột Tùy Chỉnh

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Định nghĩa tên cột tùy chỉnh cho thời gian tạo và cập nhật
    const CREATED_AT = 'created_on';
    const UPDATED_AT = 'updated_on';
}

Cách Hoạt Động

  • Lưu Trữ Trong Cơ Sở Dữ Liệu: Eloquent sẽ sử dụng các tên cột tùy chỉnh (created_onupdated_on) thay vì các tên mặc định (created_atupdated_at) khi lưu trữ giá trị thời gian vào cơ sở dữ liệu.
  • Lấy Dữ Liệu: Khi bạn lấy dữ liệu từ cơ sở dữ liệu, Eloquent sẽ sử dụng các tên cột tùy chỉnh này để gán giá trị cho thuộc tính created_atupdated_at của mô hình.

# Không Cập Nhật updated_at

Nếu bạn muốn thực hiện các thao tác với mô hình mà không làm thay đổi giá trị của timestamp updated_at, bạn có thể sử dụng phương thức withoutTimestamps. Phương thức này cho phép bạn thực hiện các thao tác trên mô hình mà không ảnh hưởng đến giá trị của updated_at.

Ví Dụ Cụ Thể

Giả sử bạn có một mô hình Post và bạn muốn cập nhật một thuộc tính của mô hình mà không làm thay đổi timestamp updated_at, bạn có thể sử dụng withoutTimestamps để thực hiện điều này.

Cập Nhật Mô Hình Mà Không Cập Nhật updated_at

use App\Models\Post;

// Tìm mô hình cần cập nhật
$post = Post::find(1);

// Thực hiện cập nhật mà không làm thay đổi timestamp
$post->withoutTimestamps(function () use ($post) {
    // Cập nhật thuộc tính của mô hình
    $post->title = 'New Title';
    $post->save();
});
Routing

Routing

01.08.2024
Author: ADMIN

# Basic Routing

1. Khái niệm về Route

Route trong Laravel là cách bạn định nghĩa URL cho ứng dụng của mình. Route giúp bạn chỉ định URL nào sẽ gọi đến Controller nào hoặc thực hiện hành động gì.

2. Định nghĩa Route Cơ Bản

Tất cả các route của Laravel được định nghĩa trong các file nằm trong thư mục routes. Các file này được tự động tải bởi App\Providers\RouteServiceProvider của ứng dụng của bạn. Có bốn file route chính:

  • web.php: Định nghĩa các route cho web application.
  • api.php: Định nghĩa các route cho API.
  • console.php: Định nghĩa các route cho console commands.
  • channels.php: Định nghĩa các route cho event broadcasting channels.

Định nghĩa route trong web.php

Dưới đây là một ví dụ đơn giản về cách định nghĩa một route trong file web.php:

Route::get('/', function () {
    return view('welcome');
});

Trong ví dụ trên:

  • Route::get('/'): Định nghĩa một route sử dụng phương thức GET cho URL /.
  • function () { return view('welcome'); }: Định nghĩa hành động sẽ thực hiện khi người dùng truy cập vào URL /. Ở đây, Laravel sẽ trả về view welcome.

3. Các Phương Thức Route

Laravel hỗ trợ nhiều phương thức HTTP khác nhau, bao gồm:

  • GET: Dùng để truy xuất dữ liệu từ server.
  • POST: Dùng để gửi dữ liệu lên server.
  • PUT: Dùng để cập nhật dữ liệu trên server.
  • PATCH: Dùng để cập nhật một phần tài nguyên trên server. Tương tự như PUT nhưng chỉ cập nhật các phần cụ thể của tài nguyên.
  • DELETE: Dùng để xóa dữ liệu từ server.
  • OPTIONS: Dùng để truy vấn các phương thức HTTP mà server hỗ trợ cho một URL cụ thể. Thường được sử dụng trong các ứng dụng RESTful API để kiểm tra các tùy chọn giao tiếp.

Ví dụ về các phương thức khác nhau:

Route::get('/products', function () {
    return 'Get all products';
});

Route::post('/products', function () {
    return 'Create a new product';
});

Route::put('/products/{id}', function ($id) {
    return 'Update the product with ID ' . $id;
});

Route::patch('/products/{id}', function ($id) {
    return 'Partially update the product with ID ' . $id;
});

Route::delete('/products/{id}', function ($id) {
    return 'Delete the product with ID ' . $id;
});

Route::options('/products', function () {
    return response()->json(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
});

4. Route với Tham Số

Bạn có thể định nghĩa route có tham số như sau:

Route::get('/user/{id}', function ($id) {
    return 'User '.$id;
});

Trong ví dụ này, {id} là một tham số động. Khi người dùng truy cập vào URL user/1, Laravel sẽ gán giá trị 1 vào biến $id và trả về User 1.

5. Route Groups

Bạn có thể nhóm các route lại với nhau bằng cách sử dụng Route::group. Điều này giúp bạn dễ dàng áp dụng middleware hoặc tiền tố URL cho một nhóm route.

Route::group(['prefix' => 'admin'], function () {
    Route::get('/users', function () {
        // Matches The "/admin/users" URL
    });

    Route::get('/settings', function () {
        // Matches The "/admin/settings" URL
    });
});

Trong ví dụ trên, tất cả các route trong nhóm này sẽ có tiền tố admin.

6. Middleware

Middleware là các lớp trung gian mà HTTP request phải đi qua trước khi đến Controller. Bạn có thể áp dụng middleware cho route như sau:

Route::get('/profile', function () {
    // Only authenticated users may enter...
})->middleware('auth');

Trong ví dụ này, middleware auth sẽ kiểm tra xem người dùng có được xác thực hay không trước khi cho phép truy cập vào route /profile.

Laravel cung cấp hai nhóm middleware chính cho các file route:

  • web middleware group: Được áp dụng cho các route trong routes/web.php. Middleware nhóm này bao gồm các tính năng như:
    • Session state
    • CSRF protection
    • Cookie encryption
    • ...
  • api middleware group: Được áp dụng cho các route trong routes/api.php. Middleware nhóm này bao gồm các tính năng như:
    • Stateless (không trạng thái)
    • Token-based authentication
    • Rate limiting
    • ...

7. CSRF Protection

Hãy nhớ rằng, bất kỳ biểu mẫu HTML nào trỏ tới các route sử dụng phương thức POST, PUT, PATCH, hoặc DELETE được định nghĩa trong file route web cần phải bao gồm trường token CSRF. Nếu không, yêu cầu sẽ bị từ chối. Bạn có thể đọc thêm về bảo vệ CSRF trong tài liệu CSRF:

<form method="POST" action="/profile">
    @csrf
    <!-- Các trường input khác -->
    <button type="submit">Submit</button>
</form>

Việc bảo vệ CSRF rất quan trọng để ngăn chặn các tấn công giả mạo yêu cầu từ trang chéo, đảm bảo rằng các yêu cầu tới server đến từ nguồn đáng tin cậy.

8. Redirect Routes

Nếu bạn định nghĩa một route để chuyển hướng đến một URI khác, bạn có thể sử dụng phương thức Route::redirect. Phương thức này cung cấp một cách tắt thuận tiện để bạn không phải định nghĩa một route hoặc controller đầy đủ cho việc thực hiện chuyển hướng đơn giản.

Ví dụ:

Route::redirect('/here', '/there');

Mặc định, Route::redirect sẽ trả về mã trạng thái 302. Mã trạng thái 302 cho biết rằng tài nguyên đã được di chuyển tạm thời đến một vị trí mới.

Tuỳ Chỉnh Mã Trạng Thái

Bạn có thể tuỳ chỉnh mã trạng thái bằng cách sử dụng tham số thứ ba tùy chọn:

Route::redirect('/here', '/there', 301);

Trong ví dụ này, mã trạng thái 301 được sử dụng để chỉ ra rằng tài nguyên đã được di chuyển vĩnh viễn đến một vị trí mới.

Sử Dụng Route::permanentRedirect

Hoặc, bạn có thể sử dụng phương thức Route::permanentRedirect để trả về mã trạng thái 301:

Route::permanentRedirect('/here', '/there');

9. The Route List

Lệnh Artisan route:list là một công cụ mạnh mẽ giúp bạn dễ dàng xem tất cả các route đã được định nghĩa trong ứng dụng của bạn. Dưới đây là các cách sử dụng lệnh route:list cùng với giải thích chi tiết:

Hiển Thị Danh Sách Các Route

Để xem tất cả các route được định nghĩa trong ứng dụng của bạn, bạn có thể sử dụng lệnh:

php artisan route:list

Lệnh này hiển thị một bảng tổng quan của tất cả các route trong ứng dụng, bao gồm các thông tin như phương thức HTTP, URI, tên route, và hành động (action) của route đó. Đây là cách nhanh chóng để bạn kiểm tra cấu hình các route hiện tại của ứng dụng.

Hiển Thị Middleware và Tên Các Nhóm Middleware

Mặc định, lệnh route:list không hiển thị các middleware gán cho mỗi route. Để hiển thị các middleware và tên các nhóm middleware, bạn có thể sử dụng tùy chọn -v:

php artisan route:list -v

Thêm -v (verbose) vào lệnh sẽ hiển thị thêm các thông tin về các middleware áp dụng cho từng route. Nếu bạn muốn mở rộng thêm thông tin về các nhóm middleware, bạn có thể sử dụng -vv:

php artisan route:list -vv

Tùy chọn -vv cung cấp một cái nhìn chi tiết hơn về các nhóm middleware và các middleware cá nhân được gán cho các route, giúp bạn thấy rõ hơn cách các route được xử lý.

Hiển Thị Các Route Bắt Đầu Với Một URI Cụ Thể

Để chỉ hiển thị các route bắt đầu với một URI cụ thể, bạn có thể sử dụng tùy chọn --path:

php artisan route:list --path=api

Thêm tùy chọn --path=api sẽ lọc các route và chỉ hiển thị các route có URI bắt đầu bằng /api. Đây là cách hữu ích để bạn chỉ xem các route liên quan đến API của bạn.

Ẩn Các Route Được Định Nghĩa Bởi Các Gói Thứ Ba

Để ẩn bất kỳ route nào được định nghĩa bởi các gói bên ngoài, bạn có thể sử dụng tùy chọn --except-vendor:

php artisan route:list --except-vendor

Tùy chọn --except-vendor sẽ loại bỏ các route đến từ các gói bên ngoài, giúp bạn tập trung vào các route được định nghĩa trong ứng dụng của bạn.

Chỉ Hiển Thị Các Route Được Định Nghĩa Bởi Các Gói Thứ Ba

Ngược lại, để chỉ hiển thị các route được định nghĩa bởi các gói bên ngoài, bạn có thể sử dụng tùy chọn --only-vendor:

php artisan route:list --only-vendor

Tùy chọn --only-vendor sẽ lọc các route và chỉ hiển thị các route đến từ các gói bên ngoài, giúp bạn xem xét các route của bên thứ ba mà không bị phân tâm bởi các route của ứng dụng của bạn.

Tóm Tắt Các Tùy Chọn Của route:list

  • php artisan route:list: Hiển thị danh sách tất cả các route.
  • php artisan route:list -v: Hiển thị danh sách route kèm theo thông tin về middleware và nhóm middleware.
  • php artisan route:list -vv: Hiển thị thông tin chi tiết về middleware và nhóm middleware.
  • php artisan route:list --path=api: Hiển thị các route có URI bắt đầu bằng /api.
  • php artisan route:list --except-vendor: Ẩn các route từ các gói bên ngoài.
  • php artisan route:list --only-vendor: Chỉ hiển thị các route từ các gói bên ngoài.

Tóm lại

Route là một phần không thể thiếu trong bất kỳ ứng dụng Laravel nào. Việc hiểu rõ và sử dụng thành thạo các route cơ bản sẽ giúp bạn xây dựng ứng dụng một cách hiệu quả và dễ dàng. Hy vọng bài viết này đã giúp bạn có cái nhìn tổng quan về hệ thống routing trong Laravel.

# Optional Parameters

Khi làm việc với các route trong Laravel, đôi khi bạn cần định nghĩa một tham số route mà không phải lúc nào cũng có mặt trong URI. Bạn có thể thực hiện điều này bằng cách đặt dấu ? sau tên tham số và cung cấp một giá trị mặc định cho biến tương ứng trong route. Dưới đây là cách làm việc với tham số route tùy chọn, cùng với các ví dụ và giải thích chi tiết.

Route::get('/user/{name?}', function (?string $name = null) {
    return $name;
});
 
Route::get('/user/{name?}', function (?string $name = 'John') {
    return $name;
});

1. Ràng Buộc Định Dạng Tham Số Route

Dưới đây là tổng hợp các cách sử dụng ràng buộc biểu thức chính quy cho tham số route trong Laravel:

// Ràng buộc tham số phải chỉ chứa các ký tự chữ cái
Route::get('/user/{name}', function (string $name) {
    // ...
})->where('name', '[A-Za-z]+');

// Ràng buộc tham số phải chỉ chứa các chữ số
Route::get('/user/{id}', function (string $id) {
    // ...
})->where('id', '[0-9]+');

// Ràng buộc nhiều tham số với các biểu thức chính quy khác nhau
Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

// Sử dụng các phương thức tiện ích để thêm ràng buộc
Route::get('/user/{id}/{name}', function (string $id, string $name) {
    // ...
})->whereNumber('id')->whereAlpha('name');

Route::get('/user/{name}', function (string $name) {
    // ...
})->whereAlphaNumeric('name');

Route::get('/user/{id}', function (string $id) {
    // ...
})->whereUuid('id');

Route::get('/user/{id}', function (string $id) {
    //
})->whereUlid('id');

Route::get('/category/{category}', function (string $category) {
    // ...
})->whereIn('category', ['movie', 'song', 'painting']);

// Ràng buộc toàn cục cho tham số route
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}

// Cho phép ký tự '/' trong giá trị tham số
Route::get('/search/{search}', function (string $search) {
    return $search;
})->where('search', '.*');

# Route Naming

Trong Laravel, bạn có thể đặt tên cho các route để tiện lợi hơn trong việc tạo URL hoặc chuyển hướng. Điều này giúp quản lý và tham chiếu đến các route dễ dàng hơn. Dưới đây là cách sử dụng route được đặt tên và các ví dụ cụ thể.

1. Đặt Tên Cho Route

Bạn có thể đặt tên cho một route bằng cách sử dụng phương thức name sau khi định nghĩa route.

Ví Dụ

Route::get('/user/profile', function () {
    // ...
})->name('profile');

Giải Thích

  • ->name('profile'): Đặt tên profile cho route /user/profile.

2. Đặt Tên Cho Route Trong Controller

Bạn cũng có thể đặt tên cho các route trỏ tới các action trong controller:

Ví Dụ

Route::get('/user/profile', [UserProfileController::class, 'show'])->name('profile');

Giải Thích

  • [UserProfileController::class, 'show']: Định nghĩa route trỏ tới phương thức show trong controller UserProfileController.
  • ->name('profile'): Đặt tên profile cho route này.

3. Tạo URL Từ Route Được Đặt Tên

Sau khi đã đặt tên cho một route, bạn có thể sử dụng tên của route để tạo URL hoặc chuyển hướng bằng các hàm trợ giúp của Laravel như routeredirect.

Tạo URL

$url = route('profile');
// Chuyển hướng
return redirect()->route('profile');
 
return to_route('profile');

Giải Thích

  • route('profile'): Tạo URL tới route có tên profile.
  • redirect()->route('profile'): Chuyển hướng tới route có tên profile.
  • to_route('profile'): Một cách khác để chuyển hướng tới route có tên profile.

4. Truyền Tham Số Cho Route Được Đặt Tên

Nếu route có các tham số, bạn có thể truyền các tham số này như một mảng đối số thứ hai cho hàm route.

Ví Dụ

Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');
 
$url = route('profile', ['id' => 1]);

Giải Thích

  • ['id' => 1]: Tham số id được truyền vào URL.

5. Thêm Tham Số Vào Query String

Nếu bạn truyền thêm các tham số vào mảng, các cặp key/value này sẽ tự động được thêm vào query string của URL.

Ví Dụ

Route::get('/user/{id}/profile', function (string $id) {
    // ...
})->name('profile');
 
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
 
// Kết quả: /user/1/profile?photos=yes

Giải Thích

  • ['id' => 1, 'photos' => 'yes']: Tham số photos được thêm vào query string của URL.

6. Thiết Lập Giá Trị Mặc Định Cho Tham Số URL

Bạn có thể thiết lập các giá trị mặc định cho tham số URL sử dụng phương thức URL::defaults.

7. Kiểm Tra Route Hiện Tại

Bạn có thể kiểm tra xem request hiện tại có được định tuyến tới một route cụ thể hay không bằng phương thức named trên một instance của Route. Điều này hữu ích khi làm việc với middleware.

Ví Dụ Trong Middleware

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
public function handle(Request $request, Closure $next): Response
{
    if ($request->route()->named('profile')) {
        // ...
    }
 
    return $next($request);
}

Giải Thích

  • $request->route()->named('profile'): Kiểm tra nếu route hiện tại có tên profile.

# Route Caching

Khi triển khai ứng dụng Laravel lên môi trường sản xuất, bạn nên tận dụng khả năng cache route của Laravel để tăng tốc độ xử lý. Việc sử dụng cache route sẽ giảm đáng kể thời gian cần thiết để đăng ký tất cả các route của ứng dụng. Dưới đây là cách tạo và quản lý cache route trong Laravel.

1. Tạo Route Cache

Để tạo cache cho các route, bạn sử dụng lệnh Artisan route:cache:

php artisan route:cache

Giải Thích

  • Lệnh php artisan route:cache: Tạo một file cache chứa tất cả các route của ứng dụng. Sau khi lệnh này được thực thi, file cache sẽ được tải lên mỗi khi có yêu cầu đến ứng dụng, giúp tăng tốc độ xử lý route.

2. Lưu Ý Khi Sử Dụng Route Cache

Sau khi chạy lệnh route:cache, file cache sẽ được tải mỗi khi có yêu cầu đến ứng dụng. Tuy nhiên, nếu bạn thêm hoặc thay đổi bất kỳ route nào, bạn cần tạo lại cache mới. Do đó, bạn chỉ nên chạy lệnh route:cache trong quá trình triển khai (deployment) của dự án.

3. Xóa Route Cache

Nếu bạn cần xóa cache route, bạn có thể sử dụng lệnh Artisan route:clear:

php artisan route:clear

Giải Thích

  • Lệnh php artisan route:clear: Xóa bỏ file cache route hiện tại. Điều này hữu ích khi bạn muốn cập nhật route mà không cần tạo cache mới ngay lập tức.

Quy Trình Sử Dụng Route Cache Trong Deployment

  1. Triển khai ứng dụng lên môi trường sản xuất.
  2. Chạy lệnh php artisan route:cache để tạo file cache cho route.
  3. Khi cần cập nhật hoặc thêm route mới, hãy chạy lệnh php artisan route:clear để xóa cache hiện tại và sau đó tạo lại cache bằng lệnh php artisan route:cache.

Ví Dụ Quy Trình Deployment

# Bước 1: Triển khai ứng dụng
# (Thực hiện các bước triển khai thông thường như kéo code mới, cài đặt dependency, v.v.)

# Bước 2: Tạo route cache
php artisan route:cache

# Sau khi thêm hoặc thay đổi route
# Bước 3: Xóa route cache hiện tại
php artisan route:clear

# Bước 4: Tạo lại route cache mới
php artisan route:cache

Tóm Tắt

Việc sử dụng cache route trong Laravel giúp cải thiện hiệu suất của ứng dụng khi triển khai lên môi trường sản xuất. Tuy nhiên, bạn cần nhớ rằng mỗi khi thay đổi hoặc thêm mới route, bạn phải xóa cache cũ và tạo lại cache mới. Điều này đảm bảo rằng ứng dụng của bạn luôn sử dụng các route mới nhất mà bạn đã định nghĩa.

# Tạo cache cho route
php artisan route:cache

# Xóa cache route hiện tại
php artisan route:clear

Bằng cách tuân thủ quy trình trên, bạn sẽ có thể tận dụng tối đa hiệu quả của tính năng route cache trong Laravel, giúp ứng dụng của bạn hoạt động nhanh hơn và hiệu quả hơn.

 

Database: Migrations

Database: Migrations

01.08.2024
Author: ADMIN

# Database Migrations

Migrations là một tính năng mạnh mẽ của Laravel giúp bạn quản lý cấu trúc cơ sở dữ liệu của ứng dụng một cách dễ dàng. Chúng cho phép bạn định nghĩa và thay đổi bảng trong cơ sở dữ liệu bằng mã PHP thay vì phải sử dụng SQL thuần.

Tạo Migration

Bạn có thể tạo một migration mới bằng cách sử dụng Artisan command make:migration:

php artisan make:migration create_users_table

Lệnh này sẽ tạo một file migration trong thư mục database/migrations. File migration có tên dựa trên timestamp hiện tại và mô tả mục đích của migration.

Cấu Trúc Migration

Một file migration điển hình gồm hai phương thức: updown.

  • up: Phương thức này dùng để định nghĩa các thay đổi bạn muốn thực hiện lên cơ sở dữ liệu (tạo bảng, thêm cột, thay đổi cột, ...).
  • down: Phương thức này dùng để đảo ngược các thay đổi đã thực hiện trong phương thức up.
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Chạy Migration

Sau khi tạo migration, bạn có thể chạy nó bằng lệnh sau:

php artisan migrate

Lệnh này sẽ thực hiện tất cả các file migration chưa được chạy trước đó.

Rollback Migration

Nếu bạn muốn quay lại migration cuối cùng đã chạy, bạn có thể sử dụng lệnh:

php artisan migrate:rollback

Để rollback nhiều migration, bạn có thể thêm tùy chọn --step:

php artisan migrate:rollback --step=3

Reset và Refresh Migration

  • Reset: Để rollback tất cả các migration:

    php artisan migrate:reset
    
  • Refresh: Để rollback tất cả các migration và sau đó chạy lại tất cả các migration từ đầu:
    php artisan migrate:refresh
    

Thêm Cột vào Bảng

Nếu bạn muốn thêm cột vào một bảng hiện có, bạn cần tạo một migration mới:

php artisan make:migration add_profile_to_users_table --table=users

Trong file migration, bạn có thể thêm cột như sau:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('profile')->nullable();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('profile');
    });
}

Xóa Bảng hoặc Cột

Để xóa bảng hoặc cột, bạn cũng tạo một migration mới và định nghĩa hành động trong phương thức updown.

php artisan make:migration drop_users_table

Trong file migration, bạn có thể xóa bảng như sau:

public function up()
{
    Schema::dropIfExists('users');
}

public function down()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

Tóm Tắt

Migrations là một phần quan trọng trong Laravel, giúp bạn quản lý cơ sở dữ liệu của ứng dụng một cách dễ dàng và hiệu quả. Chúng cho phép bạn định nghĩa các thay đổi đối với cấu trúc cơ sở dữ liệu bằng mã PHP, giúp việc theo dõi và quản lý các thay đổi trở nên dễ dàng hơn. Sử dụng migrations cũng giúp bạn duy trì tính nhất quán và khả năng sao lưu dữ liệu trong quá trình phát triển ứng dụng.