ThinkPHP模型详解

模型定义,默认情况下,ThinkPHP的模型类是位于/Home/Model/目录之下,模型类通常需要继承系统的\Think\Model类或其子类,下面是一个Home\Model\UserModel类的定义:

文件命名遵守UserModel.class.php的方式,跟控制器的命名一样

<?php
namespace Home\Model;

use Think\Model;

class UserModel extends Model {
}

模型类的作用大多数情况是操作数据表的,如果按照系统的规范来命名模型类的话,大多数情况下是可以自动对应数据表,但你可以根据自己的需求来定制自己的数据表设置和操作。

首先我们需要在配置文件设置我们的数据库连接信息:

  'DB_TYPE'        => 'mysql',
  'DB_HOST'        => 'localhost',
  'DB_NAME'        => 'database',
  'DB_USER'        => 'username',
  'DB_PWD'        => 'password',
  'DB_PORT'        => '3306',

这些配置信息还是在/Home/Conf/config.php文件里设置。

指定数据表前缀

指定标前缀,我们在第一课的配置项已经指定,以下的文字表示你可以灵活配置你的数据表。

protected $tablePrefix = 'top_';

如果数据库的表没有表前缀,使用空字符串代替

protected $tablePrefix = '';

指定数据表,此处的指定的数据表的不需要添加表前缀:

protected $tableName = 'user';

举个例子说,比如说你的数据库中有一个没有表前缀的,名为users的数据表,可以用以下的两种方法在模型中进行下面的定义:

第一,直接根据系统的规范来命名模型类来命名模型,比如说就命名为UsersModel那么只需要在这个类里面加上下面的设置就可以了:

protected $tablePrefix = '';

ThinkPHP系统就会自动定位到users表了。

第二种情况时,如果你的模型类没有按照系统规范来命名,比如说不小心命名为UserModel,这种情况下可以同时指定表前缀和表明,比如:

protected $tablePrefix = '';

protected $tableName = 'users';

或者你直接指定trueTableName:

protected $trueTableName = 'users';

既然模型通常是用来操作数据表,那么我们来看看模型的基本CURD:

注:为了方便演示,我们在UserController中定义一个testDemo()方法用于演示

public function testDemo()
  {

  }

以下的代码将会一段一段在这个方法里演示,你可以通过访问http://localhost:8999/index.php/Home/User/testDemo来看到实际效果。

添加纪录

$user = M('User');
$data['username'] = 'ThinkPHP';
$data['email'] = 'ThinkPHP@gmail.com';
$user->create($data);
$record = $user->add();
dump($record);

add()返回的是插入数据的id,对于不存在的表字段,add()方法会自动过滤。

读取纪录

在ThinkPHP中读取数据的方式很多,通常分为读取数据、读取数据集和读取字段值

$user = M('User');

$record = $user->where('username="ThinkPHP"')->find();

dump($record);

读取字段值

$user = M('User');

$record = $user->where('id=3')->getField('username');

dump($record);

默认情况下,当只有一个字段的时候,返回满足条件的数据表中的该字段的第一行的值.如果getField()传入多个字段,返回值将是一个关联数组:

$user = M('User');

$record = $user->getField('username,email');
dump($record);

这个数组总是以传入的第一个第一个字段为键值的。如果修改为:

$user = M('User');

$record = $user->getField('email,username');

dump($record);

将上面的两次代码分别放到testDemo(),你就会看到不一样的结果集。

用save()方法更新数据

$user = M('User');

$data['username'] = 'ThinkPHPSave';
$data['email'] = 'ThinkPHPSave@outlook.com';

$record = $user->where('id=3')->save($data);

dump($record);

这里的$record返回的事1,表示成功更改。

当然,你也可以这样:

$user = M('User');

$user->username = 'ThinkPHP';
$user->email = 'ThinkPHP@outlook.com';

$record = $user->where('id=3')->save();

dump($record);

