Skip to content

Tutorial.Database Operation I.zh_cn

linzongshu edited this page Jul 4, 2013 · 2 revisions

English

在上一章里,我们已经实现了获取用户提交的数据,并对数据作处理,但这些数据并没有保存下来,在这一章中,我们将介绍Pi Engine的数据库操作。

Pi Engine对Zend的数据库操作的类进行了继承和扩展,更方便使用。当然数据库操作机制还是基于Zend的,因此一些更详细的增、删、改、查的方法也可以参考Zend的文档。

  1. 类的调用机制

对于每一次数据表请求,Pi Engine都实例化一个相应的类来操作该数据表。这个类用户可以自己定义,也可以使用Pi Engine的通用类,即Pi\Application\Model\Model。对于用户自定义的类,Pi Engine规定好一套调用机制,开发者必须遵循这个机制才能正确地使用自定义的类来操作数据表。类的调用机制的主体逻辑都定义在Pi\Application\Db类的model()方法里。

Pi Engine中有两类型的表,系统表的表名格式为{prefix}core{table name},而模块表的表名格式为{prefix}{module name}{table name}。不同类型的表,其类所在目录也不一样。对于系统表,Pi Engine先根据表名到Pi\Application\Model目录下去寻找是否有相关的类,这个类的路径也和表名相关,如core_block表将会查询是否存在Pi\Application\Model\Block类、core_user_account对应的是Pi\Application\Model\User\Account类。若不存在,则用通过类Pi\Application\Model\Model来操作数据库。

对于模块类,模块下的src/Model目录里的类将会先被查询,同样如member_member表对应于Member\Model\Member类,若不存在,就返回通用类。

因此开发者若想对数据库操作的功能进行扩展,就需要在Model文件夹下自定义类。当然这些类都必须继承自Pi\Application\Model\Model。具体类的扩展将在下面的章节里介绍。

  1. 配置模块数据库

模块的配置需要通过单独的文件完成,这些文件在模块安装的时候将被读取或执行,模块的配置主要包括数据表配置以及安装文件。

2.1 数据表配置

在之前介绍模块配置的一节里,我们已经提到过了数据表的配置。这部分的代码主要在config/module.php里实现。在module.php里的resource数组里添加如下代码:

路径:usr/module/member/config/module.php

Code 4.2.1

<?php
return array(
...
    'maintenance' => array(
        'resource'      => array(
            'database'      => array(
                'sqlfile'      => 'sql/mysql.sql',
                'schema'       => array(
                    'account'      => 'table',
                ),
            ),
        ),
    ),
);

上述代码里,database数组就配置了模块数据表的相关信息,sqlfile字段定义了sql文件的路径,这个文件里为sql语句,安装模块时将会执行这些语句,完成数据表的插入;schema字段定义了模块卸载时需要删除的数据表,其中键值为表名,值为table。

2.2 创建sql文件

上一节的配置指定了使用sql目录下的mysql.sql文件创建数据表,因此,我们需要在member目录下创建sql文件,并添加mysql.sql文件。这个文件里就是可执行的sql代码,主要用于创建数据表,不建议在这个文件里添加插入初始数据的代码。

member
|- sql
   |- mysql.sql

路径:usr/module/member/sql/mysql.sql

Code 4.2.2

CREATE TABLE `{account}` (
    `id`           INT(10) UNSIGNED         NOT NULL AUTO_INCREMENT,
    `username`     VARCHAR(64)              NOT NULL DEFAULT '',
    `password`     VARCHAR(255)             NOT NULL DEFAULT '',
    `gender`       ENUM('M','F')            DEFAULT 'M',
    `country`      VARCHAR(64)              DEFAULT NULL,
    `feedback`     TINYINT(1)               DEFAULT '1',
    `introduction` TEXT                     DEFAULT NULL,

    PRIMARY KEY        (`id`),
    UNIQUE KEY         (`username`),
    KEY                (`gender`),
    KEY                (`country`)
);

上述代码就是创建一个完整的表名为{prefix}_member_account的数据表,这里需要注意下,表名account需要用{}括起来。如果在这里需要创建系统表,还需要在表名前core前缀,如{core_test},将会生成{prefix}_core_test表。

下面的代码就是创建表里的字段了,开发者可根据需求添加自己的字段,需要注意的是,为了查询优化,对于经常就查询的字段需要创建索引,如这里的username, gender, country三个字段,其中username为唯一,即不允许有重复的用户名。另外需要注意的地方就是CREATE语句的最后一行不可加逗号(这里是(country)后面),否则后面的数据表将都不会安装。

