12/08/2018, 16:17

View & Blade Templates in Laravel

Blade rất đơn giản, nhưng lại là một templating engine đầy mạnh mẽ. Bài viết này sẽ hướng dẫn các bạn cách sử dụng Blade Template. Không giống những PHP templating engine phổ biến khác, Blade không giới hạn chúng ta sử dụng code PHP trong views. Tất cả các file Blade sẽ được dịch thành file code ...

Blade rất đơn giản, nhưng lại là một templating engine đầy mạnh mẽ. Bài viết này sẽ hướng dẫn các bạn cách sử dụng Blade Template.

Không giống những PHP templating engine phổ biến khác, Blade không giới hạn chúng ta sử dụng code PHP trong views. Tất cả các file Blade sẽ được dịch thành file code PHP và cache cho đến khi file Blade bị thay đổi; điều đó cũng có nghĩa là Blade tự làm tất cả những việc cần thiết để có thể chạy views cho ứng dụng của bạn. Các file view dùng cho Blade có phần tên đuôi file là .blade.php và được lưu trong thư mục resources/views.

Tôi muốn nói thêm về templating engine (TE) cho những ai mới bắt đầu có khái niệm về template và view, nhưng sợ bài dài quá làm các bạn ngán đọc, bấm vào đây để bỏ qua giới thiệu. Thông cảm cho tôi xíu nhé! Tại sao chúng ta lại cần TE? Các bạn biết đấy, để xuất dữ liệu từ PHP ra, theo cách truyền thống chúng ta phải nhúng code PHP vào HTML, đại loại kiểu thế này:

<div class="article">
  <h1><?php echo $article->title; ?></h1>
  <p><?php echo $article->content; ?></p>
</div>

Ok, mọi thứ trông có vẻ ổn, cho đến khi chúng ta cần làm nhiều hơn với HTML, Js, CSS để trang web hoàn thiện và có thể xem “được”. Lúc đó thì chúng ta sẽ chết chìm trong mớ hỗn độn giữa HTML, Js, CSS và PHP thế này:

<div class="article col-lg-3 col-md-4 col-sm-6 col-xm-1">
  <h1 class="article-title hight-light-link"><a href="<?php echo $article->getUrl() ?>"><?php echo $article->title; ?></a></h1>
  <p><?php echo $article->content; ?></p>
</div>

Đây chỉ là ví dụ nhỏ để chúng ta đủ điên đầu với việc mở đóng thẻ <?php ?> chỉ để echo! Chưa kể đến còn nhiều thứ khác như if…else, while, foreach,…

Đó chính là lý do ngay từ ngày đầu đến với PHP, tôi đã lựa chọn TE cho các dự án PHP của mình trước cả khi học dùng các PHP Framework. TE giúp chúng ta tách biệt hẳn các syntax của PHP ra khỏi HTML, nhằm cho file template trở nên đơn giản, dễ đọc cũng như chỉnh sửa nâng cấp.

Bây giờ chúng ta sẽ tạo file blade đầu tiên, nó không khác biệt file PHP bình thường, ngoại trừ có phần mở rộng .blade.php

 
<div class="article">
  <h1>Bài hướng dẫn cách dùng Blade trong Laravel</h1>
  <p><?php echo $name ?></p>
</div>

Vậy là đã có file blade, nhìn nó rất bình thường như bao file PHP khác đúng không? Khi chạy lần đầu, Blade sẽ dịch file này thành file PHP. Chúng ta có thể sử dụng file Blade như các file view khác bằng cách gọi hàm view(), xem nào:

Route::get('/example', function ()    {
    return view('example', ['name' => 'James']);
});

Sướng không? chúng ta cũng chỉ cần gọi tên view là example mà không phải ghi rõ example.blade.php

Để hiển thị dữ liệu trong Blade, chúng ta dùng cặp dấu {{ và }} bọc quanh biến dữ liệu truyền vào Blade:

Route::get('greeting', function () {
    return view('welcome', ['name' => 'Samantha']);
});

Bạn sẽ cần hiển thị nội dung của biến name như sau: <p>{{ $name }}</p>

Cặp dấu ngoặc {{ và }} sẽ thực hiện echo ra thông tin. Đối với echo, bạn thường phải dùng strip_tags() và htmlentities() để lọc text xuất ra, tránh bị các lỗi XSS. Nhưng với Blade, cặp dấu xuất này cũng thực hiện việc bao gói dữ liệu xuất ra cho bạn, chúng ta không cần xử lý dữ liệu trước khi echo.

Tương tự, để hiển thị dữ liệu từ mảng, object hay từ hàm trả về, ta cũng thực hiện tương tự:

