首页 > PHP开发 > Yii2 > Yii初学者必看
2014
12-11

Yii初学者必看

对yii深入了解总结出:希望对初学者有些帮助

Active Record (AR) 是一个流行的 对象-关系映射 (ORM) 技术。 每个 AR 类代表一个数据表(或视图),数据表(或视图)的列在 AR 类中体现为类的属性,一个 AR 实例则表示表中的一行。 常见的 CRUD 操作作为 AR 的方法实现。因此,我们可以以一种更加面向对象的方式访问数据。 例如,我们可以使用以下代码向 tbl_post 表中插入一个新行。

yii 表单验证规则

<?php
classContactFormextendsCFormModel
{
    public$_id;
    public$contact;//联系人
    public$tel;//电话
    public$fax;//传真
    public$zipcode;//邮编
    public$addr;//地址
    public$mobile;//手机
    public$email;//邮箱
    public$website;//网址
    public$qq;//QQ
    public$msn;//MSN
    publicfunctionrules()
    {
        returnarray(
            array('contact','required','on'=>'edit','message'=>'联系人必须填写.'),
            array('contact','length','on'=>'edit','min'=>2,'max'=>10,'tooShort'=>'联系人长度请控制在2-10个字符.','tooLong'=>'联系人长度请控制在2-10个字符.'),
             
            array('tel','match','pattern'=>'/^(\d{3}-|\d{4}-)(\d{8}|\d{7})?$/','message'=>'请输入正确的电话号码.'),
            array('fax','match','pattern'=>'/^(\d{3}-|\d{4}-)(\d{8}|\d{7})?$/','message'=>'请输入正确的传真号码.'),
            array('mobile','match','pattern'=>'/^13[0-9]{1}[0-9]{8}$|15[0189]{1}[0-9]{8}$|189[0-9]{8}$/','message'=>'请输入正确的手机号码.'),
 
            array('email','email','on'=>'edit','message'=>'邮箱输入有误.'),
             
            array('zipcode','required','on'=>'edit','message'=>'邮编必须填写.'),
            array('zipcode','numerical','on'=>'edit','message'=>'邮编是6位数字.'),
            array('zipcode','length','on'=>'edit','min'=>6,'max'=>6,'tooShort'=>'邮编长度为6位数.','tooLong'=>'邮编长度为6位数.'),
             
            array('website','url','on'=>'edit','message'=>'网址输入有误.'),
            array('qq','match','pattern'=>'/^[1-9]{1}[0-9]{4,11}$/','message'=>'请输入正确的QQ号码.'),
            array('msn','email','on'=>'edit','message'=>'MSN输入有误.'),
        );
    }
 
}

$post=Post::model()->find(array(
    'select'=>'title',
    'condition'=>'postID=:postID',
    'params'=>array(':postID'=>10),
));
// 查找 postID=10 的那一行
$post=Post::model()->find('postID=:postID', array(':postID'=>10));
$criteria = new CDbCriteria();
$criteria->select = 'table_name,model_id,sum(amount) total';
$criteria->group = 'table_name,model_id';
$criteria->addCondition("$nIdcId=4");//也可以$criteria->condition = "$nIdcId=4";
$aResult = accessory_info::model()->findAll($criteria);


$c = new CDbCriteria();
$c->select = 't.id, t.created_at, t.outsource_id, t.user_id, t.operate, t.content';
$c->join = 'LEFT JOIN outsource ON outsource.id=t.outsource_id';
$c->condition = 'outsource.idc_id IN(' . implode(',', $idc_ids)  . ')';

if($last_log_id) {
$c->condition .= " AND t.id > $last_log_id";
}

$c->limit = 20;
$c->order = 't.id DESC';

$logs = OutsourceProcessLog::model()->findAll($c);

array(
'header'=>'支付渠道',
'name'=>'buy_method_id',
'value'=>'$data->buyMethod->title',
'filter'=>CHtml::listData(CoinBuyMethod::model()->findAll(), 'id', 'title'),//filter过滤筛选
),
array(
'name' => 'admin.username',
'filter' => CHtml::activeDropDownList($model, 'admin_id', CHtml::listData(Admin::model()->findAll(), 'id', 'username'), array('empty' => '-全部管理员-')),
),


$post=new Post;
$post->title='sample post';
$post->content='post body content';
$post->save();

