博主信息
Victor的博客
博文
32
粉丝
0
评论
0
访问量
6169
积分:0
P豆:68

PHP-用MVC搭建一个框架,自动加载视图-2019年10月15日

2019年10月18日 19:32:55阅读数:500博客 / 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结构的使用,离熟练使用还差得很远,需要多多练习。











批改状态:合格

老师批语:完成的不错

全部评论

文明上网理性发言,请遵守新闻评论服务协议

条评论
暂无评论暂无评论!