经过这两步的配置后,就可以安装数据表了,由于更改了config目录下的文件,所以我们需要先卸载已有模块后重新安装模块,而数据表也会模块安装的同时添加到数据库里。 重新安装模块后,我们在数据库里看到了这个表的信息:

fig4-1

图4-1 安装后的数据表信息

  1. 数据表操作

有了数据表,我们就可以进行数据表的相关操作了,主要包括增、删、改、查。首先我们需要介绍下如何获取Model实例。

3.1 获取Model实例

获取Model实例的方法主要有两种Pi::model()和getModel(),这两种方法都有自己的应用场景,开发者需要根据不同的情况调用。

  • Pi::model()

从方法的调用方式就可以看出,这是一个系统的API,因此在使用这个API前需要引用Pi类,即在文件开头添加:

use Pi;

这个API可以在任何地方使用,它有三种调用方式:

$model = Pi::model('block');
$model = Pi::model('member/account');
$model = Pi::model('account', 'member');

假设现在系统的表前缀为pi,其中,对于第一种,将会关联系统的block表,即pi_core_block表;第二种和第三种方式用于调用模块的表,它们执行的结果都一致,将会关联pi_member_account表。member就是模块名,account就是表名。

  • getModel()

这个方法只能在action里使用,它是Pi\Mvc\Controller\ActionController的一个公有方法,因此调用的方法为:

$model = $this->getModel('account');

这个方法只能调用当前模块的表,假设上面代码在Module\Member\RegisterController的indexAction()里,那么它将会关联pi_member_account表。

对于在action里调用,我们建议使用getModel()方法,因为对于可多实例的模块,getModel()方法将会关联到当前操作的模块,用Pi::model()方法可能会因为把模块名给写死造成访问错误的表。

由于我们没有创建Account类来关联account表,因此打印出$model变量,可以看到它是一个Pi\Application\Model\Model实例:

fig4-2

图4-2 关联account表的实例

3.2 查询操作

数据表的查询操作基本上都是使用Zend提供的接口,这里就简单介绍一些比较常用的API,更多的接口可以参考Zend的文档。

$select = $model->select();
$rowset = $model->selectWith($select);

$select = $model->select()->where(array('username' => 'root'));
$rowset = $model->selectWith($select);

$rowset = $model->select(array('username' => 'root'));

上述代码里给出了三种查询数据表的方式,第一、二种为分两步查询,其中第一种为查询该表内所有数据,第二种增加了条件查询;第三种方式为一步查询,和第二种的查询效果一样。这类方式查询后,将$rowset转换为数组后将会得到二维数组,不管查询的结果是否为一条。如果只查询一条记录,可用下面语句:

$rowset = $model->find($id);
$rowset = $model->find($username, 'username');

第一条代码是根据id来查询记录,因为id为唯一的,所以记录肯定只有一条,第二种是查询username字段里的$username,因为username字段也定义为唯一的,所以查询结果也最多只有一条。这种方式得到的结果转换成数组后为一维数组。

注意,这种方式获取到的记录是以数组对象存在的,因此只能foreach一次,如果需要多次循环取值的话,需要将其转换成数组。

$rows = $rowset->toArray();

这部分更多的API可参考Pi或Zend的文档,这里不再赘述。

3.3 插入操作

数据表的插入操作也很简单,需要构造一个数组保存在插入的值,而数组里元素的键值需要和数据表的字段保持一致:

$data = array(
    'username'   => 'admin',
    'gender'     => 'M',
    'feedback'   => 0,
);
$row = $model->createRow($data);
$row->save();
if (!$row->id) {
    return false;
}

上面代码可以看出,$data里元素的键值就是account表的字段名,代码调用了createRow()和save()两个方法完成数据的插入,通过$row->id可以知道数据是否正确插入。

3.4 更新操作

更新操作有两种方法,一种是和插入操作一样,调用save()方法,另一种是通过update()方法完成。

  • 使用save()方法

代码如下:

$row = $model->find('admin', 'username');
$row->gender = 'F';
$row->save();

代码里,首先获取需要修改的记录的数组对象,然后直接给数组对象里需要更改的字段赋值,最后用save()方法保存更改。

  • 使用update()

使用update()方法就更简单了:

$model->update(array('gender' => 'F', array('username' => 'admin')));

这个方法的第一个参数为要更新的数据,第二参数就条件查询要更新的记录。

3.5 删除操作

删除操作可以直接使用delete()方法:

$row = $model->find('admin', 'username');
$row->delete();

$model->delete(array('username' => 'admin'));

这里的第一种方法是先得到所有记录的数组对象,然后调用delete()方法把这些数据全部删除;第二种方法是直接在delete方法的参数里指定查询条件。

[Database Operation II](Tutorial.Database Operation II.zh_cn)

Clone this wiki locally