Hướng dẫn render html laravel - kết xuất html ấu trùng
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. Show
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à 1 và được lưu trữ trong thư mục 2.II. Layout template1. 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.
Đâ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ạ: 3, 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.
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 3 và 8 là dùng cho mục đích kế thừa. Blade view 9 là parent, vì nó là layout cho ứng dụng, vì vậy mình sẽ tạo một blade view 0 đóng vai trò là child kế thừa parent 9.
Mình đã sử dụng cú pháp 2, điều này giúp blade view 0 có thể kế thừa 9. Tiếp theo mình đã xác định nội dung cho section 5 thông qua thẻ 3. Bây giờ đăng ký route và xem thử nó hoạt động như thế nào.
Ở đây chúng ta render view 0 chứ không phải 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 5, nên lệnh 4 sẽ thực hiện công việc render. Nhưng sao section 01 vẫn được hiển thị? Mình dùng 3 để xác định nội dung 01 như 5 thôi mà. Hãy quan sát so sánh sau:Cú pháp 3 cho section 5 thì như sau:
Nó có thẻ mở 3 và thẻ đóng 08. Trong khi đó, lệnh 3 cho section 01 thì khác một chút:
Thẻ đóng lúc này là 11, chính vì thể cú pháp này không chỉ là xác định nội dung cho 01 mà đồng với với 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 4 luôn cho tiện mà phải dùng 3 rồi đóng bằng thẻ 11 để render? Cái gì cũng có nguyên nhân của nó cả, vì khi sử dụng 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 18 và thêm đoạn code này vào:
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 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ẻ 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 0 đã extend blade view 9 nên chính vì thế khi khai báo lại section 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ẻ 20? Vâng, lúc này section 01 được khai báo trong blade view 0 sẽ ghi đè hoàn toàn lên section 01 ở blade view 9.
Nói một chút về 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:
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, 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.
III. Component & SlotComponent 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.
1. Khởi tạo component & slot (Creating component & slot)Bây giờ mình sẽ tạo component modal đặt trong file 32 với nội dung sau: Cú pháp 33 sẽ chứa nội dung thông báo thay đổi liên tục trong suốt ứng dụng.
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 0 hồi nãy để test luôn. 0Chúng ta sử dụng cặp thẻ 36 để gọi component 37, đồng thời khai báo slot. Tham số trong 38 là tên blade view chứa component, nội dung trong cặp thẻ chính là giá trị mà 34 nhận được. Nạp lại server và chạy đường dẫn http://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: 12. The first available componentBạn cũng có thể tùy chỉnh các giao diện của component nào đó với 40, về tính năng thì nó cũng tương tự như 41. 2 3. Truyền dữ liệu cho component (Passing data to component)Đôi khi với một 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 34 mặc định để ứng dụng của bạn linh hoạt hơn. 3Sử dụng 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 45, bạn chỉnh sửa nội dung như sau: 4Laravel sẽ hiểu phần nội dung bạn khai báo ở 44 sẽ truyền vào 47, còn phần chỉ nằm trong cặp thẻ 48 thì sẽ truyền vào 34 mặc định. Mình xin tản mạn một chút, cú pháp 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: 5Tham số thứ hai trong 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 componentBạ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: 6Laravel hiểu mong muốn của bạn, vì thế đã định nghĩa method 52 trong 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 54, cụ thể làm method 55: 7Ở đây bắt buộc chúng ta phải 56 Blade facade để có thể gọi method 52 ra. Method này sẽ nhận hai tham số:
Bây giờ bạn có thể khai báo component 45 theo cú pháp sau: 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 59, ví dụ mình đăng ký một route: 9Tiếp đó các bạn tạo blade view 60 và code nó như sau: 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ị 61 thay vì phải code dài như thế này: 1
1. Displaying unescaped dataGiờ các bạn thử chèn cặp thẻ 63 cho giá trị 61 như thế này: 2Đoán xem chữ "Lê Chí Huy" có được bôi đen không? Đáp án là "Không". Vì cú pháp 59 trước khi hiển thị dữ liệu thì nó đã đưa qua hàm 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 67 để có thể hiển thị cả mã HTML 3Một kết quả đầy mong đợi:
Cú pháp 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ể 69 kết quả bất kì hàm PHP nào, chẳng hạn như: 42. Rendering JSONNế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ẽ: 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 70, nó sẽ nhận các tham số tương tự như 71. 6Nếu như bạn truyền 70 trong một thuộc tính của thẻ thì nên để trong nó trong cặp dấu 73. 73. Blade & JavaScript FrameworksCó một số Javascript framework sử dụng cặp 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ự 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. 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 74 mà bạn không muốn phải cất công thêm tiền tố 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ẻ 78 như thế này: 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 79 bằng các thẻ 80, 81, 82 và 83. 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ẻ 84: 1Phương thức 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à 86. Nếu các bạn đã học qua chương trình tiếng Anh phổ cập thì sẽ biết 87 đồng nghĩa với 88.Ngoài ra còn có 89 và 90, hai thẻ này đại diện cho hai hàm quen thuộc trong PHP là 91 và 92. 2a. Authentication 93 và 94 và hai thẻ dùng để kiểm tra xem user hiện tại có đăng nhập hay chưa. 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. 4b. SectionBạn có thể kiểm tra sự tồn tại của một section bằng thẻ 95 với tham số truyền vào là tên của section cần kiểm tra. 52. Câu lệnh "switch" ("switch" statement)Lệnh switch được khởi tạo bằng các thẻ 96, 97, 98, 99 và 00. 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. 7Laravel cung cấp cho chúng ta thẻ 01, thẻ này hoạt động giống như là 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ẻ 90.Bạn có thể test đoạn code này thì sẽ hiểu rõ thẻ 01 ngay. 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ẻ 90. Kết qua ta thu được sẽ là:Nói về vòng lặp thì không thể thiếu 06 và 07 được, đương nhiên hai lệnh này vẫn được Blade template chuyển cú pháp thành 08 và 98. 9Nếu bạn thấy mỗi lần muốn 07 hoặc 06 phải lồng trong một câu lệnh 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ẻ 98 và 08 để rút ngắn thời gian cho bạn. 04. Biến vòng lặp (The loop variable)Khi sử dụng các lệnh vòng lặp 15, 16 mặc định sẽ có sẵn 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... 1Nếu bạn có các vòng lặp lồng nhau thì có thể tham chiếu 17 của vòng lặp cha bằng thuộc tính 19 trong vòng lặp con. 2Dưới đây là toàn bộ các thông tin là 17 có thể cung cấp:
Lấy Route::get('/', function() { return view('child'); }); 17 của vòng lặp cha trong vòng lặp con5. Comment 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 4
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. Form1. 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 37, cũng như là 38, 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ẻ 40. 5Giờ mình sẽ tạo blade view 60 với nội dung sau:Form này sẽ gửi một request với method 37 với URI 43 khi submit. 6Sau đó các bạn đăng ký hai route này trong 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 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 http://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.2. Trường phương thức (Method field) Đối với những phương thức khác như 38, 39 và 51 ta không thể khai báo trong thuộc tính 52 của thẻ 53 được, chính vì vậy Laravel cung cấp cho ta thẻ 54 để khai báo một Unsafe HTTP method khác ngoài 37. 7Các bạn thêm thẻ 54 với tham số 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: 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.3. Validation error 9Với cặp thẻ 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ẻ.VII. Liên kết sub-view (Including sub-view) 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. 0Chẳng hạn mình có cấu trúc thư mục như sau: 1Ở blade view 60 ta code:Như các bạn thấy, mình đã sử dụng cú pháp 62 với tham số là tên view liên kết cần đưa vào blade view 60 này. Ngoài ra mình có khai báo biến 61 để thử xem là blade view 67 có nhận được hay không. 2Tại blade view 67 mình code như sau: 3Cuối cùng là đăng ký route để render blade view 60 ra: 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.1. Một số cú pháp khác hỗ trợ cho include (Some other syntax support for including) 5Trong trường hợp nếu bạn 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ẻ 72 thay cho 62. 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 26. 7Như dòng code này, nếu view 76 tồn tại thì nó sẽ include view này và bỏ qua view 77. Còn nếu view 76 không tồn tại thì nó sẽ bỏ qua và tiếp tục kiểm tra view 77.
2. Aliasing includeNế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 54, ngay tại method 55. 8Rồi bây giờ ta chỉ cần include view 67 theo cú pháp đã đăng ký: 93. Rendering views for collectionsNế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 85 thay vì 02 và 62.Chẳng hạn mình có cấu trúc thư mục như sau: 0Đầu tiên mình sẽ thử sử dụng cách thông thường đó là dùng 02 và 62. Tại blade view 90 mình sẽ code nội dung như sau: 1Và blade view 91: 2Sau đó chúng ta đăng ký route và chạy thử: 3Bây giờ chúng ta sẽ dùng 85 để thay thế cách trên. Ta chỉ cần thay đổi đoạn vòng lặp trong blade view 93. 4 85 này sẽ nhận:
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ư ở 85 với giá trị là tên view chứa nội dung thông báo. 5
VIII. StacksNó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ụ: 6Ở blade view 99, ta có nội dung sau: 7Còn blade view 00 thì: 8Bây giờ mình muốn include file JS 01 thì cách nhanh nhất là bỏ dòng code include JS vào trong section 02 ở blade view 03 như thế này: 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ẻ 04 và 05. Bạn hãy tưởng tưởng 04 giống như một kệ sách, còn 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 08 vào một kệ sách nào đó trong 09 thì mình phải khai báo kệ sách đó trước đã. 0Như các bạn thấy mình đã khởi tạo một kệ sách với tên là 10 rồi, việc cần làm bây giờ là đưa cuốn sách 08 về kệ sách 10 thôi.Tại blade view 03, mình chỉnh sửa nội dung lại như sau: 1Giờ chắc các bạn đã hiểu cách hoạt động của 04 và 05 rồi đúng không nào. Ngoài ra, Laravel còn cung cấp thẻ 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. 2IX. Service injectionCá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 17. 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 18 có trong 53 facade. Việc này đương nhiên chúng ta cũng sẽ code trong 55 của 54. 4Quan sát đoạn code trên, tại method 22:
Sau khi đăng ký xong, ta có thể test thẻ 24 như sau: 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 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 25. 6Sau đó mình thử gọi 24 và truyền nhiều tham số vào nó: 7Đây là kết quả: Như các bạn thấy, 25 trả về chuỗi với dạng: 8Các bạn có thể tùy biến để có thể lấy các giá trị tham số từ 25.
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 31 được đăng ký tại 55 của 54. 9Với 31 thì:
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ề 26, còn không thì trả về 86.Ta có thể sử dụng trong blade view như sau: 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.
|