Rất vui được gặp lại tất cả các bạn. Như đã nói ở tập trước thì ngày hôm nay, nội dung sẽ nói về "Blade template" trong Laravel. Tập ngày hôm nay chủ yếu chỉ học cú pháp và lợi ích của từng cú pháp đó, tuy dài nhưng không khó. Không luyên thuyên nữa, chúng ta vào bài thôi.
Vì editor của Viblo không hỗ trợ Blade template Laravel nên đôi khi màu sắc code có chỗ khó nhìn, mong các bạn thông cảm.
I. Giới thiệu [Introduction]
Blade là một template engine được cung cấp bởi Laravel. Đây là một engine khá mạnh mẽ, không như những các template engine khác, Blade không hạn chế việc sử dụng mã code PHP thuần túy trong template của bạn ngoài những cú pháp riêng biệt của nó. Thực tế thì Blade template được biên dịch thành các file PHP và được lưu vào cache. Blade template có đuôi mở rộng là
resources/
├── views/
| ├── components/
| | | ...
1 và được lưu trữ trong thư mục resources/
├── views/
| ├── components/
| | | ...
2.II. Layout template
1. Xác định bố cục [Defining layout]
Có hai lợi ích chính trong việc sử dụng Blade template là layout và section. Để bắt đầu chúng ta sẽ đi vào một ví dụ đơn giản. Như các bạn đã biết, trong một ứng dụng thì đa phần các trang con đều được thừa hưởng một cấu trúc layout chung. Blade template cho phép chúng ta định nghĩa một layout cho ứng dụng với duy nhất một blade view.
Laravel
@section['sidebar']
Sidebar
@show
@yield['content']
Đây chỉ là nội dung của một đoạn mã HTML bình thường, nhưng có chút đặt biệt là nó có hai cú pháp lạ:
resources/
├── views/
| ├── components/
| | | ...
3, resources/
├── views/
| ├── components/
| | | ...
4. Đây chính là một trong những cú pháp riêng biệt của Blade template dùng cho mục đích kế thừa qua lại giữa parent-child.
3: dùng để xác định một phần nội dungresources/ ├── views/ | ├── components/ | | | ...
4: dùng để hiển thị nội dung của một phần đã được xác địnhresources/ ├── views/ | ├── components/ | | | ...
Hiện tại khó mà để hiểu theo giải thích bằng văn được. Để các bạn có thể hiểu chi tiết công dụng của hai cú pháp này, mình sẽ làm sáng tỏ chúng qua ví dụ.
2. Kế thừa layout [Extending layout]
Như đã nói ở trên, công dụng chung của hai thằng
resources/
├── views/
| ├── components/
| | | ...
3 và resources/
├── views/
| ├── components/
| | | ...
8 là dùng cho mục đích kế thừa. Blade view resources/
├── views/
| ├── components/
| | | ...
9 là parent, vì nó là layout cho ứng dụng, vì vậy mình sẽ tạo một blade view
{{ $slot }}
0 đóng vai trò là child kế thừa parent resources/
├── views/
| ├── components/
| | | ...
9.@extends['app']
@section['content']
My content
@endsection
Mình đã sử dụng cú pháp
{{ $slot }}
2, điều này giúp blade view
{{ $slot }}
0 có thể kế thừa resources/
├── views/
| ├── components/
| | | ...
9. Tiếp theo mình đã xác định nội dung cho section
{{ $slot }}
5 thông qua thẻ resources/
├── views/
| ├── components/
| | | ...
3. Bây giờ đăng ký route và xem thử nó hoạt động như thế nào.Route::get['/', function[] {
return view['child'];
}];
Ở đây chúng ta render view
{{ $slot }}
0 chứ không phải resources/
├── views/
| ├── components/
| | | ...
9 nhé. Kết qua thu được như thế này:Chữ "My content" xuất hiện thì khá dễ hiểu, vì chúng đã xác định nội dung cho section
{{ $slot }}
5, nên lệnh resources/
├── views/
| ├── components/
| | | ...
4 sẽ thực hiện công việc render. Nhưng sao section @extends['app']
@section['content']
My content
@endsection
01 vẫn được hiển thị? Mình dùng resources/
├── views/
| ├── components/
| | | ...
3 để xác định nội dung @extends['app']
@section['content']
My content
@endsection
01 như
{{ $slot }}
5 thôi mà. Hãy quan sát so sánh sau:Cú pháp
resources/
├── views/
| ├── components/
| | | ...
3 cho section
{{ $slot }}
5 thì như sau:@section['content']
My content
@endsection
Nó có thẻ mở
resources/
├── views/
| ├── components/
| | | ...
3 và thẻ đóng @extends['app']
@section['content']
My content
@endsection
08. Trong khi đó, lệnh resources/
├── views/
| ├── components/
| | | ...
3 cho section @extends['app']
@section['content']
My content
@endsection
01 thì khác một chút:@section['sidebar']
Sidebar
@show
Thẻ đóng lúc này là
@extends['app']
@section['content']
My content
@endsection
11, chính vì thể cú pháp này không chỉ là xác định nội dung cho @extends['app']
@section['content']
My content
@endsection
01 mà đồng với với @extends['app']
@section['content']
My content
@endsection
11 nó sẽ render section này luôn. Đó là lý do vì sao mà chữ "Sidebar" lại xuất hiện.Nhưng tại sao lại không dùng
resources/
├── views/
| ├── components/
| | | ...
4 luôn cho tiện mà phải dùng resources/
├── views/
| ├── components/
| | | ...
3 rồi đóng bằng thẻ @extends['app']
@section['content']
My content
@endsection
11 để render? Cái gì cũng có nguyên nhân của nó cả, vì khi sử dụng @extends['app']
@section['content']
My content
@endsection
17 trong layout thì bạn có thể làm một điều thú vị trong các trang con. Mình sẽ dẫn chứng ngay và luôn, các bạn mở file @extends['app']
@section['content']
My content
@endsection
18 và thêm đoạn code này vào:@section['sidebar']
@parent
Item 1
Item 1
@endsection
Giờ cứ thử xem kết quả trước đã rồi mình sẽ giải thích.
Như các bạn thấy, section
@extends['app']
@section['content']
My content
@endsection
01 không chỉ không mất chữ "Sidebar" mà còn có thêm cái list mình mới vừa tạo. Bây giờ hãy bắt đầu quan sát lại đoạn code vừa thêm ở trên, mình đã có thêm thẻ @extends['app']
@section['content']
My content
@endsection
20. Với thẻ này thì các section được định nghĩa lại trong trang con sẽ append vào section ở blade view cha. Trong trường hợp này blade view
{{ $slot }}
0 đã extend blade view resources/
├── views/
| ├── components/
| | | ...
9 nên chính vì thế khi khai báo lại section @extends['app']
@section['content']
My content
@endsection
01 thì nó đã append thêm cái list ở dưới chữ "Sidebar".Vậy thử đoán xem điều gì sẽ xảy ra nếu mình bỏ đi thẻ
@extends['app']
@section['content']
My content
@endsection
20? Vâng, lúc này section @extends['app']
@section['content']
My content
@endsection
01 được khai báo trong blade view
{{ $slot }}
0 sẽ ghi đè hoàn toàn lên section @extends['app']
@section['content']
My content
@endsection
01 ở blade view resources/
├── views/
| ├── components/
| | | ...
9.
Nói một chút về
resources/
├── views/
| ├── components/
| | | ...
3 thì ngoài cách khai báo xác định nội dung trên thì ta còn có một cú pháp khác để xác định nội dung của một phần nào đó như sau:@section['title', 'Laravel']
Thông thường với cách này thường áp dụng cho các section chứa nội dung ngắn gọn hoặc không chứa các thẻ HTML.
Ngoài ra,
resources/
├── views/
| ├── components/
| | | ...
4 còn có thể nhận tham số thứ hai làm giá trị mặc định nếu các trang con extend với nó không xác định nội dung cho phần đã khai báo.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
Lưu ý: Kết thúc mỗi thẻ trong cú pháp Blade template không có dấu
31. Kết thúc mỗi thẻ trong cú pháp Blade template không có dấu@extends['app'] @section['content'] My content @endsection
31.@extends['app'] @section['content'] My content @endsection
III. Component & Slot
Component và slot cung cấp tính năng khá giống với section và layout, nhưng có vài chỗ thì component và slot dễ hiểu hơn nhiều. Hiểu đơn giản thì component là các thành phần, còn slot là nơi chứa nội dung sẽ thay đổi nhiều lần. Hãy tưởng tượng nếu ứng dụng của bạn có nhiều xử lý cần hiện modal để thông báo, nhưng bạn lại muốn có thể sử dụng lại mà không cần phải khai báo nhiều lần. Lúc này component chính là modal, và nội dung thông báo chính là slot.
Thông thường các component được khai báo trong view, bạn có thể tự tổ chức cấu trúc thư mục để lưu trữ các component, hoặc là có thể tham khảo theo cấu trúc của mình.
resources/
├── views/
| ├── components/
| | | ...
1. Khởi tạo component & slot [Creating component & slot]
Bây giờ mình sẽ tạo component modal đặt trong file
@extends['app']
@section['content']
My content
@endsection
32 với nội dung sau:
{{ $slot }}
Cú pháp
@extends['app']
@section['content']
My content
@endsection
33 sẽ chứa nội dung thông báo thay đổi liên tục trong suốt ứng dụng.Lưu ý::
34 không thể thay đổi tên biến khác.:@extends['app'] @section['content'] My content @endsection
34 không thể thay đổi tên biến khác.@extends['app'] @section['content'] My content @endsection
Mọi thiết lập đã hoàn tất, giờ chỉ cần lấy ra sử dụng thôi. Mình sẽ sử dụng lại blade view
{{ $slot }}
0 hồi nãy để test luôn.@extends['app']
@section['content']
My content
@endsection
0Chúng ta sử dụng cặp thẻ
@extends['app']
@section['content']
My content
@endsection
36 để gọi component @extends['app']
@section['content']
My content
@endsection
37, đồng thời khai báo slot. Tham số trong @extends['app']
@section['content']
My content
@endsection
38 là tên blade view chứa component, nội dung trong cặp thẻ chính là giá trị mà @extends['app']
@section['content']
My content
@endsection
34 nhận được. Nạp lại server và chạy đường dẫn //localhost:8000 ta sẽ được kết quả như hình:Bạn có thể gọi một component nhiều lần như thế này:
@extends['app']
@section['content']
My content
@endsection
12. The first available component
Bạn cũng có thể tùy chỉnh các giao diện của component nào đó với
@extends['app']
@section['content']
My content
@endsection
40, về tính năng thì nó cũng tương tự như @extends['app']
@section['content']
My content
@endsection
41.@extends['app']
@section['content']
My content
@endsection
2 3. Truyền dữ liệu cho component [Passing data to component]
Đôi khi với một
@extends['app']
@section['content']
My content
@endsection
34 thì bị hạn chế cho việc tùy chỉnh nội dung một component, chính vì thế Laravel cho phép truyền slot khác ngoài @extends['app']
@section['content']
My content
@endsection
34 mặc định để ứng dụng của bạn linh hoạt hơn.@extends['app']
@section['content']
My content
@endsection
3Sử dụng
@extends['app']
@section['content']
My content
@endsection
44 với tham số là tên biến nhận dữ liệu trong blade view component để khai báo một giá trị khác mà component có thể nhận.Tại component
@extends['app']
@section['content']
My content
@endsection
45, bạn chỉnh sửa nội dung như sau:@extends['app']
@section['content']
My content
@endsection
4Laravel sẽ hiểu phần nội dung bạn khai báo ở
@extends['app']
@section['content']
My content
@endsection
44 sẽ truyền vào @extends['app']
@section['content']
My content
@endsection
47, còn phần chỉ nằm trong cặp thẻ @extends['app']
@section['content']
My content
@endsection
48 thì sẽ truyền vào @extends['app']
@section['content']
My content
@endsection
34 mặc định. Mình xin tản mạn một chút, cú pháp @extends['app']
@section['content']
My content
@endsection
50 là dùng để hiển thị dữ liệu của biến.Và đây là kết quả sau khi tải lại trang:
Ngoài ra bạn có thể thay thế cách truyền dữ liệu cho component trên bằng cách:
@extends['app']
@section['content']
My content
@endsection
5Tham số thứ hai trong
@extends['app']
@section['content']
My content
@endsection
38 sẽ nhận một mảng chứa dữ liệu và lấy tên key làm tên biến trong component. Với cách này thông thường dùng để truyền các dữ liệu ngắn, không chứa thẻ HTML.4. Aliasing component
Bạn có nghĩ mình sẽ có thể tự đặt cú pháp cho component để trông code dễ hiểu, dễ hình dung hơn không, chẳng hạn:
@extends['app']
@section['content']
My content
@endsection
6Laravel hiểu mong muốn của bạn, vì thế đã định nghĩa method
@extends['app']
@section['content']
My content
@endsection
52 trong @extends['app']
@section['content']
My content
@endsection
53 facade để ta có thể dễ dàng alias cú pháp cho bất kì component nào. Laravel khuyên nên thực hiện việc này tại @extends['app']
@section['content']
My content
@endsection
54, cụ thể làm method @extends['app']
@section['content']
My content
@endsection
55:@extends['app']
@section['content']
My content
@endsection
7Ở đây bắt buộc chúng ta phải
@extends['app']
@section['content']
My content
@endsection
56 Blade facade để có thể gọi method @extends['app']
@section['content']
My content
@endsection
52 ra. Method này sẽ nhận hai tham số:- Tham số thứ nhất là tên component
- Tham số thứ hai là tên cú pháp thay thế
Bây giờ bạn có thể khai báo component
@extends['app']
@section['content']
My content
@endsection
45 theo cú pháp sau:@extends['app']
@section['content']
My content
@endsection
8Bạn có thể test để so sánh kết quả, đảm bảo vẫn không thay đổi gì.
IV. Hiển thị dữ liệu [Displaying data]
Bạn có thể hiện thị dữ liệu được truyền đến blade view bằng cách đặt biến đó giữa cặp
@extends['app']
@section['content']
My content
@endsection
59, ví dụ mình đăng ký một route:@extends['app']
@section['content']
My content
@endsection
9Tiếp đó các bạn tạo blade view
@extends['app']
@section['content']
My content
@endsection
60 và code nó như sau:Route::get['/', function[] {
return view['child'];
}];
0Đây là kết quả chúng ta thu được:
Như bạn thấy cú pháp này vô cùng ngắn gọn để hiển thị
@extends['app']
@section['content']
My content
@endsection
61 thay vì phải code dài như thế này:Route::get['/', function[] {
return view['child'];
}];
1Lưu ý: Bạn chỉ có thể sử dụng các cú pháp của Blade template khi đuôi mở rộng có dạng
1. Bạn chỉ có thể sử dụng các cú pháp của Blade template khi đuôi mở rộng có dạngresources/ ├── views/ | ├── components/ | | | ...
1.resources/ ├── views/ | ├── components/ | | | ...
1. Displaying unescaped data
Giờ các bạn thử chèn cặp thẻ
@extends['app']
@section['content']
My content
@endsection
63 cho giá trị @extends['app']
@section['content']
My content
@endsection
61 như thế này:Route::get['/', function[] {
return view['child'];
}];
2Đoán xem chữ "Lê Chí Huy" có được bôi đen không? Đáp án là "Không". Vì cú pháp
@extends['app']
@section['content']
My content
@endsection
59 trước khi hiển thị dữ liệu thì nó đã đưa qua hàm @extends['app']
@section['content']
My content
@endsection
66, việc này sẽ tránh các cuộc tất công XSS. Nói một cách đơn giản thì kiểu tấn công này lợi dụng việc có thể hiển thị các thẻ HTML thông qua chức năng viết bài, comment... để chèn mã script độc, tấn công hệ thống.Vậy nếu giờ bạn muốn chèn HTML vào dữ liệu của mình thì sao? Laravel không tuyệt đường bất kỳ mong muốn nào của coder cả, họ cung cấp cho chúng ta cú pháp
@extends['app']
@section['content']
My content
@endsection
67 để có thể hiển thị cả mã HTMLRoute::get['/', function[] {
return view['child'];
}];
3Một kết quả đầy mong đợi:
Lưu ý: Để tránh bị tân công XSS, bạn nên dùng cú pháp này show các dữ liệu do bạn xác định, admin cpanel xác định chứ không nên show các dữ liệu do người dùng nhập như viết bài, comment... để tránh chèn mã độc. Để tránh bị tân công XSS, bạn nên dùng cú pháp này show các dữ liệu do bạn xác định, admin cpanel xác định chứ không nên show các dữ liệu do người dùng nhập như viết bài, comment... để tránh chèn mã độc.
Cú pháp
@extends['app']
@section['content']
My content
@endsection
59 không giới hạn việc hiển thị dữ liệu của biến truyền vào blade view. Bạn có thể @extends['app']
@section['content']
My content
@endsection
69 kết quả bất kì hàm PHP nào, chẳng hạn như:Route::get['/', function[] {
return view['child'];
}];
42. Rendering JSON
Nếu bạn truyền một mảng đến blade view và muốn render nó như một JSON để gán giá trị cho biến nào đó trong đoạn mã script. Thông thường với PHP, bạn sẽ:
Route::get['/', function[] {
return view['child'];
}];
5 Nhưng đối với Blade template Laravel thì cú pháp sẽ gọn đi rất nhiều. Thay vì gọi thủ công như thế thì ta có thể sử dụng cú pháp
@extends['app']
@section['content']
My content
@endsection
70, nó sẽ nhận các tham số tương tự như @extends['app']
@section['content']
My content
@endsection
71.Route::get['/', function[] {
return view['child'];
}];
6Nếu như bạn truyền
@extends['app']
@section['content']
My content
@endsection
70 trong một thuộc tính của thẻ thì nên để trong nó trong cặp dấu @extends['app']
@section['content']
My content
@endsection
73.Route::get['/', function[] {
return view['child'];
}];
73. Blade & JavaScript Frameworks
Có một số Javascript framework sử dụng cặp
@extends['app']
@section['content']
My content
@endsection
74 làm cú pháp của mình, chính vì thế đôi khi Blade template sẽ hiểu nhầm là cú pháp của nó và compile, có thể gây lỗi. Để tránh điều đó, bạn chỉ cần thêm ký tự @extends['app']
@section['content']
My content
@endsection
75 trước câu lệnh thì Blade template sẽ hiểu nó không phải là cú pháp cần compile.Route::get['/', function[] {
return view['child'];
}];
8Đây là kết quả:
Nếu trong trường hợp có nhiều cú pháp Javascript framework có chứa cặp
@extends['app']
@section['content']
My content
@endsection
74 mà bạn không muốn phải cất công thêm tiền tố @extends['app']
@section['content']
My content
@endsection
75 trước từng câu lệnh. Laravel cung cấp cho chúng ta một giải pháp đó chính là đưa tất cả các cú pháp Javascript framework ấy vào trong cặp thẻ @extends['app']
@section['content']
My content
@endsection
78 như thế này:Route::get['/', function[] {
return view['child'];
}];
9V. Cấu trúc điều khiển [Control structure]
Ngoài các tính năng lợi ích trên, Laravel còn cung cấp cho chúng ta các cú pháp ngắn gọn cho các cấu trúc điều khiển của PHP như if, for, foreach... Những cú pháp này rất thuận tiện, nhanh gọn nhưng lại không làm mất đi bản chất vốn có của các cấu trúc điều khiển.
1. Câu lệnh "if" ["if" statement]
Bạn có thể khởi tạo câu lệnh
@extends['app']
@section['content']
My content
@endsection
79 bằng các thẻ @extends['app']
@section['content']
My content
@endsection
80, @extends['app']
@section['content']
My content
@endsection
81, @extends['app']
@section['content']
My content
@endsection
82 và @extends['app']
@section['content']
My content
@endsection
83.@section['content']
My content
@endsection
0Như bạn thấy, chỉ là cú pháp khác, cách khai báo các điều kiện và hoạt động vẫn không khác gì cấu trúc điều kiện thuần túy.
Blade template cung cấp cho chúng ta thẻ
@extends['app']
@section['content']
My content
@endsection
84:@section['content']
My content
@endsection
1Phương thức
@extends['app']
@section['content']
My content
@endsection
85 là dùng để kiểm tra xem user có đăng nhập hay chưa. Hiện tại chúng ta chưa học tới nên chắn chắc method này sẽ trả về giá trị là @extends['app']
@section['content']
My content
@endsection
86. Nếu các bạn đã học qua chương trình tiếng Anh phổ cập thì sẽ biết @extends['app']
@section['content']
My content
@endsection
87 đồng nghĩa với @extends['app']
@section['content']
My content
@endsection
88.Ngoài ra còn có
@extends['app']
@section['content']
My content
@endsection
89 và @extends['app']
@section['content']
My content
@endsection
90, hai thẻ này đại diện cho hai hàm quen thuộc trong PHP là @extends['app']
@section['content']
My content
@endsection
91 và @extends['app']
@section['content']
My content
@endsection
92.@section['content']
My content
@endsection
2a. Authentication
@extends['app']
@section['content']
My content
@endsection
93 và @extends['app']
@section['content']
My content
@endsection
94 và hai thẻ dùng để kiểm tra xem user hiện tại có đăng nhập hay chưa.@section['content']
My content
@endsection
3Ngoài ra bạn có thể truyền tham số cho hai thẻ này để kiểm tra trạng thái đăng nhập của user với tư cách là ai. Chẳng hạn một tài khoản có vai trò là "user" thì sau khi đăng nhập vẫn không thể truy cập vào admin cpanel được. Tính năng này được gọi là "Authentication Guard", chúng ta sẽ tìm hiểu sau.
@section['content']
My content
@endsection
4b. Section
Bạn có thể kiểm tra sự tồn tại của một section bằng thẻ
@extends['app']
@section['content']
My content
@endsection
95 với tham số truyền vào là tên của section cần kiểm tra.@section['content']
My content
@endsection
52. Câu lệnh "switch" ["switch" statement]
Lệnh switch được khởi tạo bằng các thẻ
@extends['app']
@section['content']
My content
@endsection
96, @extends['app']
@section['content']
My content
@endsection
97, @extends['app']
@section['content']
My content
@endsection
98, @extends['app']
@section['content']
My content
@endsection
99 và Route::get['/', function[] {
return view['child'];
}];
00.@section['content']
My content
@endsection
63. Vòng lặp [Loop]
Cũng giống như các cấu trúc điều khiển khác, các câu lệnh loop trong Blade template vẫn được giữ nguyên cách thức hoạt động.
@section['content']
My content
@endsection
7Laravel cung cấp cho chúng ta thẻ
Route::get['/', function[] {
return view['child'];
}];
01, thẻ này hoạt động giống như là Route::get['/', function[] {
return view['child'];
}];
02 nhưng ta có thể kiểm tra nhanh xem object tham chiếu trong loop có rỗng hay không, nếu có thì sẽ thực thi lệnh gì đó thông qua thẻ @extends['app']
@section['content']
My content
@endsection
90.Bạn có thể test đoạn code này thì sẽ hiểu rõ thẻ
Route::get['/', function[] {
return view['child'];
}];
01 ngay.@section['content']
My content
@endsection
8Như quan sát, mình đã truyền một mảng rỗng vào vòng lặp, lặp tức thì nó sẽ được kiểm tra qua thẻ
@extends['app']
@section['content']
My content
@endsection
90. Kết qua ta thu được sẽ là:Nói về vòng lặp thì không thể thiếu
Route::get['/', function[] {
return view['child'];
}];
06 và Route::get['/', function[] {
return view['child'];
}];
07 được, đương nhiên hai lệnh này vẫn được Blade template chuyển cú pháp thành Route::get['/', function[] {
return view['child'];
}];
08 và @extends['app']
@section['content']
My content
@endsection
98.@section['content']
My content
@endsection
9Nếu bạn thấy mỗi lần muốn
Route::get['/', function[] {
return view['child'];
}];
07 hoặc Route::get['/', function[] {
return view['child'];
}];
06 phải lồng trong một câu lệnh @extends['app']
@section['content']
My content
@endsection
79 thì hơi dài và khá rối mắc. Chính vì thế Laravel cho phép bạn truyền điều kiện vào hai thẻ @extends['app']
@section['content']
My content
@endsection
98 và Route::get['/', function[] {
return view['child'];
}];
08 để rút ngắn thời gian cho bạn.@section['sidebar']
Sidebar
@show
04. Biến vòng lặp [The loop variable]
Khi sử dụng các lệnh vòng lặp
Route::get['/', function[] {
return view['child'];
}];
15, Route::get['/', function[] {
return view['child'];
}];
16 mặc định sẽ có sẵn Route::get['/', function[] {
return view['child'];
}];
17 bên trong vòng lặp. Biến này cho phép ta lấy các thông tin hay sử dụng như index hiện tại, index đầu, index cuối vòng lặp...@section['sidebar']
Sidebar
@show
1Nếu bạn có các vòng lặp lồng nhau thì có thể tham chiếu
Route::get['/', function[] {
return view['child'];
}];
17 của vòng lặp cha bằng thuộc tính Route::get['/', function[] {
return view['child'];
}];
19 trong vòng lặp con.@section['sidebar']
Sidebar
@show
2Dưới đây là toàn bộ các thông tin là
Route::get['/', function[] {
return view['child'];
}];
17 có thể cung cấp:
21 | Lấy index hiện tại [bắt đầu từ 0] |
22 | Lấy số lần đã lặp hiện tại [bắt đầu từ 1] |
23 | Lấy số lần lặp còn lại |
24 | Lấy tổng số vòng lặp sẽ lặp |
25 | Nếu tại vòng lặp đầu tiên thì trả về 26 |
25 | Nếu tại vòng lặp đầu tiên thì trả về 26 |
Nếu tại vòng lặp cuối cùng thì trả về 26 | 29 |
Nếu index vòng lặp hiện tại chẵn thì trả về 26 | 31 |
Nếu index vòng lặp hiện tại lẻ thì trả về 26 | 33 |
Lấy độ sâu của vòng lặp hiện tại | 34 |
Lấy Route::get['/', function[] {
return view['child'];
}];
17 của vòng lặp cha trong vòng lặp con
Route::get['/', function[] {
return view['child'];
}];
5. Comment
@section['sidebar']
Sidebar
@show
3Blade template cũng cho phép chúng ta comment để code dễ hiểu, dễ quản lý hơn với cú pháp:
6. PHP
@section['sidebar']
Sidebar
@show
4Bạn cũng có thể chèn code PHP vào trong Blade template trong cặp thẻ
36. Bạn không nên qua lạm dụng thể này để thực thi một số xử lý logic phức tạp, điều này sẽ làm mất bản chất của view. Với các xử lý logic phức tạp, bạn nên thực thi ở view composer hoặc controller action, sau đó mới truyền đến view đển render.Route::get['/', function[] { return view['child']; }];
Lưu ý: Bạn không nên qua lạm dụng thể này để thực thi một số xử lý logic phức tạp, điều này sẽ làm mất bản chất của view. Với các xử lý logic phức tạp, bạn nên thực thi ở view composer hoặc controller action, sau đó mới truyền đến view đển render.
VI. Form
1. Trường CSRF [CSRF field]
Bạn còn nhớ vấn đề ở tập Routing chứ, chúng ta không thể truy cập route với phương thức
Route::get['/', function[] {
return view['child'];
}];
37, cũng như là Route::get['/', function[] {
return view['child'];
}];
38, Route::get['/', function[] {
return view['child'];
}];
39... vì thiếu CSRF field này. Vì vậy khi khởi tạo một HTML form thì chúng ta phải khái báo CSRF field thông qua thẻ Route::get['/', function[] {
return view['child'];
}];
40.@section['sidebar']
Sidebar
@show
5Giờ mình sẽ tạo blade view
@extends['app']
@section['content']
My content
@endsection
60 với nội dung sau:Form này sẽ gửi một request với method
Route::get['/', function[] {
return view['child'];
}];
37 với URI Route::get['/', function[] {
return view['child'];
}];
43 khi submit.@section['sidebar']
Sidebar
@show
6Sau đó các bạn đăng ký hai route này trong
Route::get['/', function[] {
return view['child'];
}];
44:Với route đầu tiên thì sẽ render view chứa form của chúng ta. Còn route thứ hai mang phương thức
Route::get['/', function[] {
return view['child'];
}];
37 sẽ được gọi khi chúng ta click vào nút "Send post".
Bây giờ ta hãy thử truy cập đường dẫn //localhost:8000 và F12 lên để xem source HTML của form vừa tạo.
Route::get['/', function[] {
return view['child'];
}];
40 đã tạo một input hidden với name là Route::get['/', function[] {
return view['child'];
}];
47 và value chứa CSRF token, có field này chắc chắn ta sẽ gửi được request với method Route::get['/', function[] {
return view['child'];
}];
37. Việc cuối cùng là click vào nút "Send post" thôi.
Route::get['/', function[] {
return view['child'];
}];
Route::get['/', function[] {
return view['child'];
}];
Route::get['/', function[] {
return view['child'];
}];
2. Trường phương thức [Method field]
Đối với những phương thức khác như
Route::get['/', function[] {
return view['child'];
}];
38, Route::get['/', function[] {
return view['child'];
}];
39 và Route::get['/', function[] {
return view['child'];
}];
51 ta không thể khai báo trong thuộc tính Route::get['/', function[] {
return view['child'];
}];
52 của thẻ Route::get['/', function[] {
return view['child'];
}];
53 được, chính vì vậy Laravel cung cấp cho ta thẻ Route::get['/', function[] {
return view['child'];
}];
54 để khai báo một Unsafe HTTP method khác ngoài Route::get['/', function[] {
return view['child'];
}];
37.@section['sidebar']
Sidebar
@show
7Các bạn thêm thẻ
Route::get['/', function[] {
return view['child'];
}];
54 với tham số Route::get['/', function[] {
return view['child'];
}];
38 này như sau:Sau đó thử click nút "Send post" lại xem, chắc chắn xuất hiện lỗi:
@section['sidebar']
Sidebar
@show
8Vì chúng ta đã thay đổi HTTP request thành Route::get['/', function[] {
return view['child'];
}];
38 nên ở route đăng ký cũng phải thay đổi.
Route::get['/', function[] {
return view['child'];
}];
3. Validation error
@section['sidebar']
Sidebar
@show
9Với cặp thẻ
Route::get['/', function[] {
return view['child'];
}];
59 ta có thể dễ dàng bắt bất kỳ thông báo nào khi request trả về lỗi. Về "Validation error message" ta sẽ tìm hiểu ở những tập sau nên phần này mình chỉ nó qua về cú pháp để kiểm tra có tồn tại lỗi được trả về tại blade template hay không.Route::get['/', function[] {
return view['child'];
}];
60 sẽ nhận tham số là tên lỗi mà chúng ta xử lý trước khi trả về cho blade view. Nếu Route::get['/', function[] {
return view['child'];
}];
26 thì nó sẽ thực thị lệnh trong cặp thẻ.
Route::get['/', function[] {
return view['child'];
}];
Route::get['/', function[] {
return view['child'];
}];
VII. Liên kết sub-view [Including sub-view]
Route::get['/', function[] {
return view['child'];
}];
62 trong Blade template cho phép bạn có thể liên kết một blade view với một view khác. Tất cả các biến dữ liệu ở parent view đều được truyền đến view include.@section['sidebar']
@parent
Item 1
Item 1
@endsection
0Chẳng hạn mình có cấu trúc thư mục như sau:
@section['sidebar']
@parent
Item 1
Item 1
@endsection
1Ở blade view
@extends['app']
@section['content']
My content
@endsection
60 ta code:Như các bạn thấy, mình đã sử dụng cú pháp
Route::get['/', function[] {
return view['child'];
}];
62 với tham số là tên view liên kết cần đưa vào blade view @extends['app']
@section['content']
My content
@endsection
60 này. Ngoài ra mình có khai báo biến @extends['app']
@section['content']
My content
@endsection
61 để thử xem là blade view Route::get['/', function[] {
return view['child'];
}];
67 có nhận được hay không.@section['sidebar']
@parent
Item 1
Item 1
@endsection
2Tại blade view
Route::get['/', function[] {
return view['child'];
}];
67 mình code như sau:@section['sidebar']
@parent
Item 1
Item 1
@endsection
3Cuối cùng là đăng ký route để render blade view
@extends['app']
@section['content']
My content
@endsection
60 ra:@section['sidebar']
@parent
Item 1
Item 1
@endsection
4Kết quả này chứng minh cho việc ta có thể lấy tất cả các dữ liệu tại view liên kết từ parent view. Ngoài ra bạn cũng có thể truyền một dữ liệu bất kì cho view liên kết thông qua tham số thứ hai của thẻ Route::get['/', function[] {
return view['child'];
}];
62.
Route::get['/', function[] {
return view['child'];
}];
1. Một số cú pháp khác hỗ trợ cho include [Some other syntax support for including]
@section['sidebar']
@parent
Item 1
Item 1
@endsection
5Trong trường hợp nếu bạn
Route::get['/', function[] {
return view['child'];
}];
62 một view không tồn tại thì framework sẽ báo lỗi. Chính vì vậy khi include một view không chắc chắn sẽ tồn tại thì ta sử dụng thẻ Route::get['/', function[] {
return view['child'];
}];
72 thay cho Route::get['/', function[] {
return view['child'];
}];
62.@section['sidebar']
@parent
Item 1
Item 1
@endsection
6Bạn cũng có thể include một view khi kiểm tra một điều kiện nào đó trả về boolean
Route::get['/', function[] {
return view['child'];
}];
26.@section['sidebar']
@parent
Item 1
Item 1
@endsection
7Như dòng code này, nếu view
Route::get['/', function[] {
return view['child'];
}];
76 tồn tại thì nó sẽ include view này và bỏ qua view Route::get['/', function[] {
return view['child'];
}];
77. Còn nếu view Route::get['/', function[] {
return view['child'];
}];
76 không tồn tại thì nó sẽ bỏ qua và tiếp tục kiểm tra view Route::get['/', function[] {
return view['child'];
}];
77.Lưu ý: Bạn nên tránh sử dụng
80 vàRoute::get['/', function[] { return view['child']; }];
81 trong blade view vì chúng chỉ trả kết quả đường dẫn của các file cache hay compile view, không cung cấp thông tin cần thiết. Bạn nên tránh sử dụngRoute::get['/', function[] { return view['child']; }];
80 vàRoute::get['/', function[] { return view['child']; }];
81 trong blade view vì chúng chỉ trả kết quả đường dẫn của các file cache hay compile view, không cung cấp thông tin cần thiết.Route::get['/', function[] { return view['child']; }];
2. Aliasing include
Nếu blade view include một view nằm trong sub-directory, mà phải tham chiếu một tên rất dài. Chúng ta có thể alias cú pháp include một view nào đó giống như là component. Ta cũng sẽ làm việc này tại
@extends['app']
@section['content']
My content
@endsection
54, ngay tại method @extends['app']
@section['content']
My content
@endsection
55.@section['sidebar']
@parent
Item 1
Item 1
@endsection
8Rồi bây giờ ta chỉ cần include view
Route::get['/', function[] {
return view['child'];
}];
67 theo cú pháp đã đăng ký:@section['sidebar']
@parent
Item 1
Item 1
@endsection
93. Rendering views for collections
Nếu bạn có một mảng dữ liệu và muốn truyền từng dữ liệu vào một view nào đó thì bạn có thể sử dụng
Route::get['/', function[] {
return view['child'];
}];
85 thay vì Route::get['/', function[] {
return view['child'];
}];
02 và Route::get['/', function[] {
return view['child'];
}];
62.Chẳng hạn mình có cấu trúc thư mục như sau:
@section['title', 'Laravel']
0Đầu tiên mình sẽ thử sử dụng cách thông thường đó là dùng
Route::get['/', function[] {
return view['child'];
}];
02 và Route::get['/', function[] {
return view['child'];
}];
62. Tại blade view Route::get['/', function[] {
return view['child'];
}];
90 mình sẽ code nội dung như sau:@section['title', 'Laravel']
1Và blade view
Route::get['/', function[] {
return view['child'];
}];
91:@section['title', 'Laravel']
2Sau đó chúng ta đăng ký route và chạy thử:
@section['title', 'Laravel']
3Bây giờ chúng ta sẽ dùng
Route::get['/', function[] {
return view['child'];
}];
85 để thay thế cách trên. Ta chỉ cần thay đổi đoạn vòng lặp trong blade view Route::get['/', function[] {
return view['child'];
}];
93.@section['title', 'Laravel']
4Route::get['/', function[] {
return view['child'];
}];
85 này sẽ nhận:- Tham số đầu tiên là tên view include
- Tham số thứ hai là biến chứa mảng dữ liệu
- Tham số thứ ba là tên biến nhận giá trị trong view include.
Ngoài ra trong trường hợp nếu mảng dữ liệu rỗng thì ta có thể include view hiện thông báo gì đó bằng cách khai báo thêm tham số thứ tư ở
Route::get['/', function[] {
return view['child'];
}];
85 với giá trị là tên view chứa nội dung thông báo.@section['title', 'Laravel']
5Lưu ý: Các view được render thông qua
85 không thể nhận các biến dữ liệu được truyền đến parent view. Nên bạn cần cần nhắc sử dụngRoute::get['/', function[] { return view['child']; }];
02 vàRoute::get['/', function[] { return view['child']; }];
62 để thay thế nếu các view include cần những biến dữ liệu này. Các view được render thông quaRoute::get['/', function[] { return view['child']; }];
85 không thể nhận các biến dữ liệu được truyền đến parent view. Nên bạn cần cần nhắc sử dụngRoute::get['/', function[] { return view['child']; }];
02 vàRoute::get['/', function[] { return view['child']; }];
62 để thay thế nếu các view include cần những biến dữ liệu này.Route::get['/', function[] { return view['child']; }];
VIII. Stacks
Nói về thuật ngữ này bằng văn bản thì rất khó hình dung nên mình sẽ đi qua ví dụ để các bạn thấy công dụng, từ đó có thể hiểu được nó. Chẳng hạn trong ứng dụng của bạn có rất nhiều trang con, tất cả các trang con đều được include với một file JS chung. Một số trang con đặc biệt sẽ có file JS riêng để xử lý.
Đây là cấu trúc thư mục cho ví dụ:
@section['title', 'Laravel']
6Ở blade view
Route::get['/', function[] {
return view['child'];
}];
99, ta có nội dung sau:@section['title', 'Laravel']
7Còn blade view
@section['content']
My content
@endsection
00 thì:@section['title', 'Laravel']
8Bây giờ mình muốn include file JS
@section['content']
My content
@endsection
01 thì cách nhanh nhất là bỏ dòng code include JS vào trong section @section['content']
My content
@endsection
02 ở blade view @section['content']
My content
@endsection
03 như thế này:@section['title', 'Laravel']
9Cách trên thì có thể code vẫn hoạt động bình thường nhưng sẽ cảm thấy một chút gì đó rất khó chịu, có thể gây một số phiền phức sau này như không tốt cho SEO hoặc bất đồng bộ trong code Javascript.
Laravel cung cấp cho ta một giải pháp để giải quyết tình huống trên dựa vào hai thẻ
@section['content']
My content
@endsection
04 và @section['content']
My content
@endsection
05. Bạn hãy tưởng tưởng @section['content']
My content
@endsection
04 giống như một kệ sách, còn @section['content']
My content
@endsection
05 giống như những cuốn sách, dù bạn đặt những cuốn sách ở đâu thì sau quá trình dọn dẹp [biên dịch] thì những cuốn sách sẽ được đưa vào kệ sách.Tức là bây giờ mình muốn đưa cuốn sách
@section['content']
My content
@endsection
08 vào một kệ sách nào đó trong @section['content']
My content
@endsection
09 thì mình phải khai báo kệ sách đó trước đã.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
0Như các bạn thấy mình đã khởi tạo một kệ sách với tên là
@section['content']
My content
@endsection
10 rồi, việc cần làm bây giờ là đưa cuốn sách @section['content']
My content
@endsection
08 về kệ sách @section['content']
My content
@endsection
10 thôi.Tại blade view
@section['content']
My content
@endsection
03, mình chỉnh sửa nội dung lại như sau:// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
1Giờ chắc các bạn đã hiểu cách hoạt động của
@section['content']
My content
@endsection
04 và @section['content']
My content
@endsection
05 rồi đúng không nào. Ngoài ra, Laravel còn cung cấp thẻ @section['content']
My content
@endsection
16, thẻ này giúp ta sẽ thêm cuốn sách "yêu thích" nào đó vào đầu ngăn sách.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
2IX. Service injection
Cái này chắc đã quá quen thuộc rồi, Laravel cho phép chúng ta lấy một service bất kỳ có trong service container thông qua
@section['content']
My content
@endsection
17.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
3X. Mở rộng Blade [Extending Blade]
Laravel cho phép chúng ta tự định nghĩa các thẻ bằng phương thức
@section['content']
My content
@endsection
18 có trong @extends['app']
@section['content']
My content
@endsection
53 facade. Việc này đương nhiên chúng ta cũng sẽ code trong @extends['app']
@section['content']
My content
@endsection
55 của @extends['app']
@section['content']
My content
@endsection
54.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
4Quan sát đoạn code trên, tại method
@section['content']
My content
@endsection
22:- Tham số thứ nhất là tên thẻ
- Tham số thứ hai là một Closure object, nó sẽ chứa biến dữ liệu nhận được qua các tham số của thẻ trong blade view. Trong Closure này, ta sẽ
23 mã PHP được viết dưới dạng chuỗi.@section['content'] My content @endsection
Sau khi đăng ký xong, ta có thể test thẻ
@section['content']
My content
@endsection
24 như sau:// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
5Nếu bạn muốn truyền nhiều tham số cho thẻ của mình thì bạn có thể xử lý chuỗi
@section['content']
My content
@endsection
25 để lấy các giá trị tham số.Để mình test cho các bạn xem, tại Closure object mình sẽ dump
@section['content']
My content
@endsection
25.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
6Sau đó mình thử gọi
@section['content']
My content
@endsection
24 và truyền nhiều tham số vào nó:// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
7Đây là kết quả:
Như các bạn thấy,
@section['content']
My content
@endsection
25 trả về chuỗi với dạng:// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
8Các bạn có thể tùy biến để có thể lấy các giá trị tham số từ
@section['content']
My content
@endsection
25.Lưu ý: Trong khi phát triển ứng dụng, nếu có sử dụng thẻ riêng trong blade view thì sau mỗi lần sửa đổi code xử lý trong mỗi thẻ riêng thì phải chạy lệnh Artisan
30 để xóa cache và compile lại các view. Trong khi phát triển ứng dụng, nếu có sử dụng thẻ riêng trong blade view thì sau mỗi lần sửa đổi code xử lý trong mỗi thẻ riêng thì phải chạy lệnh Artisan@section['content'] My content @endsection
30 để xóa cache và compile lại các view.@section['content'] My content @endsection
Ngoài ra bạn cũng có thể tự tạo cho mình lệnh điều kiện riêng có thể gọi trong blade view bằng method
@section['content']
My content
@endsection
31 được đăng ký tại @extends['app']
@section['content']
My content
@endsection
55 của @extends['app']
@section['content']
My content
@endsection
54.// Nhận giá trị mặc định là view
@yield['content', View::make['view.name']]
// Nhận giá trị mặc định là một chuỗi
@yield['content', 'default']
9Với
@section['content']
My content
@endsection
31 thì:- Tham số thứ nhất là tên lệnh điều kiện,
- Tham số thứ hai là Closure nhận biến giá trị truyền vào và trả về boolean
Như đăng ký trên, nó sẽ kiểm tra môi trường hiện tại của ứng dụng, nếu trùng khớp thì sẽ trả về
Route::get['/', function[] {
return view['child'];
}];
26, còn không thì trả về @extends['app']
@section['content']
My content
@endsection
86.Ta có thể sử dụng trong blade view như sau:
resources/
├── views/
| ├── components/
| | | ...
0Cảm ơn các bạn đã quan tâm theo dõi. Cùng đồng hành với mình qua những tập tiếp theo tại series "Hành trình chinh phục Laravel Framework" nhé! Chúc may mắn và hẹn gặp lại.
Mình đang xây dựng blog riêng là lechihuy.dev , mong các bạn ghé sang ủng hộ, mình cảm ơn rất nhiều ạ