20.5 ThinkPHP的模型
视频讲解:光盘TMlx20ThinkPHP的模型.exe
顾名思义,模型就是按照某一个形状进行操作的代名词。模型的主要作用是,封装数据库的相关逻辑。也就是说,每执行一次数据库操作,都要遵循定义的数据模型规则来完成。
20.5.1 模型的命名
在定义模型时,ThinkPHP要求数据库的表名和模型类的命名遵循一定的规范,首先数据库的表名和字段全部采用小写形式,模型类的命名规则是除去表前缀的数据表名称,并且首字母大写,然后加上模型类的后缀定义。
例如,UserModel表示User数据对象,假设数据库的前缀定义是think_,则其对应的数据表应该是think_user; UserTypeModel对应的数据表是think_user_type。
如果你的规则和系统的约定不符合,那么需要设置Model类的tableName属性。在ThinkPHP的模型里面,有两个数据表名称的定义:
tableName
不包含表前后缀的数据表名称,一般情况下默认和模型名称相同,只有当表名和当前模型类的名称不同时才需要定义。例如,在数据库里面有一个think_categories表,而定义的模型类名称是CategoryModel,按照系统的约定,这个模型的名称是Category,对应的数据表名称应该是think_category (全部小写),但是现在的数据表名称是think_categories,因此就需要设置tableName属性来改变默认的规则(假设已经在配置文件里面定义了DB_PREFIX为think_)。
protected $tableName = 'categories';
注意
这个属性的定义不需要加表的前缀think_。
trueTableName
包含前后缀的数据表名称,也就是数据库中的实际表名,该名称无须设置,只有当上面的规则都不适用的情况或者特殊情况下才需要设置。例如,数据库中有一个表(top_depts)的前缀和其他表前缀不同,不是think_而是top_,这个时候需要定义trueTableName属性。
protected $trueTableName = 'top_depts';
注意
trueTableName需要完整的表名定义。
除了数据表的定义外,还可以对数据库进行定义:
dbName定义模型当前对应的数据库名称,只有当前的模型类对应的数据库名称和配置文件不同时才需要定义,例如:
protected $dbName = 'top';
20.5.2 实例化模型
在ThinkPHP中,无须进行任何模型定义(只有在需要封装单独的业务逻辑的时候,模型类才是必须被定义的),可以直接进行模型的实例化操作。根据不同的模型定义,实例化模型的方法也有所不同,下面来分析一下什么情况下使用什么方法。
1.实例化基础模型(Model)类
在没有定义任何模型的时候,可以使用下面的方法实例化一个模型类来进行操作:
$User = new Model('User'); $User->select(); //进行其他的数据操作
或者使用M快捷方法进行实例化,其效果是相同的。
$User = M('User'); $User->select(); //进行其他的数据操作
这种方法最简单高效,因为不需要定义任何的模型类,所以支持跨项目调用。缺点也是因为没有自定义的模型类,因此无法写入相关的业务逻辑,只能完成基本的CURD操作。在例20.2和例20.4中采用的都是实例化基础模型类,对数据库中数据进行读取、添加操作。
2.实例化其他模型类
第一种方式实例化因为没有模型类的定义,因此很难封装一些额外的逻辑方法,不过大多数情况下,也许只是需要扩展一些通用的逻辑,那么就可以尝试下面一种方法。
M方法默认是实例化Model类,如果需要实例化其他模型类,可以使用:
$User = new CommonModel('User', 'think_', 'db_config');
由上面的代码可见,模型类的实例化方法有三个参数,第一个参数是模型名称,第二个参数用于设置数据表的前缀(留空则取当前项目配置的表前缀),第三个参数用于设置当前使用的数据库连接信息(留空则取当前项目配置的数据库连接信息)。
第三个连接信息参数可以使用DSN配置或者数组配置,甚至可以支持配置参数。用M方法实现的话,上面的方法可以写成:
$User = M('CommonModel:User', 'think_', 'db_config');
M方法默认是实例化Model类,第二个参数用于指定表前缀,第三个参数就可以指定其他的数据库连接信息。
因为系统的模型类都能够自动加载,因此不需要在实例化之前手动进行类库导入操作。模型类commonModel必须继承Model,如果没有定义别名导入,需要放在项目Model下。可以在CommonModel类里面定义一些通用的逻辑方法,就可以省去为每个数据表定义具体的模型类,如果项目的数据表超过100个,而且大多数都是执行基本的CURD操作,只是个别模型有一些复杂的业务逻辑需要封装,那么第一种方式和第二种方式的结合是一个不错的选择。
3.实例化用户定义的模型(×××Model)类
这种情况是使用得最多的,一个项目不可避免地需要定义自身的业务逻辑实现,就需要针对每个数据表定义一个模型类,例如UserModel、InfoModel等。
定义的模型类通常都是放到项目的LibModel目录下。例如:
class UserModel extends Model{ Public function myfun(){ //添加自己的业务逻辑 … } }
其实,模型类还可以继承一个用户自定义的公共模型类,而不是只能继承Model类。要实例化自定义模型类,可以使用下面的方式:
$User = new UserModel(); $User->select(); //进行其他的数据操作
还可以使用D快捷方法进行实例化,其效果是相同的。
$User = D('User'); $User->select(); //进行其他的数据操作
D方法可以自动检测模型类,不存在时系统会抛出异常,同时对于已实例化过的模型,不会重复去实例化。默认的D方法只能支持调用当前项目的模型,如果需要跨项目调用,需要使用:
$User=D('Admin://User'); //实例化Admin项目下面的User模型 $User->select();
如果启用模块分组功能,还可以使用:
$User = D('Admin/User'); //实例化Admin分组的User模型
4.实例化空模型类
如果仅仅是使用原生SQL查询,不需要使用额外的模型类,实例化一个空模型类即可进行操作,例如:
$Model = new Model(); // 或者使用M快捷方法实例化是等效的 // $Model = M(); $Model->query('SELECT * FROM think_user where status=1');
空模型类也支持跨项目调用。
【例20.5】通过M方法实例化Model类,完成数据库中用户信息和类别信息的输出。(实例位置:光盘TMsl205)
关键操作步骤如下:
(1)创建5项目根目录,在根目录下创建项目文件夹App和Public文件夹存储css、图片和JS脚本等文件。
(2)在5项目根目录下编辑index.php入口文件。其关键代码如下:
<?php define('THINK_PATH', '../ThinkPHP/'); //定义ThinkPHP框架路径(相对于入口文件) define('APP_NAME', '5'); //定义项目名称 define('APP_PATH', './App/'); //定义项目路径 require(THINK_PATH."/ThinkPHP.php"); //加载框架入口文件 ?>
(3)在IE浏览器中运行入口文件,自动生成项目目录。
(4)定位到AppConf目录下,编辑config.php文件,完成项目中数据库的配置。其代码如下:
<?php return array( 'APP_DEBUG'=>false, //关闭调试模式 'DB_TYPE'=>'mysql', //数据库类型 'DB_HOST'=>'localhost', //数据库服务器地址 'DB_NAME'=>'db_database20', //数据库名称 'DB_USER'=>'root', //数据库用户名 'DB_PWD'=>'111', //数据库密码 'DB_PORT'=>'3306', //数据库端口 'DB_PREFIX'=>'think_', //数据表前缀 ); ?>
(5)定位到AppLibAction目录下,编写项目的控制器。创建Index模块,继承系统的Action基础类,定义index方法,通过M方法实例化模型类,读取think_user数据表中的数据,并且将查询结果赋给模板变量,指定模板页;定义type方法,通过M方法实例化模型类,读取类型数据表think_type中的数据,同样将查询结果赋给模板变量,指定模板页。IndexAction.class.php的代码如下:
<?php header("Content-Type:text/html; charset=utf-8"); //设置页面编码格式 class IndexAction extends Action{ public function index(){ $db=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $select=$db->select(); //查询数据 $this->assign('select', $select); //模板变量赋值 $this->display(); //指定模板页 } public function type(){ $dba=M('Type'); //实例化模型类,参数数据表名称,不包含前缀 $select=$dba->select(); //查询数据 $this->assign('select', $select); //模板变量赋值 $this->display('type'); //指定模板页 } } ?>
(6)定位到AppTpl目录下,创建Index模块文件夹。首先,编辑index操作的模板文件index.html,循环输出模板变量传递的数据。其关键代码如下:
<volist name='select' id='user' > <tr class="content"> <td bgcolor="#FFFFFF"> {$user.id}</td> <td bgcolor="#FFFFFF"> {$user.user}</td> <td bgcolor="#FFFFFF"> {$user.address}</td> </tr> </volist>
然后编辑type.html模板文件,循环输出类型数据表中的数据。其关键代码如下:
<volist name='select' id='type' > <tr class="content"> <td bgcolor="#FFFFFF"> {$type.id}</td> <td bgcolor="#FFFFFF"> {$type.typename}</td> <td bgcolor="#FFFFFF"> {$type.dates}</td> </tr> </volist>
(7)在IE浏览器中输入http://localhost/TM/sl/20/5/index.php,其运行结果如图20.14所示。在IE浏览器中输入http://localhost/TM/sl/20/5/index.php/index/type,其运行结果如图20.15所示。
图20.14 输出用户信息
图20.15 输出类别信息
说明
在Model类里面根本没有定义任何User表、Type表的字段信息,但是系统是如何做到属性对应数据表的字段呢?这是因为ThinkPHP可以在运行时自动获取数据表的字段信息(确切地说,是在第一次运行的时候,将其存储于缓存文件,以后会永久缓存字段信息,除非设置不缓存或者删除),包括数据表的主键字段和是否自动增长等,如果需要显式获取当前数据表的字段信息,可以使用模型类的getDbFields方法来获取。如果在开发过程中修改了数据表的字段信息,需要清空Data/_fields目录下的缓存文件,让系统重新获取更新的数据表字段信息。
20.5.3 属性访问
ThinkPHP利用PHP 5的魔术方法机制来实现属性的直接访问。这也是最常用的访问方式,通过数据对象访问,例如:
<?php $User = new Model('User'); $User->find(1); echo$User->name; //获取name属性的值 $User->name='ThinkPHP'; //设置name属性的值 ?>
还有一种属性的操作方式是通过返回数组的方式,例如:
<?php $Type=D('Type'); //注意这里返回的type数据是一个数组 $type = $Type->find(1); echo$type['name']; //获取type属性的值 $type['name']='ThinkPHP'; //设置type属性的值 ?>
20.5.4 连接数据库
ThinkPHP内置抽象数据库访问层,把不同的数据库操作封装起来,只需使用公共的Db类进行操作,而无须针对不同的数据库写不同的操作代码,Db类会自动调用相应的数据库适配器来处理。目前的数据库包括MySQL、MSSQL、PgSQL、SQLite、oracle、Ibase以及PDO的支持,如果应用需要使用数据库,必须配置数据库连接信息,数据库的配置文件有多种定义方式。
1.在项目配置文件里面定义
在前面的实例中已经见识过了。其代码如下:
<?php return array( 'APP_DEBUG'=>false, //关闭调试模式 'DB_TYPE'=>'mysql', //数据库类型 'DB_HOST'=>'localhost', //数据库服务器地址 'DB_NAME'=>'db_database20', //数据库名称 'DB_USER'=>'root', //数据库用户名 'DB_PWD'=>'111', //数据库密码 'DB_PORT'=>'3306', //数据库端口 'DB_PREFIX'=>'think_', //数据表前缀 ); ?>
系统推荐使用这种方式,因为一般一个项目的数据库访问配置是相同的。使用该方法,系统在连接数据库的时候会自动获取,无须手动连接。
说明
可以对每个项目定义不同的数据库连接信息,还可以在调试配置文件里面定义调试数据库的配置信息,如果在项目配置文件和调试模式配置文件里面同时定义了数据库连接信息,那么在调试模式下后者生效,部署模式下前者生效。
2.使用DSN方式在初始化Db类的时候传参数
$db_dsn="mysql://root:[email protected]:3306/db_database20"; //定义DSN $db=new Db(); //执行类的实例化 $conn=$db->getInstance($db_dsn); //连接数据库,返回数据库驱动类
该方式主要用于在控制器里面自己手动连接数据库的情况,或者用于创建多个数据库连接。
【例20.6】通过DSN方式完成与数据库的连接,并且输出数据库中的数据。(实例位置:光盘TMsl206)
本例是例20.5的延伸,仍然输出数据库中用户和类别表中的数据,只是对其连接数据库的方法进行了修改。
关键操作步骤如下:
(1)删除AppConf目录下的配置文件config.php。
(2)在AppLibActionIndex目录下,修改控制器Index。在index方法中,应用DSN方式完成与数据库的连接,并且查询think_user表中的数据。其关键代码如下:
public function index(){ $db_dsn="mysql://root:[email protected]:3306/db_database20"; //定义DSN $db=new Db(); //执行类的实例化 $conn=$db->getInstance($db_dsn); //连接数据库,返回数据库驱动类 $select=$conn->query('select*from think_user'); //执行查询语句 $this->assign('select', $select); //模板变量赋值 $this->display(); //指定模板页 }
在type方法中,应用DSN方式完成数据库的连接操作,并且查询think_type表中的数据。其关键代码如下:
public function type(){ $db_dsn="mysql://root:[email protected]:3306/db_database20"; //定义DSN $db = new Db(); $conn=$db->getInstance($db_dsn); //连接数据库,返回数据库驱动类 $select=$conn->query('select*from think_type'); //执行查询语句 $this->assign('select', $select); //模板变量赋值 $this->display('type'); //指定模板页 }
上述是在例20.5中所做的修改,至于其他步骤与例20.5相同,这里不再赘述。其运行结果也与例20.5相同。
3.在模型类里面定义参数,连接数据库
protected $connection = array( 'dbms' => 'mysql', 'username' => 'username', 'password' => 'password', 'hostname' => 'localhost', 'hostport' => '3306', 'database' => 'dbname' ); //或者使用下面的方式定义 protected $connection = "mysql://username:password@localhost:3306/DbName";
如果在某个模型类里面定义了connection属性,则在实例化模型对象的时候,会使用该数据库连接信息进行数据库连接。通常用于某些数据表位于当前数据库连接之外的其他数据库。
说明
ThinkPHP并不是在一开始就会连接数据库,而是在有数据查询操作的时候才会去连接数据库。额外的情况是,在系统第一次操作模型的时候,框架会自动连接数据库获取相关模型类的数据字段信息,并缓存下来。
4.使用PDO方式连接数据库
这里在项目配置文件中应用PDO连接数据库,其定义的数组内容如下:
return array( 'DB_TYPE'=> 'pdo', //注意DSN的配置针对不同的数据库有所区别 'DB_DSN'=> 'mysql:host=localhost; dbname=db_database20', 'DB_USER'=>'root', 'DB_PWD'=>'111', 'DB_PREFIX'=>'think_', … //其他项目配置参数 'APP_DEBUG'=>false, //关闭调试模式 );
注意
在使用PDO方式的时候,要注意检查PHP环境是否开启相关的PDO模块。同时还要确保ThinkPHP核心包中包含DbPdo.class.php文件。另外,还要注意参数DB_DSN仅对PDO方式连接才有效。
【例20.7】在项目配置文件中,以PDO方式连接数据库,并且输出数据库中的数据。(实例位置:光盘TMsl207)
在例20.5中,数据库的连接方法定义到配置文件config.php中,而应用PDO连接MySQL数据库仍然需要在配置文件中进行操作,那么只需对例20.5中的config.php文件进行修改,就完成了例20.7,即应用PDO连接MySQL数据,并且输出查询结果。其修改后的config.php文件的代码如下:
<?php return array( 'DB_TYPE'=> 'pdo', //注意DSN的配置针对不同的数据库有所区别 'DB_DSN'=> 'mysql:host=localhost; dbname=db_database20', 'DB_USER'=>'root', 'DB_PWD'=>'111', 'DB_PREFIX'=>'think_', … //其他项目配置参数 'APP_DEBUG'=>false, //关闭调试模式 ); ?>
本例的运行结果与例20.5相同,这里不再赘述。
20.5.5 创建数据
ThinkPHP可以自动根据表单数据创建数据对象,这个优势在一个数据表的字段非常多的情况下尤其明显。例如,在User控制器中定义insert方法,首先实例化模型类,然后调用Create方法根据表单提交的POST数据创建数据对象,最后调用add方法把创建的数据对象写入数据库。其关键代码如下:
class UserAction extends Action{ //定义类,继承基础类 public function insert(){ //定义方法 $ins=new Model('user'); //实例化模型类,传递参数为没有前缀的数据表名称 $ins->Create(); //创建数据对象 $result=$ins->add(); //写入数据库 $this->redirect('Index/index', '',5, ’页面跳转中’); //页面重定向 } }
短短的3行代码(加粗部分),完成数据的添加操作,其具体应用可以参考例20.4。
其中的Create方法还支持其他方式提交的数据对象。例如,以数组形式提交数据,从其他的数据对象中获取的数据等。其关键代码如下:
//数组形式提交数据 $data['user'] = 'mrsoft'; $data['address'] = ’长春市’; $User->Create($data); //从User数据对象创建新的Member数据对象 $User=M("User"); //实例化User对象 $User->find(1); //读取数据 $Member=M("Member"); //创建Member对象 $Member->Create($User);
Create方法在创建数据对象的同时,还实现了一些非常有意义的功能,包括支持多种数据源、数据自动验证、字段类型检查和数据自动完成等。
Create方法创建的数据对象被保存在内存中,并没有实际写入数据库中,直到使用add或者save方法,才真正将数据添加到数据库中。如果只是想简单创建一个数据对象,那么可以使用data方法。例如,实例化User模型,通过data和add方法将数据添加到数据库中,其关键代码如下:
$User=M('User'); //实例化User模型 //创建数据后写入数据库中 $data['user'] = 'mrsoft'; $data['address'] = ’长春市’; $User->data($data)->add(); //执行数据对象的创建
注意
使用data方法创建的数据对象不会进行自动验证和过滤操作,需要自行处理。但在进行add或者save操作的时候,数据表中不存在的字段以及非法的数据类型(例如对象、数组等非标量数据)是会自动过滤的,不用担心非数据表字段的写入导致SQL错误的问题。
20.5.6 连贯操作
ThinkPHP模型基础类提供的连贯操作方法,可以有效地提高数据存取的代码的清晰度和开发效率。例如,查询一个User表的满足状态为1的前5条记录,并按照用户的ID排序,其关键代码如下:
$User->where('status=1')->order('id')->limit(5)->select();
在连贯操作中,select方法必须放到最后一个,其他的连贯操作方法调用顺序没有先后。如果不习惯使用连贯操作,那么新版还支持直接使用参数进行查询的方式。例如,上面的代码可以改写为:
$User->select(array('order'=>'id', 'where'=>'status=1', 'limit'=>'5'));
如果使用数组参数方式,索引的名称就是连贯操作的方法名称。其实,不仅仅是查询方法可以使用连贯操作,包括add、save、delete等方法都可以使用,例如:
$User->where('id=1')->field('id, user, address')->find(); $User->where('status=1 and id=1')->delete();
下面对连贯操作的方法进行一下总结(更多的用法将在CURD操作的过程中详细描述),如表20.3所示。
表20.3 连贯操作方法总结
注意
有关上述方法的应用,将在后面的CURD操作中体现,这里不再一一举例。
20.5.7 CURD操作
ThinkPHP提供了灵活和方便的数据操作方法,CURD(创建、更新、读取和删除)是四个最基本的数据库操作。CURD操作通常与连贯操作配合使用。下面将对各种操作的使用方法进行分析(在执行类的实例化操作时,统一使用M方法)。
1.创建操作
在ThinkPHP中使用add方法完成数据的添加操作。其使用方法如下:
$User=M("User"); //实例化User对象 $data['name'] = 'ThinkPHP'; $data['email'] = '[email protected]'; $User->add($data);
或者使用data方法进行连贯操作。其代码如下:
$User->data($data)->add();
如果在add之前已经创建数据对象(例如使用了Create或者data方法),则add方法就不需要再传入数据了。
2.更新数据
第一种,在ThinkPHP中使用save方法更新数据库,并且也支持连贯操作的使用。例如,更新数据表中name和email字段的值。其代码如下:
$User=M("User"); //实例化User对象 $data['name']='ThinkPHP'; //要修改的数据对象属性赋值 $data['email'] = '[email protected]'; $User->where('id=5')->save($data); //根据条件保存修改的数据
save方法在执行更新数据的操作时,如果没有设置任何更新条件,且数据对象本身也不包含主键字段,那么save方法不会更新任何数据库的记录。
第二种,通过data方法创建要更新的数据对象,然后通过save方法进行保存。例如:
$User=M("User"); //实例化User对象 $data['name']='ThinkPHP'; //要修改的数据对象属性赋值 $data['email']='[email protected]'; //要修改的数据对象属性赋值 $User->where('id=5')->data($data)->save(); //根据条件保存修改的数据
第三种,针对某个字段的值,应用setField方法进行更新。例如,更新数据表中字段name的值,条件是ID为5的记录。
$User=M("User"); //实例化User对象 $User->where('id=5')->setField('name', 'ThinkPHP');//更改用户的name值
如果要更新多个字段的值,也可以应用setField方法,只需要传入数组即可,例如:
$User=M("User"); //实例化User对象 //更改用户的name和email的值 $User-> where('id=5')->setField(array('name', 'email'), array('ThinkPHP', '[email protected]'));
第四种,应用setInc和setDec方法对统计字段(通常指的是数字类型)中的值进行增减操作。例如,对指定用户的积分进行增、减操作。
$User=M("User"); //实例化User对象 $User->setInc('score', 'id=5',3); //用户的积分加3 $User->setInc('score', 'id=5'); //用户的积分加1 $User->setDec('score', 'id=5',5); //用户的积分减5 $User->setDec('score', 'id=5'); //用户的积分减1
3.读取数据
在ThinkPHP中读取数据的方式很多,通常分为读取某个字段的值、读取数据和读取数据集。读取字段的值使用getField方法,读取数据使用find方法,读取数据集使用select方法。
getField方法读取某个字段的值,如果传入多个字段,可以返回一个关联数组。返回的list是一个数组,键名是用户的id,键值是用户的昵称nickname。例如,获取ID为3的用户的昵称,获取所有用户的ID和昵称列表。
$User=M("User"); //实例化User对象 $nickname=$User->where('id=3')->getField('nickname'); //获取ID为3的用户的昵称 $list=$User->getField('id, nickname'); //获取所有用户的ID和昵称列表
select方法的返回值是一个二维数组,如果没有查询到任何结果,也是返回一个空的数组。配合上面提到的连贯操作方法可以完成复杂的数据查询。例如,查找status值为1的用户数据以创建时间排序返回10条数据。
$User=M("User"); //实例化User对象 $list = $User->where('status=1')->order('create_time')->limit(10)->select();
find方法与select方法类似,select方法可用的所有连贯操作方法也都可以用于find方法,区别在于find方法最多只会返回一条记录,因此limit方法对于find方法查询操作是无效的。例如,查找status值为1, name值为think的用户数据。
$User=M("User"); //实例化User对象 $User->where('status=1 and name="think" ')->find();
注意
即使满足条件的数据不止一条,find方法也只会返回第一条记录。
【例20.8】通过add方法向数据库中添加数据,然后,查询数据表中用户名为mr的记录,按照降幂排列,循环输出3条记录。(实例位置:光盘TMsl208)
在讲解本例的实现步骤过程中,省略了项目目录的创建、入口文件的编写和配置文件的设置,其具体步骤可以参考例20.4或者例20.5。这里将直接讲解在控制器中如何完成数据的添加和查询操作。
(1)定位到8AppLibAction目录下,编写项目控制器。创建Index模块,继承系统的Action基础类,定义index方法,通过M方法实例化模型类,应用连贯操作中的where、order、limit和select方法读取think_user数据表中的数据,并且将查询结果赋给模板变量,指定模板页;定义insert方法,通过M方法实例化模型类,应用add方法向指定的数据表中添加数据。IndexAction.class.php的代码如下:
<?php header("Content-Type:text/html; charset=utf-8"); //设置页面编码格式 class IndexAction extends Action{ public function index(){ $db=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $select=$db->where('user="mr"')->order('id desc')->limit(3)->select(); //执行查询语句 $this->assign('select', $select); //模板变量赋值 $this->display(); //指定模板页 } public function insert(){ $dba=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $data['user'] = 'mr'; $data['pass'] = md5('mrsoft'); $data['address'] = ’长春市’; $result=$dba->add($data); //执行添加数据 if($result){ $this->redirect('Index/index', '',2, ’页面跳转中’); //页面重定向 } } } ?>
(2)定位到AppTpl目录下,创建Index模块文件夹。编辑index操作的模板文件index.html,应用ThinkPHP内置模板引擎中的foreach标签循环输出模板变量传递的数据;创建添加数据的表单,将数据提交到控制器的insert方法中进行处理。其关键代码如下:
<foreach name='select' item='user' > <tr class="content"> <td bgcolor="#FFFFFF"> {$user.id}</td> <td bgcolor="#FFFFFF"> {$user.user}</td> <td bgcolor="#FFFFFF"> {$user.address}</td> </tr> </foreach> <form id="form1" name="form1" method="post" action="__URL__/insert"> <input type="submit" name="button" id="button" value="数据添加" /> </form>
其运行效果如图20.16所示。
图20.16 数据添加、查询后的运行结果
4.删除数据
在ThinkPHP中使用delete方法删除数据库中的记录。同样可以使用连贯操作进行删除操作。例如,删除数据表中ID为5的记录。
$User=M("User"); //实例化User对象 $User->where('id=5')->delete(); //删除ID为5的用户数据
delete方法可以用于删除单个或者多个数据,主要取决于删除条件,也就是where方法的参数,也可以用order和limit方法来限制要删除的个数。例如,删除所有状态为0的5个用户数据按照创建时间排序。
$User=M("User"); //实例化User对象 $User->where('status=0')->order('create_time')->limit('5')->delete();
【例20.9】应用ThinkPHP中的CURD操作,实现对用户信息的查询、更新和删除操作。(实例位置:光盘TMsl209)
这里直接讲解在控制器中如何完成定义index方法循环输出数据库中的数据,定义update方法完成数据的更新,定义delete方法实现数据的删除。
(1)定位到AppLibAction目录下,编写项目控制器。创建Index模块,继承系统的Action基础类,定义index方法,以记录的ID值为条件,降幂循环输出10条记录。其代码如下:
<?php header("Content-Type:text/html; charset=utf-8"); //设置页面编码格式 class IndexAction extends Action{ public function index(){ $db=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $select = $db->order('id desc')->limit(10)->select(); $this->assign('select', $select); //模板变量赋值 $this->display(); //指定模板页 }
定义update方法,首先根据超链接传递ID值执行查询,查询出指定的数据,并且将查询结果赋给指定的模板变量。然后,判断表单提交的ID值是否存在,如果存在则以ID为条件,对指定的数据进行更新操作。其关键代码如下:
public function update(){ $db=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $select = $db->where('id='.$_GET['id'])->select(); $this->assign('select', $select); //模板变量赋值 $this->display(update); //指定模板页 if(isset($_POST['id'])){ $data['user']=$_POST['user']; //要修改的数据对象属性赋值 $data['pass'] = md5($_POST['pass']); $data['address'] = $_POST['address']; $result=$db->where('id='.$_POST['id'])->save($data); //根据条件保存修改的数据 if($result){ $this->redirect('Index/index', '',2, ’数据更新成功’); //页面重定向 } } }
定义delete方法,根据超链接传递的ID值,删除数据库中指定的记录。其关键代码如下:
public function delete(){ $db=M('User'); //实例化模型类,参数数据表名称,不包含前缀 $result=$db->where('id='.$_GET['id'])->delete(); //删除ID为5的用户数据 if($result){ $this->redirect('Index/index', '',2, ’数据删除成功’); //页面重定向 } } } ?>
(2)定位到AppTpl目录下,创建Index模块文件夹。编辑index操作的模板文件index.html,应用ThinkPHP内置模板引擎中的foreach标签循环输出模板变量传递的数据;创建更新和删除超链接,将指定记录的ID作为参数进行传递。其关键代码如下:
<foreach name='select' item='user' > <tr class="content"> <td bgcolor="#FFFFFF"> {$user.id}</td> <td bgcolor="#FFFFFF"> {$user.user}</td> <td bgcolor="#FFFFFF"> {$user.address}</td> <td bgcolor="#FFFFFF"><a href="__URL__/update? id={$user.id}">更新</a>/<a href="__URL__/delete? id= {$user.id}">删除</a></td> </tr> </foreach>
(3)在Index模块文件夹下编辑update.html模板文件,创建表单,将从模板变量中读取的数据作为表单元素的默认值进行输出,将表单中的数据提交到控制器的update方法中完成数据的更新操作。其关键代码如下:
<form id="form2" name="form2" method="post" action="__URL__/update"> <table width="405" border="1" cellpadding="1" cellspacing="1" bgcolor="#99CC33" bordercolor="#FFFFFF"> <foreach name='select' item='user' > <tr class="content"> <td bgcolor="#FFFFFF" class="right" width="103">名称:</td> <td bgcolor="#FFFFFF" width="289"> <input type="hidden" name="id" id="hiddenField" value="{$user.id}" /><input name="user" type="text" id="user" size="20" value="{$user.user}" /></td> </tr> <tr class="content"> <td bgcolor="#FFFFFF" class="right">密码:</td> <td bgcolor="#FFFFFF"><input name="pass" type="password" id="pass" size="20" value="{$user.pass}" /> </td> </tr> <tr class="content"> <td bgcolor="#FFFFFF" class="right"> ;地址:</td> <td bgcolor="#FFFFFF"> <input name="address" type="text" id="address" size="30" value="{$user.address}" /> </td> </tr> <tr class="content"> <td bgcolor="#FFFFFF"><input type="submit" name="button" id="button" value="更新" /></td> </tr> </foreach> </table> </form>
其运行结果如图20.17所示。
图20.17 数据更新和删除
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。