06/04/2021, 14:49

Bài 19: Rewrite URL trong Codeigniter - Lập trình Codeigniter 3x

Version: Codeigniter 3x Sau một khoảng thời gian không đụng tới Codeigniter thì hôm nay lại có dịp tiếp xúc với Framework này. Chuyện là mình đang làm một dự án sử dụng Codeigniter nên hôm nay hứng thú làm một tuts và sẽ viết tiếp serie của tác giả Kaito. Trong ...

Sau một khoảng thời gian không đụng tới Codeigniter thì hôm nay lại có dịp tiếp xúc với Framework này. Chuyện là mình đang làm một dự án sử dụng Codeigniter nên hôm nay hứng thú làm một tuts và sẽ viết tiếp serie của tác giả Kaito.

Trong bài này mình se hướng dẫn các bạn làm thế nào để viết lại đường dẫn trong Codeigniter (Rewrite URL). Chức năng này khá quan trọng khi bạn làm web bởi vì nó thân thiện với người dùng và tốt cho SEO. Nếu gặp khách hàng hiểu biết SEO thì có khi họ yêu cầu bạn Rewrite URL theo ý họ luôn ấy.

Trong bài này mình hướng dẫn các vấn đề chính như sau:

  • Tìm hiểu Route trong Codeigniter
  • Rewrite URL cho trang sản phẩm
  • Rewrite URL cho trang chi tiết
  • Rewrite URL cho trang tag
  • Rewrite URL cho trang chuyên mục

Ok ta bắt đầu nhé.

1. Tìm hiểu Route trong Codeigniter

Nếu bạn đang dùng Codeigniter 3x hay 2x thì đừng quá lo lắng nhé, vì nó cũng tương tự như nhau, chỉ khác ở một điểm là Route trong CI3X sẽ có chức năng callback. 

Ok. Mọi thứ liên quan đến Rewrite URL trong Codeigniter  đều nằm trong file application/config/routes.php, bạn mở file này lên nó sẽ có một số dữ liệu như sau:

$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;<br><br>

Trong đó:

  • default_controller: là controller mặc định, nếu bạn truy cập với URL ko có khai báo controller thì nó sẽ gọi tới controller mặc định này. Ví dụ: $route['default_controller'] = 'product/index';
  • 404_override: Nếu bạn không khai báo thì nó sẽ lấy trang mặc định lỗi của CI, còn nếu ban khai báo thì nó sẽ gọi đến controller và action trong đó. Ví dụ: $route['404_override'] = 'error/show404';
  • translate_uri_dashes: Cái này không phải là route mà nó là một option với giá trị là TRUE hoặc FALSE. Nếu TRUE thì CI sẽ chuyển đổi ký tự gạch ngang (-) thành gạch dưới (_) và ráp vào controller. Ví dụ bạn có controller tên Product_shop thì bạn sẽ gõ URL là http://domain.com/product-shop sẽ sai, nhưng nếu bạn khai báo $route['translate_uri_dashes'] = TRUE; thì sẽ được.

Thêm mới route như thế nào?

Để thêm mới một route thì bạn chỉ cần thêm bên dưới cùng của file với cấu trúc: 

$route['url-tren-trinh-duyet'] = 'controller/action/param1/param2...';

Nguyên tắc capturing group trong regular expression

Để xử lý tốt route trong CI thì  bạn phải biết khái niệm capturing group (xem bài các ký hiệu regex căn bản). Nhưng tôi cũng giải thích sơ qua cho bạn hiểu nhé.

Ví dụ ta có chuỗi 'san-pham/([a-zA-Z0-9]+)/([0-9]+)' thì chúng ta có ba group:

  • Group0: toàn bộ chuỗi 'san-pham/([a-zA-Z0-9]+)/([0-9]+)' ký hiệu $0
  • Group1:  ([a-zA-Z0-9]+) ký hiệu $1
  • Group2: ([0-9]+) ký hiệu $2

