MVC CMS- Xây dựng thư viện xử lý template

PHP MVC 20/04/2017 07:00 946
Tiếp tục với series về xây dựng một CMS MVC hoàn chỉnh thì trong bài viết này mình sẽ tiếp tục xây dựng thư viện xử lý template. Một trong na thành phần quan trọng nhất của mô hình MVC.

Trong bài trước thì mình đã tích hợp Smarty template engine vào hệ thống TzCMS thành công thì trong bài viết này mình sẽ tiếp tục viết thư viện xử lý template.Thì trong bài viết trước chúng ta đã dừng lại ở file /application/templates/index.html đã có thể assign một biến $controller hay $action ra view ở đây là file /application/templates/index.html.

Mình sẽ nói về hệ thống template trong TzCMS.

Tạm thời mình có ba controller.

1. HomeController: Controller này có 2 action.

  • default: Trang chủ
  • 404: Trang lỗi 404

2. NewsController: Controller tin tức có 3 action

  • default: Trang chủ trang tin tức
  • cat: Trang danh dách tin tức
  • detail: Trang chi tiết tin tức

3. SearchController: Controller tìm kiếm có 1 action.

  • result: Trang kết quả tìm kiếm

Thì mỗi một action như vậy sẽ tương ứng với một template.

Ví dụ: Khi truy cập vào đường dẫn http://localhost/tzCMS?c=News sẽ gọi tới actiontemplate  function default_default() và template là default.html

Khi truy cập vào đường dẫn http://localhost/tzCMS?c=News&a=cat sẽ gọi tới action và template lần lượt là function default_cat()cat.html.

Thêm nữa là chúng ta có hai file _header.html_footer.html thì đây là 2 template view của _header.php _footer.php. Một điều lưu ý rằng trong mỗi controller có thể định nghĩa một _header_footer khác nhau. Nếu không định nghĩa thì nó sẽ lấy template _header _footer mặc định.

Nếu bạn đã từng sử dụng một số Framework ví dụ như Codeigniter hay Laravel thì bạn thường phải có thao tác là chọn view. Thì điều này sẽ làm cho bạn chủ động hơn. Và khả năng tuy biến cao nhưng trong TzCMS bạn không cần làm điều đó chúng ta sẽ code làm sao cho chúng tự phát hiện và gắn bó với nhau nhé.

Bạn có thể tiếp tục với code bạn đã download về từ bài viết trước. Nếu bạn chưa download về thì bạn có thể tải chúng bằng cách nhấn vào đây.

Trong folder /core/common/ chúng ta tạo một file template.class.php.

