博主信息
Victor的博客
博文
35
粉絲
0
評論
0
訪問量
7944
積分:0
P豆:76

PHP-用MVC搭建一個框架,自動加載視圖-2019年10月15日

2019年10月18日 19:32:55閱讀數:557博客 / Victor的博客 / PHP

10月15日:

用MVC搭建一個框架,自動加載視圖

    使用影片網站后臺管理的實戰案例, 結合MVC的設計模式,使用php路由機制,搭建一個url驅動運行的CMS應用。

    MVC的工作流程程如下:

  • 1. 瀏覽者->發出指令,后臺調用控制器處理

  • 2. 控制器->按指令選取一個合適的模型    (動作集)

  • 3. 模型->按照控制器指令選取相應的數據    (功能集)

  • 4. 控制器->按指令選取相應的視圖

  • 5. 視圖->把第三步取到的數據按用戶想要的樣子顯示出來    (顯示集)

實例說明:

    現有的案例采用面向過程的編寫方法,我將它改寫為面向對象的編寫模式,用面向對象模式可以更好地組織控制器,和管理目標組(產品族:目前管理的產品有導演、演員和影片)

【1】編寫一個Router.php來解析url。所有url采用全動態生成,約定a代表模塊,page代表分頁 * 入口地址統一為: index.php?a=模塊,

例如:index.php?a=login。按照這種約定來來解析出的對應的控制器(login)的相應操作(loginAction);

【2】編寫一個自動加載文件AutoLoad.php,實現所有類的動態懶加載;

【3】編寫一個入口文件index.php,在此引入url解析的模塊 - ->然后在 控制器中 -->派發到model執行 -->返回在controller里 派送到視圖模版顯示;

【4】編寫一個控制器文件controller.php,這里主要是邏輯處理的操作,去請求數據結果 , 然后送去顯示;

【5】編寫model.php,這里主要實現數據庫操作、方法庫等與數據資源相關的操作;

【6】view模塊中,這里主要功能是把獲得的數據資源展示給用戶,是PHP與html/js相關的內容混編的。

代碼實現:(主要是model和controller兩個核心模塊代碼實現的一部分)

namespace controller;
use \model\DB;