Nghĩa là nếu ta khai báo cặp dấu () thì nó sẽ hiểu là một group. Tuy nhiên route trong CI không sử dụng Group0 nhé các bạn.

Các ký hiệu hay dùng trong Route

Route trong CI có các ký hiệu như sau:

  • (:any) - đại diện cho các ký tự bất kì
  • (:num) - đại diện cho các số tự nhiên

Sau đây là một số ví dụ sử dụng routes trong codeigniter.

$route['Zaidap.com-blog'] = 'blog/user';

Trong route này nếu trình duyệt là http://domain.com/Zaidap.com-blog thì nó sẽ gọi tới blog controller và user action.

$route['Zaidap.com-blog/(:num)'] = 'blog/user/$1';

Trong ví dụ này action user trong controller blog sẽ có một tham số truyền vào và giá trị của nó là đằng sau Zaidap.com-blog/.

  • Nếu bạn gõ URL là http://domain.com/Zaidap.com-blog/thehalfheart thì sẽ sai vì ký tự đằng sau được khai báo là (:num)
  • Nếu bạn gõ URL là http://domain.com/Zaidap.com-blog/12 thì đúng

Nhưng nếu bạn khai báo như sau thì cả hai URL trên đều đúng:

$route['Zaidap.com-blog/(:any)'] = 'blog/user/$1';

Sử dụng Regular Expression trong route

Bạn có thể sử dụng Regular Expression để sử dụng trong route. Thông thường chúng ta sử dụng các chuỗi regex sau:

  • ([0-9]+) tương đương với (:num)
  • ([a-zA-Z0-9]+) gần tương đương với (:any)

Mình không liệt kê hết được, nếu bạn muốn thì hãy học regular expression nhé.

Route Callback trong Codeigniter

Chức năng này mới được thêm từ Version CI3X, các versions trước không có nhé các bạn.

Thay vì bạn khai báo là $route['url'] = 'value' thì bạn sẽ khai báo function cho nó với cú pháp như sau:

$route['url'] = function(){
    return 'controller/action';
};

Tới đây bạn sẽ có thắc mắc là nếu có tham số truyền vào controller thì sao? Đơn giản là tuân theo capturing group nhé. Nghĩa là group1 tương đương tham số 1, group2 tương đương tham số 2.

$route['product/(:any)-(:num)'] = function($any, $num){
    return 'controller/action/' . $any . '/' . $num;
};

Có lẽ tới đây thôi vì lý thuyết hơi dài dòng, ta đi vào làm thực tế nhé.

2. Rewrite UR cho trang sản phẩm

Trước tiên bạn tạo một controller Product như sau:

class Product extends CI_Controller 
{
        public function index($page = '')
        {
                echo '<h1>Home page</h1>';
                echo 'Page: ', $page;
        }

        public function category($cate_slug = '', $page = '')
        {
                echo '<h1>Category page</h1>';
                echo 'Slug: ', $cate_slug, '<br/>';
                echo 'Page: ', $page, '<br/>';
        }

        public function tag($tag_slug = '', $page = '')
        {
                echo '<h1>Tag page</h1>';
                echo 'Slug: ', $tag_slug, '<br/>';
                echo 'Page: ', $page, '<br/>';
        }

        public function detail($post_slug = '', $post_id = '')
        {
                echo '<h1>Detail page</h1>';
                echo 'Slug: ', $post_slug, '<br/>';
                echo 'ID: ', $post_id, '<br/>';
        }
}

Trong controller này tôi có tạo 4 action:

  • index: trang chủ
  • category: trang sản phẩm theo chuyên mục
  • tag: trang sản phẩm theo tag
  • detail: trang chi tiết sản phẩm

Rewrite trang chủ

Trang chủ ở đây không phải là trang home chính nha các bạn mà là trang hiển thị danh sách tất cả các sản phẩm nên nó sẽ có URL như sau:

  • domain.com/san-pham
  • domain.com/san-pham/page/1