日常开发的时候经常会遇到一些只更新某些字段的情况,可以通过下面的方式来实现:

$user = M("User");
$record = $user->where('id=4')->setField('username','ThinkPHPChangeName');

dump($record);

同时更新多个字段,可以将数据以数组的形式传给setField()方法:

$user = M('User');
$data = array('username'=>'ThinkPHPChangeArray','email'=>'ThinkPHP@array.com');
$record = $user-> where('id=6')->setField($data);
dump($record);

ThinkPHP删除数据使用delete方法,例如:

$user = M('User');
$record = $user->where('id=3')->delete();
dump($record);

或者你可以直接使用:

$record = $user->delete('1,2,5');
dump($record);

这样就达到了删除主键1,2,5这三条纪录了。

ActiveRecords

ThinkPHP实现了ActiveRecords模式的ORM模型,采用了非标准的ORM模型:表映射到类,记录映射到对象。以下实例将使用ActiveRecords重现对数据表的CURD,看看ActiveRecords给我们带来了什么好处。

$user = M("User");

$user->username = 'ThinkPHPWithActive';
$user->email = 'ThinkPHPActive@gmail.com';

$record = $user->add();

dump($record);

读取纪录

AR最大的特点可能就是它的查询模式了,模式简单易用,因为更多情况下面查询条件都是以主键或者某个关键的字段。这种类型的查询,ThinkPHP有着很好的支持。

比如说获取主键为2的用户信息:

$user = M("User");

$record = $user->find(2);

dump($record);

直接不用where()查询了,简单友好吧。再比如:

$user = M("User");

$record = $user->getByUsername("jelly");

dump($record);

如果是查询多条纪录,使用以下方式:

$user = M("User");

$record = $user->select('1,3,8');

dump($record);

更新记录

$user = M("User");
$user->find(21);
$user->username = 'TOPThinkChangeWithAR';
$record = $user->save();

dump($record);

删除记录

删除单条纪录

$user = M("User");

$record = $user->delete(8);

dump($record);

删除多条纪录

$user = M("User");

$record = $user->delete('15,16');

dump($record);

// todo: 这里的自动验证和关联模型 调试不出来。

自动完成

自动完成是ThinkPHP提供用来完成数据自动处理和过滤的方法,当使用create()方法创建数据对象的时候会触发自动完成数机制。

因此,在ThinkPHP鼓励使用create()方法来创建数据对象,因为这是一种更加安全的方式,直接通过add()或者save()方法实现数据写入无法出发自动完成机制。

自动完成通常用来完成默认字段写入(比如添加时间戳),安全字段过滤(比如加密密码)以及业务逻辑的自动处理等。可以通过模型类里面通过$_auto属性定义处理规则。下面演示如何自动完成添加时间戳:

在UserModel中,声明自动完成的定义数组$_auto :

protected $_auto = array (
    array('created_at','date("Y-m-d H:i:s", time())',3,'function'),
    array('updated_at','date("Y-m-d H:i:s", time())',3,'function'),
  );

还有一种是理由auto()方法动态设置自动完成的机制,可以到官方文档去看看

设置完成之后,我们在testDemo()方法中创建一条用户数据:

$user = D('User');
$data['username'] = "ThinkPHP";
$data['email'] = "ThinkPHP@gmail.com";
$user->create($data);
$record = $user->add();
dump($record);

测试,如果返回纪录的id值,说明用户纪录创建成功。要验证数据是否自动完成,你可以直接使用:

$user = D('User');
$record = $user->find(id);
dump($record);

自动验证

自动验证是ThinkPHP模型层提供的一种数据验证方法,可以在使用create()创建数据对象的时候自动进行数据验证。

数据验证可以进行数据类型、业务规则、安全判断等方面的验证操作。

通常用于表单验证

数据验证有两种方式:

静态方式:在模型类里面通过$_validate属性定义验证规则。

动态方式:使用模型类的validate()方法动态创建自动验证规则。

