Dao层
  1. 什么是Dao

    Dao是一个思想,如果不正确使用就跟Model一样。Dao我们可以想象成一张表,多张表就多个Dao,也可以想成绑定表。什么意思呢?
    比如:现在有张user表,那么我们对应Dao文件就是UserDao.php,那么我们UserDao.php就可以对user表增删改查。
    切勿如下操作:
    我们有user表和user_vip表,然后只创建一个Dao文件。
    那就没有意义了,那我们还不如建Model文件,我们要遵守一个Dao文件对应一张表才可以灵活使用与扩展。
  2. Dao层规范

    1.Dao类文件都放在application/classes/Dao文件夹里面
    2.Dao必须要继承Soter_Dao抽象类,实现父类抽象方法。
    3.Dao类内部访问数据库,必须使用$this->getDb(),而不是Sr::db()。
    示例如下:
    2.1.新建Dao文件application/classes/Dao/TestDao.php
    2.2.输入以下代码:
                                                    <?php
    
                                                    class Dao_TestDao extends Soter_Dao {
                                                            
                                                            public function getTable(){}
    
                                                            public function getPrimaryKey(){}
    
                                                            public function getColumns(){}
                                                    }
                                            
    可以看到Dao_TestDao需要继承3个方法,getTablegetPrimaryKeygetColumns分别什么意思呢?
    第一个getTable是获取表,比如:我们有个user表,那么函数里面可以有return 'user';
    第二个getPrimaryKey是获取主键,比如:我们user表定义一个id字段为主键,那么函数里面可以有return 'id';
    第三个getColumns是获取字段名称数组,比如:我们有user表里面有id、uid和username等等……字段
    示例如下:
                                                   public  function getColumns(){
                                                            return array(
                                                                    'id',
                                                                    'uid',
                                                                    'username',
                                                                    ……
                                                            );
                                                    }
                                            
    提示:
    以上三个方法都可以自己扩展,但是我们要记得一个Dao文件对应一个表。
  3. 使用Dao层

    可以在任意地方使用下面的代码加载一个dao层类:
    示例如下:
                                                    Sr::dao('TestDao');
                                            
    我们可以看到上面有一个参数,这个是什么意思呢,是加载dao类的时候,不需要前缀Dao_
    比如上面的:Dao_TestDao,加载的时候只用Sr::dao('TestDao');
    例如:我们要创建Dao类文件名为ListDao.php,类名就是Dao_ListDao,那么参数就要输入ListDao
  4. 示例一

    比如有文件:classes/Dao/ArticleUser.php
    那么ArticleUser.php文件里面的类名就应该是:Dao_ArticleUser。
    那么要加载Dao类如下:
                                                    Sr::dao('ArticleUser');
                                            
  5. 示例二

    比如有文件:classes/Dao/Vip/User.php
    那么User.php文件里面的类名就应该是:Dao_Vip_User,也就是下划线代表着文件夹的分隔符。
    那么要加载Dao类如下:
                                                    Sr::dao('Vip_User');
                                                    //还有另一种方式例如以下
                                                    Sr::dao('Vip/User.php');
                                                    //我们也可以不用带.php后缀,例如以下:
                                                    Sr::dao('Vip/User');
                                            
  6. 创建自己的Dao类

    下面我们自定义一个加载Dao类
    1.创建test_dao数据库
    2.执行以下sql:
                                                    create database test_dao CHARACTER SET utf8 COLLATE utf8_general_ci; 
                                            
    3.创建users数据表
    4.执行以下sql:
                                            DROP TABLE IF EXISTS `users`;
                                            CREATE TABLE `users` (
                                                    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '标识',
                                                    `uid` int(11) NOT NULL COMMENT '用户id',
                                                    `username` varchar(20) NOT NULL COMMENT '用户名',
                                                    `email` varchar(30) NOT NULL COMMENT '邮箱',
                                                    PRIMARY KEY (`id`)
                                            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
                                            INSERT INTO `users` VALUES ('1', '1', '刘一', '111@qq.com');
                                            INSERT INTO `users` VALUES ('2', '2', '陈二', '222@qq.com');
                                            INSERT INTO `users` VALUES ('3', '3', '张三', '333@qq.com');
                                            INSERT INTO `users` VALUES ('4', '4', '李四', '444@qq.com');
                                            
    5.修改数据库配置文件application/config/default/database.php
    6.修改一下代码
                                                    'mysql' => array(
                                                            'database' => 'test_dao',
                                                            'masters' => array(
                                                                    'master01' => array(
                                                                            'hostname' => '127.0.0.1',
                                                                            'port' => 3306,
                                                                            'username' => '用户名',
                                                                            'password' => '密码',
                                                                    )
                                                            ),
                                                    ),
                                            
    详细请看数据库手册的“数据库配置信息说明
    7.新建Dao文件application/classes/Dao/Users.php
    8.输入以下代码:
                                                    <?php
    
                                                    class Dao_User extends Soter_Dao {
    
                                                            public function getColumns() {
                                                                    return array(
                                                                                    'id'//标识
                                                                                    ,'uid'//用户id
                                                                                    ,'username'//用户名
                                                                                    ,'email'//邮箱
                                                                                    );
                                                            }
    
                                                            public function getPrimaryKey() {
                                                                    return 'id';
                                                            }
    
                                                            public function getTable() {
                                                                    return 'users';
                                                            }
    
                                                            //这里我们做一个简单查询,详细可以查看“数据库手册”的“查询数据”和“查询结果集的使用”
                                                            public function getUserName(){
                                                                    $table = $this->getTable();
                                                                    $username = $this->getDb()->select('username')
                                                                                    ->from($table)
                                                                                    ->limit(0,1)
                                                                                    ->execute()
                                                                                    ->value('username');
                                                                    return $username;
                                                            }
    
                                                    }
                                            
    9.新建控制器文件application/classes/Controller/Welcome.php
    10.输入以下代码:
                                                    <?php
    
                                                    class Controller_Welcome extends Soter_Controller {
    
                                                            public function do_dao() {
                                                                    $dao = Sr::dao('User');
                                                                    echo $dao->getUserName();
                                                            }
                                                    }  
                                            
    11.浏览器访问:http://127.0.0.1/index.php/Welcome/dao.do
    //将输出:刘一
    为什么会输出“刘一”?
    我们可以从上面例子看Controller_Welcome控制器类,
    在do_dao方法里面做了加载Dao层中的Dao_User类赋值给$dao
    然后通过$dao输出Dao_User类中的getUserName方法,
    getUserName方法,主要是去数据库查询users表查询username字段的第一条数据,最后得到查询结果数据数组中的username字段。
    详细请看数据库手册的“查询数据”和“查询结果集的使用”,
    所以浏览器才会显示“刘一”。
  7. Dao层实用方法介绍

    假如我们有这样的数据库,如下:
                                                    DROP TABLE IF EXISTS `test`;
                                                    CREATE TABLE `test` (
                                                            `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '标识',
                                                            `username` varchar(20) NOT NULL COMMENT '用户名',
                                                            `addtime` int(10) NOT NULL COMMENT '添加时间',
                                                            PRIMARY KEY (`id`)
                                                    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
                                                    INSERT INTO `test` VALUES ('1', '刘一', '1431356499');
                                                    INSERT INTO `test` VALUES ('2', '陈二', '1422806400');
                                                    INSERT INTO `test` VALUES ('3', '张三', '1425312000');
                                                    INSERT INTO `test` VALUES ('4', '李四', '1428076800');
                                            
    新建Dao文件application/classes/Dao/Test.php
    代码如下:
                                                    <?php
    
                                                    class Dao_Test extends Soter_Dao {
    
                                                            public function getColumns() {
                                                                    return array(
                                                                                    'id'//标识
                                                                                    ,'username'//用户名
                                                                                    ,'addtime'//添加时间
                                                                                    );
                                                            }
    
                                                            public function getPrimaryKey() {
                                                                    return 'id';
                                                            }
    
                                                            public function getTable() {
                                                                    return 'test';
                                                            }
    
                                                    }
    
                                            
    下面介绍Dao层常用方法:

    1.设置Dao中使用的数据库操作对象

    通过setDb(Soter_Database_ActiveRecord $db)方法,设置Dao中使用的数据库操作对象。
    默认情况下Dao层使用Sr::db()连接数据库,如果我们不再使用Sr::db()连接数据库,
    那么我们可以通过setDb()来设置另外一个数据库。
    然后我们在Dao类内部就可以通过$this->getDb()访问数据库,
    $this->getDb()返回的就是setDb()设置的数据库对象。

    示例如下:
                                                    class Dao_Test extends Soter_Dao {
    
                                                            public function __construct(){
                                                                    parent::__construct();
                                                                    $dbConfig = array(
                                                                            'driverType' => 'mysql',
                                                                            'debug' => true,
                                                                            'pconnect' => false,
                                                                            'charset' => 'utf8',
                                                                            'collate' => 'utf8_general_ci',
                                                                            'database' => 'test_name',
                                                                            'tablePrefix' => '',
                                                                            'tablePrefixSqlIdentifier' => '_tablePrefix_',
                                                                            //是否开启慢查询记录
                                                                            'slowQueryDebug' => false,
                                                                            'slowQueryTime' => 3000, //慢查询最小时间,单位毫秒,1秒=1000毫秒
                                                                            'slowQueryHandle' => new Soter_Database_SlowQuery_Handle_Default(),
                                                                            /**
                                                                            * 是否开启没有满足设置的索引类型的查询记录
                                                                            */
                                                                            'indexDebug' => false,
                                                                            /**
                                                                            * 索引使用的最小情况,只有小于最小情况的时候才会记录sql到日志
                                                                            * minIndexType值从好到坏依次是:
                                                                            * system > const > eq_ref > ref > fulltext > ref_or_null 
                                                                            * > index_merge > unique_subquery > index_subquery > range 
                                                                            * > index > ALL 一般来说,得保证查询至少达到range级别,最好能达到ref
                                                                            * 避免ALL即全表扫描
                                                                            */
                                                                            'minIndexType' => 'index',
                                                                            'indexHandle' => new Soter_Database_Index_Handle_Default(),
                                                                            'masters' => array(
                                                                                'master01' => array(
                                                                                    'hostname' => '127.0.0.1',
                                                                                    'port' => 3306,
                                                                                    'username' => 'root',
                                                                                    'password' => '',
                                                                                )
                                                                            ),
                                                                            'slaves' => array()
                                                                    );
                                                                    $db = Sr::db($dbConfig);
                                                                    $this->setDb($db);
                                                            }
    
                                                            public function getColumns() {
                                                                    return array(
                                                                                    'id'//标识
                                                                                    ,'username'//用户名
                                                                                    ,'addtime'//添加时间
                                                                                    );
                                                            }
    
                                                            public function getPrimaryKey() {
                                                                    return 'id';
                                                            }
    
                                                            public function getTable() {
                                                                    return 'test';
                                                            }
                                                    }
                                            

    2.添加数据

    通过insert($data)方法,来添加数据,返回值是插入数据的ID,失败为0。
    $data 必填:需要添加的数据 例如:array('username' => '张三', 'addtime' => time());
    假如我们Business要调用,如下:
                                                    //添加一条username为"张三",addtime为当前时间戳的数据
                                                    $data = array('username' => '张三', 'addtime' => time());
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->insert($data);
                                            

    3.批量添加数据

    通过insertBatch($data)方法,来批量添加数据,返回值是插入数据中第一条数据的ID,失败为0。
    $data 必填:需要批量添加的数据 例如:array(array('username' => '李四', 'addtime' => time()),array('username' => '张三', 'addtime' => time()));
    假如我们Business要调用,如下:
                                                    //一次添加两条数据
                                                    $data = array(array('username' => '李四', 'addtime' => time()),array('username' => '张三', 'addtime' => time()));
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->insertBatch($data);
                                            

    4.更新数据

    通过update($data, $where)方法,来更新数据,返回值是1或者0,1是代表执行成功,0是代表执行失败。
    $data 必填:需要更新的数据 例如:array('username' => '李四', 'addtime' => time());
    $where 必填:可以是$where条件关联数组,还可以是主键值。
    假如我们Business要调用,如下:
                                                    //1.修改主键是1的记录
                                                    $data = array('username' => '王五', 'addtime' => time());
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->update($data, 1);
    
                                                    //2.修改addtime为当前时间戳,条件username为'王五'、id为1的记录
                                                    $data = array('addtime' => time());
                                                    $where = array('id' => 1, 'username' => '王五');
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->update($data, $where);
                                            

    5.批量更新数据

    通过updateBatch($data, $index)方法,来更新数据,返回值是数据库中受到影响的行数。
    $data 必填:需要更新的数据 例如:array(array('id'=>2,'username' => '李四', 'addtime' => time()),array('id'=>3,'username' => '张三', 'addtime' => time()));
    $index 必填:数据中主键或者唯一索引列名称,数据中必须包含这一列,比如上面的id。
    假如我们Business要调用,如下:
                                                    //1.同时修改id主键2对应的数据和id主键是3的数据
                                                    $data = array(array('id'=>2,'username' => '李四', 'addtime' => time()),array('id'=>3,'username' => '张三', 'addtime' => time()));
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->update($data, 'id');
                                            

    6.获取一条或者多条数据

    通过find($values, $isRows = false, Array $orderBy = array())方法,我们可以获取一条或者多条数据。
    $values 必填:可以是一个主键的值或者主键的值数组,还可以是where条件
    $isRows 选填:返回多行记录还是单行记录,true:多行,false:单行
    $orderBy 选填:当返回多行记录时,可以指定排序。例如:array('time'=>'desc') 或者 array('time'=>'desc','id'=>'asc')
    假如我们Business要调用,如下:
                                                    //1.获取主键是10的记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->find(10);
    
                                                    //2.获取主键是1,2的两条记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->find(array(1,2), true);
                                                    
                                                    //3.根据条件获取一条记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->find(array('id' => 1));
    
                                                    //4.根据条件获取多条记录
                                                    $where = array('username' => array('刘一', '陈二'));
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->find($where, true);
    
                                                    //5.获取用户名是'刘一','陈二'的两条记录,并用addtime排序
                                                    $where = array('username' => array('刘一', '陈二'));
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->find($where, true, array('addtime' => 'asc'));
                                            

    7.获取多条数据

    通过findAll($where = null, Array $orderBy = array(), $limit = null, $fields = null)方法,我们可以获取一条或者多条数据。
    $where 选填:where条件数组
    $orderBy 选填:排序,比如:array('time'=>'desc')或者array('time'=>'desc','id'=>'asc')
    $limit 选填:limit数量,比如:10
    $fields 选填:要搜索的字段,比如:id,name。留空默认*
    假如我们Business要调用,如下:
                                                    //1.查询表所有数据
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->findAll();
    
                                                    //2.查询表中username为"刘一"的所有数据。
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->findAll(array('username' => '刘一'));
    
                                                    //3.查询表中id为1的所有数据,并且按着id倒序排列。
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->findAll(array('id' => 1), array('id' => 'desc'));
    
                                                    //4.查询表中id为1的按着id倒序排列的100条数据。
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->findAll(array('id' => 1), array('id' => 'desc'), 100);
    
                                                    //5.查询表中id为1的按着id倒序排列的100条数据,同时只获取id和username两个字段。
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->findAll(array('id' => 1), array('id' => 'desc'), 100, 'id,username');
                                            

    8.根据条件获取一个字段的值或者数组

    通过findCol($col, $where, $isRows = false, Array $orderBy = array())方法,我们可以根据条件获取一个字段的值或者数组。
    $col 必填:字段名称
    $where 必填:可以是一个主键的值或者主键的值数组,还可以是where条件(这个跟find的$values参数一样)
    $isRows 选填:返回多行记录还是单行记录,true:多行,false:单行
    $orderBy 选填:当返回多行记录时,可以指定排序,比如:array('time'=>'desc')或者array('time'=>'desc','id'=>'asc')
    查询字段数据findColfind类似,值是获取的是某个字段的值或者数组,示例可以参考find方法。

    7.根据条件删除记录

    通过delete($values, Array $cond = NULL)方法,来删除记录,返回值是1或者0,1是代表执行成功,0是代表执行失败。
    $values 选填:以是一个主键的值或者主键主键的值数组
    $cond 选填:附加的where条件,关联数组
    假如我们Business要调用,如下:
                                                    //1.删除主键是1的记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->delete(1);
    
                                                    //2.记录中username是'刘一'的记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->delete(null, array('username' => '刘一'));
    						
    						//3.删除主键是1,2,3的记录,记录中username是'刘一'的记录
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->delete(array(1,2,3), array('username' => '刘一'));
    						
    						//4.删除整个test表数据
                                                    $userDao = Sr::dao('Test');
                                                    $userDao->delete();
                                            

    9.分页方法

    通过getPage($page, $pagesize, $url, $fields = '*', Array $where = null, $orderBy = array(), $pageBarOrder = array(1, 2, 3, 4, 5, 6), $pageBarACount = 10)方法,我们可以分页获取数据。
    $page 必填:第几页
    $pagesize 必填:每页多少条
    $url 必填:基础url,里面的{page}会被替换为实际的页码
    $fields 选填:select的字段,全部用*,多个字段用逗号分隔
    $where 选填:where条件,关联数组
    $orderBy 选填:排序字段,比如:array('time'=>'desc')或者array('time'=>'desc','id'=>'asc')
    $pageBarOrder 选填:分页条组成,可以参考系统方法手册中分页条方法
    $pageBarACount 选填:分页条a的数量,可以参考系统方法手册中分页条方法
    假如我们Business要调用,如下:
    						//第一页,每页10条      
    						$userDao = Sr::dao('Test');
    						$data=$userDao->getPage(1, 10, 'index.do?p={page}', '*', null, array(), array(1, 2, 3, 4, 5, 6), 10);
    						$rows=$data['items'];
    						$pageBar=$data['page'];
                                            
    getPage方法返回的是形如:array('items'=>array(array(...),...),'page'=>'...')关联数组,
    items键的值是数据,page是分页条html字符串。

    10.SQL搜索

    通过search($page, $pagesize, $url, $fields, $cond, Array $values = array(), $pageBarOrder = array(1, 2, 3, 4, 5, 6), $pageBarACount = 10)方法,来获取SQL搜索。
    $page 必填:第几页
    $pagesize 必填:每页多少条
    $url 必填:基础url,里面的{page}会被替换为实际的页码
    $fields 选填:select的字段,全部用*,多个字段用逗号分隔
    $cond 必填:SQL语句where后面的部分,不要带limit
    $values 必填:$cond中的问号的值数组,$cond中使用?可以防止sql注入
    $pageBarOrder 选填:分页条组成,可以参考系统方法手册中分页条方法
    $pageBarACount 选填:分页条a的数量,可以参考系统方法手册中分页条方法
    假如我们Business要调用,如下:
    						//搜索id大于1,每页2条。
    						$userDao = Sr::dao('Test');
    						$userDao->search(1, 2, '#', '*','id>?', array(1));
    						$rows=$data['items'];
    						$pageBar=$data['page'];
                                            
    search方法返回的是形如:array('items'=>array(array(...),...),'page'=>'...')关联数组,
    items键的值是数据,page是分页条html字符串。