$User = User::model();
$User->setIsNewRecord(true);
$User->name='wangliweid';
$User->sex=1;
$User->insert();

$User = new User;
$User->name='wangdsdfliweid';
$User->insert();

$User = User::model()->findByPk(1);
$User->name='wangliwei';
$User->sex=1;
$User->save();

public function tableName()
{
    return '{{post}}'; //使用表前缀功能
}

$post=Post::model()->findByPk(10); // 假设有一个帖子,其 ID 为 10
$post->delete(); // 从数据表中删除此行

AR 依靠表中良好定义的主键。如果一个表没有主键,则必须在相应的 AR 类中通过如下方式覆盖 primaryKey() 方法指定哪一列或哪几列作为主键。

public function primaryKey()
{
    return 'id';
    // 对于复合主键,要返回一个类似如下的数组
    // return array('pk1', 'pk2');
}

3. 创建记录 
要向数据表中插入新行,我们要创建一个相应 AR 类的实例,设置其与表的列相关的属性,然后调用 save() 方法完成插入:

$post=new Post;
$post->title='sample post';
$post->content='content for the sample post';
$post->create_time=time();
$post->save();


记录在保存(插入或更新)到数据库之前,其属性可以赋值为 CDbExpression 类型。 例如,为保存一个由 MySQL 的 NOW() 函数返回的时间戳,我们可以使用如下代码:

$post=new Post;
$post->create_time=new CDbExpression('NOW()');
// $post->create_time='NOW()'; 不会起作用,因为
// 'NOW()' 将会被作为一个字符串处理。
$post->save();
提示: 由于 AR 允许我们无需写一大堆 SQL 语句就能执行数据库操作, 我们经常会想知道 AR 在背后到底执行了什么 SQL 语句。这可以通过开启 Yii 的 日志功能 实现。例如,我们在应用配置中开启了 CWebLogRoute ,我们将会在每个网页的最后看到执行过的 SQL 语句。

4. 读取记录 
要读取数据表中的数据,我们可以通过如下方式调用 find 系列方法中的一种:

// 查找满足指定条件的结果中的第一行
$post=Post::model()->find($condition,$params);
// 查找具有指定主键值的那一行
$post=Post::model()->findByPk($postID,$condition,$params);
// 查找具有指定属性值的行
$post=Post::model()->findByAttributes($attributes,$condition,$params);
// 通过指定的 SQL 语句查找结果中的第一行
$post=Post::model()->findBySql($sql,$params);


$criteria=new CDbCriteria;
$criteria->select='title';  // 只选择 'title' 列
$criteria->condition='postID=:postID';
$criteria->params=array(':postID'=>10);
$post=Post::model()->find($criteria); // $params 不需要了
注意,当使用 CDbCriteria 作为查询条件时,$params 参数不再需要了,因为它可以在 CDbCriteria 中指定,就像上面那样。

一种替代 CDbCriteria 的方法是给 find 方法传递一个数组。 数组的键和值各自对应标准(criterion)的属性名和值,上面的例子可以重写为如下:

$post=Post::model()->find(array(
    'select'=>'title',
    'condition'=>'postID=:postID',
    'params'=>array(':postID'=>10),
));



// 获取满足指定条件的行数
$n=Post::model()->count($condition,$params);
// 通过指定的 SQL 获取结果行数
$n=Post::model()->countBySql($sql,$params);
// 检查是否至少有一行复合指定的条件
$exists=Post::model()->exists($condition,$params);

直接更新数据表中的一行或多行而不首先载入也是可行的。 AR 提供了如下方便的类级别方法实现此目的:

// 更新符合指定条件的行
Post::model()->updateAll($attributes,$condition,$params);
// 更新符合指定条件和主键的行
Post::model()->updateByPk($pk,$attributes,$condition,$params);
// 更新满足指定条件的行的计数列
Post::model()->updateCounters($counters,$condition,$params);
在上面的代码中, $attributes 是一个含有以 列名作索引的列值的数组; $counters 是一个由列名索引的可增加的值的数组;$condition 和 $params 在前面的段落中已有描述。

如果一个 AR 实例被一行数据填充,我们也可以删除此行数据。

$post=Post::model()->findByPk(10); // 假设有一个帖子,其 ID 为 10
$post->delete(); // 从数据表中删除此行
注意,删除之后, AR 实例仍然不变,但数据表中相应的行已经没了。