无论是什么方式,验证规则的定义是统一的规则,定义格式为:

array(
     array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
     array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
     ......
);
下面以$_validate静态方式举例如何使用自动验证:

在UserController中创建register()方法,对,几乎每一个Web应用都需要实现用户注册这一步。

public function register()
  {
    $this->display();
  }

对,就是这么简单,这个方法只是将相应的视图文件渲染出来。所以接下来我们创建对应的视图文件,也就是:./Application/Home/View/User/register.html

<extend name="Index/base" />
<block name="main" >
<form method="post" action="__URL__/registerValidate">
  <div class="form-group">
    <label for="exampleInputName">Name</label>
    <input type="text" name="username" class="form-control" id="exampleInputName" placeholder="Name">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail">Email</label>
    <input type="email" name="email" class="form-control" id="exampleInputEmail" placeholder="Email">
  </div>

  <button type="submit" class="btn btn-default">Submit</button>
</form>
</block>

上面就是一些HTML代码和一点模板的知识,对于模板,我们后续会讲到,但不管怎样,现在我们访问
http://localhost:8999/Home/User/register,就可以看到我们的注册表单页面了。

注意到form表单中,action="__URL__/registerValidate",这表示提交到当前的控制器的registerValidate()方法处理,所以我们在UserController中增加registerValidate()方法:

public function registerValidate()
  {
    $data['username'] = $_POST['username'];
    $data['email'] = $_POST['email'];

    $user = D("User");

    if ( !$user->create($data) ) {
      exit($user->getError());
    }
    //todo: validation passes, add data to database and redirect somewhere

    echo 'validation passes';

  }

这里的if ( !$user->create($data) )会触发自动验证并判断验证是否通过验证。你可以尝试在表单里填写不同的数据来进行测试,也可以修改一下验证规则,更多规则可以到官网查看:

http://document.thinkphp.cn/manual_3_2.html#auto_validate

关联模型

通常我们所说的关联关系包括下面三种:

一对一关联 :ONE_TO_ONE,包括HAS_ONE 和 BELONGS_TO
一对多关联 :ONE_TO_MANY,包括HAS_MANY 和 BELONGS_TO
多对多关联 :MANY_TO_MANY

关联定义

ThinkPHP可以很轻松的完成数据表的关联CURD操作,目前支持的关联关系包括下面四种:
HAS_ONE、BELONGS_TO、HAS_MANY和MANY_TO_MANY。
一个模型根据业务模型的复杂程度可以同时定义多个关联,不受限制,所有的关联定义都统一在模型类的 $_link 成员变量里面定义,并且可以支持动态定义。要支持关联操作,模型类必须继承Think\Model\RelationModel类,关联定义的格式类似于:

namespace Home\Model;
use Think\Model\RelationModel;
class UserModel extends RelationModel{
   protected $_link = array(
    '关联' => array(
      '关联属性1' => '定义',
      '关联属性N' => '定义',
    ),
   );
}

关于关联属性的定义和值,你可以到官方文档仔细查看,我们下面也会给出一些最常用的。

在我们的讲解例子中,会采用HAS_MANY和BELONGS_TO来演示,对于其他的几个关系模型,可以参考官方文档举一反三。

首先我们知道数据库里面有两张表,用户表和文章表,并且我们也为其创建了不同的模型(UserModel ArticelModel)。

现在我们仔细来想想他们之间的对应关系:一个用户可以拥有多篇文章,而每一篇文章都属于某个特定的用户。所以我们可以分别为这两种关系添加关联模型:

在UserModel中:

protected $_link = array(
    'Article' => self::HAS_MANY
  );

在ArticleModel中:

protected $_link = array(
    'User' => self::BELONGS_TO
  );

以上者两种都是最简洁的模型关联声明。因为在最开始设计数据库的时候,我们遵守了ThinkPHP的官方的规范:

