fred-ye / summary

my blog
43 stars 9 forks source link

[PHP]MongoDB与Yii搭建API服务-1 #40

Open fred-ye opened 9 years ago

fred-ye commented 9 years ago

[PHP]MongoDB与Yii搭建API服务-1

在上一个项目中,我们采用MongoDB和Yii框架来为手机端提供API,那是我第一次学习并采用Yii来开发项目,确实深刻的体会到Yii的便捷和高效。代码写起来感觉非常的清晰,今天来对上一个项目里面的东西进行总结一下。主要是总结MongoDB和Yii的操作,当然也会写一些边边角角的东西。当前是采用Yii 1.1, MongoDB的扩展是1.3.6

如何整合

  1. 首先需在配置php对mongodb的扩展,此处就不说了。然后我们需要mongodb对yii的扩展,将相关代码拷到Yii应用的 protected/extensions目录下。
  2. 在Yii应用的config/main.php中引入mongodb的扩展并配置连接参数,如下:
    'import'=>array(
        'application.models.*',
        'application.components.*',
        'ext.mongo.*',
    ),
    'components' => array(
      ...
         'mongodb'=>array(
             'class' => 'EMongoDB' ,
             'connectionString' => 'mongodb://irunning:abc123_@localhost:27017/irunning',
             'dbName' => 'irunning',
             'fsyncFlag' => true,
             'safeFlag'=>true,
             'useCursor'=>false,
         ),
   )

到此,我们的配置便完成了,接着就可以开始使用Yii和MongoDB

Yii操作MongoDB

Model定义

我们先定义一个BaseModel, 在这个Model中定义部分公共的属性。如下:


<?php
class BaseModel extends EMongoDocument
{
    public $_id;
    public $created_time;
    public $updated_time;
    public $deleted;
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
    public function getCollectionName()
    {
        return null;
    }
    public function rules()
    {
        return array(
            array('_id', 'default', 'value' => new MongoId()),
            array('deleted', 'default', 'value' => Constant::UNDELETE),
            array('created_time', 'default', 'value' => new MongoDate()),
            array('updated_time', 'default', 'value' => new MongoDate()),
        );
    }
    public function attributeLabels()
    {
    }
}

然后,我们来定义一个实际会使用的Model--> User.

class User extends BaseModel {
    public $name;
    public $password;
    public $nickname;
    public $email;
    public $height;
    public $weight;
    public $gender;
    public $register_time;
    public $last_login_time;

    public static function model($className=__CLASS__) {
        return parent::model($className);
    }

    /**
     * @return string the associated collection name
     */
    public function getCollectionName() {
        return 'user';
    }

    public function rules() {
        return  array_merge(parent::rules(), array(
            ...
        ));
    }
}

定义好了Model之后,我们可以像操作其它AR一样来操作了。

对MongoDB的操作

对MongoDB的操作是通过Model来完成的。在EmongoDocument中定义了不少操作DB的方法,如:

$user = new User();
$user->_id = new MongoId();
$user->name = "user1";
......
$user->save();
EmongoCriteria的使用

EmongoCriteria是用来封装条件的,在我们进行CRUD操作时都会使用到,需要掌握好。其使用方式如下: 第一种方式是使用array来指定查询条件:

//指定查询条件
$condition = array(
    'name'=>$username,
);
//new 一个EmongoCriteria实例
$criteria = new EmongoCriteria();
//将查询条件设定到criteria中。
$criteria->setConditions($condition);
//用model执行find方法。
$user = User::model->find($criteria);

另一种方式是直接对EmongoCriteria添加条件,如下:

$criteria = new EmongoCriteria();
$criteria->select(array('name', 'age', 'password')); //指定查询的列
$criteria->addCond('name', '==', $username);
//$criteria->name = $username;当然也可以这么写,和上一行的效果是一样的
//条件是可以不断追加的
$criteria->addCond('deleted', '==', 0);
$criteria->addCond('start_time', '>=', $startTime);
$criteria->addCond('start_time', '<', $endTime);

//用model执行find方法。
$user = User::model->find($criteria);

1.多个条件的组合。例如我要查询用户名是'user1',age是18的用户,只需要将上面的$condition稍做修改即可:

$condition = array(
    'name'=>'user1',
    'age'=> 18
);

2.如果是表示的关系

$condition = array(
    '$or' => array(
        'age' => 18,
        'age' => 28
    )
)

3.分页和排序

分页和排序的操作也是非常的简单,只要在$criteria对象上接着添加方法便好

$criteria->setLimit($pageSize);//每页多少条数目
$criteria->setOffset($startIndex); //起始位置
$criteria->setSort(array('start_time'=>EMongoCriteria::SORT_DESC));

如果是采用array来指定分页和排序的参数,要注意array的层次结构。以下使用一个官方的例子

$array = array(
    'conditions'=>array(
        // field name => operator definition
        'FieldName1'=>array('greaterEq' => 10), // Or 'FieldName1'=>array('>=', 10)
        'FieldName2'=>array('in' => array(1, 2, 3)),
        'FieldName3'=>array('exists'),
    ),
    'limit'=>10,
    'offset'=>25,
    'sort'=>array('fieldName1'=>EMongoCriteria::SORT_ASC,
                  'fieldName4'=>EMongoCriteria::SORT_DESC),
);
$criteria = new EMongoCriteria($array);
$user = User::model()->find($criteria);

4.统计数量User::model()->count($criteria)

MongoDBRef的使用

MongDBRef是用来表示两个表之间字段的关联关系。 假设有这么一个场景,员工和部门之间是一对多的关系。我们有一个Employeemodel和一个Deptmodel,在Employeemodel中会有一个$dept的属性,这个$dept属性并不是一个Dept类型的实例,它是一个MongoDBRef类型,有点类似于关系数据库中的外键。或以把它理解成是一个dept_id指向的是Dept表中的的_id。于是有以下代码:

class Employee extends BaseModel {
    public $user_id;
    public $name;
    public $email;
    public $dept;

    //于是添加一条中奖记录的代码如下:
    public function addEmployee($userId, $name, $email, $deptId) {
        $employee = new Employee();
        $employee->user_id = $userId;
        $employee->name= $name;
        $employee->email = $email;
        $employee->dept = MongoDBRef::Create('dept', $deptId); //dept是Dept这个Model对应的collection.
        //给个时间
        $currentTime = gettimeofday();
        $userAward->created_time = new MongoDate($currentTime['sec'], $currentTime['usec']);
        $userAchievement->save()
     }
    public function getEmployee($name) {
        $criteria = new EMongoCriteria();
        $criteria->addCond('name', '==', $name);
        $employee = $this->findAll($criteria);
        foreach ($employee as $value) {
            $deptObj = MongoDBRef::get($value->db, $value->dept);
            $item['name'] = $deptObj['name'];
            $item['description'] = $deptObj['description'];
            .....
        }
    }     
}