使用下面的类级别代码,可以无需首先加载行就可以删除它。

// 删除符合指定条件的行
Post::model()->deleteAll($condition,$params);
// 删除符合指定条件和主键的行
Post::model()->deleteByPk($pk,$condition,$params);



当调用 save() 时, AR 会自动执行数据验证。 验证是基于在 AR 类的 rules() 方法中指定的规则进行的。 关于验证规则的更多详情,请参考 声明验证规则 一节。 下面是保存记录时所需的典型的工作流。

if($post->save())
{
    // 数据有效且成功插入/更新
}
else
{
    // 数据无效,调用  getErrors() 提取错误信息
}
当要插入或更新的数据由最终用户在一个 HTML 表单中提交时,我们需要将其赋给相应的 AR 属性。 我们可以通过类似如下的方式实现:

$post->title=$_POST['title'];
$post->content=$_POST['content'];
$post->save();

如果有很多列,我们可以看到一个用于这种复制的很长的列表。 这可以通过使用如下所示的 attributes 属性简化操作。 更多信息可以在 安全的特性赋值 一节和 创建动作 一节找到。

// 假设 $_POST['Post'] 是一个以列名索引列值为值的数组
$post->attributes=$_POST['Post'];
$post->save();


CActiveRecord 提供了几个占位符方法,它们可以在子类中被覆盖以自定义其工作流。

beforeValidate 和
beforeSave 和 afterSave: 这两个将在保存 AR 实例之前和之后被调用。
beforeDelete 和 afterDelete: 这两个将在一个 AR 实例被删除之前和之后被调用。
afterConstruct: 这个将在每个使用 new 操作符创建 AR 实例后被调用。
beforeFind: 这个将在一个 AR 查找器被用于执行查询(例如 find(), findAll())之前被调用。 1.0.9 版本开始可用。
afterFind: 这个将在每个 AR 实例作为一个查询结果创建时被调用。

10. 使用 AR 处理事务 
每个 AR 实例都含有一个属性名叫 dbConnection ,是一个 CDbConnection 的实例,这样我们可以在需要时配合 AR 使用由 Yii DAO 提供的 事务 功能:

$model=Post::model();
$transaction=$model->dbConnection->beginTransaction();
try
{
    // 查找和保存是可能由另一个请求干预的两个步骤
    // 这样我们使用一个事务以确保其一致性和完整性
    $post=$model->findByPk(10);
    $post->title='new post title';
    $post->save();
    $transaction->commit();
}
catch(Exception $e)
{
    $transaction->rollBack();
}

$url=$this->createUrl($route,$params);
$this指的是控制器实例; $route指定请求的route 的要求;$params 列出了附加在网址中的GET参数。

默认情况下,URL以get格式使用createUrl 创建。例如,提供$route='post/read'和$params=array('id'=>100) ,我们将获得以下网址:

/index.php?r=post/read&id=100

$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();

$command = Yii::app()->db->createCommand('SELECT * FROM tbl_user');
$user = $command->queryRow();

$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();

// 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 `tbl_user` SET `name`=:name WHERE id=:id
$command->update('tbl_user', array(
    'name'=>'Tester',
), 'id=:id', array(':id'=>1));

4. Building Schema Manipulation Queries 
Besides normal data retrieval and manipulation queries, the query builder also offers a set of methods for building and executing SQL queries that can manipulate the schema of a database. In particular, it supports the following queries:

createTable(): creates a table
renameTable(): renames a table
dropTable(): drops a table
truncateTable(): truncates a table
addColumn(): adds a table column
renameColumn(): renames a table column
alterColumn(): alters a table column
dropColumn(): drops a table column
createIndex(): creates an index
dropIndex(): drops an index

如果浏览器重定位到登录页面,而且登录成功,我们将重定位浏览器到引起验证失败的页面。我们怎么知道这个值呢?我们可以通过用户部件的returnUrl 属性获得。我们因此可以用如下执行重定向:

Yii::app()->request->redirect(Yii::app()->user->returnUrl);




$this->preinit();
$this->init();

self::$classMap 可以在这里定义类的路径,在autoload里调用

//页面缓存控制器入口
可在main.php 中  设置catchAllRequest
$route=$this->catchAllRequest[0];

CModule 重载了 Ccomponent 的__get 方法

Yii::setApplication($this); 将app设置为了application对象

