Blogger Information
Blog 35
fans 0
comment 0
visits 44133
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
PHP-用MVC搭建一个框架,自动加载视图-2019年10月15日
Victor的博客
Original
1584 people have browsed it

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结构的使用,离熟练使用还差得很远,需要多多练习。











Correction status:qualified

Teacher's comments:完成的不错
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post