class Template{
	private static $_instance = null;
	private $action = null;
	private $controller = null;
	private $template_name = null;
	/*
	|----------------------------------
	| Contructor
	|----------------------------------
	*/
	private function __construct($config){
		if(is_array($config)){
			foreach($config as $k=>$v){
				$this->{$k} = $v;
			}
		}
	}
	public static function getInstance($config){
		if(!isset(self::$_instance)){
			self::$_instance = new Template($config);
		}
		return self::$_instance;
	}
	function set_template($template_name){
		$this->template_name = $template_name;
	}
	function get_template(){
		return $this->template_name;
	}

Trong đoạn code này các bạn chú ý tới hàm khởi tạo nó sẽ nhận tối thiểu một array chứa hai tham số là controlleraction hiện tại. Từ đó thì chúng ta mới xác đinh được là templateFile nào sẽ được triệu gọi.

Trong file /core/bootstrap.php mình viết đoạn code khởi tạo đối tượng template như sau.

/*
|---------------------------------------
| Get controller & action
|---------------------------------------
*/
$controller = strtolower(Input::get('c', 'home'));
$action = strtolower(Input::get('a', 'default'));

....Some code ...

/*
|---------------------------------------
| Template constructor
|---------------------------------------
*/
$tmpl = Template::getInstance(
	array(
		'controller' => $controller,
		'action'	=> $action
	)
);
/*
|---------------------------------------
| Template output
|---------------------------------------
*/
$assign_list['tmpl'] = $tmpl;
$smarty->assign($assign_list);

Mình sử dụng hàm get_current_template_path() này để trả về đường dẫn tới folder template theo controller. Ví dụ nếu bạn truy cập vào controller News thì đó hàm này nó sẽ trả về ../TzCMS/application/templates/news/

/*
|----------------------------------
| Get curent template path
| @No parameter
|----------------------------------
*/
function get_current_template_path(){
	return DIR_TEMPLATES.'/'.strtolower($this->controller);
}

Thêm một hàm. Hàm này dùng để kiểm tra xem templateFile đó có tồn tại hay không nó same same như hàm file_exists() trong PHP.

/*
|----------------------------------
| Check template exists
|----------------------------------
*/
public function template_exists($template){
	global $smarty;
	return $smarty->template_exists($template);
}

Tiếp theo thì đây mới là cái chúng ta cần quan tâm.

/*
|----------------------------------
| Header template
|----------------------------------
*/
public function getHeader(&$html=null){
	global $smarty;
	if($this->template_exists($this->get_current_template_path()."/_header.html")){
		$html = $smarty->fetch($this->get_current_template_path().'/_header.html');
	}else{
		$html = $smarty->fetch(DIR_TEMPLATES.'/_header.html');
	}
	return $html;
}
/*
|----------------------------------
| Footer template
|----------------------------------
*/
public function getFooter(&$html=null){
	global $smarty;
	if($this->template_exists($this->get_current_template_path()."/_footer.html")){
		$html = $smarty->fetch($this->get_current_template_path().'/_footer.html');
	}else{
		$html = $smarty->fetch(DIR_TEMPLATES.'/_footer.html');
	}
	return $html;
}
/*
|----------------------------------
| Block main template
|----------------------------------
*/
function run(&$html=null){
	global $smarty;
	$templateFile = $this->action.'.html';
	if($this->action != 'default'){
		if($this->template_exists($this->get_current_template_path().DS.$templateFile)){
			$html = $smarty->fetch($this->get_current_template_path().DS.$templateFile);		
		}else{
			trigger_error('Error 404! Action File not Found ',E_USER_WARNING);
		}
	}else{
		$html = $smarty->fetch($this->get_current_template_path().'/default.html');
	}
	return $html;
}
/*
|----------------------------------
| Block general template
|----------------------------------
*/
public function getBlock($block_name="default", $param=null){
	global $smarty, $assign_list, $_SITE_ROOT;
	$file_block_name = DIR_BLOCKS."/".$block_name.".php";
	$file_block_temp = DIR_TEMPLATES."/blocks/".$block_name.".html";
	$html = "";
	if (file_exists($file_block_name)){
		require_once($file_block_name);
		if ($this->template_exists($file_block_temp)){
			$html = $smarty->fetch($file_block_temp);
		}else{
			trigger_error("Error 404. ".ucfirst(strtolower($block_name))." template block is not found!", E_USER_ERROR);
		}
		return $html;
	}else{
		trigger_error("Error 404. ".ucfirst(strtolower($block_name))." is not found!", E_USER_ERROR);
	}
}

Nếu các bạn đã hiểu ý tưởng của mình rồi thì có lẽ không khó để các bạn hiểu. Riêng trong thư viện này có thêm một hàm getBlock() thì phải nói chính xác nó là thành phần Widget có lẽ sẽ dễ dàng hiểu hơn. Nhưng mình thích cái tên block hơn. Mỗi một block là một là một nhóm các điều khiển chúng ta tách ra từ một template lớn. Mỗi một block có thể nhứng vào nhiều nơi bằng lệnh getBlock();

Final code thư viện.

<?php if (!defined('ABSPATH')) exit('No direct script access allowed'); 
	/*
	|------------------------------------------------------------
	| TzCMS - Content management system website
	| @Author	: Tz.Thiêm (buivanthiem.it@gmail.com)
	| @Date		: 2009/1/18
	| @Version	: 2.1.1
	| @Copyright (c) TzCMS. All Rights Reserved,
	|------------------------------------------------------------
	| Email: info@chiasephp.net
	| Website: http://www.chiasephp.net
	| -----------------------------------------------------------
	*/
	class Template{
		private static $_instance = null;
		private $action = null;
		private $controller = null;
		private $template_name = null;
		/*
		|----------------------------------
		| Contructor
		|----------------------------------
		*/
		private function __construct($config){
			if(is_array($config)){
				foreach($config as $k=>$v){
					$this->{$k} = $v;
				}
			}
		}
		public static function getInstance($config){
			if(!isset(self::$_instance)){
				self::$_instance = new Template($config);
			}
			return self::$_instance;
		}
		function set_template($template_name){
			$this->template_name = $template_name;
		}
		function get_template(){
			return $this->template_name;
		}
		/*
		|----------------------------------
		| Get curent template path
		| @No parameter
		|----------------------------------
		*/
		function get_current_template_path(){
			return DIR_TEMPLATES.'/'.strtolower($this->controller);
		}
/*
|----------------------------------
| Check template exists
|----------------------------------
*/
public function template_exists($template){
	global $smarty;
	return $smarty->template_exists($template);
}
		/*
		|----------------------------------
		| Header template
		|----------------------------------
		*/
		public function getHeader(&$html=null){
			global $smarty;
			if($this->template_exists($this->get_current_template_path()."/_header.html")){
				$html = $smarty->fetch($this->get_current_template_path().'/_header.html');
			}else{
				$html = $smarty->fetch(DIR_TEMPLATES.'/_header.html');
			}
			return $html;
		}
		/*
		|----------------------------------
		| Footer template
		|----------------------------------
		*/
		public function getFooter(&$html=null){
			global $smarty;
			if($this->template_exists($this->get_current_template_path()."/_footer.html")){
				$html = $smarty->fetch($this->get_current_template_path().'/_footer.html');
			}else{
				$html = $smarty->fetch(DIR_TEMPLATES.'/_footer.html');
			}
			return $html;
		}
		/*
		|----------------------------------
		| Block main template
		|----------------------------------
		*/
		function run(&$html=null){
			global $smarty;
			$templateFile = $this->action.'.html';
			if($this->action != 'default'){
				if($this->template_exists($this->get_current_template_path().DS.$templateFile)){
					$html = $smarty->fetch($this->get_current_template_path().DS.$templateFile);		
				}else{
					trigger_error('Error 404! Action File not Found ',E_USER_WARNING);
				}
			}else{
				$html = $smarty->fetch($this->get_current_template_path().'/default.html');
			}
			return $html;
		}
		/*
		|----------------------------------
		| Block general template
		|----------------------------------
		*/
		public function getBlock($block_name="default", $param=null){
			global $smarty, $assign_list, $_SITE_ROOT;
			$file_block_name = DIR_BLOCKS."/".$block_name.".php";
			$file_block_temp = DIR_TEMPLATES."/blocks/".$block_name.".html";
			$html = "";
			if (file_exists($file_block_name)){
				require_once($file_block_name);
				if ($this->template_exists($file_block_temp)){
					$html = $smarty->fetch($file_block_temp);
				}else{
					trigger_error("Error 404. ".ucfirst(strtolower($block_name))." template bloc is not found!", E_USER_ERROR);
				}
				return $html;
			}else{
				trigger_error("Error 404. ".ucfirst(strtolower($block_name))." is not found!", E_USER_ERROR);
			}
		}
	}
?>

Như mình đã nói ở bài trước thì file /application/templates/index.html đóng vài trò là Master Layout. Chúng ta sẽ cài đặt các thành phần của template trên file này.

<!DOCTYPE html>
<html>
<head>
<title>TzCMS - Hệ thống quản trị nội dung website Pro !</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
    {$tmpl->getHeader()}
    {$tmpl->run()}
    {$tmpl->getFooter()}
</body>
</html>

Truy cập vào http://localhost/TzCMS/

Truy cập vào http://localhost/TzCMS/?c=News

Tổng kết.

Như vậy mình đã hoàn thành xong thư viện xử lý template của hệ thống TzCMS. Nếu xét ở vai trò một người học thì các bạn cần lắm rõ nguyên lý của nó thì bạn sẽ thấy nó cũng không khó khăn lắm và phụ thuộc vào mong muốn hay yêu cầu của bạn đặt ra. Trong bài viết tiếp theo mình sẽ viết tiếp thư viện xử lý lớp Session.

Xem Thêm

Profile photo of adminTheHalfHeart

B.V.T

Sinh ra và lớn nên ở Bắc Giang. Hiện tại thì tôi đang là một lập trình viên tại VietISO. Tôi lập website này với mục đích là bookmark những gì tôi đã đọc qua và mong muốn chia sẻ những gì tôi biết.