先注册component,这时并没有加载他们,只有在getcomponet时才加载。


 var menuId = $("ul.nav").first().attr("id");var request = $.ajax({  url: "script.php",  type: "POST",  data: {id : menuId},  dataType: "html"}); request.done(function(msg) {  $("#log").html( msg );}); request.fail(function(jqXHR, textStatus) {  alert( "Request failed: " + textStatus );}); 

Example: Load and execute a JavaScript file.
 $.ajax({  type: "GET",  url: "test.js",  dataType: "script"}); 

设置cookie
$cookie = new CHttpCookie('mycookie','this is my cookie');
$cookie->expire = time()+60*60*24*30;  //有限期30天
Yii::app()->request->cookies['mycookie']=$cookie;
这里的cookies 继承了CCookieCollection ,他是CMap类型,重写了add等等,在add中设置了cookie.
比如$cookie = Yii::app()->request->cookies;
$cookies['name'] = $cookie;
复制
读取cookie:
$cookie = Yii::app()->request->getCookies();
echo $cookie['mycookie']->value;
复制
销毁cookie:
$cookie = Yii::app()->request->getCookies();
unset($cookie[$name]);

//异步提交
$('#g').click(function(){
$.post('index.php',$('form').serialize());
}); 

//在控制器中都会先执行init 再执行beforeAction

过滤器
public function filterAccessAuth($filterChain) {  
echo 'a';
$filterChain->run();
}

public function filterAbc($filterChain) {  
$filterChain->run();
}
public function filters() {  
        return array(  
            'accessAuth  + session',  
'abc',
        );  
    }

Similar to .empty(), the .remove() method takes elements out of the DOM. Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.

$.ajax({  url: "test.html",  context: document.body}).done(function() {  $(this).addClass("done");});

Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are deprecated as of jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

原生js设置属性
 this.style.color = "blue";
 js原生函数:decodeURIComponent()
最后为了更好的区分attribute和property,基本可以总结为attribute节点都是在HTML代码中可见的,而property只是一个普通的名值对属性。

 Yii中有个场景的概念,我们用到场景的地方主要是在model中定义rules规则的时候,可以对不同的场景使用不同的校验规则,所以,自然而然会认为所谓的场景就是对应的action的名字。其实场景和action的名字是不同的概念来的,不能混为一谈。scenario则是M的一种属性,理论上,scenario是独立于action概念的,可以在没有action的场合下使用scenario。model的scenario是通过设置它的scenario属性设置的,它和使用model的action没有任何关系。

比如:

$model=new User;
$model->scenario = 'create';


$model=new User('create');

都是设置了执行一个action的时候对model进行校验的场景

public function rules()
{
return array(
array('name','required'),
array('name', 'length', 'max'=>10,'min'=>5,'on'=>'a1 a2','except'=>'c1 c2'), on 用来设置场景,except用来排除场景
array('sex','required myvalitor'),
);
}

当model调用model->validate()时将加载rules中包含的类,每个涉及到的属性都会被被判断。

public function myvalitor($name,$params){}

$loginType = Yii::app()->controller->module->loginType;
Yii::app()->controller //当前请求的controller对象
Yii::app()->controller->module//当前请求的controller对象所属的module

在main的  'params' => include(dirname(__FILE__) . '/params.php'),里设置一些其他信息。

$this->redirect() //控制器的方法
$this->createUrl() //控制器的方法


public function run()
{
if($this->hasEventHandler('onBeginRequest'))
$this->onBeginRequest(new CEvent($this));
$this->processRequest();
if($this->hasEventHandler('onEndRequest'))
$this->onEndRequest(new CEvent($this));
}

public function run($actionID)
{
if(($action=$this->createAction($actionID))!==null)
{
if(($parent=$this->getModule())===null)
$parent=Yii::app();
if($parent->beforeControllerAction($this,$action))
{
$this->runActionWithFilters($action,$this->filters());
$parent->afterControllerAction($this,$action);
}
}
else
$this->missingAction($actionID);
}


//yii 执行流程
获取控制器,init,filters ,beforeAction,

filter 的循环
filter 链通过调用自身的run($this) 形成一个循环,循环结束条件为filter容器中的所有filter都执行完毕,如果一个filter没有运行run,那么action将不会执行,这样就实现了过滤作用。