class Action {
	public static function loginAction() {
		return 'login_tpl';
	}
	public static function logoutAction() {
		if (session_destroy()) {
			echo "<script>
			location.href='/mytest/cms/index.php';
			</script>";
		}
		return '';
	}
	public static function indexAction() {
		self::getData(DB::DIRECTOR_TABLE, 'index');
		return 'index_tpl';
	}
	public static function userAction() {
		self::getData(DB::USER_TABLE, 'user');
		return 'user_tpl';
	}
	public static function videoAction() {
		self::getData(DB::VIDEO_TABLE, 'video');
		return 'video_tpl';
	}
	private static function getData($table, $flag) {
		// 分頁
		$gpage = isset($_GET['page']) ? $_GET['page'] : 1;
		$limit = ($gpage - 1) * DB::NUM_PER_PAGE; //第幾頁,第一個數據是0開始,0*10=0
		$limit = $limit . ',' . DB::NUM_PER_PAGE; //組裝limit
		// 條件
		if ($table === DB::VIDEO_TABLE) {
			if (!empty($_GET['va'])) {
				if ($_GET['select'] == 1) {
					$where = DB::table($table)
						->field('tid')
						->where(array('name' => $_GET['va']))
						->find();
				} else {
					$where = DB::table($table)
						->field('uid')
						->where(array('name' => $_GET['va']))
						->find();
					// $where = find($db,$userTable,'uid',array('name'=>$_GET['va']));
				}
			} else {
				$where = '';
			}
			// 查詢影片
			// $video = select($db,$videoTable,'*',$where,'add_time DESC',$limit);
			$video = DB::table($table)
				->field('*')
				->where($where)
				->orderBy('add_time', 'DESC')
				->limit($limit)
				->select();

			if ($video) {
				foreach ($video as &$v) {
					$tname = DB::table($table)
						->field('name')
						->where(array('tid' => $v['tid']))
						->find();
					// find($db,$directorTable,'name',array('tid'=>$v['tid']));
					$v['tname'] = $tname['name'];
					$uname = DB::table($table)
						->field('name')
						->where(array('uid' => $v['uid']))
						->find();
					// find($db,$userTable,'name',array('uid'=>$v['uid']));
					$v['uname'] = $uname['name'];
				}
			}
			$list['video'] = $video;
			// 查詢導演,作為參照
			$list['director'] = DB::table(DB::DIRECTOR_TABLE)
				->field('*')
				->where($where)
				->select();
			// select($db,$directorTable,'*','');
			// 查詢明星,作為參照
			$list['user'] = DB::table(DB::USER_TABLE)
				->field('*')
				->where($where)
				->select();
			// select($db,$userTable,'*','');
		} else {
			if (!empty($_GET['va'])) {
				if ($_GET['select'] == 1) {
					$where['name'] = $_GET['va'];
				} else {
					$where['phone'] = $_GET['va'];
				}
			} else {
				$where = '';
			}
			$list = DB::table($table)
				->field('*')
				->where($where)
				->orderBy('add_time', 'DESC')
				->limit($limit)
				->select();
		}

		$count_number = DB::table($table)
			->field('*')
			->where($where)
			->count_number();

		if ($count_number > 0) {
			$number = ceil($count_number / DB::NUM_PER_PAGE);
			$page = '';
			for ($p = 1; $p <= $number; $p++) {
				$url = '/mytest/cms/index.php?a=' . $flag . '&page=' . $p;

				if (!empty($_GET['va'])) {
					$url .= '&va=' . $_GET['va'];
					if (!empty($_GET['select'])) {
						$url .= '&select=' . $_GET['select'];
					}
				}
				if ($p == $gpage) {
					$page .= '<a class="btn btn-success" href="' . $url . '">';
				} else {
					$page .= '<a class="btn btn-default" href="' . $url . '">';
				}
				$page .= $p;
				$page .= '</a>';
			}
		}
		DB::$sql_list = $list;
		DB::$sql_page = $page;

	}
}
namespace model;

//定義一個包含數據庫連接參數的接口+增刪改查
interface iDbconfig {
	const TYPE = 'mysql';
	const HOST = '127.0.0.1';
	const DBNAME = 'test';
	const USER_NAME = '*****';
	const PASSWORD = '*****';

	public function insert($data);
	public function update($data);
	public function select();
	public function find();
	public function delete();
	public function count_number();
}

//定義Dbset類,實現接口方法
class DbSet implements iDbconfig {
	private static $instance = null;
	//SQL關鍵詞
	protected $table;
	private $field;
	private $where;
	private $limit;
	private $orderBy;