<p>{{ foo('name') }}</p>
<p>{{ bar['name'] }}</p>
<p>{{ $object->name }}</p>

3.1. Hiển thị dữ liệu thô

Để có thể hiển thị dữ liệu dạng raw text, nghĩa là có thể xuất HTML, JS… thì phải dùng cặp dấu {!! và !!} . Nhưng cần chú ý sử dụng trong các trường hợp khác nhau. Ví dụ, không nên hiển thị comment từ người duyệt web bằng cặp dấu này, hacker có thể lợi dụng để thực hiện chèn mã độc lên website. Hello, {!! $name !!}.

3.2. Dùng chung Blade template với các Javascript Framework

Rất nhiều Js framework cũng sử dụng {{ và }} để hiển thị nội dung lên trình duyệt, do đó khi code có khả năng bị “xung đột” với Blade. Bạn có thể dùng @{{ và }} để báo cho Blade biết đừng đụng vào, vị trí này cho Js, ví dụ:

<h1>Laravel</h1>
 
Hello, @{{ name }}.

Trong ví dụ này, khi dịch ra PHP, Blade sẽ xóa @ đi, và để nguyên nội dung {{ name }} lại, cho phép bạn xuất nội dung qua Js Framework.

3.3. Echo dữ liệu nếu tồn tại

Đôi khi chúng ta cần echo một biến, nhưng lại không chắc chắn biến đó đã được khởi tạo hay gán dữ liệu chưa, chúng ta có thể biểu diễn biểu lệnh xuất dữ liệu trong một dòng PHP như sau:

{{ isset($name) ? $name : 'Default' }}

Tuy nhiên, Blade cung cấp lối viết tắt còn ngắn gọn hơn thế nữa!

{{ $name or 'Default' }}

Trong ví dụ trên, nếu $name tồn tại, giá trị của nó được hiển thị, ngược lại, nếu không tồn tại, từ “Default” sẽ hiển thị.

Cũng giống như việc hiển thị dữ liệu bằng PHP thuần, chúng ta luôn cần dùng các cấu trúc điều khiển để kiểm tra, phù hợp với điều kiện nào thì hiển thị cái nào ra. Blade cung cấp các lối viết tắt ngắn gọn, súc tích mà vẫn giữ được sự quen thuộc với code PHP.

4.1. Câu lệnh If

Với câu lệnh if, bạn có thể dùng các chỉ thị trong template như @if , @else , @elseif , @endif . Các từ khóa chỉ thị này có ý nghĩa tương tự với lệnh dùng trong PHP.

@if (count($records) === 1)
    Tôi có 1 bản ghi!
@elseif (count($records) > 1)
    Tôi có nhiều bản ghi!
@else
    Tôi không có bản ghi nào.
@endif

Với câu lệnh @if chỉ có 1 điều kiện, Blade cung cấp lối viết tắt ngắn gọn @unless:

@unless (Auth::check())
    Bạn chưa đăng nhập
@endunless

4.2. Vòng lặp

Blade cung cấp các từ khóa chỉ thị tương ứng với các lệnh lặp trong PHP:

@for ($i = 0; $i < 10; $i++)
    Giá trị hiện tại là {{ $i }}
@endfor

@foreach ($users as $user)
    <p>Đây là user có mã {{ $user->id }}</p>
@endforeach

