• Yii 编码规范简记 (他山之石)

    1 概括

    • 文件必须只使用
    • PHP文件必面只全名用UTF-8编辑,无BOM头。
    • 代码使用tab做为缩进,不使用空格
    • 类名定义必需使用 驼峰式大小写 http://baike.baidu.com/view/2359058.htm
    • 类常量定义必须使用会大写,多个单词使用下划线分开.
    • 自定义类方法必须使用 驼峰拼写法 http://baike.baidu.com/view/2140462.htm
    • controllerID, moduleId, actionId 需要使用 驼峰拼写法 http://baike.baidu.com/view/2140462.htm
    • 除对ORACLE的模型外,类属性必须使用 驼峰拼写法 http://baike.baidu.com/view/2140462.htm
    • 私有属性必须以下划线开头
    • 使用elseif 而不使用else if

    2 文件

    • PHP标签
      • 文件必须只使用
      • 在只有php代码的文件中,应该不包含 ?>
      • 不要在最后一行点空格
      • 所有包含php代码的文件,都要以.php做为扩展名。
    • 字符编码
      PHP文件必面只全名用UTF-8编辑,无BOM头。

    3 类名

    类名定义必需使用 驼峰式大小写 http://baike.baidu.com/view/2359058.htm
    例如:Controller, Model

    4 类

    这里的类,包含类及接口。

    • 类的名字应该使用驼峰式大小写
    • 大括号,应该写下类名的下一行
    • 每个类都应该有一些注解
    • 每个类的应该有同一的缩进格式
    • 一个文件,应该仅包含一个类
    • 类的名字应该与类的文件命匹配。
    /**
     * Documentation
     */
    class MyClass extends Object implements MyInterface
    {
        // code
    }

    4.1 常量

    类常量定义必须使用会大写,多个单词使用下划线分开.

    <?php
    class Foo
    {
        const VERSION = '1.0';
        const DATE_APPROVED = '2012-06-01';
    }

    4.2 属性

    • 公有属性,应该明确指定public关键词
    • 变量应该定义在所有方法之前
    • 私有变量应该类似于 $_varName;
    • 类成量变量及普通变量,能应该使用驼峰拼写法
    • 尽量使用具有描述性的变理名,不要使用$i 或 $j

    如下:

    <?php
    class Foo
    {
        public $publicProp;
        protected $protectedProp;
        private $_privateProp;
    }

    4.3 方法

    • 函数及类方法,应该使用驼峰拼写法
    • 函数及方法名称应具有功能的描述性
    • 类方法应该使用private , protected和public修饰符声明。
    • 大括号需要另起一行
    /**
     * Documentation
     */
    class Foo
    {
        /**
         * Documentation
         */
        public function bar()
        {
            // code
            return $value;
        }
    }

    明确类型传递,应明确类型

    public function __construct(CDbConnection $connection)
    {
        $this->connection = $connection;
    }

    4.4 文档块

    @param, @var, @property and @return 应该定义类型 如 boolean, integer, string, array or null。Model 或 ActiveRecord也可以使用类名. 类型数组如ClassName[].

    4.5 构造函数

    • 使用__construct做为构造函数
    • 初始化类的实例时,应该使用new MyClass(); 而不是 new MyClass;.

    5 PHP

    5.1 类型

    所有PHP内置类型或值使用全小所,如:true, false, null和array。

    关联数组,如下:

    $config = array(
        'name'  => 'Yii',
        'options' => array(
            'usePHP' => true,
        ),
    );

    5.2 字符串

    如果字符串不包含变量,请使用单引号

    $str = 'Like this.';

    如果字符串包含单引号,应该使用双引号,避免转义

    变量内插

    $str1 = "Hello $username!";
    $str2 = "Hello {$username}!";

    下面是不允许的

    $str3 = "Hello ${username}!";

    连接

    连接字符串,使用.进行连接

    $name = 'Yii' . ' Framework';

    当字符串过长或过多,使用如下格式:
    $sql = "SELECT *" 
        . "FROM `post` " 
        . "WHERE `id` = 121 ";

    5.3 数组

    数字索引

    不要使用负数的索引下标
    使用如下方式定义:

    $arr = array(3, 14, 15, 'Yii', 'Framework');

    如果元素太多,可分行定义
    $arr = array(
        3, 14, 15,
        92, 6, $test,
        'Yii', 'Framework',
    );

    关系数组

    关联数组定义如下:

    $config = array(
        'name'  => 'Yii',
        'options' => array(
            'usePHP' => true,
        ),
    );

    5.4 控制语句

    • 控制语句的条件必须与大括号之间有一个空格
    • 条件中的各个部分以一个空格分开
    • 开大括号与条件在同一行
    • 结尾大括号另起一行
    if ($event === null) {
        return new Event();
    } elseif ($event instanceof CoolEvent) {
        return $event->instance();
    } else {
        return null;
    }
    
    // 下面是不允许的
    if(!$model)
        throw new Exception('test');

    switch

    switch格式如下:

    switch ($this->phpType) {
        case 'string':
            $a = (string)$value;
            break;
        case 'integer':
        case 'int':
            $a = (integer)$value;
            break;
        case 'boolean':
            $a = (boolean)$value;
            break;
        default:
            $a = null;
    }

    5.5 函数调用

    doIt(2, 3);
    
    doIt(array(
        'a' => 'b',
    ));
    
    doIt('a', array(
        'a' => 'b',
    ));

    文档

    • 参考phpDoc的文档语法
    • 不允许代码没有文档
    • 所有类必须包含类级别的文档和方法的文档
    • 如果方法没有返回值,不需要使用@return

    /**
     * 类的功能描述
     *
     * @author yangsong
     */
    class Component extends Object
    
    h2. 函数/方法
    
    <pre>
    /**
     * 功能描述
     * 用法
     *
     * ~~~
     * $component->getEventHandlers($eventName)->insertAt(0, $eventHandler);
     * ~~~
     *
     * @param string $name 事件名称
     * @return Vector列表
     * @throws Exception 如果event未定义
     */
    public function getEventHandlers($name)
    {
        if (!isset($this->_e[$name])) {
            $this->_e[$name] = new Vector;
        }
        $this->ensureBehaviors();
        return $this->_e[$name];
    }
    </pre>
    
    h2. 注释
    
    单行注释应该以 // 开始,不要使用#
  • Yii用户手册数据库操作篇

    (ps: 往日翻译,弃之可惜,于是在这边做个简略的记录吧 :)  )

    Yii 1.1.13 版用户手册第四章翻译--简略版

    语言即工具,最终目的只有一个,那就是解决问题
    但是方法和方式是可以多种多样的
    当然为了把工具弄到手,学习首先是必不可少的
    --以上纯属扯淡,下面进入正题
    第四章——操作数据库
    4.1数据库操作前奏
       基于PDO扩展,Yii框架提供了DAO(Data Access Objects) 以及 AR(Active Record)两种方式访问和操作数据库。当然你也可以使用第三方扩展,只要最终实现了目的即可,对于数据操作就是CRUD(create,read,update and delete)。通俗点就是增删改查,这边就不废话了。
    4.2数据访问对象(DAO)
        DAO为不同的数据库操作管理提供了一种通用的API,它是基于PDO(PHP Data Objects)创建的,适用于大多数的数据库管理,如MySql,PostgreSQL。当然你要使用DAO的话,首先得确保你的服务环境安装的PDO及相关的PDO数据库扩展。
        Yii DAO主要包含以下几个类:
        CDbConnection   实现数据库连接
        CDbCommand     实现数据库操作语句生成与执行
        CDbDataReader    实现数据流操作
        CDbTransaction    实现数据库交互
        接下来,我们就来看看不同场景下Yii DAO的使用
    4.2.1 建立数据库连接
        要连接数据库,先创建一个CDbConnection实例化对象并激活它。相关的数据是必不可少的,如:数据源名称,用户名,密码,当然你得确保这些信息是对的,然后你就可以创建连接了:
        $connection=new CDbConnection($dsn,$username,$password);
        // establish connection. You may try...catch possible exceptions
        $connection->active=true;
        ......
        $connection->active=false; // close connection
        DSN的格式取决于你所使用的数据库类型,参考PDO的说明文档,我们给出以下几种数据库的DSN书写格式:
        SQLite: sqlite:/path/to/dbfile
        MySQL: mysql:host=localhost;dbname=testdb
        PostgreSQL: pgsql:host=localhost;port=5432;dbname=testdb
        SQL Server: mssql:host=localhost;dbname=testdb
        Oracle: oci:dbname=//localhost:1521/testdb
        由于CDbConnection继承自CApplicationComponent,所以我们也可以把它当作组件来使用。在配置文件设置组件db(或其他自定义名称)如下:
        array(
            ......
            'components'=>array(
                ......
                'db'=>array(
                    'class'=>'CDbConnection',
                    'connectionString'=>'mysql:host=localhost;dbname=testdb',
                    'username'=>'root',
                    'password'=>'password',
                    'emulatePrepare'=>true, // needed by some MySQL installations
                ),
            ),
        )
        这样我们就可以使用Yii::app()->db 来操作某个数据库连接了。
    4.2.2 执行SQL语句
        完成数据库连接后,使用CDbCommand就可以实现SQL语句的执行了。以下是创建执行语句的一个范例:
        $connection=Yii::app()->db; // assuming you have configured a "db" connection
        // If not, you may explicitly create a connection:
        // $connection=new CDbConnection($dsn,$username,$password);
        $command=$connection->createCommand($sql);
        // 需要时,SQL语句可以使用如下方式进行更新:
        // $command->text=$newSQL;
        CDbCommand执行SQL语句有两种方式:
        execute():执行一条非查询SQL语句,如INSERT,UPDATE及DELETE。如果执行成功,则返回影响的行数
        query():执行一条数据查询语句,如SELECT。如果执行成功,它将返回一个包含查询结果的CDbDataReader实例化对象。类似的,queryXXX()方法也是直接返回查询结果。
        如果执行SQL语句报错,Yii就会抛出异常
        $rowCount=$command->execute(); // 执行非查询语句
        $dataReader=$command->query(); // 执行查询语句
        $rows=$command->queryAll(); // 返回所有查询结果
        $row=$command->queryRow(); // 返回查询结果的第一行
        $column=$command->queryColumn(); // 返回查询结果的第一列
        $value=$command->queryScalar(); // 返回查询结果的第一行第一列
    4.2.3 读取查询结果
        获取查询数据后,就可以通过CDbDataReader::read()来读取相应的数据了。这边你可以使用foreach的数据结构来读取:
        $dataReader=$command->query();
        // 重复调用read()方法,知道返回false
        while(($row=$dataReader->read())!==false) { ... }
        // 使用foreach遍历数据行
        foreach($dataReader as $row) { ... }
        // 一次性置入到一个数组中
        $rows=$dataReader->readAll();
        注意:与query()不同,queryXXX()方法均直接返回查询数据。
    4.2.4 执行交互动作
        当应用执行一些语句对数据库进行读写操作,有必要确定数据库执行了所有的操作语句。交互动作是CDbTransaction在Yii中的实例话,通常执行流程如下:
            交互动作开始
            执行语句有序执行,数据库更新不可见
            提交交互结果,数据库更新可见
            如果中途有一条语句执行异常,交互就会执行回滚动作
        上述流程示例代码如下:
        $transaction=$connection->beginTransaction();
        try
        {
            $connection->createCommand($sql1)->execute();
            $connection->createCommand($sql2)->execute();
            //.... other SQL executions
            $transaction->commit();
        }
        catch(Exception $e) // an exception is raised if a query fails
        {
            $transaction->rollback();
        }
    4.2.5 绑定参数
        为了防止SQL注入攻击,提升SQL语句可读性,我们可以先使用占位符,然后再将具体的参数值赋给占位符即可。
        占位符可以命名,也可以不命名(用?)。使用CDbCommand::bindParam()或者CDbCommand::bindValue()方法替换实际值给占位符,参数绑定需要在SQL语句执行前完成
        // an SQL with two placeholders ":username" and ":email"
        $sql="INSERT INTO tbl user (username, email) VALUES(:username,:email)";
        $command=$connection->createCommand($sql);
        // replace the placeholder ":username" with the actual username value
        $command->bindParam(":username",$username,PDO::PARAM_STR);
        // replace the placeholder ":email" with the actual email value
        $command->bindParam(":email",$email,PDO::PARAM STR);
        $command->execute();
        // insert another row with a new set of parameters
        $command->bindParam(":username",$username2,PDO::PARAM_STR);
        $command->bindParam(":email",$email2,PDO::PARAM_STR);
        $command->execute();
        bindParam()方法和bindValue()方法非常相似,唯一的区别就是前者是才PHP变量传递参数的形式,而后者是直接传递值。当参数比较复杂时,建议使用第一种方式。更多说明,请参考相关PHP文档。
    4.2.6 绑定列
        当获取查询结果时,我们也可以将列绑定到PHP变量上,这样在每次取值的时候它们就会被自动命名了。
        $sql="SELECT username, email FROM tbl user";
        $dataReader=$connection->createCommand($sql)->query();
        // 绑定第一列 (username) 给变量 $username
        $dataReader->bindColumn(1,$username);
        // 绑定第二列 (email)  给变量 $email 
        $dataReader->bindColumn(2,$email);
        while($dataReader->read()!==false)
        {
            // $username and $email contain the username and email in the current row
        }
    4.2.7 使用数据表前缀
        Yii提供了数据表前缀支持。表前缀是指常见表名前面附加的一个标识字符串,通常用来标识特定的应用,或者区分表格用途。例如,'tbl_','dede_'等。
        如果要使用表前缀,配置CDbConnection::tablePrefix属性值即可。在SQL语句中使用{{TableName}}的格式给表名自动添加前缀。例如有一张表'tbl_user',而我们的tablePrefix配置为'tbl_',那么我们就可以使用类似以下的语句直接操作tbl_user表:
        $sql='SELECT * FROM {{user}}';
        $users=$connection->createCommand($sql)->queryAll();
       
    4.3 查询语句生成器
        Yii框架中,使用DAO可以自动生成相关的查询语句。以下是一个基本的查询示例:
        $user = Yii::app()->db->createCommand()
                                ->select('id, username, profile')
                                ->from('tbl user u')
                                ->join('tbl profile p', 'u.id=p.user id')
                                ->where('id=:id', array(':id'=>$id))
                                ->queryRow();
        语句生成器用在需要程序化组装查询语句或者参杂着一些应用逻辑时比较合适。使用它有几个好处:
            可以程序化的完成一条SQL语句的生成
            可以自动为表名和列名添加引号,避免语句中的单词与SQL保留词冲突
            可以给参数添加引号或者使用占位符,防止SQL注入攻击
            实现了一定程度的数据库抽象话,易于不同数据库平台下的移植
        当你的查询很简单的时候,你也可以直接写整个SQL语句,而没必要非要使用语句生成器,除非你犯傻。注意,语句生成器不能用于更改一条已成的SQL执行语句。例如,以下的添加条件代码是无效的:
        $command = Yii::app()->db->createCommand('SELECT * FROM tbl user');
        // the following line will NOT append WHERE clause to the above SQL
        $command->where('id=:id', array(':id'=>$id));
        简单来说就是,绝对的SQL语句是不能和语句生成器混用的。
    4.3.1 语句生成器准备知识
        Yii框架的语句生成器由CDbCommand提供,主要的数据操作类前面我们已经介绍了。使用语句生成器,我们首先创建一个CDbCommand的实例化对象:
        $command = Yii::app()->db->createCommand();
        上面的代码,我们先使用Yii::app()->db取得了数据库连接,然后调用CDbConnection::createCommand()方法创建了我们需要的对象。注意这边createCommand()的参数我们留空了,因为接下来我们将使用程序化的方法来完成SQL查询语句的构建。
    4.3.2 构建查询语句
        数据查询语句就是类似Select...的SQL语句。sql生成器提供了一系列的方法来实现查询语句的细化。因为每个方法返回的都是CDbCommand对象,所以我们可以使用方法链的形式调用。类似前面给出的,详细方法列表如下:
        select():  指定查询语句的 SELECT 部分
        selectDistinct(): 指定查询语句的 SELECT 部分并添加DISTINCT标识
        from(): 指定查询语句的FROM部分
        where(): 指定查询语句的where部分
        andWhere(): 指定查询语句的where部分,条件以AND分隔
        orWhere(): 指定查询语句的where部分,条件以OR分隔
        join(): 附加内联接查询片段
        leftJoin(): 附加一个左外连接查询片段
        rightJoin(): 附加一个右外连接查询片段
        crossJoin(): 附加一个交叉联接查询片段
        naturalJoin(): 附加自然连接查询片段
        group(): 指定查询语句的GROUP BY部分
        having(): 指定查询语句的HAVING部分
        order(): 指定查询语句的ORDER BY部分
        limit(): 指定查询语句的LIMIT部分
        offset(): 指定查询语句的OFFSET部分
        union(): 附加一个联合查询
        下面,我就详细解释一下这些生成器方法如何使用。样例代码用于MySQL,数据表字段及值与实际使用时有所差别:
        select()
        function select($columns='*')
        select()方法生成查询语句的SELECT部分。$columns参数代表需要查询的列,它可以是一个以逗号分隔列名的字符串,也可以是一个数组。列名可以包含表名或者使用别名,方法会自动为列名添加引号。下面是一些范例:
        // SELECT *
        select()
        // SELECT `id`, `username`
        select('id, username')
        // SELECT `tbl user`.`id`, `username` AS `name`
        select('tbl user.id, username as name')
        // SELECT `id`, `username`
        select(array('id', 'username'))
        // SELECT `id`, count(*) as num
        select(array('id', 'count(*) as num'))
        ---------------------------------------------
        selectDistinct()
        function selectDistinct($columns)
        与select方法类似不过生成的语句有加DISTINCT标识,比如selectDistinct('id, username') 生成的SQL形如:SELECT DISTINCT `id`, `username`
        ------------------------------------------------
        from()
        function from($tables)
        from()方法生成查询语句的FROM部分。$tables参数代表要查询的表,它可以是一个以逗号分开的字符串,也可以是一个数组。不赘述了,如下是一些范例
        // FROM `tbl user`
        from('tbl user')
        // FROM `tbl user` `u`, `public`.`tbl profile` `p`
        from('tbl user u, public.tbl profile p')
        // FROM `tbl user`, `tbl profile`
        from(array('tbl user', 'tbl profile'))
        // FROM `tbl user`, (select * from tbl profile) p
        from(array('tbl user', '(select * from tbl profile) p'))
        ---------------------------------------------
        where()
        function where($conditions, $params=array())
        where()方法生成查询语句的WHERE部分。$conditions参数为条件语句,与$params参数共同构成查询条件。$conditions可以是一个字符串(如id=1)也可以是如下格式的数组:
        array(operator, operand1, operand2, ...)
        这边operator有如下几种:
            and:  条件(operands)将以'AND'进行组合。如array('and','id=1','id=2')会生成id=1 AND id=2。如果条件是一个数组,它将以相同的规则生成查询条件。例如array('and','type=1',array('or','id=1','id=2'))会生成 type=1 AND (id=1 OR id=2)这边不会自动添加引号和去空格。
            or:   与'and'类似,不同的是在组合条件时使用OR
            in:   条件1必须为某个数据列或者表达式,条件2为此列或表达式可能的值组成的数组。例如,array('in','id',array(1,2,3))会生成id IN (1,2,3)。方法会自动添加引号,排除异常。
            not in:  与'in'类似
            like:   条件1必须为某个数据列或者表达式,条件2为此列或表达式可能符合的字符串或数组。例如,array('like','name','%tester%')会生成name LIKE '%tester%'。当条件2为数组时,条件会以AND进行关联。例如,array('like','name',array('%test%','%sample%'))会生成name LIKE '%test%' AND name LIKE '%sample%'。方法会自动添加引号,排除异常。
            not like: 与like类似
            or like: 与like类似,在条件2为数组时用OR关联
            or not like: 与or like类似
        下面是where()的一些使用范例:
        // WHERE id=1 or id=2
        where('id=1 or id=2')
        // WHERE id=:id1 or id=:id2
        where('id=:id1 or id=:id2', array(':id1'=>1, ':id2'=>2))
        // WHERE id=1 OR id=2
        where(array('or', 'id=1', 'id=2'))
        // WHERE id=1 AND (type=2 OR type=3)
        where(array('and', 'id=1', array('or', 'type=2', 'type=3')))
        // WHERE `id` IN (1, 2)
        where(array('in', 'id', array(1, 2))
        // WHERE `id` NOT IN (1, 2)
        where(array('not in', 'id', array(1,2)))
        // WHERE `name` LIKE '%Qiang%'
        where(array('like', 'name', '%Qiang%'))
        // WHERE `name` LIKE '%Qiang' AND `name` LIKE '%Xue'
        where(array('like', 'name', array('%Qiang', '%Xue')))
        // WHERE `name` LIKE '%Qiang' OR `name` LIKE '%Xue'
        where(array('or like', 'name', array('%Qiang', '%Xue')))
        // WHERE `name` NOT LIKE '%Qiang%'
        where(array('not like', 'name', '%Qiang%'))
        // WHERE `name` NOT LIKE '%Qiang%' OR `name` NOT LIKE '%Xue%'
        where(array('or not like', 'name', array('%Qiang%', '%Xue%')))
        当使用like条件时,我们需要注意明确一下通配符(比如%和_)。如果条件为用户输入,我们就需要确保这些条件语句不会被解释为通配符:
        $keyword=$ GET['q'];
        // escape % and _ characters
        $keyword=strtr($keyword, array('%'=>'n%', ' '=>'n '));
        $command->where(array('like', 'title', '%'.$keyword.'%'));
        ---------------------------------------------
        andWhere()
        function andWhere($conditions, $params=array())
        这个方法生成WHERE部分语句,以AND分隔
        ---------------------------------------------
        orWhere()
        function orWhere($conditions, $params=array())
        这个方法生成WHERE部分语句,以OR分隔
        ---------------------------------------------
        order()
        function order($columns)
        order()生成ORDER BY部分语句。$columns参数代表需要排序的列,可以是一个以逗号分隔的字符串(包含顺序ASC或DESC)或者数组。可以指定表名,如下一些范例:
        // ORDER BY `name`, `id` DESC
        order('name, id desc')
        // ORDER BY `tbl profile`.`name`, `id` DESC
        order(array('tbl profile.name', 'id desc'))
        ------------------------------------------------
        limit() 和 offset()
        function limit($limit, $offset=null)
        function offset($offset)
        以下是一些范例
        // LIMIT 10
        limit(10)
        // LIMIT 10 OFFSET 20
        limit(10, 20)
        // OFFSET 20
        offset(20)
        -----------------------------------------------
        join()及其同类方法
        function join($table, $conditions, $params=array())
        function leftJoin($table, $conditions, $params=array())
        function rightJoin($table, $conditions, $params=array())
        function crossJoin($table)
        function naturalJoin($table)
        以下是一些范例
        // JOIN `tbl_profile` ON user_id=id
        join('tbl_profile', 'user_id=id')
        // LEFT JOIN `pub`.`tbl_profile` `p` ON p.user_id=id AND type=1
        leftJoin('pub.tbl_profile p', 'p.user_id=id AND type=:type', array(':type'=>1))
        --------------------------------------------------------
        group()
        function group($columns)
        使用范例:
        // GROUP BY `name`, `id`
        group('name, id')
        // GROUP BY `tbl profile`.`name`, `id`
        group(array('tbl profile.name', 'id'))
        -----------------------------------------------------
        having()
        function having($conditions, $params=array())
        使用范例
        // HAVING id=1 or id=2
        having('id=1 or id=2')
        // HAVING id=1 OR id=2
        having(array('or', 'id=1', 'id=2'))
        ----------------------------------------------------
        union()
        function union($sql)
        使用范例
        // UNION (select * from tbl profile)
        union('select * from tbl profile')
        ----------------------------------------
        执行查询
        使用上面的方法后,我们成功构建了查询语句,接下来就是调用DAO的方法来执行查询了。例如我们使用CDbCommand::queryRow()查询一条记录,或者执行CDbCommand::queryAll()查询所有记录。如下:
        $users = Yii::app()->db->createCommand()
                            ->select('*')
                            ->from('tbl user')
                            ->queryAll();
        获取生成的SQL语句
        除了执行构建的语句外,我们也可以获取到这个构建的SQL语句,使用CDbCommand::getText()方法即可:
        $sql = Yii::app()->db->createCommand()
                            ->select('*')
                            ->from('tbl user')
                            ->text;
        如果构建的时候有参数,这些参数将自动被CDbCommand::params中的属性替换。
        建立查询语句替代语法
        像前面说的,方法是多种多样的,在Yii中我们可以用不同的写法来实现相同的效果,比如:
        $command->select(array('id', 'username'));
        $command->select = array('id', 'username');
        $row = Yii::app()->db->createCommand(array(
            'select' => array('id', 'username'),
            'from' => 'tbl user',
            'where' => 'id=:id',
            'params' => array(':id'=>1),
        ))->queryRow();
        查询对象的复用
        CDbCommand对象可以被多次复用。在复用时,需要使用CDbCommand::reset()方法来清除原有查询条件。如下:
        $command = Yii::app()->db->createCommand();
        $users = $command->select('*')->from('tbl users')->queryAll();
        $command->reset(); // clean up the previous query
        $posts = $command->select('*')->from('tbl posts')->queryAll();
    4.3.3 构建数据操作语句
        数据操作语句就是表示一些个SQL操作,对某张表的插入,更新,删除操作。Yii提供了insert,update和delete的语句生成器,不过与SELECT有所不同,这些数据操作将被即时解析和执行
        insert(): inserts a row into a table
        update(): updates the data in a table
        delete(): deletes the data from a table
        下面是关于这些方法的详细描述
        insert()
        function insert($table, $columns)
        ($columns参数为'列=>值'数组)范例如下:
        // build and execute the following SQL:
        // INSERT INTO `tbl user` (`name`, `email`) VALUES (:name, :email)
        $command->insert('tbl user', array(
            'name'=>'Tester',
            'email'=>'tester@example.com',
        ));
        ----------------------------------------------------
        update()
        function update($table, $columns, $conditions='', $params=array())
        使用范例如下:
        // build and execute the following SQL:
        // UPDATE `tbl user` SET `name`=:name WHERE id=:id
        $command->update('tbl user', array(
            'name'=>'Tester',
        ), 'id=:id', array(':id'=>1));
        --------------------------------------------------
        delete()
        function delete($table, $conditions='', $params=array())
        使用范例如下:
        // build and execute the following SQL:
        // DELETE FROM `tbl user` WHERE id=:id
        $command->delete('tbl user', 'id=:id', array(':id'=>1));
    4.3.4    构建数据库结构操作语句
       
       
       
  • Yii用户手册基础篇

    (ps: 往日翻译,弃之可惜,于是在这边做个简略的记录吧 :)  )

    Yii 1.1.13 版用户手册翻译

    部分省略 (结合个人思维描述,如有雷同,纯属用词不当)

    2、 基础知识
    2.1 模型-视图-控制器(MVC)
        Yii框架使用的是MVC设计模式,MVC模式在Web开发中应用的相当广泛,其主要目的就是实现业务逻辑、用户界面操作 以及 底层数据操作的分离。这样开发者在编码的过程中,就能更清晰的有针对性的修改代码,从而实现相关的业务需求。MVC中,模型层主要实现底层数据的操作及与控制器的交互; 视图层主要是显示用户界面,展示相关的数据和表单;控制层主要是实现用户界面操作与底层数据操作的中间层业务逻辑。
        在基础的MVC结构上,Yii还实现了一些自定义的控制器前奏动作,实现用户请求到对应控制器的分发。简单的解析一下Yii的MVC逻辑流程: 用户输入url访问对应的web应用,服务端执行入口文件,执行控制器前奏操作,分发用户相关的请求到对应的控制器,控制器完成逻辑处理后将相关数据及挂件传递到视图文件中,视图层解析布局及控制层传递过来的数据后生成用户所请求的页面,最终显示在了用户的浏览器中。
    2.2 入口文件脚本
        Yii的入口文件即网站根目录下的index.php文件:
        // remove the following line when in production mode
        defined('YII_DEBUG') or define('YII_DEBUG',true);
        // include Yii bootstrap file
        require_once('path/to/yii/framework/yii.php');
        // create application instance and run
        $configFile='path/to/config/file.php';
        Yii::createWebApplication($configFile)->run();
        脚本首先加载了框架应用文件,然后根据相关配置执行创建相应的Web应用并执行。
    2.2.1 调试模式
        Yii应用通过静态变量YII_DEBUG控制应用的使用环境(调试环境或生产环境)。默认设置为false,即应用处于生产环境。如果需要设置为调试环境,在引用框架文件yii.php之前,将YII_DEBUG设置为true就可以了。调试模式下应用的执行效率相对较低,因为在应用执行的过程中生成并保留了相当多的信息日志。当然,调试环境在开发的过程中还是相当有用的,出错的时候,我们可以通过它找到更多的信息,从而提高问题的解决效率。
    2.3 Yii应用
        应用对象在相关请求执行前,先完成了必要的信息处理。比如url的参数规范化,应用配置的加载与保存,分发请求到指定的控制器。所以我们可以称这个应用对象为 执行控制器的一个前奏。前奏控制在入口脚本文件中已经有调用,不过我们可以通过使用Yii::app() 随时调用它。
    2.3.1 应用配置
        默认情况下,应用对象是CWebApplication的一个实例。我们通常设定一个配置文件来初始化这个对象,以实现相关的需求。配置就是由多对'键——值'构成的数组。键名均为应用示例化对象中的属性,键值即为对象属性的初始值。例如,下面的数组就是应用 名称及默认控制器的配置.
        array(
        'name'=>'Yii Framework',
        'defaultController'=>'site',
        )
        配置通常保存在protected/config/main.php文件中,当然你也可以自己指定。然后在入口脚本文件中进行调用就ok了。
    2.3.2 应用基目录
        应用基目录是保存逻辑代码和数据的目录,默认名称即为 protected ,当然这个也可以同过修改 basePath 属性 设置为其他目录。目录下的文件需要考虑其安全性,通常是禁止用户直接访问的。在Apache环境下我们可以在 目录下添加 .htaccess 文件 并设置 deny from all ,起到简单的保护作用。
    2.3.3 应用组件
        通过应用组件的配置与调用,我们可以简单的实现一些功能丰富的应用。我们可以设置组件的初始值来配置适合于自己的组件,例如下面的代码是针对CMemCache组件 多服务器的一个配置范例:
        array(
            ......
            'components'=>array(
                ......
                'cache'=>array(
                    'class'=>'CMemCache',
                    'servers'=>array(
                        array('host'=>'server1', 'port'=>11211, 'weight'=>60),
                        array('host'=>'server2', 'port'=>11211, 'weight'=>40),
                    ),
                ),
            ),
        )
        通过上面的配置,我们在组件列表中加入了cache组件,此组件使用CMemCache类,并初始化了CMemCache类中的servers属性值。
        我们可以通过类似Yii::app()->ComponentID的模式对组件进行调用。例如这边的ComponentID为 cache, 那么我们要使用这个组件时,使用代码Yii::app()->cache即可。
        如果我们需要禁用一个组件,那么我们在配置文件中设置其 enabled 属性为 false 即可。
        注:组件通常是按需求加载的,如果有些组件是必要的,我们通常将其添加到preload中。
    2.3.4 Yii的核心组件
        Yii框架为常见的应用开发需求提供了一整套的功能组件。比如,request 组件提供了 收集用户信息及请求等功能。Yii框架下,我们可以通过设置组件的初始值实现各个方面的行为控制。
        以下是CWebApplication 所提供的核心组件列表:
        assetManager:CAssetManager  管理资源文件
        authManager:CAuthManager  管理用户权限(RBAC)
        cache: CCache  提供数据缓存功能。注意,这边你需要指定一个特定的类(如CMemCache,CDbCache),否则使用这个组件没有任何实际效果。
        clientScript:CClientScript 管理客户端脚本(js 和 css)
        coreMessages:CPhpMessageSource 提供用于Yii框架的核心信息翻译
        db:CDbConnection 提供数据库连接。注意,使用组件时必须指定connectionString
        errorHandler:CErrorHandler 处理未捕获的PHP错误及异常
        format:CFormatter   格式化数据的值用于显示
        messages:CPhpMessageSource 提供用于 应用的翻译信息
        request:CHttpRequest 提供用户请求的相关信息
        securityManager:CSecurityManager 提供安全相关的功能,如哈希 加密等
        session:CHttpSession  提供session相关的功能
        statePersister:CStatePersister 提供操作全局状态的功能
        urlManager:CUrlManager 提供Url解析和创建功能
        user:CWebUser   当前用户身份相关的信息
        themeManager:CThemeManager   管理主题模板
    2.3.5 应用生命周期
        在处理一个用户请求的过程中,应用的生命周期过程演示如下:
        1 使用CApplication::preinit() 对应用进行初始化
        2 挂载 自动加载及错误处理类
        3 注册核心应用组件
        4 加载应用配置
        5 使用CApplication::init()初始化应用
            注册应用行为
            加载静态应用组件
        6 执行一个onBeginRequest动作
        7 执行用户的请求:
            收集请求相关信息
            创建关联控制器
            执行控制器动作
        8 执行一个onEndRequest动作
    2.4控制器
        一个控制器是 CController类(子类)的实例,控制器运行的过程中通常是根据请求执行一个动作,完成数据层和视图层的逻辑处理。动作(action)就是控制器中以action开头的方法。
        一般控制器都有一个默认的动作,当用户没有指定执行的动作时,执行默认动作。缺省设置下,默认动作的名称为Index,当然,你可以通过修改CController::defaultAction属性来设置。下面的代码定义了一个 site控制器及index contact两个动作
        class SiteController extends CController
        {
            public function actionIndex()
            {
                // ...
            }
            public function actionContact()
            {
                // ...
            }
        }
    2.4.1 路由
        控制器和动作都是通过其ID来确定调用的,例如访问一个path/to/xyz的控制器,我们需要在类文件protected/controllers/path/to/XyzController.php中实现该控制器类。当然名称xyz是自定义的,比如post控制器,则实现protected/controllers/PostController.php中的类。动作的ID是控制器中不包含action前缀的部分。例如,一个控制器包含方法actionEdit,则该动作的ID就是edit。
        用户请求特定 的控制器和动作即路由。一个路由通常由控制器和动作加斜线连接而成。比如 post/edit 这个路由就是请求 PostController 中的 actionEdit 。注意:默认情况下路由是大小写敏感的,我们可以通过修改CUrlManager::caseSensitive 为false 使路由忽略大小写。在敏感状态下,你需要确保请求路由中的控制器和动作大小写是否正确,否则请求可能出现异常。
        应用还可以包含模块,一个模块的路由格式如:moduleID/controllerID/actionID,更多说明可以参见 模块文档
    2.4.2 控制器实例
        当CWebApplication处理一个请求时,控制器实例就随之创建。获取控制器标识后,应用程序会通过以下途径搜索对应的控制器。
            如果 CWebApplication::catchAllRequest 有设置,那么控制器就会基于这个属性创建,而用户请求的控制器标识就直接被忽略了。(主要用于应用程序维护时,重定向所有请求到通知页面)
            如果请求的控制器标识存在于CWebApplication::controllerMap中,那么配置规则将用于创建控制器实例
            如果请求的ID格式为“path/to/xyz”,那控制器类名为XyzController,文件路径为:protected/controllers/path/to/XyzController.php。 例如,一个标识为 admin/user的控制器 就是定向到 protected/controllers/admin/UserController.php 文件中的 UserController类.如果文件不存在就会报404异常。
        在模块中,上面的过程是略有不同的。通常,应用程序会检测请求的标识是否在某个模块中,如果是则先创建模块实例,而后控制器实例才会被创建。
    2.4.3 动作
        上面提到过,动作就是以action作为前缀的一些方法。一个可定义性更强的方式就是创建一个动作类,在路由请求的时候加载它。这就使得动作的可定制性更自由更强大了。 例如下面的代码创建了一个动作类
        class UpdateAction extends CAction
        {
            public function run()
            {
                // 一些逻辑代码
            }
        }
        然后通过 actions() 方法将此动作挂载到需要的控制器中
        class PostController extends CController
        {
            public function actions()
            {
                return array(
                    'edit'=>'application.controllers.post.UpdateAction',
                );
            }
        }
        上面我们使用了指向对应动作类文件的别名
        动作的参数绑定
        Yii从版本1.1.4开始,添加的自动绑定参数的功能。就是一个控制器动作可以定义一些自定义参数,并使用$_GET对其赋值。示范一下,我们在PostController中定义一个动作create 包含两个参数 :
            category: 一个整型变量,表示新日志创建时 所属的分类id;
            language: 一个字符型变量,表示 新日志所使用的语言。
        我们使用如下代码实现参数值的获取
        class PostController extends CController
        {
            public function actionCreate()
            {
                if(isset($ GET['category']))
                    $category=(int)$ GET['category'];
                else
                    throw new CHttpException(404,'invalid request');
                if(isset($ GET['language']))
                    $language=$ GET['language'];
                else
                    $language='en';
                // ... 一些功能代码 ...
            }
        }
        如果使用函数传参的形式,我们可以更方便的实现需求
        class PostController extends CController
        {
            public function actionCreate($category, $language='en')
            {
                $category=(int)$category;
                // ... 一些功能代码 ...
            }
        }
        注意,这边$language默认为en,而$category参数没有设置默认值,如果在使用的过程中,没有传递该参数,则会出现400错误。
        Yii自1.1.5版本在执行动作时开始支持数组类型的参数传递
        class PostController extends CController
        {
            public function actionCreate(array $categories)
            {
                // Yii will make sure that $categories is an array
            }
        }
        即我们在参数前添加了array类型标识.这样,当我们传递的categories是一个字符串时,它将被自动被转换为一个包含此字符串的数组。注意:如果没有明确的标识参数类型,那么参数必须是一个纯变量,如果传递数组则会导致异常。
        版本1.1.7起,动作类中的run方法 也实现了参数传递的功能
    2.4.4 过滤器
        过滤器是一段实现在控制器动作执行之前或(和)之后的代码。比如,一个入口控制器通常在用户请求执行某个动作之前先对用户的身份进行判断;一个性能控制器可能用来判断动作消耗的执行时间。一个动作可以有多个过滤器。过滤器会按过滤器列表依次执行。一个过滤器可以控制某个动作以及其余的控制器是否执行。
        过滤器可以定义为一个控制器类的方法,当然,这个方法需要以filter为前缀。比如名为filterAccessControl的方法就是一个名为accessControl过滤器的定义。过滤器方法必须有正确的签名:
        public function filterAccessControl($filterChain)
        {
            // call $filterChain->run() to continue filter and action execution
        }
        $filterChain是CFilterChain的实例,代表与此动作相关的过滤器列表。过滤器方法中,我们使用$filterChain->run()实现过滤器与动作的关联执行。
        过滤器也可以是CFilter或其子类的实例。以下代码即一个控制器类的定义
        class PerformanceFilter extends CFilter
        {
            protected function preFilter($filterChain)
            {
                // 一些在动作执行之前的逻辑代码
                return true; // false 如果控制不被执行
            }
            protected function postFilter($filterChain)
            {
                // 一些在动作执行之后的逻辑代码
            }
        }
        如果希望将过滤器用于动作,我们需要重写CController::filters()方法。该方法返回一个过滤器配置数组。比如,
        class PostController extends CController
        {
            ......
            public function filters()
            {
                return array(
                    'postOnly + edit, create',
                    array(
                        'application.filters.PerformanceFilter - edit, create',
                        'unit'=>'second',
                    ),
                );
            }
        }
        以上代码指定了两个过滤器:postOnly和PerformanceFilter。postOnly过滤器是一个方法(已定义在CController类中);PerformanceFilter过滤器是一个对象。路径别名application.filters.PerformanceFilter说明这个过滤器类文件为protected/filters/PerformanceFilter.php。我们使用数组来配置某个过滤器从而实现一些必要属性的初始化。比如这边PerformanceFilter过滤器的unit属性被初始化为second
        使用+、-标识符,控制某些动作执行或者不执行相应的过滤器。拿上面的代码来说,postOnly过滤器在edit,create动作中有效,而PerformanceFilter过滤器在除edit,create之外的动作中有效。如果没有+-标识,则该过滤器在所有的动作中均有效。
    2.5 模型
        模型是CModel的实例或者子类。模型一般用于实现数据保存以及保存数据的一些逻辑规则。一个模型代表一个单一数据对象。它可以是数据表中的一条记录,也可以是用户提交的一个html表单数据。数据对象的每一个字段都代表着模型中的一个属性。各个属性有其对应的标签和验证规则。
        Yii框架提供两种模型:表单模型和有效活动记录模型。他们都继承自同一个基类,CModel。表单模型是CFormModel的实例化。表单模型用于收集用户输入数据(收集——使用——丢弃)。例如,在登录页,我们可以使用一个表单模型收集用户输入的用户名和密码信息。详细请参考Yii关于表单的文档。活动记录(AR)是用于数据库操作面向对象化的一种设计模式。每个AR对象都是是CActiveRecord或其子类的实例,代表着数据库中的某条记录。记录中的字段即为该AR对象的属性。详细可参考ActiveRecord的说明文档
    2.6 视图
        视图就是一个php文件,主要包含一些用户界面元素。他可以包含PHP数据报表,但是不建议在视图中直接操作数据模型,且应该保证其相对独立。在逻辑与视图分离的主旨下,大部分的逻辑代码都应该在控制器或者模型层实现,而不应该放到视图中。
        视图有一个用于渲染调用时使用的名称,即该视图的文件名。比如,edit视图指向的是一个edit.php文件。使用CController::render()对某个视图进行渲染。这个方法将在protected/views/ControllerID目录下查找对应名称的视图文件。
        视图文件中,我们可以直接使用$this操作其控制器的对象。使用$this->propertyName引入我们需要的控制器属性。我们也可以使用以下方法向视图中传递参数:
        $this->render('edit', array(
            'var1'=>$value1,
            'var2'=>$value2,
        ));
        上述代码中,render()方法将把第二个数组参数转换为变量,这样我们就可以在视图中使用变量$var1 和 $var2了。
    2.6.1 布局
        布局是一个用来控制视图布局的特殊视图。它通常包含一系列用户视图中通用的模块。比如,一个视图应该包含:头部和脚部,并在中间嵌入相关视图:
        ......header here......
        <?php echo $content; ?>
        ......footer here.....
        这边$content就是视图文件渲染后的效果。布局是在调用render()方法时隐式加载的。一般情况下,protected/views/layouts/main.php为默认布局。我们通过修改CWebApplication::layout()或者CController::layout来自定义布局。如果在渲染视图时不希望用到布局文件,就使用 renderPartial()方法。
    2.6.2 挂件
        挂件是CWidget或其子类的实例化。它是一个主要用于前台展示的组件。挂件通常被嵌入到视图中,实现部分效果。例如,一个日历挂件可以用于某个复杂的日历相关视图的渲染。挂件的主要功能就是,方便用户视图模块的复用。挂件的调用方法如下所示:
        <?php $this->beginWidget('path.to.WidgetClass'); ?>
            ...body content that may be captured by the widget...
        <?php $this->endWidget(); ?>
        或者
        <?php $this->widget('path.to.WidgetClass'); ?>
        挂件可以通过配置初始化属性值在调用CBaseController::beginWidget或者CBaseController::widget时实现一些行为的自定义。例如,使用CMaskedTextField挂件时,我们通常希望设置一个范例值。为了实现这个,我们可以传递一个初始化的属性数组(数组的键值分别对应挂件的属性名和初始化值),如下:
        <?php
        $this->widget('CMaskedTextField',array(
            'mask'=>'99/99/9999'
        ));
        ?>
        挂件的自定义可以通过继承CWidget,重写其init()和run()方法来实现,如:
        class MyWidget extends CWidget
        {
            public function init()
            {
                // this method is called by CController::beginWidget()
            }
            public function run()
            {
                // this method is called by CController::endWidget()
            }
        }
        与控制器类似,挂件也可以有自己的视图。默认情况下,挂件的视图文件位于挂件声明类同目录下的views目录中。与控制器类似这些挂件视图可以通过使用CWidget::render()调用。不同的是,挂件的视图不会加载任何布局,并且$this代表的是widget实例而非控制器实例。提示:使用CWidgetFactory::widgets可以实现站内自由配置挂件,使挂件设置更灵活,更多说明参见主题文档。
    2.6.3 系统视图
        Yii框架系统视图通常用于错误提示以及记录日志信息。比如,在用户请求不存在的控制器或动作时,Yii会抛出异常及错误提示,而这些说明提示就是使用系统视图进行渲染展示的。系统视图也遵循一定的命名规则,像名称为errorXXX的视图通常用于显示代码为XXX的(CHttpException)异常信息,比如CHttpException的异常代码为404,则显示名为error404的视图。Yii框架提供了一些默认的系统视图,位于framework/views目录下。你可以在protected/views/system目录下创建同名文件进行自定义

    2.7 组件
        Yii应用是由一些规范的组件对象构成的。组件是CComponent或其子类的实例化,组件的使用主要涉及到属性的访问以及事件的加载与处理。CCompoent基类指定了定义属性和事件的方法。
    2.7.1 组件属性   
        组件属性与对象的公共成员变量类似,我们可以读取和赋值。比如:
        $width=$component->textWidth; // get the textWidth property
        $component->enableCaching=true; // set the enableCaching property   
        声明组件属性,我们可以直接在组件类中定义公共成员变量。还有个更灵活的方法,就是使用getter和setter魔术方法,如下:
        public function getTextWidth()
        {
            return $this-> textWidth;
        }
        public function setTextWidth($value)
        {
            $this-> textWidth=$value;
        }
        上述代码定义了一个可写的属性,名为textWidth(不区分大小写)。读取属性值时getTextWidth()方法被调用;设置属性值时setTextWidth()方法被调用。如果setter方法未实现,则该属性为只读,如果对齐进行赋值就会出现异常。使用getter和setter方法可以方便我们在读取或设置相关属性时添加一些逻辑代码(比如验证,载入事件)。注意:直接声明和使用魔术方法声明的属性在大小写敏感上有所区别。
    2.7.2 组件事件
        组件事件是一些特殊属性,它的值是方法(事件处理)。将方法附加到事件上,可以使方法在事件触发时自动执行。这样,我们在开发组件的过程中,就可以使用一些不确定行为(而无需预先规划好整个逻辑流程及其具体实现的功能)。
        组件事件的声明由一个on为前缀的方法声明来完成。与魔术方法声明属性类似,事件名称不区分大小写。如下代码声明了一个onClicked事件:
        public function onClicked($event)
        {
            $this->raiseEvent('onClicked', $event);
        }
        这边$event是CEvent或者其代表事件参数的子类。我们可以使用如下格式的代码将某个方法关联到此事件:$component->onClicked=$callback;  这边$callback代表的是一个PHP回调方法。它可以是一个全局方法,也可以是某个类中的方法。如果是类的方法,则$callback是类似于array($object,'methodName')的一个数组。
        一个事件处理的签名必须采用如下格式:
        function methodName($event)
        {
            ......
        }
        这边$event是描述此事件的参数(源于raiseEvent()调用方法),$event参数是CEvent或其子类的实例,它至少包含了事件调用源的信息。PHP5.3后,可以使用匿名函数定义事件处理。例如:
        $component->onClicked=function($event) {
            ......
        }
        现在如果调用onClicked(),那么onClicked事件将会被触发(包含在onClicked()中),而且关联的事件处理函数将会自动调用。一个事件可以关联多个处理函数(句柄)。当事件被触发时,事件中关联的函数会被自动调用。如果某个处理函数希望终止事件的执行,那么在这个处理函数中设置$event->handled 为true就OK了。
    2.7.3 组件行为
        组件支持混入模式并且可以关联多个行为。行为是一个对象,它的方法可以被组件以收集的方式实现继承,而不必拘泥于特定的格式规范(即常规的类继承)。一个组件可以关联多个行为,继而实现多重继承。
        行为类必须实现IBehavior接口。一般的行为可以直接继承CBehavior。如果一个行为需要与一个模型进行关联,它可以继承实现了一些特定方法的CModelBehavior或者CActiveRecordBehavior类。
        使用行为时,必须先将行为方法附加到组件中(attach()--IBehavior::attach),然后我们就可以在组件中调用行为方法了:
        // $name uniquely identifies the behavior in the component
        $component->attachBehavior($name,$behavior);
        // test() is a method of $behavior
        $component->test();
        附加的行为可以当作组件的属性来用。比如,我们在组件中关联了一个tree的行为,我们可以用下面的方法来使用这个行为对象:
        $behavior = $component->tree;
        //与下述方法相同
        // $behavior = $component->asa('tree');
        行为可以自由启用或禁用,这样就实现了控制其方法在组件中是否有效。
        $component->disableBehavior($name);
        //the following statement will throw an exception
        $component->test();
        $component->enableBehavior($name);
        //it works now
        $component->test();
        有时候附加到组件中的行为包含同名的方法,这种情况下,会执行先加载行为的方法。与事件一起使用,会让行为的作用得到更有效的发挥。当组件附加了某个行为时,这个行为的方法可以附加关联到组件的事件中。如此一来,行为就可以执行或改变组件的常规执行流程。
        行为的属性也可以在其附加的组件中进行调用,包括公共成员变量以及使用魔术方法定义的变量。例如,某个行为拥有一个名为xyz的属性并且被附加到组件$a中,那么我就可以使用$a->xyz来访问这个行为的属性。
    2.8 模块
        模块是一个自足的软件单元,它包含模型,视图,控制器以及组件等。从各个方面来看,模块与应用类似,主要的区别就是模块无法独立部署,它必须包含于应用之种。用户可以采用与访问应用控制器类似的形式访问模块中的控制器。模块在几种场景下比较有用。开发大型应用时,我们可以将其分割为多个模块,进行独立的开发和维护。一些通用的需求,例如用户管理,评论管理,可以使用模块的形式进行开发,方便在以后的项目中复用。
    2.8.1 创建模块
        模块通常组织在一个目录下,目录名称即模块的独立标识。模块的目录结构与应用的基础目录结构类似。如下是一个名为forum的模块目录结构:
        forum/
            ForumModule.php 模块类文件
            components/ containing reusable user components
            views/ containing view files for widgets
            controllers/ containing controller class files
                DefaultController.php the default controller class file
            extensions/ containing third-party extensions
            models/ containing model class files
            views/ containing controller view and layout files
                layouts/ containing layout view files
                default/ containing view files for DefaultController
                    index.php the index view file
        每个模块都需要有一个继承自CWebModule类的子类。类名通常格式为ucfirst($id).'Module',这边$id即为模块的标识(模块的目录名)。模块类是模块代码及信息的核心位置。我们可以使用CWebModule::params来保存模块参数,使用CWebModule::components来分享应用的组件到模块中。提示:我们可以使用Gii来创建一个模块的骨架。
    2.8.2 使用模块
        使用模块,首先要将模块的文件放置到应用的模块目录,然后将模块id包含到应用的modules属性中。比如这边我们需要加载上面的forum模块,我们可以使用如下配置:
        return array(
            ......
            'modules'=>array('forum',...),
            ......
        );
        模块也可以配置初始化属性值。与组件的配置类似,例如forum模块类中有一个postPerPage属性,我们可以使用如下方式配置其初始值:
        return array(
            ......
            'modules'=>array(
                'forum'=>array(
                    'postPerPage'=>20,
                ),
            ),
            ......
        );
       
  • 没文化真可怕(转:我所遇到最牛的sshd远程连接)

    我所遇到最牛的sshd远程连接
    源自: http://netsecurity.51cto.com/art/200706/48649.htm
    2007年5月30日,与我方合作的新疆某局要求我们把他们4台linux服务器的ip访问控制取消,以便新的合作方可以方便的登陆进行新的开 发。先介绍一下基本情况:四个机器,都是RedHat AS 4 linux,基于安全考虑,在乌鲁木齐电信机房安装系统的时候,我用新版的ssh代替系统自带的open-ssh,在sshd的配置文件中加入了ip限制 (AllowHost这样的行),这意味着只有加入到这个行里的ip段可以远程连接到本服务器的sshd服务;最后还在文件/etc/rc.local写 了若干行iptbles语句来限制远程访问。

    接下来,我按这样的步骤取消这些访问限制:

    1、执行命令 ntsysv,把sshd服务打上钩

    2、把文件/etc/rc.local文件里以前添加的行全部用“#”号注释掉,或者干脆给删除。

    3、修改完成后重启系统(需事先征得同意,否则要扯皮的呀!新疆某局同意先重起某个任务不繁忙的服务器)。

    启 完系统我用不加sock5代理的ssh客户端连接服务器,一切正常,再找一个外面的人帮我测试(这样可以测试不同ip段的访问情况),也是很正常的。然后 我在qq里告诉他,让他们那里连接一下,看是否正常。一会儿那边反馈连不上,我上去多次测试,没问题呀!又叫他们自己去试。都快下班了,还不行,把我弄烦 了,我对合作方说:“你去看一下那个开发人员怎么连的呀”?不多久,答曰:“他(开发人员)用windows的远程桌面在连接…”,我一听,差点摔倒了。

    终端服务的客户端能连linux的sshd服务端,从业10年来闻所未闻。能连通,真实奇迹!我问合作方:“这样的水平,你们也放心”?答曰:“领导放心,我不放心”!

  • 平淡的人生(转)

    原文转自:百度2012贴吧,一楼原题为:中国人唯一不认可的成功——就是家庭的和睦,人生的平淡。稍觉不妥遂加以修改,如题。
    英国某小镇。
    有一个青年人,整日以沿街为小镇的人说唱为生;这儿,有一个华人妇女,远离家人,在这儿打工。他们总是在同一个小餐馆用餐,于是他们屡屡相遇。时间长了,彼此已十分的熟悉。
    有一日,我们的女同胞,关切地对那个小伙子说:“不要沿街卖唱了,去做一个正当的职业吧。我介绍你到中国去教书,在那儿,你完全可以拿到比你现在高得多的薪水。”
    小伙子听后,先是一愣,然后反问道:“难道我现在从事的不是正当的职业吗?我喜欢这个职业,它给我,也给其他人带来欢乐。有什么不好?我何必要远渡重洋,抛弃亲人,抛弃家园,去做我并不喜欢的工作?”
    邻桌的英国人,无论老人孩子,也都为之愕然。他们不明白,仅仅为了多挣几张钞票,抛弃家人,远离幸福,有什么可以值得羡慕的。在他们的眼中,家人团聚,平平安安,才是最大的幸福。它与财富的多少,地位的贵贱无关。于是,小镇上的人,开始可怜我们的女同胞了。
    中国山东,有这样一对夫妇
    刚刚结婚时,妻子在济宁,丈夫在枣庄;过了若干年,妻子调到了枣庄,丈夫却一纸调令到了菏泽。若干年后,妻子又费尽周折,调到了菏泽,但不久,丈夫又被提拔到了省城济南。妻子又托关系找熟人,好不容易调到了济南。可是不到一年,丈夫又被国家电业总公司调到重庆。
    于 是,她所有的朋友,就给她开玩笑——你们俩呀,天生就是牛郎织女的命。要我们说呀,你也别追了,干脆辞职,跟着你们家老张算了。但是,她以及公婆、父母, 都一致反对。“干了这么多年,马上就退休了,再说,你的这么好,辞职多可惜。要丢掉多少钱呀!再干几年吧,也给孩子多挣一些。”
    其实,他们家的经济条件已经非常优越。早已是中层阶级,但是他们仍然惦念着那一退休.于是,夫妻两个至今依然是牛郎织女。
    我们,是一个尚义轻利的民族。
    中国人一直是为了某种自己未必真正明白的主义而活着。于是,中国人,不能在没有目标的生活中活着。而这个目标,可以是工作,可以是理想,可以是金钱,可以是孩子,可以是老人……但是,唯一不可能是的,就是自己。
    中国人,可以很委屈的活着。可以是工作上的极不顺心,可以是婚姻上的勉强维持,可以是人际关系上的强作笑颜,可以是所有欲望的极端压制,可以是为了一个所谓的户口……哪怕牺牲自己一生的幸福,也在所不惜。
    中国人,可以过异常艰难的日子,但并不能安贫乐道,他所遭受的一切不幸,必定有一个近乎玩笑的借口;中国人,可以把高官厚禄当作成功,中国人可以把身家百万当作理想,中国人可以抛却天伦之乐四海飘荡,但是,中国人唯一不认可的成功——是家庭的和睦,人生的平淡。
    于 是,一个有着五千年文明历史的国度,把爱国、崇高、献身、成功、立业的情结推向了极致——他们要么在大公无私,其实是舍本逐末的漩涡里苦苦挣扎,要么在肩 负重任,其实是徒有其名的怪圈里受尽折磨……唯一遗漏的就是自由和自我。于是,在外国,妇孺皆知的道理;在中国,没人能明白。
    人的一生,到底在追求什么?
    有 一个美国商人坐在墨西哥海边一个小渔村的码头上,看着一个墨西哥渔夫划着一艘小船靠岸,小船上有好几尾大黄鳍鲔鱼。这个美国商人对墨西哥渔夫能抓这么高档 的鱼恭维了一番,还问要多少时间才能抓这么多?墨西哥渔夫说,才一会儿功夫就抓到了。美国人再问,你为什么不待久一点,好多抓一些鱼?墨西哥渔夫觉得不以 为然:这些鱼已经足够我一家人生活所需啦!
    美国人又问:那么你一天剩下那么多时间都在干什么?
    墨西哥渔夫解释:我呀?我每天睡到自然醒,出海抓几条鱼,回来后跟孩子们玩一玩;再跟老婆睡个午觉,黄昏时晃到村子里喝点小酒,跟哥儿们玩玩吉他。我的日子可过得充满又忙碌呢!
    美国人不以为然,帮他出主意,他说:我是美国哈佛大学企管硕士,我倒是可以帮你忙!你应该每天多花一些时间去抓鱼,到时候你就有钱去买条大一点的船。自然你就可以抓更多鱼,在买更多渔船。然后你就可以拥有一个渔船队。
    到时候你就不必把鱼卖给鱼贩子,而是直接卖给加工厂。然后你可以自己开一家罐头工厂。如此你就可以控制整个生产、加工处理和行销。然后你可以离开这个小渔村,搬到墨西哥城,再搬到洛杉矶,最后到纽约,在那经营你不断扩充的企业。
    墨西哥渔夫问:这又花多少时间呢?
    美国人回答:十五到二十年。
    墨西哥渔夫问:然后呢?
    美国人大笑着说:然后你就可以在家当皇帝啦!时机一到,你就可以宣布股票上市,把你的公司股份卖给投资大众;到时候你就发啦!你可以几亿几亿地赚!
    然后呢?
    美国人说:到那个时候你就可以退休啦!你可以搬到海边的小渔村去住。每天睡到自然醒,出海随便抓几条鱼,跟孩子们玩一玩,再跟老婆睡个午觉,黄昏时,晃到村子里喝点小酒,跟哥儿们玩玩吉他。
    墨西哥渔夫疑惑的说:我现在不就是这样了吗?
    人的一生,到底在追求什么?
    人 的一生, 究竟在追求什么? 这是一个没有标准答案的问题, 一千个人可能会有一千个不同的回答. 但我们应该知道成功有很多种定义, 有些人终生都在追逐名利, 他们生活得很快乐(也许), 有些人毕生都在灯红酒绿, 他们生活得也很幸福(当然); 还有更多的人在平淡充实, 日复一日的工作和生活中度过平凡的一生, 这又何尝不是一种幸福呢.
    或许, 真正的成功只有一个, 就是按照自己喜欢的方式, 去度过人生.
click
©2010-2024 Jeen All Rights Reserved.Powered by emlog 京ICP备15058100号-1