Ok ta sẽ viết hai routes cho đơn giản nhé:

$route['san-pham/page/(:num)'] = 'product/index/$1';
$route['san-pham'] = 'product/index';

Tại sao mình lại đặt route có phân trang ở trên? Tại vì theo quy luật nó sẽ lặp danh sách các URL từ trên xuống dưới, nếu cái nào khớp thì nó sẽ ngưng. Chính vì vậy ta nên đặt có phân trang ở trên và ko có phân trang ở dưới. Bây giờ bạn chạy hai URL trên sẽ thấy kết quả bất ngờ.

Rewrite trang category

Trang danh sách sản phẩm mình muốn nhận slug của category để truy vấn database nên nó sẽ có dạng sau:

  • domain.com/slug-chuyen-muc
  • domain.com/slug-chuyen-muc/page/1

Trong controller mình có nhận sẵn hai tham số rồi nên bây giờ ta chỉ viết routes thôi.

$route['(:any)/page/(:num)'] = 'product/category/$1/$2';
$route['(:any)'] = 'product/category/$1';

Các bạn để ý các ký hiệu $1$2 nhé, nó là capturing group đấy.

Rewrite trang tag

Tương tự như trang danh sách chuyên mục, nhưng để phân biệt giữa tag và chuyên mục thì trên URL mình sẽ thêm chữ tag nữa. 

  • domain.com/tag/slug-cua-tag
  • domain.com/tag/slug-cua-tag/page/1

Và đây là routes:

$route['tag/(:any)/page/(:num)'] = 'product/tag/$1/$2';
$route['tag/(:any)'] = 'product/tag/$1';

Bạn chạy URL trên có thể sẽ thấy không đúng thì tức là tại bạn đặt sai vị trí cho route này, bạn phải đặt nó trên route của cate nhé, bởi vì trong route của cate có $route['(:any)'] = 'product/category/$1'; nên nó sẽ đúng với bất kì trường hợp nào, chính vì vậy nó sẽ ngưng và ko duyệt xuống dưới nên giải pháp là đặt tag lên trên category.

// Home
$route['san-pham/page/(:num)'] = 'product/index/$1';
$route['san-pham'] = 'product/index';

// Tag
$route['tag/(:any)/page/(:num)'] = 'product/tag/$1/$2';
$route['tag/(:any)'] = 'product/tag/$1';

// Category
$route['(:any)/page/(:num)'] = 'product/category/$1/$2';
$route['(:any)'] = 'product/category/$1';

Rewrite trang detail

Trang chi tiết sản phẩm ở controller mình nhận hai tham số là slug của tin và id của tin, như vậy UR sẽ có dạng:

  • domain.com/{tieu-de-cua-san-pham}-{id}.html

Ok ta viết route như sau:

$route['(:any)-(:num).html'] = 'product/detail/$1/$2';

Tương tự bạn phải đặt route này trên cùng nhé, bởi vì nó là cái đặ biệt nên dễ bị trùng với category.

// Detail
$route['(:any)-(:num).html'] = 'product/detail/$1/$2';

// Home
$route['san-pham/page/(:num)'] = 'product/index/$1';
$route['san-pham'] = 'product/index';

// Tag
$route['tag/(:any)/page/(:num)'] = 'product/tag/$1/$2';
$route['tag/(:any)'] = 'product/tag/$1';

// Category
$route['(:any)/page/(:num)'] = 'product/category/$1/$2';
$route['(:any)'] = 'product/category/$1';

Vậy là bạn đã rewrite được URL rồi đấy :D.

3. Lời kết

Bài này cũng tương đối đơn giản vì nó mang tính chất tham khảo, nếu làm không được bạn hãy comment để mình có thể giải đáp thắc mắc cho bạn, hoặc bạn có thể đặt câu hỏi trong phần hỏi đáp. Chúc bạn học tốt

Bài tiếp

Trịnh Tiến Mạnh

27 chủ đề

6824 bài viết

Cùng chủ đề
0