@while (true)
    <p>Tôi đang lặp mãi mãi :(</p>
@endwhile

Nếu bạn có như cầu hiển thị nội dung thay thế cho @foreach , khi duyệt gặp một mảng rỗng, null, Blade hỗ trợ cú pháp ngắn gọn sau:

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>Không có user nào!</p>
@endforelse

Trong ví dụ trên, bạn thấy @forelse không có trong PHP, vậy nó là gì? Thực ra nó giống với @foreach . Blade sẽ thay chúng ta kiểm tra biến $users, nếu có dữ liệu sẽ thực hiện xuất qua vòng lặp foreach, nếu không có dữ liệu, sẽ chuyển qua xuất dữ liệu ở giữa @empty và @endforelse.

Ở trên, chúng ta đã học được cách tạo template và sử dụng chúng để xuất dữ liệu một cách đơn giản và sạch sẽ. Tuy nhiên, với một trang web có rất nhiều trang khác nhau, chúng ta không thể liên tục tạo mới file template cho từng trang trong khi chúng chỉ khác về nội dung chứ bố cục tổng thể thì không thay đổi. Chúng ta không nên và cũng không thể copy lặp đi lặp lại cùng một đoạn code (DRY – Don’t Repeat Yourself), việc đó sẽ làm chúng ta rất mất thời gian để tạo ra cũng như bảo trì, nâng cấp các file template. May thay, Laravel 5 cung cấp cho chúng ta giải pháp đơn giản để tổ chức hệ thống file template theo layout gọn gàng, có cấu trúc, giúp giảm thiểu tối đa thời gian triển khai giao diện. Bạn nào hỏi layout là gì thì có cái hình đây, xem chơi nha.

5.1. Định nghĩa một layout

Hai lợi ích chính của việc sử dụng Blade là kế thừa template và chia phần template thành section. Để bắt đầu, hãy xem qua một ví dụ đơn giản. Đầu tiên, chúng ta xem xét trang layout chính. Hầu hết các ứng dụng web đều duy trì layout cơ bản giống nhau trên nhiều trang, điều đó rất tiện cho chúng ta để định nghĩa layout này như một view Blade đã học ở trên:

 
 
<html>
    <head>
        <title>App Name - @yield('title')</title>
    </head>
    <body>
        @section('sidebar')
            <h3>Đây là sidebar chính.</h3>
        @show
 
        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

Như bạn thấy, file này chứa phần lớn code HTML. Tuy nhiên, chú ý vào hai từ khóa chỉ thị @section và @yield . Chỉ thị @section định nghĩa một mảnh/phần/đoạn nội dung, trong khi chỉ thị @yield dùng để hiển thị nội dung của một phần nhất định.

Bây giờ chúng ta đã có một layout được định nghĩa cho ứng dụng của mình. Hãy tiếp tục định nghĩa các trang con kế thừa từ layout chính này.

5.2. Mở rộng layout

Khi định nghĩa một trang con, bạn có thể sử dụng từ khóa chỉ thị @extends để chỉ định trang con nên kế thừa từ layout nào. Các view kế thừa từ Blade layout có thể chèn nội dung vào các section ở layout đã định nghĩa bằng @section . Nên nhớ, như đã xem ví dụ ở trên, nội dung của section cũng sẽ hiển thị trong layout ở những nơi có dùng @yield :

 
 
@extends('layouts.master')
 
@section('title', 'Tiêu đề trang')
 
@section('sidebar')
    @parent
 
    <p>Đây là phần thêm vào bên dưới sidebar chính ở layout.</p>
@endsection
 
@section('content')
    <p>Đây là phần nội dung trong trang.</p>
@endsection

Trong ví dụ này, section sidebar lợi dụng từ khóa chỉ thị @parent để nối thêm vào (đúng hơn là ghi đè) nội dung lên sidebar chính của layout. Chỉ thị @parent sẽ được thay thế bởi nội dung của layout khi view được render (biên dịch thành PHP rồi thành HTML)

Dĩ nhiên, cũng giống như PHP view, Blade view có thể được dùng đơn giản bằng cách return từ hàm view():

Route::get('blade', function () {
    return view('child');
});

Như vậy, layout Blade được tạo ra để các page khác nhau kế thừa và dùng lại. Chúng ta khi gọi view sử dụng thì gọi trực tiếp vào view của từng page mà không gọi vào layout.

5.3. Sự khác nhau giữa @yield và @section

Rõ ràng chúng ta đều thấy child page dùng hai từ khóa này để chỉ thị việc chèn nội dung vào master layout. Vậy chúng khác nhau như thế nào? Khi nào thì dùng cái nào? Theo tôi sự khác nhau nằm ở chính cái tên của chúng, cần hiểu rõ để biết khi nào sử dụng:

  • @yield: bản thân từ này đồng nghĩa với từ output, do đó dĩ nhiên nhiệm vụ của nó là xuất dữ liệu. Vậy ta chỉ nên dùng cho việc xuất những dữ liệu nhỏ.
  • @section: có nghĩa là phần, đoạn hay mảnh. Rõ ràng từ khóa này nhắm tới việc phân nhỏ layout ra thành từng đoạn nhỏ để các trang con ghi nội dung vào các vị trí đánh dấu này!

Về mặt kỹ thuật, thật sự khi sử dụng @section , các trang con sẽ có thể ghi đè, hoặc ghi nối thêm nội dung bằng từ khóa @parent . Khi có từ khóa này, Blade sẽ lấy nội dung trong section của layout “chắp vào” trước nội dung của @section ở trang con. Còn khi sử dụng @yield , nội dung ở trang con sẽ luôn luôn ghi đè vào vị trí đánh dấu ở layout, mà không thể nối thêm dữ liệu ở layout vào như khi dùng @section.

Blade in Laravel Docs

0