public function filter($filterChain)
{
if($this->preFilter($filterChain))
{
$filterChain->run();
$this->postFilter($filterChain);
}
}
从上边可以看出,以类实现的filter,将过滤函数一般写在方法prefilter中

CActiveDataProvider provides data in terms of ActiveRecord objects which are of class modelClass. It uses the AR CActiveRecord::findAll method to retrieve the data from database. The criteria property can be used to specify various query options. 

$dataProvider=new CActiveDataProvider('Post', array(
    'criteria'=>array(
        'condition'=>'status=1',
        'order'=>'create_time DESC',
        'with'=>array('author'),
    ),
    'pagination'=>array(
        'pageSize'=>20,
    ),
));
// $dataProvider->getData() will return a list of Post objects

When data needs to be rendered in multiple pages, we can use CPagination to represent information such as total item count, page size, current page, etc. These information can be passed to pagers to render pagination buttons or links. 

Example: 

Controller action:
function actionIndex(){
    $criteria=new CDbCriteria();
    $count=Article::model()->count($criteria);
    $pages=new CPagination($count);

    // results per page
    $pages->pageSize=10;
    $pages->applyLimit($criteria);
    $models=Article::model()->findAll($criteria);

    $this->render('index', array(
    'models' => $models,
         'pages' => $pages
    ));
}


View:
<?php foreach($models as $model): ?>
    // display a model
<?php endforeach; ?>

// display pagination
<?php $this->widget('CLinkPager', array(
    'pages' => $pages,
)) ?>



/**
* Renders a view.
*
* The named view refers to a PHP script (resolved via {@link getViewFile})
* that is included by this method. If $data is an associative array,
* it will be extracted as PHP variables and made available to the script.
*
* This method differs from {@link render()} in that it does not
* apply a layout to the rendered result. It is thus mostly used
* in rendering a partial view, or an AJAX response.
*
* @param string $view name of the view to be rendered. See {@link getViewFile} for details
* about how the view script is resolved.
* @param array $data data to be extracted into PHP variables and made available to the view script
* @param boolean $return whether the rendering result should be returned instead of being displayed to end users
* @param boolean $processOutput whether the rendering result should be postprocessed using {@link processOutput}.
* @return string the rendering result. Null if the rendering result is not required.
* @throws CException if the view does not exist
* @see getViewFile
* @see processOutput
* @see render
*/
public function renderPartial($view,$data=null,$return=false,$processOutput=false)


/**
* Sends existing file to a browser as a download using x-sendfile.
*
* X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver
* that in turn processes the request, this way eliminating the need to perform tasks like reading the file
* and sending it to the user. When dealing with a lot of files (or very big files) this can lead to a great
* increase in performance as the web application is allowed to terminate earlier while the webserver is
* handling the request.
*
* The request is sent to the server through a special non-standard HTTP-header.
* When the web server encounters the presence of such header it will discard all output and send the file
* specified by that header using web server internals including all optimizations like caching-headers.
*
* As this header directive is non-standard different directives exists for different web servers applications:
* <ul>
* <li>Apache: {@link http://tn123.org/mod_xsendfile X-Sendfile}</li>
* <li>Lighttpd v1.4: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-LIGHTTPD-send-file}</li>
* <li>Lighttpd v1.5: {@link http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file X-Sendfile}</li>
* <li>Nginx: {@link http://wiki.nginx.org/XSendfile X-Accel-Redirect}</li>
* <li>Cherokee: {@link http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile X-Sendfile and X-Accel-Redirect}</li>
* </ul>
* So for this method to work the X-SENDFILE option/module should be enabled by the web server and
* a proper xHeader should be sent.
*
* <b>Note:</b>
* This option allows to download files that are not under web folders, and even files that are otherwise protected (deny from all) like .htaccess
*
* <b>Side effects</b>:
* If this option is disabled by the web server, when this method is called a download configuration dialog
* will open but the downloaded file will have 0 bytes.
*
* <b>Known issues</b>:
* There is a Bug with Internet Explorer 6, 7 and 8 when X-SENDFILE is used over an SSL connection, it will show
* an error message like this: "Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found.".
* You can work around this problem by removing the <code>Pragma</code>-header.
//需要加载这个模块
LoadModule xsendfile_module modules/mod_xsendfile.so
XSendFile on
XSendFilePath D:/

* <b>Example</b>:
* <pre>
* <?php
*    Yii::app()->request->xSendFile('/home/user/Pictures/picture1.jpg',array(
*        'saveName'=>'image1.jpg',
*        'mimeType'=>'image/jpeg',
*        'terminate'=>false,
*    ));
* ?>
 

* </pre>
* @param string $filePath file name with full path
* @param array $options additional options:
* <ul>
* <li>saveName: file name shown to the user, if not set real file name will be used</li>
* <li>mimeType: mime type of the file, if not set it will be guessed automatically based on the file name, if set to null no content-type header will be sent.</li>
* <li>xHeader: appropriate x-sendfile header, defaults to "X-Sendfile"</li>
* <li>terminate: whether to terminate the current application after calling this method, defaults to true</li>
* <li>forceDownload: specifies whether the file will be downloaded or shown inline, defaults to true. (Since version 1.1.9.)</li>
* <li>addHeaders: an array of additional http headers in header-value pairs (available since version 1.1.10)</li>
* </ul>
*/
public function xSendFile($filePath, $options=array())