外键的默认规则是当前数据对象名称_id,例如:UserModel对应的可能是表think_user,那么think_user表的外键默认为user_id,如果你的外键不是user_id,而是其他自定义的字段如:user_identify,那么就必须在定义关联的时候定义 foreign_key 。如下:

在UserModel中:

protected $_link = array(
    'mapping_type' => self::HAS_MANY,
    'class_name'  => 'Article',
    'foreign_key'  => 'user_identify',
  );

更多自定义的关联模型参数可以到官网查看。

有了以上的定义之后,我们就可以在检索用户数据的同时将属于他的文章也一起检索出来,使用relation()。

同样是在testDemo()这个方法中:

$user = D('User');
$record = $user->relation(true)->find(4);
dump($record);

访问熟悉的http://localhost:8999/Home/User/testDemo,你将会看到神奇的结果。

以上所述就是本文的全部内容了,希望大家能够喜欢。

(0)

相关推荐

  • ThinkPHP关联模型操作实例分析

    通常我们所说的关联关系包括下面三种: ◇ 一对一关联 : ONE_TO_ONE , 包括 HAS_ONE 和 BELONGS_TO ◇ 一对多关联 : ONE_TO_MANY , 包括 HAS_MANY 和 BELONGS_TO ◇ 多对多关联 : MANY_TO_MANY 关联定义 数据表的关联 CURD 操作,目前支持的关联关系包括下面四种:HAS_ONE . BELONGS_TO . HAS_MANY . MANY_TO_MANY . 一个模型根据业务模型的复杂程度可以同时定义多个关联,不

  • ThinkPHP视图查询详解

    ThinkPHP提供的视图查询应用功能十分强大,用户利用视图查询功能可以将多个数据表的字段内容按需要进行指定和筛选,组织成一个基于这些数据表的视图模型,然后就可以通过该模型直接进行多表联合查询,非常方便和简单. 例如在项目中,我们定义有三个表: user          用户基础表, user_info   用户详细信息表, dept          部门分类表 现在我们需要获取某个用户信息, 该信息要包括用户的帐号名称和相关资料与及所在部门的名称, 这时候我们可以利用视图查询进行处理. 下

  • ThinkPHP中实例Model方法的区别说明

    在TP中,我们可以用下面两种方法去创建一个数据表的映射对象(我暂时用到的) 第一种:$Test = D('Test') 第二种:$Test = new Model('Test') 虽然这两种都可以对数据进行select,insert,delete,udpate操作,在数据验证上有很大的不同, 我们来看看效果,先创建一个 TestModel 复制代码 代码如下: class TestModel extends Model{ protected $_validate = array{ array('

  • thinkphp3.x自定义Action、Model及View的简单实现方法

    本文实例讲述了thinkphp3.x自定义Action.Model及View的实现方法.分享给大家供大家参考,具体如下: 1.在xmall/Lib/Action中创建文件TestAction.class.php class TestAction extends Action{ function index(){ $this->display("test"); } } 2.在xmall/tpl下创建default文件夹,在default下创建Test文件夹,在Test下创建test

  • ThinkPHP3.2.2的插件控制器功能

    3.2.2版本开始支持插件控制器的调用,可以通过更加方便的URL地址访问到模块中某个插件定义的控制器. 当URL中传入插件控制器变量的时候,会自动定位到插件控制器中的操作方法. 插件控制器的变量由参数 VAR_ADDON 进行设置,默认为addon,例如我们在URL中传入: 复制代码 代码如下: http://serverName/Home/info/index/addon/SystemInfo 由于传入了addon参数,因此这里的User控制器并非原来的 复制代码 代码如下: Home/Con

  • ThinkPHP中URL路径访问与模块控制器之间的关系

    ThinkPHP中URL路径访问与模块控制器之间的关系是ThinkPHP程序开发中非常重要的一个环节.熟练的掌握该技巧对于进一步学习ThinkPHP起着至关重要的作用.具体分析如下: 打开控制器页面: UserAction.class.php  //路径:admin\Lib\Action\   此处的admin为新建的项目对应的目录 我们都知道在Action里的方法默认为Public属性,私有属性的方法没法访问,但定义私有属性的方法也有其意义所在. 在其中定义私有方法的意义:主要体现在,能够在这

  • ThinkPHP实例化模型的四种方法概述

    本文讲述了ThinkPHP实例化模型的四种方法,对于ThinkPHP程序设计来说有非常重要的应用.具体如下: 1.创建一个基础模型:实例化一个系统自带的数据库操作类 Test.Model.class.php页面代码如下: class TestModel extends Model{ } UserAction.class.php页面代码如下: function test(){ $test=M('test');//表示实例化的是自带的Model类,并且传入test值表示操作的是test表 //等同于

  • thinkPHP模型初始化实例分析

    本文实例讲述了thinkPHP模型初始化的方法.分享给大家供大家参考,具体如下: /* $dsn = 'mysql://bookman:book123@localhost:3306/Weapons'; $guns_tab = M('guns','',$dsn); $gun1 = $guns_tab ->select(); echo $guns_tab -> getLastSql(); dump($gun1); */ /* $guns_tab = M('guns'); $gun1 = $guns

  • 浅谈thinkphp的实例化模型

    thinkphp实例化模型给我们提供了三种方法 第一种 比较平常使用 就是$user=new Model('user'); //也等于 $user=M('user') 第二种就是我们如果有公共模型 我们的使用是这样的 譬如我们新建一个model   CommonModel.class.php这个公共模型 我们实例化就是这样的 复制代码 代码如下: $user=new CommonModel('user'); 这样我们既可以实例化user模型 又可以调用公共模型里边的方法 第三种就是针对我们的实例

  • thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法

    本文实例讲述了thinkphp视图模型查询失败提示:ERR: 1146:Table 'db.pr_order_view' doesn't exist解决办法.分享给大家供大家参考.具体方法如下: 一.问题描述: 想用thinkphp的视图模型进行关联查询,结果出现了这样的问题(log日志记录):ERR: 1146:Table 'db.pr_order_view' doesn't exist,我就纳闷,视图模型怎么出来的sql是这样的呢,视图模型如下: 复制代码 代码如下: class Order

  • ThinkPHP中的关联模型注意点

    初学ThinkPHP时,ThinkPHP中的关联模型有一处易错点,现举例如下:需用到的表:id_elite_major和id_elite_student代码举例如下: 复制代码 代码如下: class EliteMajorModel extends RelationModel{protected $_link=array('EliteStudent'=>array('mapping_type'=>HAS_MANY,  //易错点: 此处在 HAS_MANY 时常会加上 '' 容易写成 'HAS

  • ThinkPHP3.1新特性之Action参数绑定

    ThinkPHP3.1版的Action参数绑定功能提供了URL变量和操作方法的参数绑定支持,这一功能可以使得你的操作方法定义和参数获取更加清晰,也便于跨模块调用操作方法.这一新特性对以往的操作方法使用没有任何影响,你也可以用新的方式来改造以往的操作方法定义. Action参数绑定的原理是把URL中的参数(不包括分组.模块和操作地址)和控制器的操作方法中的参数进行绑定.例如,我们给Blog模块定义了两个操作方法read和archive方法,由于read操作需要指定一个id参数,archive方法需

  • ThinkPHP控制器间实现相互调用的方法

    本文实例讲述了ThinkPHP控制器间实现相互调用的方法.分享给大家供大家参考.具体实现方法如下: ThinkPHP同一个项目里,两个控制器的方法如何相互调用呢?ThinkPHP提供了一个A(),通过它可以使控制器之间的方法相互调用,使得代码可以重复利用. 官方似乎对A()方法没有相关使用文档,现在通过一个例子来说一下如使用A()方法. 有两个控制器,ColumnsAction和NewsAction.ncatlist()是ColumnsAction的分类列表方法,现在我要在控制器NewsActi

随机推荐