	//構造函數中自動連接數據庫
	private function __construct() {
		$dsn = iDbconfig::TYPE
		. ':host='
		. iDbconfig::HOST
		. '; dbname='
		. iDbconfig::DBNAME;
		$user = iDbconfig::USER_NAME;
		$password = iDbconfig::PASSWORD;
		$pdo = new \PDO($dsn, $user, $password);
	}
	//禁止克隆
	private function __clone() {}
	//創建實例
	public static function getInstance() {
	        private static $pdo;
		if (is_null(self::$instance)) {
			self::$instance = new self();
		}
		return self::$instance;
	}
	//SQL 語句關鍵詞處理
	public function table($tableName) {

		$this->table = $tableName;
		return $this;
	}
	public function field($fields) {
		$fieldlist = '';
		if (is_array($fields)) {
			foreach ($fields as $field) {
				$fieldlist .= $field . ', ';
			}
		} else {
			$fieldlist .= $fields;
		}
		$fieldlist = rtrim(trim($fieldlist), ',');
		$this->field = empty($fieldlist) ? '*' : $fieldlist;
		return $this;
	}
	public function where($where) {
		$whereList = '';
		if (is_array($where)) {
			foreach ($where as $k => $v) {
				$whereList .= $k . '="' . $v . '" ,';
			}
		} else {
			$whereList .= $where;
		}
		$whereList = rtrim(trim($whereList), ',');

		$this->where = empty($whereList) ? $whereList : ' WHERE ' . $whereList;

		return $this;
	}
	public function limit($limit) {
		$this->limit = empty($limit) ? $limit : ' LIMIT ' . $limit;
		return $this;
	}
	public function orderBy($orderBy, $option = 'ASC') {
		$sort = in_array($option, ['DESC', 'ASC']) ? $option : 'ASC';
		$this->orderBy = empty($orderBy) ? $orderBy : ' ORDER BY ' . $orderBy . ' ' . $sort;
		return $this;
	}
	//----------------以下數據庫的增刪改查方法---------------------------
	public function insert($data) {
		$fields = '';
		$value = '';
		foreach ($data as $key => $v) {
			$fields = $fields . ',' . $key;
			$value = $value . ',:' . $key;
		}
		$fields = '(' . ltrim($fields, ',') . ')';
		$value = '(' . ltrim($value, ',') . ')';
		$sql = 'INSERT INTO '
		. $this->table
			. ' '
			. $fields
			. ' VALUES '
			. $value;
		$stmt = $this->pdo->prepare($sql);
		$stmt->execute($data);
		return [
			'count' => $stmt->rowCount(),
			'id' => $this->pdo->lastInsertId(),
		];
	}
	public function update($data) {
		$keyArr = array_keys($data);
		$set = '';
		foreach ($keyArr as $value) {
			$set .= $value . '=:' . $value . ',';
		}
		$set = rtrim($set, ',');
		$sql = 'UPDATE '
		. $this->table
		. ' SET '
		. $set
		. $this->where;
		$stmt = $this->pdo->prepare($sql);
		$stmt->execute($data);
		return $stmt->rowCount();
	}
	public function select() {
		$sql = 'SELECT '
		. $this->field
		. ' FROM '
		. $this->table
		. $this->where
		. $this->orderBy
		. $this->limit;
		$stmt = $this->pdo->prepare($sql);
		if ($stmt->execute()) {
			// if($stmt->rowCount()>0){
			// $stmt->setFetchMode(\PDO::FETCH_ASSOC);
			return $stmt->fetchAll(\PDO::FETCH_ASSOC);
			// }
		} else {
			return false;
		}
	}
	public function find() {
		$sql = 'SELECT '
		. $this->field
		. ' FROM '
		. $this->table
		. $this->where
		. $this->orderBy
		. $this->limit;
		$stmt = $this->pdo->prepare($sql);
		$stmt->execute()) 
		return $stmt->fetch(\PDO::FETCH_ASSOC);
	}
	public function delete() {
		$sql = 'DELETE FROM '
		. $this->table
		. $this->where
		. $this->orderBy
		. $this->limit;
		$stmt = $this->pdo->prepare($sql);
		$stmt->execute();
		return $stmt->rowCount();
	}
	public function count_number() {
		$sql = 'SELECT count(*) as count_number '
		. ' FROM '
		. $this->table
		. $this->where;

		$stmt = $this->pdo->prepare($sql);
		if ($stmt->execute()) {
			if ($stmt->rowCount() > 0) {
				$row = $stmt->fetch(\PDO::FETCH_ASSOC);
				$rows = $row['count_number'];
				return $rows;
			}
		} else {
			return false;
		}
	}
}

運行效果展示:

mvc.jpg

總結:

1、view視圖雖然是用模版完成,但html中嵌入php、js混編,完成起來太繁瑣,后期改版維護也不方便,應該有更好的辦法;

2、MVC架構中,一個健壯的url地址管理機制是必須的;

3、model的數據轉到view中,使用了全局變量,但實際上view中是要引入model中的部分內容的,所以我使用數據庫連接類中的靜態屬性,來傳遞這個數據。

4、頁面中演員、導演和影片的管理動作 可以建立一個工廠模式來實現,后期擴容方便。

通過本次練習,熟悉了MVC結構的使用,離熟練使用還差得很遠,需要多多練習。











批改狀態:合格

老師批語:完成的不錯

全部評論

文明上網理性發言,請遵守新聞評論服務協議

條評論
暫無評論暫無評論!
  • 第十期線上培訓班 白小姐救世民彩图2019