CAction is the base class for all controller action classes. 
CAction provides a way to divide a complex controller into smaller actions in separate class files. 
Derived classes must implement run() which is invoked by controller when the action is requested.

 
CViewAction represents an action that displays a view according to a user-specified parameter.
By default, the view being displayed is specified via the view GET parameter. The name of the GET parameter can be customized via viewParam. If the user doesn't provide the GET parameter, the default view specified by defaultView will be displayed. 
Users specify a view in the format of path.to.view, which translates to the view name BasePath/path/to/view where BasePath is given by basePath. 

CForm represents a form object that contains form input specifications.

The main purpose of introducing the abstraction of form objects is to enhance the reusability of forms. In particular, we can divide a form in two parts: those that specify each individual form inputs, and those that decorate the form inputs. A CForm object represents the former part. It relies on the rendering process to accomplish form input decoration. Reusability is mainly achieved in the rendering process. That is, a rendering process can be reused to render different CForm objects. 

A form can be rendered in different ways. One can call the render method to get a quick form rendering without writing any HTML code; one can also override render to render the form in a different layout; and one can use an external view template to render each form element explicitly. In these ways, the render method can be applied to all kinds of forms and thus achieves maximum reusability; while the external view template keeps maximum flexibility in rendering complex forms. 

Form input specifications are organized in terms of a form element hierarchy. At the root of the hierarchy, it is the root CForm object. The root form object maintains its children in two collections: elements and buttons. The former contains non-button form elements (CFormStringElement, CFormInputElement and CForm); while the latter mainly contains button elements (CFormButtonElement). When a CForm object is embedded in the elements collection, it is called a sub-form which can have its own elements and buttons collections and thus form the whole form hierarchy. 

Sub-forms are mainly used to handle multiple models. For example, in a user registration form, we can have the root form to collect input for the user table while a sub-form to collect input for the profile table. Sub-form is also a good way to partition a lengthy form into shorter ones, even though all inputs may belong to the same model. 


$components=array(
'coreMessages'=>array(
'class'=>'CPhpMessageSource',
'language'=>'en_us',
'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages',
),
'db'=>array(
'class'=>'CDbConnection',
),
'messages'=>array(
'class'=>'CPhpMessageSource',
),
'errorHandler'=>array(
'class'=>'CErrorHandler',
),
'securityManager'=>array(
'class'=>'CSecurityManager',
),
'statePersister'=>array(
'class'=>'CStatePersister',
),
'urlManager'=>array(
'class'=>'CUrlManager',
),
'request'=>array(
'class'=>'CHttpRequest',
),
'format'=>array(
'class'=>'CFormatter',
),
)

$components=array(
'session'=>array(
'class'=>'CHttpSession',
),
'assetManager'=>array( 
'class'=>'CAssetManager',
),
'user'=>array(
'class'=>'CWebUser',
),
'themeManager'=>array(
'class'=>'CThemeManager',
),
'authManager'=>array(
'class'=>'CPhpAuthManager',
),
'clientScript'=>array(
'class'=>'CClientScript',
),
'widgetFactory'=>array(
'class'=>'CWidgetFactory',
),
);

<script>
jQuery.validator.addMethod('username',function(value, element, param) {
return false;
},'ni {0} ming zhi shu cuo le');

