thinkphp视图模型使用详解

大兄弟 2018年09月11日0   214

写了一大段,浏览器卡住把页面刷新了一遍,mmp。。。

大家对视图应该不陌生,就是在数据库建立一个虚拟的表,查询的时候可以借用这个虚拟表的数据集进行查询。

tp的视图模型也是同样的思想,但tp使用的是数据库的多表关联原理。为了能详细讲解视图模型的作用,我们使用真正的业务进行分析讲解吧。

业务:由于在做的项目业务不方便对外,所以我这里使用我以前做过的解密网的业务,嘿嘿,这是一个上古的业务。好了,进入正文,现有两个表user、file,其中user表就不介绍了,file表是用户解密的文件记录表,相当于解密日志表。两表有一个字段是相互关联的,分别是user.id、file.uid。但是直到有一天,我需要获取每个用户的解密文件数并以文件数进行用户排序,而user表我没有事先建立filecount进行记录用户的文件数。在没有数据库关联知识前,我们都会认为丢失了一项重要的用户数据。

分析:经过查阅资料,我们学习到了表关联的知识,并且得知事先建表的时候我们已经给予两表的关联关系了,所以我们先通过数据库语句进行统计每个用户的文件数,再通过关联用户表即可进行用户分页、排序等操作了。

实验:首先我们需要统计出每个用户的解密文件数,但是使用count函数只能得到一条数据啊,怎么才能以用户来统计呢?经过查阅资料得知,通过group by 可以进行分组统计。所以我们设计出以下查询语句:

SELECT *,count(id) as cou FROM `file` GROUP BY uid

那么运行结果会如何呢?

image.png

哈哈,成功了,我们已经得到预期的数据集了。既然能够得到数据集,那么我们就把上述的查询语句命名为filecount表,这个表是一个虚拟表,因为我们有了这个虚拟表我们就可以通过这个数据集进行关联用户表了。接下来我们继续设计关联语句:

SELECT * FROM( SELECT *,count(id) as cou FROM `file` GROUP BY uid  ) filecount
RIGHT JOIN user ON filecount.uid = user.id

运行结果:

image.png

通过对比上图可知,我们得出来的数据是完全正确的,所以我们的关联语句也是成功了。那么万事俱备只欠东风,我们接下来就进行视图模型的构建。

建立视图模型前,我们先通过官方手册正式介绍一下视图模型:

视图通常是指数据库的视图,视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。分布式查询也可用于定义使用多个异类源数据的视图。如果有几台不同的服务器分别存储组织中不同地区的数据,而您需要将这些服务器上相似结构的数据组合起来,这种方式就很有用。视图在有些数据库下面并不被支持,但是ThinkPHP模拟实现了数据库的视图,该功能可以用于多表联合查询。非常适合解决HAS_ONE 
和 BELONGS_TO 类型的关联查询。

了解过视图模型后,我们新建一个自己的业务视图模型:

image.png

富文本编辑器一贴php代码就崩,只能放图了。。图中是视图模型的基本使用方法。

那么我们的业务应该怎么建立这个视图模型呢?

<?php
namespace Home\Model;
use Think\Model\ViewModel;
class UserViewModel extends ViewModel{
        public $viewFields = array(
			'ifnull(cou,0)'=>'cou',
			'_type'=>'RIGHT'
		),
		'user'=>array(
			'email',
			'id'=>'uid',
			'_on'=>'filecount.uid = user.id'
		),
	);
	public function _initialize(){
		$this->buildVirtualTable();
	}
	/**
	 * 自动构建虚拟表
	 * @param  [type]  $map   [description]
	 * @param  boolean $field [description]
	 * @return [type]         [description]
	 */
	public function buildVirtualTable($map, $field = false){
		$model = M('File');// 虚拟表模型
		// 自动构建统计字段
                if(!$field){
                    $field = '*,count(id) as cou';
                }else if(is_string($field) && strpos($field,'cou') === false){
                    $field .= ', count(id) as cou';
                }else{
                    $field['count(id)'] = 'cou';
                }
                $sql = $model->where($map)->field($field)->group('uid')->buildSql();
                $this->viewFields['filecount']['_table'] = $sql;// 设置虚拟表
                return $sql;
	}
}

经过百般尝试,终于能粘贴php代码了,可能粘贴过程中会有问题,所以还是贴一张图保险一点:

image.png

通过这个视图模型的代码,我们的逻辑就很清晰了,但是作为一个合格的程序员,内心总有一个声音在呼唤着要看看最后会生成一个什么样的SQL语句呢?为了满足自己的好奇心我还是实操了一波:

image.png

image.png

最后得出了一个长长的SQL语句,然后我们再对比地进行查询测试:

1. 文件数从少到多:

image.png

image.png

结果:完美呈现。

2.文件数倒序:

image.png

image.png


结果:数据完美呈现。


我们解释一下代码里的视图字段吧:

_type:是关联类型、分别对应RIGHT、LEFT、INNER

_on:是表关联的条件,字段前需加表别名(或表名)。

_table:如果该表不是关联表的话,需要使用该属性进行声明。代码中我使用了_initialize方法进行自动构建虚拟表,很方便。

还有一些不常用的属性可以移步官网查阅。其实这个业务逻辑是比较简单的,如果在真实项目中可能就没那么简单了,但是也证明了视图模型能够帮我们很清晰地完成虚拟数据的构建,减少了我们开发过程中很多没必要的重复代码。