jQuery.validator.addMethod('cardNum',function(value,element,param){
return CardNumber.check(value,true);
},'请输入正确的身份证号码');

$('form').validate({
  keyup:false,
        rules: {
username : {
cardNum : true
}
}
})
</script>


jQuery.validator.addMethod('anoy',function(value,element,func){
return func;
});


$('form').validate({
rules:{
pass1 : {
anoy : function(){ console.log(arguments);return false;}
}
}
});

$(element).parentsUntil('table').find('input[name="pass2"]').val();

jQuery.validator.addClassRules('pas', {
        pass1: true 
    });


jQuery.validator.addMethod('username',function(value, element, param) {
return false;
},'ni {0} ming zhi shu cuo le');

jQuery.validator.addMethod('cardNum',function(value,element,param){
return CardNumber.check(value,true);
},'请输入正确的身份证号码');

jQuery.validator.addMethod('pass1',function(value,element,param){
return value == $(element).parentsUntil('table').find('input[name="pass2"]').val();
},'error');

jQuery.validator.addClassRules('pas', {
        pass1: true 
    });
$('form').validate({
rules:{
'pass1' : {
pass1 : true
}
}
});
if($(':input[name="isWrite"][checked]').val() == 1 )

A typical authentication process using CWebUser is as follows:
The user provides information needed for authentication.
An {@link IUserIdentity identity instance} is created with the user-provided information.
Call {@link IUserIdentity::authenticate} to check if the identity is valid.
If valid, call {@link CWebUser::login} to login the user, and Redirect the user browser to {@link returnUrl}.
If not valid, retrieve the error code or message from the identity instance and display it.


Yii::app()->user->setFlash('success', "Data1 saved!");
Yii::app()->user->setFlash('error', "Data2 failed!");
Yii::app()->user->setFlash('notice', "Data3 ignored.");
Display them in your view:

<?php
    foreach(Yii::app()->user->getFlashes() as $key => $message) {
        echo '<div class="flash-' . $key . '">' . $message . "</div>\n";
    }
?>
Setting flash messages 
A flash message is used in order to keep a message in session through one or several requests of the same user. By default, it is removed from session after it has been displayed to the user. Flash messages are usually used in combination with HTTP redirections, because in this case there is no view, so messages can only be displayed in the request that follows redirection.

www.ixuesi.com


CWebUser 和 CUserIdentity 的关系
CUserIdentity 通过用户名和密码验证用户,获取用户id,CWebUser可根据Id获取用户信息,保存在session中。
也可在CUserIdentity中获取信息到stats中,然后传递到CWebUser中

CAccessControlFilter 内部也是通过调用user->checkAccess()来判断权限
user里边通过CauthManager来提供checkAccess()方法。
可以利用filter 和 User->checkAccess()来使用yii的权限系统。当然也可以直接调用AuthManager来使用,这时需要手动传递User了。

可以再model的自定义rule中使用addError($attribute,$value)来添加一个错误,必须使用adderror,返回false是不起作用的。

keepalive="true": To conserve battery power and cpu usage, Paper.js normally stops all animation events when the window is not focused. If you want it to keep playing animations, even if the window is in the background, set keepalive="true" in your canvas tag. And again for validation, data-paper-keepalive="true" works as well.

CController中已经定义了三个filter:filterAccessControl,filterAjaxOnly,filterPostOnly,filterAccessControl需要和accessRules配合使用,
public function filterAccessControl($filterChain)
{
$filter=new CAccessControlFilter;
$filter->setRules($this->accessRules());
$filter->filter($filterChain);
}
public function filters()
    {
        return array(
            'accessControl',
        );
    }
public function accessRules()
    {
        return array(
            array('deny',
                'actions'=>array('create', 'edit'),
                'users'=>array('?'),
            ),
            array('allow',
                'actions'=>array('delete'),
                'roles'=>array('admin'),
            ),
            array('deny',
                'actions'=>array('delete'),
                'users'=>array('*'),
            ),
        );
    }

Yii::import()注册一个类路径

module里的一个函数
public function init()
{
$this->setImport(array(
'application.modules.user.models.*',
'application.modules.user.components.*',
));
}

public function filters() {  
return array(  
'accessControl', //本地函数一个简单的字符串,外部类要写在数组中
array(
'COutputCache + list',
'duration'=>300,
),
);  
}

##python  
shutil — High-level file operations

编程技巧