Yii2.0 字段验证 日期验证 DateValidator

使用yii验证日期 [php] public function rules() { return [ [array_keys($this->attributeLabels()), 'trim'], [['pop_id', 'start_day', 'end_day'], 'required'], [['pop_id'], 'integer'], [['start_day', 'end_day'], 'date', 'message' => " {attribute} 格式不正确"], ]; } [/php] start_day 为2016-03-24 总是返回不正确  可是默认的验证格式就是Y-m-d 最后发现要这么写才行 真是坑啊 [php] public function rules() { return [ [array_keys($this->attributeLabels()), 'trim'], [['pop_id', 'start_day', 'end_day'], 'required'], [['pop_id'], 'integer'], [['start_day', 'end_day'], 'date', 'format' => 'php:Y-m-d', 'message' => " {attribute} 格式不正确"], ]; } [/php]

YII访问数据库(Yii Dao)

CDbConnection: 一个抽象数据库连接 CDbCommand: SQL statement CDbDataReader: 匹配结果集的一行记录 CDbTransaction:数据库事务 访问数据库前需要建立数据库连接;使用DAO建立一个抽象数据库链接: $connection = new CDbConnection($dsn, $username, $password); $connection->active = true;     // 只有激活了连接才可以使用 // 想要关闭连接,可以这样: $connection->active = false; CDbConnection继承自CApplicationComponent,所以他可以像组件一样在任何地方使用。因此可以这样访问: Yii::app()->db //执行SQL语句需要CDbCommand对象,而该对象由CdbConnection::createCommand()返回,因此: $connection=Yii::app()->db; $command=$connection->createCommand($sql); // 如果SQL语句想要完全有自己写,可以这样: $newSQL = '写下你令人惊讶的SQL语句'; $command->text=$newSQL; // CDbCommand对象有两个方法execute()用于非查询SQL执行,而query(),通俗的讲就是用于SELECT查询 // execute()返回的是INSERT, UPDATE and DELETE操作受影响的记录行数 // query()返回一个CDbDataReader对象,使用CDbDataReader对象可以遍历匹配结果集中的所有记录。 $rowCount=$command->execute();  // execute the non-query SQL $dataReader=$command->query();  // execute a query SQL // 返回CDbDataReader对像 $rows=$command->queryAll();     // query and return all rows of result $row=$command->queryRow();      // query and return the first row of result $column=$command->queryColumn();    // query and return the first column of result $value=$command->queryScalar();     // query and return the first field in the first row // query()返回的是代表结果集的对象而非直接的结果,因此要获取结果集的记录可以这样: $dataReader=$command->query(); // CDbDataReader::read()可以一次获取一行数据,到末尾时返回false while(($row=$dataReader->read())!==false) // CDbDataReader实现了迭代器接口因此可以使用foreach遍历 foreach($dataReader as $row) // 一次性返回所有的记录(数组) $rows=$dataReader->readAll(); queryXXX() 形式的方法会直接返回匹配的记录集合,当query()不是,他返回一个代表结果集的对象 // YII中的CDbTransaction类用于事务 // 首先,建立一个连接 $connection = Yii::app()->db; // 第二,开始事务 $transaction=$connection->beginTransaction(); // 第三,执行SQL,如果错误就抛出异常,在异常处理中回滚。 try { $connection->createCommand($sql1)->execute(); $connection->createCommand($sql2)->execute(); //.... other SQL executions // 如果SQL执行都没有抛出异常,那就提交。 $transaction->commit(); } catch(Exception $e) { $transaction->rollBack();   // 在异常处理中回滚 } // 执行SQL中,一般都需要绑定一些用户参数,对于用户参数,需要防止SQL注入攻击 // PDO对象的绑定参数的方法可以防止SQL注入攻击,同样扩展自PDO的DAO也有这样的功能 // 举例说明: // 第一,建立一个连接: $connection = Yii::app()->db; // 第二,写下无敌的SQL语句,比如: $sql="INSERT INTO tbl_user (username, email) VALUES(:username,:email)"; // 第三,创建CDbCommand对象用于执行SQL $command=$connection->createCommand($sql); // 接下来,将SQL语句中的形式参数,替换为实际参数 $command->bindParam(":username",$username,PDO::PARAM_STR);   // 这与PDO有点不同,PDO中不带冒号 $command->bindParam(":email",$email,PDO::PARAM_STR);    // 同样 // 最后,执行 $command->execute(); // 如果还有其他的数据需要插入,可以再次绑定实参。 // 使用CDbDataReader对象的bindColumn()方法将结果集中的列绑定到PHP变量。 // 因此,读取一行记录,列值将自动填充到对应的PHP对象中 // 比如这样: $connection = Yii::app()->db; $sql = "SELECT username, email FROM tbl_user"; $dataReader = $connection->createCommand($sql)->query();    //很赞的方法链, 可惜不能接着.each() $dataReader->bindColumn(1, $username);  //第一列值绑定到$username $dataReader->bindColumn(2, $email);     //第二列值绑定到$email //接着循环读取并操作数据 while( $dataReader->read() !== false ) { ... // 与先前的 while(($row=$dataReader->read())!==false) 有所不同哦! } // 设置表前缀,使用 CDbConnection::tablePrefix 属性在配置文件中设置 // // Yii实现了把一条完整的SQL语句完完全全肢解的能力,比如这样: $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();       // 返回匹配的结果集的第一行 // 其实这条语句可以这样写: $newSQL ='SELECT id, username, profile from tbl_user u INNER JOIN tbl_profile p ON u.id = p.user_id WHERE u.id =:id' // 肢解法反倒让我感到厌烦了。。。。。。。。。 // yii提供了一种构建SQL的机制(也就是说不用自己写长长的SQL) // 首相要实例化一个CDbCommand对象 $command = Yii::app()->db->createCommand();     // 注意参数留空了。。 // 可用的方法列表如下: ->select(): SELECT子句 ->selectDistinct(): SELECT子句,并保持了记录的唯一性 ->from():         构建FROM子句 ->where():        构建WHERE子句 ->join():         在FROM子句中构建INNER JOIN 子句 ->leftJoin():     在FROM子句中构建左连接子句 ->rightJoin():    在FROM子句中构建右连接子句 ->crossJoin():    添加交叉查询片段(没用过) ->naturalJoin():  添加一个自然连接子片段 ->group():        GROUP BY子句 ->having():       类似于WHERE的子句,但要与GROUP BY连用 ->order():        ORDER BY子句 ->limit():        LIMIT子句的第一部分 ->offset():       LIMIT子句的第二部分 ->union():        appends a UNION query fragment select()默认返回全部列 // 但你可以这样: select('username, email'); // 或使用表限定,或使用别名 select('tbl_user.id, username name'); // 或使用数组作为参数 select(array('id', 'count(*) as num')); // 使用form() 如果制定了多个表需要使用逗号分隔的字符串,就像原生SQL语句那样: from('tbl_user, tbl_post, tbl_profile'); // 当然,你也可以使用表别名, 还可以使用完整的数据库限定名 from('tbl_user u, public.tbl_profile p'); WHERE子句 // 在where()中使用 AND where(array('and', 'id=:id', 'username=:username'), array(':id'=>$id, ':username'=>$username); // 在where()中使用 OR 与 AND用法相同,如下:  ##看起来比直接写更加繁琐## where( array('and', 'type=1', array('or', 'id=:id','username=:username') ),array(':id'=>$id, ':username'=>$username )); // IN 操作符用法 where(array('in', 'id', array(1,2,3))) // LIKE 用法 where( array('like', 'name', '%tester%') ); where( array('like','name', array('%test%', '%sample%')) ) // 等于 name LIKE '%test%' AND name LIKE '%sample% // 再这样复杂下去, 使用这种方法简直是自杀行为。 $keyword=$ GET['q']; // escape % and characters $keyword=strtr($keyword, array('%'=>'n%', ' '=>'n ')); $command->where(array('like', 'title', '%'.$keyword.'%')); // 添加了这么多,你都不知道合成后的SQL长啥样了,可以使用->text查看(魔术方法) // 如果觉得组合的SQL没有错误,那就执行他,添加->queryAll(); 这可以获得所有匹配的结果集。 // 当然,如果你确定执行的结果集中只有一行,可以添加->queryRow();来直接获取。 // 如果一个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(); /// YII的SQL构建函数就是一鸡肋。 // Active Record // 使用AR以面向对象的方式访问数据库,AR实现了ORM技术 // 当Post类表示表tbl_post时,我们可以使用这样的方式插入一条数据 $post = new Post(); $post->title = 'new title'; $post->content = 'new content'; $post->save();      // 保存即插入 // AR最典型的功能就是执行CRUD操作 // DAO定位于解决复杂的数据库查询,而AR定位于解决简单的数据库查询 // 一个AR类代表一张数据表,而一个AR对象代表表中的一行真实的记录,AR类继承CActiveRecord。 // 如果有一张POST表`tbl_post`,你可以这样定义一个AR类 class Post extends CACtiveRecord { public static function model($className = __CLASS__) { return parent::model($className); } public function tablName() { return '{{post}}'; } } // 表中的每一个字段都由AR类中的一个属性表示,如果试图通过属性访问表中没有字段,将会抛出一个异常。 // 一个AR一定需要一个主键,如果某张表没有主键,你就自己在类中伪造一个,像这样: public function primaryKey() { return 'id';        // 'id' 是关联表中的一个字段,但他不是主键,现在将它指定为主键 } // 实例化一个AR,填写信息(类似于填充用户提交的信息),然后保存 $post = new Post; $post->title = 'sample post'; $post->content = 'content for the sample post'; $post->create_time = time(); $post->save();  // 保存/插入 // 通过AR读取记录 fine() findByPk() findByAttributes() findBySql() $post=Post::model()->find($condition,$params);                  // 返回Post对象(如果有匹配记录的话), 否则返回NULL $post=Post::model()->findByPk($postID,$condition,$params); $post=Post::model()->findByAttributes($attributes,$condition,$params); $post=Post::model()->findBySql($sql,$params); // find()的一个例子: $post=Post::model()->find('postID=:postID', array(':postID'=>10)); // 如果查询条件很是复杂,就要使用CDbCriteria类 $criteria = new CDbCriteria; $criteria->select='title'; $creteria->condition='postID=:postID'; $criteria->params=array(':postID'=>10); $post=Post::model()->find($criteria);   // 不需要第二个参数 // 另一种更好的写法 $post=Post::model()->find(array( 'select' => 'title', 'condition' => 'postID=:postID', 'params' => array(':postID' => 10) )); // 如果查找的是多行记录可以使用 findAll() findAllByPk() findAllByAttributes() findAllBySql() // find all rows satisfying the specified condition $posts=Post::model()->findAll($condition,$params); // find all rows with the specified primary keys $posts=Post::model()->findAllByPk($postIDs,$condition,$params); // find all rows with the specified attribute values $posts=Post::model()->findAllByAttributes($attributes,$condition,$params); // find all rows using the specified SQL statement $posts=Post::model()->findAllBySql($sql,$params); // 如果没有匹配的行,将返回一个空数组,这可以用empty()去检测 // 另外的一些可以使用的方法: // get the number of rows satisfying the specified condition $n=Post::model()->count($condition,$params); // get the number of rows using the specified SQL statement $n=Post::model()->countBySql($sql,$params); // check if there is at least a row satisfying the specified condition $exists=Post::model()->exists($condition,$params); // 使用AR更新记录 // 一个典型的实例: $post=Post::model()->findByPk(10); $post->title='new post title'; $post->save(); // save the change to database // 怎么知道这是一条新纪录还是一条旧的记录呢?使用如下方法: if( CActiveRecord::isNewRecord ) // update the rows matching the specified condition Post::model()->updateAll($attributes,$condition,$params); // update the rows matching the specified condition and primary key(s) Post::model()->updateByPk($pk,$attributes,$condition,$params); // update counter columns in the rows satisfying the specified conditions Post::model()->updateCounters($counters,$condition,$params); // 删除记录 $post=Post::model()->findByPk(10); // assuming there is a post whose ID is 10 $post->delete(); // delete the row from the database table // 注意,当删除记录之后,$post仍然可用, 且保留了原始数据。 // 类级别的方法 // delete the rows matching the specified condition Post::model()->deleteAll($condition,$params); // delete the rows matching the specified condition and primary key(s) Post::model()->deleteByPk($pk,$condition,$params); // 数据验证 // 将用户提交的数据保存到AR对象中 $post->title = $_POST['title']; $post->content = $_POST['content']; $post->save(); // assume $ POST['Post'] is an array of column values indexed by column names $post->attributes=$ POST['Post']; $post->save(); // RAR:Relatived Actie Record // RAR本质上就是执行关系数据查询 // 如何让一个AR关联另一个AR // 4中关系类型 self::BELONGS_TO self::HAS_MANY self::HAS_ONE self::MANY_MANY 关系名称(关系类型,要关联的类名,外键名,其他额外的选项); // 定义表关系 类:Post public function relations() { return array( 'author'=>array(self::BELONGS_TO, 'User', 'author_id'),     // 返回User对象 'categories'=>array(self::MANY_MANY, 'Category', 'tbl_post_category(post_id, category_id)'), ); } // 类:User public function relations() { return array( 'posts' => array(self::HAS_MANY, 'Post', 'author_id'), 'profile' => array(self::HAS_ONE, 'Profile', 'owner_id') ); } // 定义了AR间的关系之后,当执行关系查询时,与AR关联的AR也会自动实例化, 比如这样: $author = User::model()->findByPk(1); $author->posts;         // posts关系已经定义。 // 执行关系查询 1).lazy loading approach 懒惰关系执行 // retrieve the post whose ID is 10 $post=Post::model()->findByPk(10); // retrieve the post's author: a relational query will be performed here $author=$post->author;  // 如果先前没有执行过,现在才执行这个关系查询(事情拖到这一步才做,真的是很懒啊!) // 如果关系查询执行后没有匹配的结果,返回将会是NULL或空的数组。 2).eager loading approach   热心的关系查询 //这名字真的很萌! // 也就是说一次性取回所有你想要的记录。管你要不要,这这这,太热心了吧! $posts=Post::model()->with('author')->findAll(); // SQL => 'SELECT tbl_post.*, author.* FROM tbl_post t INNER JOIN tbl_user author ON t.author = tbl_user.id' $posts=Post::model()->with('author','categories')->findAll(); // SQL => 'SELECT * FROM tbl_post t INNER JOIN tbl_user u ON t.author = u.id INNER JOIN categories c ON t.id = c.post_id' $posts=Post::model()->with( 'author.profile', 'author.posts', 'categories')->findAll(); $criteria=new CDbCriteria; $criteria->with=array( 'author.profile', 'author.posts', 'categories', ); $posts=Post::model()->findAll($criteria); 或者 $posts=Post::model()->findAll(array( 'with'=>array( 'author.profile', 'author.posts', 'categories', ) ); // 如果我们想知道用户中谁发过帖子,并且帖子的状态是“公开”。我们并不关心用户发表过的帖子的内容。 $user = User::model()->with('posts')->findAll(); 'VS' $user = User::model()->with(array( 'posts' => array( 'select' => false, 'joinType' => 'INNER JOIN', 'condition' => 'posts.published = 1' ), ) )->findAll(); // 返回的将会是所有发过帖子(且帖子已经公开)的用户 // 在relatinos()中定义更加复杂的关系 class User extends CActiveRecord { public function relations() { return array( 'posts'=>array(self::HAS MANY, 'Post', 'author id', 'order'=>'posts.create time DESC', 'with'=>'categories'), 'profile'=>array(self::HAS ONE, 'Profile', 'owner id'), ); } } // 利用别名解决歧义 $posts=Post::model()->with('comments')->findAll(array( 'order'=>'t.create time, comments.create time' )); // Dynamic Relational Query 动态关系SQL查询,更改默认插叙条件: User::model()->with(array( 'posts'=>array('order'=>'posts.create time ASC'), 'profile', ))->findAll(); $user=User::model()->findByPk(1); $posts=$user->posts(array('condition'=>'status=1'));        // 返回的都是AR对象, 而不是数据 // 统计查询 class Post extends CActiveRecord { public function relations() { return array( 'commentCount'=>array(self::STAT, 'Comment', 'post_id'), 'categoryCount'=>array(self::STAT, 'Category', 'post_category(post_id, category_id)'), ); } }

如何在yii的controller中调用外部action

在yii中,一个controller会包含若干个action。有时为了重用或代码管理等目的,我们希望这些action可以单独定义成一个类,然后在controller中使用。那么在yii中要如何实现呢?
假设我们有这样一个例子
TestController.php,文件位于wwwroot/blog/controllers/,wwwroot对应http://www.example.com/
代码如下:
[php] <?php class TestController extends Controller { public function actionHello($name='ball'){ echo "hello $name"; } } [/php]
代码功能很简单,接收一个名字参数,显示hello $name。
访问:
http://www.example.com/blog/index.php?r=test/hello&name=xuan 页面显示:
hello xuan注: actionHello函数的$name参数最好有默认值。不然当url中无$name参数时页面会报错。
实现
下面我们要做的是,将actionHello形成一个单独的类,在TestController中调用它。
1. 建立wwwroot/blog/controllers/test/目录
目录名定为test是yii推荐的写法,建议action所在的目录与对应的controller同名,当然不这样也没有关系。
2.在test目录中创建HelloAction.php文件
文件内容如下:
[php] <?php class HelloAction extends CAction{ public function run($name='ball'){ echo "Hello $name"; } } [/php]
注意:  
1.此类一定要继承自CAction类
2.必须有run方法供外部调用
3.run方法的参数,即为url中的请求参数。当然也可以通过$_GET的方式在函数内部取得
3.修改TestController.php
[php] <?php class TestController extends Controller { public function actions(){ return array('hello'=>array( 'class'=>'application.controllers.test.HelloAction', ) ); } } [/php]
好了,看看我们的成果吧,访问:
http://www.example.com/blog/index.php?r=test/hello&name=xuan 页面显示:
hello xuan
注: 对于'class'=>'application.controllers.test.HelloAction'在官方例子中你也许会看到类似'class'=>'HelloAction'的写法。 不要困惑,其实目的是一样。本例中之所以写为“application.controllers.test.HelloAction”,是因为test目录不在yii自动加载范畴。 如果之前有导入:Yii::import('application.controllers.test.*'); 那么'class'=>'HelloAction'就可以正常工作了。
More
1. 如果TestController同时定义了上述actions规则,又包含了actionHello方法会怎么样呢?
答案是优先执行actionHello方法,actions相应的规则不生效。
2.controller中如果有特殊的参数要传给actoin,如何处理?
通过actoins方法中的规则传递。
代码类似
[php] return array( 'action'=>array( 'class'=>'path.to.ActionClass', 'property1'=>'value1', 'property2'=>'value2', ), ); [/php]
但action中必须有相应的property属性,且设为public。 对应本文的例子,假设TestController要传一个somthingToSay给HelloAction,代码如下: TestController.php
[php] <?php class TestController extends Controller { public function actions(){ return array('hello'=>array( 'class'=>'application.controllers.test.HelloAction', 'somethingToSay'=>'welcome to yii', )); } } [/php]
HelloAction.php
[php] <?php class HelloAction extends CAction{ public $somethingToSay = ''; public function run($name='ball'){ echo "Hello $name, {$this->somethingToSay}."; } } [/php]
访问 http://www.example.com/blog/index.php?r=test/hello&name=xuan 页面显示: Hello xuan, welcome to yii.

YII Console

可以用来做定时程序通过命令运行代码,非url访问方式更安全 1.yiic 命令用到的是yiic.php 2.控制台的命令配置文件是应用的protected/config/console.php文件,系统默认的路径是protected/commands/shell 如果你执行单一的任务,直接在run方法里面写,另外一种就是同写你的Controller(控制器),前面增加actionXXX protected/extensions/clean_command/ECleanCommand.php [php] <?php class ECleanCommand extends CConsoleCommand { public $webRoot = null; public function getHelp() { $out = "Clean command allows you to clean up various temporary data Yii and an application are generating.\n\n"; return $out.parent::getHelp(); } public function actionCache() { $cache=Yii::app()->getComponent('cache'); if($cache!==null){ $cache->flush(); echo "Done.\n"; } else { echo "Please configure cache component.\n"; } } public function actionAssets() { if(empty($this->webRoot)) { echo "Please specify a path to webRoot in command properties.\n"; Yii::app()->end(); } $this->cleanDir($this->webRoot.'/assets'); echo "Done.\n"; } public function actionRuntime() { $this->cleanDir(Yii::app()->getRuntimePath()); echo "Done.\n"; } private function cleanDir($dir) { $di = new DirectoryIterator ($dir); foreach($di as $d) { if(!$d->isDot()) { echo "Removed ".$d->getPathname()."\n"; $this->removeDirRecursive($d->getPathname()); } } } private function removeDirRecursive($dir) { $files = glob($dir.'*', GLOB_MARK); foreach ($files as $file) { if (is_dir($file)) $this->removeDirRecursive($file); else unlink($file); } if (is_dir($dir)) rmdir($dir); } } [/php] console.php,commandMap配置后不需要指定yiic shell index.php [php] <?php // This is the configuration for yiic console application. // Any writable CConsoleApplication properties can be configured here. return array( 'basePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..', 'name' => 'My Console Application', // 'components' => array(), 'commandMap' => array( 'clean' => array( 'class' => 'ext.clean_command.ECleanCommand', 'webRoot' => 'E:\Apache2\htdocs\webapp', //注意修改 class::webRoot ), 'rbac' => array( 'class' => 'application.commands.shell.RbacCommand', ) ), ); [/php] 命令行运行cd E:\Apache2\htdocs\webapp\protected\ 进入yiic.php的目录 yiic clean [php] Usage: E:\Apache2\htdocs\webapp\protected\yiic.php clean <action> Actions: cache assets runtime [/php] yiic clean cache yiic clean assets [php] E:\Apache2\htdocs\webapp\protected>yiic clean assets Removed E:\Apache2\htdocs\webapp/assets\1f5cfc05 Removed E:\Apache2\htdocs\webapp/assets\836290cc Done. [/php] yiic clean runtime

Yii技巧汇集

YII 点滴 一、从yii权威指中学到的 db组件 'schemaCachingDuration'=>3600, 为什么不起做用? 需要开缓存 如何在页面下边显示sql的查询时间 在log组件的routes中加入 array( 'class'=>'CProfileLogRoute', 'levels'=>'error, warning', ) 同时在db组件中加入 'enableProfiling'=>true, 同时在这种情况下,可以用CDbConnection::getStats() 查看执行了多少个语句,用了多少时间 如何知道某一个程序段运行需要的时间 配置好CProfileLogRoute后,在需要测试的地方加上 Yii::beginProfile('blockID'); //程序段 Yii::endProfile('blockID'); 'enableParamLogging'=>true,的作用是? 在日志的bind的参数后边跟数的值 如何在页面底部显示所有的db相关的日志 同上,配置log组件的routes中加入 array( 'class'=>'CWebLogRoute', 'levels'=>'trace, info, error, warning', 'categories' => 'system.db.*', //'showInFireBug' => true, 将在firebug中显示日志 ), 把日志记录到数据库 array( 'class'=>'CDbLogRoute', 'logTableName'=>'applog', 'connectionID'=>'db', ), 运行时表applog会自动生成,如果不能生成,参照api自已建立 如何记录$_GET,$_SESSION等信息,在以上的routes中各个配置中加上 'filter'=>'CLogFilter', log配置中的level设置不对,可能会得不到日志信息 另外level,category的值可以随便写, 只要在用yii::Log("","自定义level","自定义的category")时对应起来即可 如何记录更详细的信息,能记录stack,在入口文件中加上 define('YII_TRACE_LEVEL',10);数字越大,记当的越详细,结果如下 [15:31:57.226][trace][system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `Bangdan` in E:APMServ5.2.6wwwhtdocsdayouhui.comprotectedmodelsBangdan.php (21) in E:APMServ5.2.6wwwhtdocsdayouhui.comprotectedcomponentsHotBangdan.php (21) in E:APMServ5.2.6 如果在调试时,终止程序运行且看到日志,不能用die及exit; 用application::end,即Yii::app()->end(),其会触发onEndRequest事件,日志就是在这个事件中记录的 activeRecord几个占位方法重写的注意点 必须带boolean返回值 如何发布一个资源文件并引用 $css=Yii::app()->getAssetManager()->publish(dirname(__FILE__)."/aa.css"); yii::app()->clientScript->registerCssFIle($css); 如果改变activelable中默认的标题 重写方法attributeLabels 过滤不良代码 $purifier=new CHtmlPurifier; $purifier->options=array("HTML.Allowed"=>"div"); $content=$purifier->purify($content); 或者 <?php $this->beginWidget('CHtmlPurifier'); ?> ...display user-entered content here... <?php $this->endWidget(); ?> 如何防止重复提交? 提交后 Ccontroler->refresh(); 如何在成功后显示一个提示,用户刷新页时去掉提示 Cwebuser->setFlash(); getFlash(); 如何防止重复提交, 并在提交成功后给出提示? 控制器中 Yii::app()->user->setFlash('submit','thanks'); $this->refresh(); view中 if(Yii::app()->user->hasFlash('submit')){ echo Yii::app()->user->getFlash('submit'); } 一般我们是跳转到列表页,或用redirect跳到编辑页,就不需要了,如果还是要显示当前页 以上就有用了,比如在当前时显示,编辑或添加新的记录 如何分页 itemCount总记录条数 CPagination代表分页信息,有多少页,每页几条记录等 CLinkPager生成分页的代码,自定义css可以给属性cssFile一个值 $criteria=new CDbCriteria(); $pages=new CPagination("数据库中的总记录数"); $pages->pageSize=2; $pages->applyLimit($criteria);//给$criteria->limit offset等符值 $posts=Post::model()->findAll($criteria); $this->widget('CLinkPager',array('pages'=>$pages)); 列表如何排序 $criteria=new CDbCriteria(); $sort = new CSort('Post'); $sort->defaultOrder=" status asc"; $sort->applyOrder($criteria); $posts=Post::model()->findAll($criteria); 应用时用 $sort->link('字段名') 实际是生成一个带参数的url,然后在在applyOrder时应用这些参数修改$criteria,得到相应的查寻结果 如何生成并验证验证码: 基本用法 <?php $this->widget('CCaptcha'); ?>  具体参数查手册 原理CCaptcha这个widget会在run时调用当前控制器的$captchaAction='captcha'方法,这个方法指到一个类CCaptchaAction 其会生成验证码图象,并记入到session中 如何显示静态页 重写actions 'help'=>array( 'class'=>'CViewAction', 'basePath'=>'help', //指定目录名 'defaultView'=>'default', 'viewParam'=>'help' //get参数 ), 假定当前控制器是post 那么可以能过/post/help/help/content访问help目录下的content.php 可以建立子目录比如help/reigterhelp/content.那可以通过/post/help/help/registerhelp.content来访问 用CViewAction的好处时,可以与其它的view共享layout 关于没有权限访问跳转的url相关 当没有权限时调用CAccessControlFilter类中的accessDenied,其调用CwebUser中的loginRequired(),记录当前的returnurl后跳转到 CWebUser配置中的loginurl,在此处登陆后,可以通过redirect跳转到returnurl(Yii::app()->request->redirect(Yii::app()->user->returnUrl);) 当强制显示登陆表单,比如判断用户是guest就一直列出登陆表单,不会调用loginRequired, 就得不到returnurl,这时候想跳回去,参见 cookbook上相关贴子 registerCoreScript 在framework/web/js/package.php中列出的才是 多对多关联条件 $criteria->addInCondition("categorys.id",$in); $criteria->addSearchCondition('Shop.name',$keyword); $shops=Shop::model()->with(array("categorys"=>array('together'=>true)))->findAll($criteria); 同时要在Shop模型中加入alias="categorys" ,另外together=true放在模型的关联中也可 YII中的RBAC权限,用数据库存item, 在system/web/auth下找到相应的sql导放到数据库中 配置'authManager' => array( 'class' => 'CDbAuthManager', 'connectionID' => 'db', ), 如果在sql中导入的三个表的表名不是默认的,需要在这上边的配置中配置,具体的看api $auth=Yii::app()->authManager; //$auth->createOperation("post",'postpost'); //$auth->createTask("post","posts"); $auth->createRole("post","post"); auth->assign("post",'demo'); if(Yii::app()->user->checkAccess("post")){ echo "yes"; else{ echo "no"; } 这种情况下三者是一样的 如何获得上一页的url以返回 Yii::app()->request->urlReferrer; accessControl 是Ccontroller中内置的过滤方法,其它的还有ajaxOnly postOnly CMaskedTextField此组件用于限制用户的输入,对应的jquery插件http://digitalbush.com/projects/masked-input-plugin/ 在一对多,多对多查询时,the eager loading 联合所有的表生成一条语句,如果主表有limit的查询选项,那么他将单独执行,然后再执行与关联表有关的语句,返回相关表的数据对象,这 就是为什么在做大优惠时,以中间表为查询条件出错的原因,解决办法 with()返回 CActiveFinder对象,其方法together(),既使主表中有LIMIT/OFFSET 也是返回一条sql; 多对多查询时,分页有时候页中显示的条数不正确,因为有重复的项,加上$criteria->group = true即可 模型的rules中,验证某个字段不能重复,array('name', 'unique','message' => '有重复的名子'), CStatePersister是yii的核心组件,提供了基于文件的数据保存方式,可以不在同的请求中使用 COutputCache 即是一个组件,又是一个filter,前者的时候用于在view中缓存内容,后者的时候用于在controller中缓存 就是说片段缓存,是把COutputCache当一个widget来用,页面缓存把COutputCache当作一个filter来用 动态缓存,用CController的一个方法 renderDynamic($callback); COutputCache几个属性,duration,dependency 另外还有几个,可以通称为Variation, 有什么作用呢? 在beginCache是需要手工指定一个id,Variation的作有就是自动给生成这个id 在布署模式的时候,有错误不会有stack样的提示,会显示一个errorxxx的错误 如何在程序有错的时候跳到指定的action 在components中设置 'errorHandler'=>array( 'errorAction'=>'site/error', ), 在此action中可以能过Yii::app()->errorHandler->error获得错误信息 把字符串分解成数组,并去掉空值 preg_split('/s*,s*/','this , is , , a test',-1,PREG_SPLIT_NO_EMPTY ) CActiveRecord::exits();判断有没有这样的记录,一般用于添加时,判断某字段有没有重复 CActiveDataProvider 一个基于ActiveRecord的数据提供源 常用的用法 $dataProvider=new CActiveDataProvider('Post', array( 'criteria'=>array(), 'pagination'=>array(), 'sort'=>array(), )); 上如'sort'=>array( 'defaultOrder'=>'status, update_time DESC', ), ClistView同上结合使用,其中的_view中可以用一个$data的变量,代表当前的model数据 如果dataProvider中的pagination,sort设为false,则CliveView中对应的部分也无法使用 $this->widget('zii.widgets.ClistView',array( 'dataProvider' => $dataprovider, 'itemView' => '_view', 'template' => '{items}{sorter}{pager}', 'sortableAttributes' => array( ), )); CGridView的使用也结合$dataprovider, 用的时候主要是对columns的配置,主要有 CDataColumn, CLinkColumn, CButtonColumn and CCheckBoxColumn.具体用法看api 总的说来CgridView没有ClistView灵活 插入meta信息 Yii::app()->clientScript->registerMetaTag('keywords','关键字'); Yii::app()->clientScript->registerMetaTag('description','一些描述'); CMap::mergeArray() 比array_merge更智能的合并数组,yii中配置的合并用这个 CClipWidget 通过ob_start ob_getconent生成一段不显示的内容,可以能过CController::clips访问,如 $this->beginWidget('CClipWidget',array('id'=>'name','renderClip'=>true)); 可以通过$this->clips['name']来显示,其中的renderClip如果为false,则在当前位置不显示内容 如果在Model一次验证多个属于,显示不同的内容?如下  [后来发现这个不起作有] return array( array('title, content', 'required', 'message'=>'Please enter a value for {attribute}.'), // ... other rules ); 获得服务器时间 $_SERVER['REQUEST_TIME'] 维护程序时,这样子所有的请求转发到一个地方 'catchAllRequest'=>array('site/all'), 根据二级域名缓存 array( 'COutputCache + search', 'duration' => 120, 'varyByParam' => array('q','page'), 'varyByExpression' => "app()->request->hostInfo", ), 有多个分站时,同步登陆,基于cookie 'user'=>array( 'identityCookie'=>array('domain'=>'.dayouhui.com'), 'allowAutoLogin' => true, ) 如果是基本于session 'session' => array( 'cookieParams' => array('domain' => '.dayouhui', 'lifetime' => 0), 'timeout' => 3600, ), 如何使用theme 在main.php中配置 'theme'=>'classic', 如何得到前前使用的主题 Yii::app()->theme 得到名子 Yii::app()->theme->name; themes文件夹和protected是同级的,其下边某个theme的目录结果同protected/views下一样 关于skin 用theme改变view的外观,skin是用来改变widgets的外观的 skin是健值对用于初始化一个widget的属性 要对widget使用skin,需要做以下几步 1:配置'widgetFactory'=>array( 'enableSkin'=>true, ), 2:在views下建立skins目录 3:在skins目录下建立与Widget名子一样的php文件,返回数组,即能用于widget的初始配置 4:在php文件中,如果有defautl的配置,会先找这个skin 5:如果应用了theme,程序会先去对应的theme目录下的skins中找配置文件 6:如果只是想给widget统一一个skin,建议用Customizing Widgets Globally 如果防止post跨站攻击 'request'=>array( 'enableCsrfValidation'=>true, ), 这时候生成的表单要用CHtml::form(),其会写一段代码在cookie中 防止Cookie攻击 'request'=>array( 'enableCookieValidation'=>true, ), 同时生成与得到cookie是要用 CHttpCookie 如何让表单验证不驼过的提示为中文 在main.php的配置中加上 'language' => 'zh_CN', 如何实现仿google的自动完成功能 <?php $this->widget('CAutoComplete', array( 'name'=>'xxx', 'url'=>array('suggestTags'), 'multiple'=>false, 'htmlOptions'=>array('size'=>50), )); ?> 然后在url指定的地址中的方法中如下输出,即可 echo "anbnc" //CGridView详解 这东西在后台比较有用,能加速开发的速度,值得一看 CGridView用表格的方式显示数据项 每一行代表一个数据项,一列通常代表数据项的一个属性 CGridView支持排序和分页,可以用ajax或普通的方式 CgridView必序和data provider一起使用 最简单的用法 $dataprovider = new CActiveDataProvider('Post'); $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, )); 这会用表格的方式显示每一条数据项,每一列是Post的一个属性 在显示中带了分页和排序 我们可以自定义CgridView::columns属性,以自定义表格列的显示方式 这个cloumns如何配置呢? 其是一个数组,每一个数组元素对应着一列的配置,可以是字符串或数组 1、如果是字符串,格式是name:type:header 后两者是可选的,根据这三个值,创建一个CdatColumn实例 其中type参见CFormatter 2、如果是数组,其可以实例化CDdataColumn、ClinkColumn,CButtonColumn,CCheckBoxColumn实例,具体实例化哪个 由数组中的class指定,默认是CDataColumn 2.1,如果class=>'CDataCloumn' 则可以指定name或者value,如果指定以value优先 用CDataColumn时如何以关联表的数据序列? 代码如下:表示可以post关联的author中的username排序列 $dataprovider = new CActiveDataProvider('Post',array( 'criteria'=>array( 'with'=>'author', ), 'sort'=>array( 'attributes'=>array( 'title','create_time', 'author_id'=>array('asc'=>'author.username asc','desc'=>'author.username desc','label'=>'作者') ) ), )); $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, 'columns'=>array( 'title', 'create_time', array('name'=>'author_id','value'=>'$data->author->username'), ), )); 另外CDataColumn还有一个filter属性,如果是空,那么生成一个textfield,如果是数组(键值),则生成一个dropDownlist在当前列的上部,供搜索 2.2:如果class=>"CLinkColumn" array('class'=>'CLinkColumn','label'=>'查看用户','url'=>Yii::app()->createURL('user/edit')) 则生成一个连接 2.3:如果class="CCheckBoxColumn" array('class'=>'CCheckBoxColumn','name'=>'title','id'=>'select'), 可以生成一个checkbox供选择,且只能选一个 可以配置CGridView::selectableRows 如果是0,则不能选,如果 1,只选一个如果是2或其它值,则可以选多个 代码如下: $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, 'selectableRows'=>2, 'columns'=>array( array('class'=>'CCheckBoxColumn','name'=>'title','id'=>'select'), ), 2.3:如果class="CButtonColumn" array( 'class'=>'CButtonColumn', 'updateButtonUrl'=>'Yii::app()->createUrl("post/edit",array("id"=>$data->id));', ), 修改updateButtonUrl为编辑贴子 如何用gridview生成一个代搜索的管理列表 1、在Model的rules 设定可以搜索的属性 array('title, status, create_time', 'safe', 'on'=>'search'), 2、在Model中,添加搜索时的方法 public function search() { $criteria=new CDbCriteria; $criteria->compare('title',$this->title,true); $criteria->compare('status',$this->status); $criteria->compare('create_time',$this->create_time); return new CActiveDataProvider('Post', array( 'criteria'=>$criteria, 'sort'=>array( 'defaultOrder'=>'status, update_time DESC', ), )); } 3、 在Controler中,写接受搜索用到的表单的值的方法 public function actionAdmin() { $model=new Post('search'); if(isset($_GET['Post'])) $model->attributes=$_GET['Post']; $this->render('admin',array( 'model'=>$model, )); } 4、在view中用CGridView显示 设置好 <?php $this->widget('zii.widgets.grid.CGridView', array( 'dataProvider'=>$model->search(), 'filter'=>$model, 'columns'=>array( ), )); ?> 以上代码大部分是yii自动生成的,只要做少量修改即可 有时候会出现,搜索后页面为空的清况,原因可能是 layout/main.php中 echo $content外层无div,就是说main.php中必须有一个div包含$content //CListView详解 其用列表的形式显示数据,不象CGridView一样,用表格显示数据,CListView用一个 view模板来显示每一条数据 其支持排序与分页 常用的代码如下 <?php $dataProvider = new CActiveDataProvider('Post',array( 'pagination'=>array( 'pageSize'=>2 ), )); $this->widget('zii.widgets.CListView',array( 'dataProvider'=>$dataProvider, 'itemView'=>'_view', 'template'=>' {summary} {items}  {pager}{sorter}', 'sortableAttributes'=>array( 'title', 'create_time'=>'Post Time', ), )); //CActiveForm详解 快速生成表单,支持ajax验证,对于比较复杂的验下最好是自己生成表单,写验证方法 常用代码,在Controller中 public function actionForm() { $post = new Post(); if(isset($_POST['ajax']) &&  $_POST['ajax']==='post'){ echo CActiveForm::validate($post); Yii::app()->end(); } if(isset($_POST['Post'])){ $post->attributes = $_POST['Post']; if($post->save()){ echo '存成功了'; } } $this->render('form',array('post'=>$post)); } 在view中 <?php $form = $this->beginWidget('CActiveForm',array( 'id'=>'post',//这里与Controller中的ajax对应 'enableAjaxValidation'=>true, )); ?> <?php echo CHtml::errorSummary($post); ?> <?php echo $form->labelEx($post,'title');?> <?php echo $form->textField($post,'title')?> <?php echo $form->error($post,'title'); ?> error一定要写上,要不不会触发ajax验证 <?php echo $form->labelEx($post,'content');?> <?php echo $form->textField($post,'content')?> <?php echo CHtml::submitButton($post->isNewRecord ? 'Create' : 'Save'); ?> <?php $this->endWidget(); ?> //CBreadcrumbs常用代码 <?php $this->widget('zii.widgets.CBreadcrumbs', array( 'links'=>$this->breadcrumbs, 'homeLink'=>'<span><a href="http://abc.com">shouye</a></span>', 'separator'=>'>>>' )); ?> 其中breadcrumbs中Controller中的一个属性,如果要出现导航,就要在view中给此属性附值 生成的html如下 <div> <span><a href="http://abc.com">shouye</a> </span>&gt;&gt;&gt;<span>Managde Posts</span>&gt;&gt;&gt; <span>b</span>&gt;&gt;&gt;<span>c</span></div> 所以如果网站用到导航的时候,美工最好把导航代码定义如上 //CDetailView  用在仅仅是为了查看数据时,还是比较有用的,比如用在后台 如何在提交后显示一段提示 在控制器中 if(isset($_POST['name'])){ Yii::app()->user->setFlash('success','you are success'); $this->refresh(); } 在view中 if (Yii::app()->user->hasFlash('success')){ echo 're is'.Yii::app()->user->getFlash('success'); }else{ echo 'no'; } 如何得到当前域名: app()->request->hostInfo activeDropDownList,给出提示,并有值 array('empty'=>array(0=>'选择分组') <input type="submit" value="提交" /> 验证码如何生成及验证: Controller中 public function actions() { return array( 'captcha'=>array( 'class'=>'CCaptchaAction', 'backColor'=>0xFFFFFF, 'maxLength'=>4, 'minLength'=>4, ), ); } View中 <?php echo CHtml::activeTextField($user, 'verifyCode');?> <?php $this->widget('CCaptcha',array( 'captchaAction' => '/site/captcha', 'showRefreshButton' => false, 'clickableImage' => true, 'imageOptions' => array('align'=>'top', 'title'=>'重新获取'), ));?> Model中 array('verifyCode', 'captcha', 'captchaAction'=>'site/captcha', 'message' => '输入的验证码不正确'), set_time_limit(0);//禁止角本超时 如何想把手工的东西记录的数据库 main.php中配置log array( 'class'=>'CDbLogRoute', 'levels'=>'info', 'logTableName'=>'Log', 'connectionID'=>'db', ), 应用时 Yii::log('信息','info'); deleteAllByAttributes(array("phone"=>$phones)直接接受一个数组,可以删除数组中符合条件的记录 YII_BLOG STUDY重新看了一遍yii blog,有些记录会与上边的重复 YII:Trace() 在debug模式是才记录信息,同时在main.php中的Log中的配置中的levels中要有trace,至于记录多少 栈由index.php中的YII_TRACE_LEVEL决定 配置Gii 'modules'=>array( 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'123', ), ), 获得客户端IP if($_SERVER['HTTP_CLIENT_IP']){ $ip = $_SERVER['HTTP_CLIENT_IP']; }elseif($_SERVER['HTTP_X_FORWARDED_FOR']){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }else{ $ip = $_SERVER['REMOTE_ADDR']; } CActiveForm还是比较强大的,建议在以后的项目中form都用这个来实现 layout/中的视图是可以继承的 <?php $this->beginContent('/layouts/main'); ?> 然后在中间出现$content即可 <?php $this->endContent(); ?> create,update最好是分开放在两个action中,共用一个form,中间可以加一层view,以在头尾显示不同的东西 成段的完成一个功能的代码尽量拿出来放到一个方法中 $this->beginWidget('CMarkdown', array('purifyOutput'=>true)); echo $data->content; $this->endWidget(); linkButton,在删除时需要用js提示,可以看下这此组件中的comfirm 而且他们的提交方式都是post,是因为在jquery.yii.js写死了 具体的以在源文件中低部找到那段js中的ajaxsubmit,所在的js看下 filter是在执行action之前或之后执行的一段代码,要应用filters必须得写 CController::filters()方法 为什么在filters方法写上 return array( 'accessControl', // perform access control for CRUD operations );能进行crud验证呢? accessController是CContronller内置的filter,其调用 accessRules,得到验证规定,所以也要重写对应的accessRules,返回一个验证规则的数组成部分 if the application uses modules, a root alias is also predefined for each module ID and refers to the base path of the corresponding module 如:echo YiiBase::getPathOfAlias('bbs');得到module bbs的路径 关于CUrlManager '模式'=>'route' matchValue是指,对于一个url规则,正常情况下是只看参数的名子是否一样就应用规则 如果matchValue=true,则也要看值 如,规则 'index-/<id:d+>'=>array("book/index",'matchValue'=>false), $this->createUrl('book/index', array('id'=>'abcd'));可以应用以上规则的, 如果规则中的matchValue=true,则就不能应用了 XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。 它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时, 嵌入其中Web里面的html代码会被执行 renderPartial() render() 后者会把需要的js,css等嵌入 前者可以通过把最后一个参数设置成true完成一样的功能 addInCondition 不用考虑数组是空的情况yii会自动处理 如何得到当前url? Yii::app()->request->url; ctype_开始的几个函数,用于检查字任串是不是符合要求,代替了简单的正则表达式 CController中的setPageState可以保存同一页中的POST的表单状态 如何通过BEhavior修改CActiveRecord? 写类文件继承自 class LLog extends CActiveRecordBehavior{ public function beforeDelete($event){ $model = get_class($this->Owner); //做要做的事,比如日志或修改模型字段内容 } } 然后修改模型文件 public function behaviors() { return array( // Classname => path to Class 'LLog'=>'application.behavior.LLog', ); } 如何在应用程序处理请求之前执行一段操作? 在main.php中配置 'onBeginRequest' => 'function' 当然这个function方法要存在 也可以写在放口文件index.php中,代码改成如下 $app = Yii::createWebApplication($config); $app->onbeginRequest = 'begin'; $app->run(); function begin(){ echo 'yyyyydddyyyyyy'; } 为什么在CActiveRecordBehavior中用 beforesave就可以代表了事件onBeforeSave 注意基为中最上边的events方法中返回的对应关系 'onBeforeSave'=>'beforeSave' 在调用attacth(CBehavior中)的时候, $owner->attachEventHandler($event,array($this,$handler)); 就指定了事件onBeforeSave的处理函数是用本类中的beforeSave YII中的CComponent,CEvent与Behavior及CActiveRecordBehavior个人理解 这一块教程少,今天个人理解了下,写了个小例子,有助于理解 完成如下功能,一个JTool类,继承CComponent,当其长度改变时,调用事件,输出"change me". JTool.php在protected/components 下 <?php class JTool extends CComponent{ private $_width; public function getWidth(){ return $this->_width ? $this->_width : 1; } public function setWidth($width){ if($this->hasEventHandler('onChange')){ $this->onChange(new CEvent()); } $this->_width = $width; } public function onChange($event){ $this->raiseEvent('onChange', $event); } } OK,功能已经实现了,找个控制器,执行 $j = new JTool(); $j->onChange = "showChange"; //给事件绑定handle showChange $j->width = 100;  //调用setWidth,解发绑定的事件showChange function showChange(){ echo 'changed me'; } 现在我们想给JTool添加一个功能,返回长度的100倍,我们可以继承JTool.php写一个方法 class JToolSub extends JTool{ public function get100width(){ return $this->width*100; } } OK,功能实现了,这个执行就简单了new JToolSub调用方法即可 上边的这两种办法,就是仅完成功能,下边演示Behavior及events来实现 如何用Behavior来实现上边的增加一个方法,返回长度的100倍的功能呢? 写类JBe JBe.php在protected/behavior 下 class JBe extends  CBehavior{ public function get100width(){ return $this->Owner->width*100; } } OK,功能已经实现了,找个控制器,执行 $j = new JTool(); $j->attachBehavior('JBe', 'application.behavior.JBe'); echo $j->get100width(); 如何用Behavior实现JTool中的长度改变时,调用一个事件的功能呢? 写类JBe class JBe extends  CBehavior{ public function events(){ return array_merge(parent::events(),array( 'onChange'=>'change', )); } public function change(){ echo 'changed'; } public function get100width(){ return $this->Owner->width*100; } } OK,功能实现随便找个控制器,执行 $j = new JTool(); $j->attachBehavior('JBe', 'application.behavior.JBe'); $j->width = 100; 这里的要点是events方法 返回的数组array('onChange'=>'change')定义了事件(event)和对应的事件处理方法(event hander) 事件是是Compents(JTool中)定义的,即JTool中的onChange 处理方法同由Behavior(JBe中)类定义的,即JBe中的change 这样子再看CActiveRecordBehavior,其是绑定给CActiveRecord 这个组件的,绑定方法重写behaviors() CActiveRecordBehavior中的events() 方法返回事件及事处理函数的对应,如: 'onBeforeSave'=>'beforeSave' 即组件CActiveRecord中的onBeforeSave这个事件对应的处理函数是 CActiveRecordBehavior中的beforeSave方法 这样子CActiveRecord在调用save()时,触发事件onBeforeSave,调用CActiveRecordBehavior对应的处理函数beforeSave 我们只要写一个CActiveRecordBehavior的子类,重写其中的beforeSave,执行一些操作,然后给CActiveRecord绑定即可 如果你自己有个目录下有些类或文件常用,可以在main.php的最上边定义一个路径别名 Yii::setPathOfAlias('local','path/to/local-folder'); 如果是多个可以在main.php中的array中加一个配置 'aliases'=>array( 'local'=>'path/to/local/' ), 如何得到proteced目录的物理路径? YII::app()->basePath; widget是发布资源 $url = Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('application.components.homeuserlived')); cs()->registerCoreScript('jquery'); cs()->registerScriptFile($url.'/location.js' ,CClientScript::POS_HEAD); cs()->registerScriptFile($url.'/YLChinaArea.js' ,CClientScript::POS_HEAD); cs()->registerCssFile($url.'/style.css'); 如何写application component, 即在main.php可配置 "my"=>array('') 可以通过Yii::app()->my来访问? 继承CApplicationComponent即可,并可以自带Behavior等 yii中读写session的两种方法 $session = Yii::app()->session; $session['terry'] = 30; var_dump($session['key']); Yii::app()->user->setState('tom', '40'); var_dump(Yii::app()->user->getState('key', 'default')); ==========================================分隔线=================================== soap非yii教程,意思是不用yii框架的时候要对象提供webservice的写法 分两种WSDL模式,和非WSDL模式,先看后者 这个也比较简单,服务器端 server.php <?php ini_set('soap.wsdl_cache_enabled',0); class Student { public function getInfo($name,$age){ if($age == 20){ throw new SoapFault(-1, 'Cannot divide by zero!'); } $xml = "<root><name>".$name."</name>"; $xml .= "<age>".$age."</age></root>"; return  $xml; } } $soapS = new SoapServer(null,array('uri' => 'http://www.dayouhui.com')); $soapS->setClass('Student'); $soapS->handle(); ?> 客户端client.php <?php $soap = new SoapClient(null,array('location'=>"http://localhost/mysoap/index.php",'uri'=>'inadex.php')); echo $soap->getInfo('a','b'); 这样子即可 ============================================= yii,Componnts那快,忘了,写了个小例子回忆了下 是写一个可以写在main.php中的Components并绑定行为,事件 ====================================== class ExtWindow extends CApplicationComponent{ private $title = 'title'; public $oldtitle; public function getTitle(){ return $this->title ? $this->title : 'old title<br />'; } public function setTitle($title){ echo '=='.$this->oldtitle.'=='; $this->oldtitle = $this->title; $this->title = $title; if($this->hasEventHandler('onTitleChange')){ $event =new CEvent($this); $this->raiseEvent('onTitleChange', $event); } } //必须有这么个方法,其和raiseEent中的事件一样,具体看代码 public function onTitleChange($event){ } } =========================== <?php class Window extends CBehavior{ public function events(){ return array_merge(parent::events(),array( 'onTitleChange'=>'titleChange', )); } public function titleChange($event){ echo $event->sender->title; echo 'event TitleChange is handled in Behavior<br />'; echo $this->owner->title; } public function titleOld(){ echo  '<br />old title is is  '.$this->owner->oldtitle; } } ============================== main.php中的写法 'ExtWin'=>array( 'class' => 'ExtWindow', 'oldtitle'=>'我是旧的', 'behaviors'=>array('win'=>'application..behavior.Window') ============================================= 一对多,多对多的关联时最后的参数 together说明 如果为false,分开查多个语句 如果为true,强制生成一个语句 如果没有设置,分页页生成多个语句,不分页时生成一个语句 ), 多对多时,查询时,中间表的名子叫 (关联名_关联名) with选项的作用是eager loading together的作用是 要不要形成一个语句 当是一个sql语句是记录会有重复,这时候分页分出现相同的记录,加上group=>true即可, 只要弄明白了,你生成的sql是一条还是多条sql就明白在多对多查询时的结果了 两个表不是用主键关联 'user' => array(self::BELONGS_TO, 'OaskUser', '','on'=>'name=userName', 'select'=>'TrueName'), 表带talbeprefix是,多对关联,键的写法 'categories'=>array(self::MANY_MANY,'Category','{{post_category}}(post_id,category_id)'),

Yii-urlManager

Yii组件机制之三:路由组件 urlManager   URL路由,是指通过分析 URL,  找出请求的控制器及动作。路由信息就是指控制器及动作组成的请求字符串,形如controllerID/ActionID 。   Yii中的路由主要有两重作用: 1. 根据请求 URL 找到应对的控制器及其方法 2. 根据提供的参数及规则生成 URL 这就称为路由双向解析。   支持两种形式的URL 解析: 1.   普通的get 传递参数方式,如 index.php?r=controller/action¶m1=value1 2.   path模式(需要服务器支持),如 index.php/name1/value1/name2/value2     URL路由处理由 urlManager 组件 ( 对应类名为 CUrlManager) 负责 ,  它也是一个组件,故可以在配置文件中设置其属性: $rules=array(); #url双向解析规则,这是最复杂的一项参数 $urlSuffix=''; #pathinfo 模式时的 url 后缀 $showScriptName=true; #是否在 URL 中显示脚本文件名称,当设置为 false 时需要服务器支持 $appendParams=true; #pathinfo模式下是否将参数追加到 URL 上,此项参数一般用于生成 URL 场景。设置为true 时 ,  参数将以斜线分隔并追加到路径后面。设为 false 时将以 query string 方式追加。 $routeVar='r'; #仅在 get 形式时有效,指定路由信息的变量名称 $caseSensitive=true; #路由信息是否区分大小写。如果设置为 false,  请求路由信息将被转换成小写,所以CWebApplication::controllerMap 、 CController::actions 、保存控制器的目录三者都应该使用小写。 $matchValue=false; #仅在 get 形式时有效。当创建 URL 前 GET 参数的值应该匹配对应的子规则,这句话不好理解,后面会详细使用案例说明 $cacheID='cache'; #路由缓存所使用的组件名称(若使用缓存机制) $useStrictParsing=false; #仅在 path 形式时有效,设置是否使用严格的 URL 解析。如果设置为 true,  则任何请求的 url 必须匹配 $rules 指定的规则,否则会引发 404 错误。 $urlRuleClass='CUrlRule'; #url规则处理组件类……   通过setter 方法定义的属性: Urlformat : 设置 url 形式,可以是 get, path 两种方式     get模式是服务器默认支持的形式,故不需要规则解析,直接通过 $_GET[$this->routeVar] 变量即可取得路由信息,相对而言 path 模式是比较消耗资源的(因为需要逐条解析规则),所以我觉得在对性能要求较高的应用中,可以考虑使用 http server 的地址重写代替 yii 的规则,从而减少 yii 中昂贵的规则分析性能代价。掌握了其规则的定义,才能从根本上熟练使用路由组件。 一个规则是由路由和匹配样式组成的,一般地,每条规则的键名为规则,值为应对的路由,均可以配置文件中指定或在运行时指定,以下是几个例子: 'post/<id:\d+>/<title:.*?>'=>'post/view' 表示匹配post/\d+/.*? 规则的请求的路由为 post/view,  且将设置两个 GET 变量,分别为 $_GET['id'] 和$_GET['title'],  指向对应的值。带尖括号的部分表示不仅要匹配而且要捕获值至变量中。 创建url 时,若指定路由为 post/view,  并提供 id, title( 可选 ) 参数,则将生成 post/$id/$title 形式的 url ,如: $app->urlManager->createUrl('post/view', array( 'id'=>23, 'title'=>'title_text', 'name1'=>'value1', 'name2'=>'value2' )); 将生成index.php/post/23/title_text?name1=value1&name2=value2   'posts/<tag:.*?>'=>'post/index' 匹配posts/.*? 的请求的路由将设置为 post/index,  同时将匹配的内容保存到 $_GET['tag'] 变量中。创建 URL 时若指定路由信息为 post/index,  并提供了 tag 参数(可选),则将生成 posts/$tag 形式 URL 。   '<controller:\w+>/<action:\w+>'=>'<controller>/<action>' 匹配 \w+/\w+ 的请求 ,  设置 $_GET['controller'] 和 $_GET['action'] 两个变量,并且路由信息中直接使用这两个变量的值作为路由信息。若指定 controller 及 action 两个参数,参将创建形如 controller/action 形式的 URL 。   了解这些,是我们使用urlManager 组件的关键。

yii 常用url地址

调用YII框架中 jquery:Yii::app()->clientScript->registerCoreScript('jquery');    
  
framework/web/js/source的js,其中registerCoreScript key调用的文件在framework/web/js/packages.php列表中可以查看
 在view中得到当前controller的ID方法 :Yii::app()->getController()->id;      
 在view中得到当前action的ID方法 :Yii::app()->getController()->getAction()->id;     
 yii获取ip地址 :Yii::app()->request->userHostAddress;   
 yii判断提交方式 :Yii::app()->request->isPostRequest  
得到当前域名: Yii::app()->request->hostInfo   
 得到proteced目录的物理路径 :YII::app()->basePath;     
 获得上一页的url以返回 :Yii::app()->request->urlReferrer;  
 得到当前url :Yii::app()->request->url;  
 得到当前home url :Yii::app()->homeUrl  
 得到当前return url :Yii::app()->user->returnUrl 
 项目路径 :dirname(Yii::app()->BasePath)
项目目录 Yii::app()->request->baseUrl

Yii 模块绑定子域名

我在dongbeta的网站上看到了这个东西,突然觉得原来子域名真的很简单,原来我还在想,如何绑定一些子域名的事情呢。 看一下原文吧,然后说明一下,官方的手册中其实已经有类似的介绍了,只是目前这一部分还是英文版的,这可能和这个功能是最新刚加入的关吧。。来源网址为:http://dongbeta.com/view/655 --start-- Yii强大的路由功能配置相当灵活,特别是增加了参数主机名路由功能之后更是可以灵活控制域名。感觉每一次提出一个提议,Yii的开发者qiang如果采纳,就会给出一个我没有想到却更加强大的解决方案。这次就是这样。 下面就是可以将所有子域名都转化为模块的路由规则,来自Yii官方论坛的一个帖子
XML/HTML代码
  1. 'http://<_m:\w+>.xxx.com<_q:.*>/*'=>'<_m><_q>',
规则写在main.php中的组件配置数组里面:
PHP代码
  1. 'urlManager'=>array(
  2.     'urlFormat'=>'path',
  3.     'showScriptName' => false,
  4.     'rules’=>array(
  5.         'http://<_m:\w+>.xxx.com<_q:.*>/*'=>'<_m><_q>',
  6.     )
  7. ),
如果仅仅是一个模块(假设是user)需要绑定子域名,可以这样写规则:
XML/HTML代码
  1. 'http://user.xxx.com<_q:.*>/*'=>'user<_q>',
如果是若干模块需要绑定子域名,可以这样写:
XML/HTML代码
  1. 'http://<_m:(user|admin|photo)>.xxx.com<_q:.*>/*'=>'<_m><_q>',
在使用的时候我注意到,如果是www开头的网址也会被转向到www模块,那么你可以使用(A|B|C)这样的规则选择要启用的模块,或者使用正则来滤掉www。 另外在路由规则里面,如果某一条匹配,则不会向下进行匹配。这是需要注意的,但是正是这样,路由才更高效,更灵活。 官方的URL管理说明文档:http://www.yiiframework.com/doc/guide/topics.url ,中文的我还没有翻译,等翻译之后,会发布到官方网站。 --EOF-- 正如上面作者所说,官方这一段确实还是英文,可以看这里:http://www.yiiframework.com/doc/guide/1.1/zh_cn/topics.url,不过也很容易理解 以下来自官方:

Parameterizing Hostnames

Starting from version 1.0.11, it is also possible to include hostname into the rules for parsing and creating URLs. One may extract part of the hostname to be a GET parameter. For example, the URL http://admin.example.com/en/profile may be parsed into GET parameters user=admin and lang=en. On the other hand, rules with hostname may also be used to create URLs with paratermized hostnames. In order to use parameterized hostnames, simply declare URL rules with host info, e.g.:
PHP代码
  1. array(
  2.     'http://<user:\w+>.example.com/<lang:\w+>/profile' => 'user/profile',
  3. )
The above example says that the first segment in the hostname should be treated as user parameter while the first segment in the path info should be lang parameter. The rule corresponds to the user/profile route. Note that CUrlManager::showScriptName will not take effect when a URL is being created using a rule with parameterized hostname. Also note that the rule with parameterized hostname should NOT contain the sub-folder if the application is under a sub-folder of the Web root. For example, if the application is under http://www.example.com/sandbox/blog, then we should still use the same URL rule as described above without the sub-folder sandbox/blog 原文地址http://www.neatstudio.com/show-1550-1.shtml

YII 总结(转)

YII 点滴(更新中)2010-08-02 09:14一、从yii权威指中学到的 db组件 'schemaCachingDuration'=>3600, 为什么不起做用? 需要开缓存 如何在页面下边显示sql的查询时间 在log组件的routes中加入 array( 'class'=>'CProfileLogRoute', 'levels'=>'error, warning', ) 同时在db组件中加入 'enableProfiling'=>true, 同时在这种情况下,可以用CDbConnection::getStats() 查看执行了多少个语句,用了多少时间 如何知道某一个程序段运行需要的时间 配置好CProfileLogRoute后,在需要测试的地方加上 Yii::beginProfile('blockID'); //程序段 Yii::endProfile('blockID'); 'enableParamLogging'=>true,的作用是? 在日志的bind的参数后边跟数的值 如何在页面底部显示所有的db相关的日志 同上,配置log组件的routes中加入 array( 'class'=>'CWebLogRoute', 'levels'=>'trace, info, error, warning', 'categories' => 'system.db.*', //'showInFireBug' => true, 将在firebug中显示日志 ), 把日志记录到数据库 array( 'class'=>'CDbLogRoute', 'logTableName'=>'applog', 'connectionID'=>'db', ), 运行时表applog会自动生成,如果不能生成,参照api自已建立 如何记录$_GET,$_SESSION等信息,在以上的routes中各个配置中加上 'filter'=>'CLogFilter', log配置中的level设置不对,可能会得不到日志信息 另外level,category的值可以随便写, 只要在用yii::Log("","自定义level","自定义的category")时对应起来即可 如何记录更详细的信息,能记录stack,在入口文件中加上 define('YII_TRACE_LEVEL',10);数字越大,记当的越详细,结果如下 [15:31:57.226][trace][system.db.CDbCommand] Querying SQL: SHOW COLUMNS FROM `Bangdan` in E:\APMServ5.2.6\www\htdocs\dayouhui.com\protected\models\Bangdan.php (21) in E:\APMServ5.2.6\www\htdocs\dayouhui.com\protected\components\HotBangdan.php (21) in E:\APMServ5.2.6 如果在调试时,终止程序运行且看到日志,不能用die及exit; 用application::end,即Yii::app()->end(),其会触发onEndRequest事件,日志就是在这个事件中记录的 activeRecord几个占位方法重写的注意点 必须带boolean返回值 如何发布一个资源文件并引用 $css=Yii::app()->getAssetManager()->publish(dirname(__FILE__)."/aa.css"); yii::app()->clientScript->registerCssFIle($css); 如果改变activelable中默认的标题 重写方法attributeLabels 过滤不良代码 $purifier=new CHtmlPurifier; $purifier->options=array("HTML.Allowed"=>"div"); $content=$purifier->purify($content); 或者 beginWidget('CHtmlPurifier'); ?> ...display user-entered content here... endWidget(); ?> 如何防止重复提交? 提交后 Ccontroler->refresh(); 如何在成功后显示一个提示,用户刷新页时去掉提示 Cwebuser->setFlash(); getFlash(); 如何防止重复提交, 并在提交成功后给出提示? 控制器中 Yii::app()->user->setFlash('submit','thanks'); $this->refresh(); view中 if(Yii::app()->user->hasFlash('submit')){ echo Yii::app()->user->getFlash('submit'); } 一般我们是跳转到列表页,或用redirect跳到编辑页,就不需要了,如果还是要显示当前页 以上就有用了,比如在当前时显示,编辑或添加新的记录 如何分页 itemCount总记录条数 CPagination代表分页信息,有多少页,每页几条记录等 CLinkPager生成分页的代码,自定义css可以给属性cssFile一个值 $criteria=new CDbCriteria(); $pages=new CPagination("数据库中的总记录数"); $pages->pageSize=2; $pages->applyLimit($criteria);//给$criteria->limit offset等符值 $posts=Post::model()->findAll($criteria); $this->widget('CLinkPager',array('pages'=>$pages)); 列表如何排序 $criteria=new CDbCriteria(); $sort = new CSort('Post'); $sort->defaultOrder=" status asc"; $sort->applyOrder($criteria); $posts=Post::model()->findAll($criteria); 应用时用 $sort->link('字段名') 实际是生成一个带参数的url,然后在在applyOrder时应用这些参数修改$criteria,得到相应的查寻结果 如何生成并验证验证码: 基本用法 widget('CCaptcha'); ?> 具体参数查手册 原理CCaptcha这个widget会在run时调用当前控制器的$captchaAction='captcha'方法,这个方法指到一个类CCaptchaAction 其会生成验证码图象,并记入到session中 如何显示静态页 重写actions 'help'=>array( 'class'=>'CViewAction', 'basePath'=>'help', //指定目录名 'defaultView'=>'default', 'viewParam'=>'help' //get参数 ), 假定当前控制器是post 那么可以能过/post/help/help/content访问help目录下的content.php 可以建立子目录比如help/reigterhelp/content.那可以通过/post/help/help/registerhelp.content来访问 用CViewAction的好处时,可以与其它的view共享layout 关于没有权限访问跳转的url相关 当没有权限时调用CAccessControlFilter类中的accessDenied,其调用CwebUser中的loginRequired(),记录当前的returnurl后跳转到 CWebUser配置中的loginurl,在此处登陆后,可以通过redirect跳转到returnurl(Yii::app()->request->redirect(Yii::app()->user->returnUrl);) 当强制显示登陆表单,比如判断用户是guest就一直列出登陆表单,不会调用loginRequired, 就得不到returnurl,这时候想跳回去,参见 cookbook上相关贴子 registerCoreScript 在framework/web/js/package.php中列出的才是 多对多关联条件 $criteria->addInCondition("categorys.id",$in); $criteria->addSearchCondition('Shop.name',$keyword); $shops=Shop::model()->with(array("categorys"=>array('together'=>true)))->findAll($criteria); 同时要在Shop模型中加入alias="categorys" ,另外together=true放在模型的关联中也可 YII中的RBAC权限,用数据库存item, 在system/web/auth下找到相应的sql导放到数据库中 配置'authManager' => array( 'class' => 'CDbAuthManager', 'connectionID' => 'db', ), 如果在sql中导入的三个表的表名不是默认的,需要在这上边的配置中配置,具体的看api $auth=Yii::app()->authManager; //$auth->createOperation("post",'postpost'); //$auth->createTask("post","posts"); $auth->createRole("post","post"); auth->assign("post",'demo'); if(Yii::app()->user->checkAccess("post")){ echo "yes"; else{ echo "no"; } 这种情况下三者是一样的 如何获得上一页的url以返回 Yii::app()->request->urlReferrer; accessControl 是Ccontroller中内置的过滤方法,其它的还有ajaxOnly postOnly CMaskedTextField此组件用于限制用户的输入,对应的jquery插件http://digitalbush.com/projects/masked-input-plugin/ 在一对多,多对多查询时,the eager loading 联合所有的表生成一条语句,如果主表有limit的查询选项,那么他将单独执行,然后再执行与关联表有关的语句,返回相关表的数据对象,这 就是为什么在做大优惠时,以中间表为查询条件出错的原因,解决办法 with()返回 CActiveFinder对象,其方法together(),既使主表中有LIMIT/OFFSET 也是返回一条sql; 多对多查询时,分页有时候页中显示的条数不正确,因为有重复的项,加上$criteria->group = true即可 模型的rules中,验证某个字段不能重复,array('name', 'unique','message' => '有重复的名子'), CStatePersister是yii的核心组件,提供了基于文件的数据保存方式,可以不在同的请求中使用 COutputCache 即是一个组件,又是一个filter,前者的时候用于在view中缓存内容,后者的时候用于在controller中缓存 就是说片段缓存,是把COutputCache当一个widget来用,页面缓存把COutputCache当作一个filter来用 动态缓存,用CController的一个方法 renderDynamic($callback); COutputCache几个属性,duration,dependency 另外还有几个,可以通称为Variation, 有什么作用呢? 在beginCache是需要手工指定一个id,Variation的作有就是自动给生成这个id 在布署模式的时候,有错误不会有stack样的提示,会显示一个errorxxx的错误 如何在程序有错的时候跳到指定的action 在components中设置 'errorHandler'=>array( 'errorAction'=>'site/error', ), 在此action中可以能过Yii::app()->errorHandler->error获得错误信息 把字符串分解成数组,并去掉空值 preg_split('/\s*,\s*/','this , is , , a test',-1,PREG_SPLIT_NO_EMPTY ) CActiveRecord::exits();判断有没有这样的记录,一般用于添加时,判断某字段有没有重复 CActiveDataProvider 一个基于ActiveRecord的数据提供源 常用的用法 $dataProvider=new CActiveDataProvider('Post', array( 'criteria'=>array(), 'pagination'=>array(), 'sort'=>array(), )); 上如'sort'=>array( 'defaultOrder'=>'status, update_time DESC', ), ClistView同上结合使用,其中的_view中可以用一个$data的变量,代表当前的model数据 如果dataProvider中的pagination,sort设为false,则CliveView中对应的部分也无法使用 $this->widget('zii.widgets.ClistView',array( 'dataProvider' => $dataprovider, 'itemView' => '_view', 'template' => '{items}{sorter}{pager}', 'sortableAttributes' => array( ), )); CGridView的使用也结合$dataprovider, 用的时候主要是对columns的配置,主要有 CDataColumn, CLinkColumn, CButtonColumn and CCheckBoxColumn.具体用法看api 总的说来CgridView没有ClistView灵活 插入meta信息 Yii::app()->clientScript->registerMetaTag('keywords','关键字'); Yii::app()->clientScript->registerMetaTag('description','一些描述'); CMap::mergeArray() 比array_merge更智能的合并数组,yii中配置的合并用这个 CClipWidget 通过ob_start ob_getconent生成一段不显示的内容,可以能过CController::clips访问,如 $this->beginWidget('CClipWidget',array('id'=>'name','renderClip'=>true)); 可以通过$this->clips['name']来显示,其中的renderClip如果为false,则在当前位置不显示内容 如果在Model一次验证多个属于,显示不同的内容?如下 [后来发现这个不起作有] return array( array('title, content', 'required', 'message'=>'Please enter a value for {attribute}.'), // ... other rules ); 获得服务器时间 $_SERVER['REQUEST_TIME'] 维护程序时,这样子所有的请求转发到一个地方 'catchAllRequest'=>array('site/all'), 根据二级域名缓存 array( 'COutputCache + search', 'duration' => 120, 'varyByParam' => array('q','page'), 'varyByExpression' => "app()->request->hostInfo", ), 有多个分站时,同步登陆,基于cookie 'user'=>array( 'identityCookie'=>array('domain'=>'.dayouhui.com'), 'allowAutoLogin' => true, ) 如果是基本于session 'session' => array( 'cookieParams' => array('domain' => '.dayouhui', 'lifetime' => 0), 'timeout' => 3600, ), 如何使用theme 在main.php中配置 'theme'=>'classic', 如何得到前前使用的主题 Yii::app()->theme 得到名子 Yii::app()->theme->name; themes文件夹和protected是同级的,其下边某个theme的目录结果同protected/views下一样 关于skin 用theme改变view的外观,skin是用来改变widgets的外观的 skin是健值对用于初始化一个widget的属性 要对widget使用skin,需要做以下几步 1:配置'widgetFactory'=>array( 'enableSkin'=>true, ), 2:在views下建立skins目录 3:在skins目录下建立与Widget名子一样的php文件,返回数组,即能用于widget的初始配置 4:在php文件中,如果有defautl的配置,会先找这个skin 5:如果应用了theme,程序会先去对应的theme目录下的skins中找配置文件 6:如果只是想给widget统一一个skin,建议用Customizing Widgets Globally 如果防止post跨站攻击 'request'=>array( 'enableCsrfValidation'=>true, ), 这时候生成的表单要用CHtml::form(),其会写一段代码在cookie中 防止Cookie攻击 'request'=>array( 'enableCookieValidation'=>true, ), 同时生成与得到cookie是要用 CHttpCookie 如何让表单验证不驼过的提示为中文 在main.php的配置中加上 'language' => 'zh_CN', 如何实现仿google的自动完成功能 widget('CAutoComplete', array( 'name'=>'xxx', 'url'=>array('suggestTags'), 'multiple'=>false, 'htmlOptions'=>array('size'=>50), )); ?> 然后在url指定的地址中的方法中如下输出,即可 echo "a\nb\nc" //CGridView详解 这东西在后台比较有用,能加速开发的速度,值得一看 CGridView用表格的方式显示数据项 每一行代表一个数据项,一列通常代表数据项的一个属性 CGridView支持排序和分页,可以用ajax或普通的方式 CgridView必序和data provider一起使用 最简单的用法 $dataprovider = new CActiveDataProvider('Post'); $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, )); 这会用表格的方式显示每一条数据项,每一列是Post的一个属性 在显示中带了分页和排序 我们可以自定义CgridView::columns属性,以自定义表格列的显示方式 这个cloumns如何配置呢? 其是一个数组,每一个数组元素对应着一列的配置,可以是字符串或数组 1、如果是字符串,格式是name:type:header 后两者是可选的,根据这三个值,创建一个CdatColumn实例 其中type参见CFormatter 2、如果是数组,其可以实例化CDdataColumn、ClinkColumn,CButtonColumn,CCheckBoxColumn实例,具体实例化哪个 由数组中的class指定,默认是CDataColumn 2.1,如果class=>'CDataCloumn' 则可以指定name或者value,如果指定以value优先 用CDataColumn时如何以关联表的数据序列? 代码如下:表示可以post关联的author中的username排序列 $dataprovider = new CActiveDataProvider('Post',array( 'criteria'=>array( 'with'=>'author', ), 'sort'=>array( 'attributes'=>array( 'title','create_time', 'author_id'=>array('asc'=>'author.username asc','desc'=>'author.username desc','label'=>'作者') ) ), )); $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, 'columns'=>array( 'title', 'create_time', array('name'=>'author_id','value'=>'$data->author->username'), ), )); 另外CDataColumn还有一个filter属性,如果是空,那么生成一个textfield,如果是数组(键值),则生成一个dropDownlist在当前列的上部,供搜索 2.2:如果class=>"CLinkColumn" array('class'=>'CLinkColumn','label'=>'查看用户','url'=>Yii::app()->createURL('user/edit')) 则生成一个连接 2.3:如果class="CCheckBoxColumn" array('class'=>'CCheckBoxColumn','name'=>'title','id'=>'select'), 可以生成一个checkbox供选择,且只能选一个 可以配置CGridView::selectableRows 如果是0,则不能选,如果 1,只选一个如果是2或其它值,则可以选多个 代码如下: $this->widget('zii.widgets.grid.CGridView',array( 'dataProvider'=>$dataprovider, 'selectableRows'=>2, 'columns'=>array( array('class'=>'CCheckBoxColumn','name'=>'title','id'=>'select'), ), 2.3:如果class="CButtonColumn" array( 'class'=>'CButtonColumn', 'updateButtonUrl'=>'Yii::app()->createUrl("post/edit",array("id"=>$data->id));', ), 修改updateButtonUrl为编辑贴子 如何用gridview生成一个代搜索的管理列表 1、在Model的rules 设定可以搜索的属性 array('title, status, create_time', 'safe', 'on'=>'search'), 2、在Model中,添加搜索时的方法 public function search() { $criteria=new CDbCriteria; $criteria->compare('title',$this->title,true); $criteria->compare('status',$this->status); $criteria->compare('create_time',$this->create_time); return new CActiveDataProvider('Post', array( 'criteria'=>$criteria, 'sort'=>array( 'defaultOrder'=>'status, update_time DESC', ), )); } 3、 在Controler中,写接受搜索用到的表单的值的方法 public function actionAdmin() { $model=new Post('search'); if(isset($_GET['Post'])) $model->attributes=$_GET['Post']; $this->render('admin',array( 'model'=>$model, )); } 4、在view中用CGridView显示 设置好 widget('zii.widgets.grid.CGridView', array( 'dataProvider'=>$model->search(), 'filter'=>$model, 'columns'=>array( ), )); ?> 以上代码大部分是yii自动生成的,只要做少量修改即可 有时候会出现,搜索后页面为空的清况,原因可能是 layout/main.php中 echo $content外层无div,就是说main.php中必须有一个div包含$content //CListView详解 其用列表的形式显示数据,不象CGridView一样,用表格显示数据,CListView用一个 view模板来显示每一条数据 其支持排序与分页 常用的代码如下 array( 'pageSize'=>2 ), )); $this->widget('zii.widgets.CListView',array( 'dataProvider'=>$dataProvider, 'itemView'=>'_view', 'template'=>' {summary} {items} {pager}{sorter}', 'sortableAttributes'=>array( 'title', 'create_time'=>'Post Time', ), )); //CActiveForm详解 快速生成表单,支持ajax验证,对于比较复杂的验下最好是自己生成表单,写验证方法 常用代码,在Controller中 public function actionForm() { $post = new Post(); if(isset($_POST['ajax']) && $_POST['ajax']==='post'){ echo CActiveForm::validate($post); Yii::app()->end(); } if(isset($_POST['Post'])){ $post->attributes = $_POST['Post']; if($post->save()){ echo '存成功了'; } } $this->render('form',array('post'=>$post)); } 在view中 beginWidget('CActiveForm',array( 'id'=>'post',//这里与Controller中的ajax对应 'enableAjaxValidation'=>true, )); ?> labelEx($post,'title');?> textField($post,'title')?> error($post,'title'); ?> error一定要写上,要不不会触发ajax验证 labelEx($post,'content');?> textField($post,'content')?> isNewRecord ? 'Create' : 'Save'); ?> endWidget(); ?> //CBreadcrumbs常用代码 widget('zii.widgets.CBreadcrumbs', array( 'links'=>$this->breadcrumbs, 'homeLink'=>'shouye', 'separator'=>'>>>' )); ?> 其中breadcrumbs中Controller中的一个属性,如果要出现导航,就要在view中给此属性附值 生成的html如下 所以如果网站用到导航的时候,美工最好把导航代码定义如上 //CDetailView 用在仅仅是为了查看数据时,还是比较有用的,比如用在后台 如何在提交后显示一段提示 在控制器中 if(isset($_POST['name'])){ Yii::app()->user->setFlash('success','you are success'); $this->refresh(); } 在view中 if (Yii::app()->user->hasFlash('success')){ echo 're is'.Yii::app()->user->getFlash('success'); }else{ echo 'no'; } 如何得到当前域名: app()->request->hostInfo activeDropDownList,给出提示,并有值 array('empty'=>array(0=>'选择分组') 验证码如何生成及验证: Controller中 public function actions() { return array( 'captcha'=>array( 'class'=>'CCaptchaAction', 'backColor'=>0xFFFFFF, 'maxLength'=>4, 'minLength'=>4, ), ); } View中 widget('CCaptcha',array( 'captchaAction' => '/site/captcha', 'showRefreshButton' => false, 'clickableImage' => true, 'imageOptions' => array('align'=>'top', 'title'=>'重新获取'), ));?> Model中 array('verifyCode', 'captcha', 'captchaAction'=>'site/captcha', 'message' => '输入的验证码不正确'), set_time_limit(0);//禁止角本超时 如何想把手工的东西记录的数据库 main.php中配置log array( 'class'=>'CDbLogRoute', 'levels'=>'info', 'logTableName'=>'Log', 'connectionID'=>'db', ), 应用时 Yii::log('信息','info'); deleteAllByAttributes(array("phone"=>$phones)直接接受一个数组,可以删除数组中符合条件的记录 YII_BLOG STUDY重新看了一遍yii blog,有些记录会与上边的重复 YII:Trace() 在debug模式是才记录信息,同时在main.php中的Log中的配置中的levels中要有trace,至于记录多少 栈由index.php中的YII_TRACE_LEVEL决定 配置Gii 'modules'=>array( 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'123', ), ), 获得客户端IP if($_SERVER['HTTP_CLIENT_IP']){ $ip = $_SERVER['HTTP_CLIENT_IP']; }elseif($_SERVER['HTTP_X_FORWARDED_FOR']){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }else{ $ip = $_SERVER['REMOTE_ADDR']; } CActiveForm还是比较强大的,建议在以后的项目中form都用这个来实现 layout/中的视图是可以继承的 beginContent('/layouts/main'); ?> 然后在中间出现$content即可 endContent(); ?> create,update最好是分开放在两个action中,共用一个form,中间可以加一层view,以在头尾显示不同的东西 成段的完成一个功能的代码尽量拿出来放到一个方法中 $this->beginWidget('CMarkdown', array('purifyOutput'=>true)); echo $data->content; $this->endWidget(); linkButton,在删除时需要用js提示,可以看下这此组件中的comfirm 而且他们的提交方式都是post,是因为在jquery.yii.js写死了 具体的以在源文件中低部找到那段js中的ajaxsubmit,所在的js看下 filter是在执行action之前或之后执行的一段代码,要应用filters必须得写 CController::filters()方法 为什么在filters方法写上 return array( 'accessControl', // perform access control for CRUD operations );能进行crud验证呢? accessController是CContronller内置的filter,其调用 accessRules,得到验证规定,所以也要重写对应的accessRules,返回一个验证规则的数组成部分 if the application uses modules, a root alias is also predefined for each module ID and refers to the base path of the corresponding module 如:echo YiiBase::getPathOfAlias('bbs');得到module bbs的路径 关于CUrlManager '模式'=>'route' matchValue是指,对于一个url规则,正常情况下是只看参数的名子是否一样就应用规则 如果matchValue=true,则也要看值 如,规则 'index-/<id:\d+>'=>array("book/index",'matchValue'=>false), $this->createUrl('book/index', array('id'=>'abcd'));可以应用以上规则的, 如果规则中的matchValue=true,则就不能应用了 XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。 它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时, 嵌入其中Web里面的html代码会被执行 renderPartial() render() 后者会把需要的js,css等嵌入 前者可以通过把最后一个参数设置成true完成一样的功能 addInCondition 不用考虑数组是空的情况yii会自动处理 如何得到当前url? Yii::app()->request->url; ctype_开始的几个函数,用于检查字任串是不是符合要求,代替了简单的正则表达式 CController中的setPageState可以保存同一页中的POST的表单状态 如何通过BEhavior修改CActiveRecord? 写类文件继承自 class LLog extends CActiveRecordBehavior{ public function beforeDelete($event){ $model = get_class($this->Owner); //做要做的事,比如日志或修改模型字段内容 } } 然后修改模型文件 public function behaviors() { return array( // Classname => path to Class 'LLog'=>'application.behavior.LLog', ); } 如何在应用程序处理请求之前执行一段操作? 在main.php中配置 'onBeginRequest' => 'function' 当然这个function方法要存在 也可以写在放口文件index.php中,代码改成如下 $app = Yii::createWebApplication($config); $app->onbeginRequest = 'begin'; $app->run(); function begin(){ echo 'yyyyydddyyyyyy'; } 为什么在CActiveRecordBehavior中用 beforesave就可以代表了事件onBeforeSave 注意基为中最上边的events方法中返回的对应关系 'onBeforeSave'=>'beforeSave' 在调用attacth(CBehavior中)的时候, $owner->attachEventHandler($event,array($this,$handler)); 就指定了事件onBeforeSave的处理函数是用本类中的beforeSave YII中的CComponent,CEvent与Behavior及CActiveRecordBehavior个人理解 这一块教程少,今天个人理解了下,写了个小例子,有助于理解 完成如下功能,一个JTool类,继承CComponent,当其长度改变时,调用事件,输出"change me". JTool.php在protected/components 下 _width ? $this->_width : 1; } public function setWidth($width){ if($this->hasEventHandler('onChange')){ $this->onChange(new CEvent()); } $this->_width = $width; } public function onChange($event){ $this->raiseEvent('onChange', $event); } } OK,功能已经实现了,找个控制器,执行 $j = new JTool(); $j->onChange = "showChange"; //给事件绑定handle showChange $j->width = 100; //调用setWidth,解发绑定的事件showChange function showChange(){ echo 'changed me'; } 现在我们想给JTool添加一个功能,返回长度的100倍,我们可以继承JTool.php写一个方法 class JToolSub extends JTool{ public function get100width(){ return $this->width*100; } } OK,功能实现了,这个执行就简单了new JToolSub调用方法即可 上边的这两种办法,就是仅完成功能,下边演示Behavior及events来实现 如何用Behavior来实现上边的增加一个方法,返回长度的100倍的功能呢? 写类JBe JBe.php在protected/behavior 下 class JBe extends CBehavior{ public function get100width(){ return $this->Owner->width*100; } } OK,功能已经实现了,找个控制器,执行 $j = new JTool(); $j->attachBehavior('JBe', 'application.behavior.JBe'); echo $j->get100width(); 如何用Behavior实现JTool中的长度改变时,调用一个事件的功能呢? 写类JBe class JBe extends CBehavior{ public function events(){ return array_merge(parent::events(),array( 'onChange'=>'change', )); } public function change(){ echo 'changed'; } public function get100width(){ return $this->Owner->width*100; } } OK,功能实现随便找个控制器,执行 $j = new JTool(); $j->attachBehavior('JBe', 'application.behavior.JBe'); $j->width = 100; 这里的要点是events方法 返回的数组array('onChange'=>'change')定义了事件(event)和对应的事件处理方法(event hander) 事件是是Compents(JTool中)定义的,即JTool中的onChange 处理方法同由Behavior(JBe中)类定义的,即JBe中的change 这样子再看CActiveRecordBehavior,其是绑定给CActiveRecord 这个组件的,绑定方法重写behaviors() CActiveRecordBehavior中的events() 方法返回事件及事处理函数的对应,如: 'onBeforeSave'=>'beforeSave' 即组件CActiveRecord中的onBeforeSave这个事件对应的处理函数是 CActiveRecordBehavior中的beforeSave方法 这样子CActiveRecord在调用save()时,触发事件onBeforeSave,调用CActiveRecordBehavior对应的处理函数beforeSave 我们只要写一个CActiveRecordBehavior的子类,重写其中的beforeSave,执行一些操作,然后给CActiveRecord绑定即可 如果你自己有个目录下有些类或文件常用,可以在main.php的最上边定义一个路径别名 Yii::setPathOfAlias('local','path/to/local-folder'); 如果是多个可以在main.php中的array中加一个配置 'aliases'=>array( 'local'=>'path/to/local/' ), 如何得到proteced目录的物理路径? YII::app()->basePath; widget是发布资源 $url = Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('application.components.homeuserlived')); cs()->registerCoreScript('jquery'); cs()->registerScriptFile($url.'/location.js' ,CClientScript::POS_HEAD); cs()->registerScriptFile($url.'/YLChinaArea.js' ,CClientScript::POS_HEAD); cs()->registerCssFile($url.'/style.css'); 如何写application component, 即在main.php可配置 "my"=>array('') 可以通过Yii::app()->my来访问? 继承CApplicationComponent即可,并可以自带Behavior等 yii中读写session的两种方法 $session = Yii::app()->session; $session['terry'] = 30; var_dump($session['key']); Yii::app()->user->setState('tom', '40'); var_dump(Yii::app()->user->getState('key', 'default')); ==========================================分隔线=================================== soap非yii教程,意思是不用yii框架的时候要对象提供webservice的写法 分两种WSDL模式,和非WSDL模式,先看后者 这个也比较简单,服务器端 server.php ini_set('soap.wsdl_cache_enabled',0); class Student { /** * * @param string $name * @param int $age * @return string */ public function getInfo($name,$age){ if($age == 20){ throw new SoapFault(-1, 'Cannot divide by zero!'); } $xml = "".$name.""; $xml .= "".$age.""; return $xml; } } $soapS = new SoapServer(null,array('uri' => 'http://www.dayouhui.com')); $soapS->setClass('Student'); $soapS->handle(); ?> 客户端client.php "http://localhost/mysoap/index.php",'uri'=>'inadex.php')); echo $soap->getInfo('a','b'); 这样子即可 ============================================= yii,Componnts那快,忘了,写了个小例子回忆了下 是写一个可以写在main.php中的Components并绑定行为,事件 ====================================== class ExtWindow extends CApplicationComponent{ private $title = 'title'; public $oldtitle; public function getTitle(){ return $this->title ? $this->title : 'old title '; } public function setTitle($title){ echo '=='.$this->oldtitle.'=='; $this->oldtitle = $this->title; $this->title = $title; if($this->hasEventHandler('onTitleChange')){ $event =new CEvent($this); $this->raiseEvent('onTitleChange', $event); } } //必须有这么个方法,其和raiseEent中的事件一样,具体看代码 public function onTitleChange($event){ } } =========================== 'titleChange', )); } public function titleChange($event){ echo $event->sender->title; echo 'event TitleChange is handled in Behavior '; echo $this->owner->title; } public function titleOld(){ echo ' old title is is '.$this->owner->oldtitle; } } ============================== main.php中的写法 'ExtWin'=>array( 'class' => 'ExtWindow', 'oldtitle'=>'我是旧的', 'behaviors'=>array('win'=>'application..behavior.Window') ============================================= 一对多,多对多的关联时最后的参数 together说明 如果为false,分开查多个语句 如果为true,强制生成一个语句 如果没有设置,分页页生成多个语句,不分页时生成一个语句 ), 多对多时,查询时,中间表的名子叫 (关联名_关联名) with选项的作用是eager loading together的作用是 要不要形成一个语句 当是一个sql语句是记录会有重复,这时候分页分出现相同的记录,加上group=>true即可, 只要弄明白了,你生成的sql是一条还是多条sql就明白在多对多查询时的结果了 两个表不是用主键关联 'user' => array(self::BELONGS_TO, 'OaskUser', '','on'=>'name=userName', 'select'=>'TrueName'), 表带talbeprefix是,多对关联,键的写法 'categories'=>array(self::MANY_MANY,'Category','{{post_category}}(post_id,category_id)'), http://hi.baidu.com/48238398/item/3cf46158128eeb11aaf6d7c2

Yii_config

  [php] // 取消下行的注释,来定义一个路径别名 // Yii::setPathOfAlias('local','path/to/local-folder'); // 这是 Web 应用配置的主体部分。任何可写的 // CWebApplication 属性可以在这里配置。 $config = array( // protected目录的基础路径 // 使用Yii::app()-&gt;basePath 来访问 'basePath'=&gt; dirname(__FILE__) . DIRECTORY_SEPARATOR .'..', //应用的名字 // 使用Yii::app()-&gt;name 来访问 'name'=&gt; 'My website', //路径别名 //可以是应用内部的路径,也可以是外部资源 'aliases'=&gt; array( 'myExternalFramework' =&gt; dirname(__FILE__) .DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' .DIRECTORY_SEPARATOR . 'myexternalframework' ), //维护程序时,这样子所有的请求转发到一个地方 'catchAllRequest' =&gt; array('site/all'), //如何在应用程序处理请求之前执行一段操作?当然这个function方法要存在index.php 'onBeginRequest' =&gt; 'function', //controllerpath 'controllerMap' =&gt; array('myController'=&gt;'myExternalFramework.controllers.MyController'), // 默认的controller 'defaultController' =&gt; 'site', // 用户语言(forLocale) 'language'=&gt; 'es', //信息和视图的语言 'sourceLanguage' =&gt; 'es', 'timeZone'=&gt; 'Asia/Shanghai', 'theme'=&gt; 'default', //使用的字符集 'charset'=&gt; 'utf-8', //预载入的应用组件 'preload'=&gt; array('log'), //自动载入的类 'import'=&gt; array( 'application.models.*', 'application.components.*', ), // 可以使用Yii::app()-&gt;params['paramName'] 访问的应用级别的参数 'params'=&gt; require(dirname(__FILE__) . '/params.php'), // 在params.php中你需要返回这个数组:Yii::app()-&gt;setParams设置的只能用Yii::app()-&gt;params['xxx']这种数组的方式访问 // returnarray('adminEmail'=&gt;'info@example.com'); //应用组件的配置 'components'=&gt; array( // assets, 参考www.yiiframework.com/doc/api/CAssetManager 'assetManager' =&gt; array( // 改变磁盘上的路径 'basePath' =&gt; dirname(__FILE__) .'/../../assets/', // 改变url 'baseUrl' =&gt; '/web/assets/' ), 'request' =&gt; array( 'enableCsrfValidation' =&gt; true, //如果防止post跨站攻击 'enableCookieValidation' =&gt; true, //防止Cookie攻击 ), // 缓存 'cache' =&gt; array( 'class' =&gt; 'A cache class, like:system.caching.CApcCache', ), 'session' =&gt; array( // memcachesession cache 'class' =&gt; 'CCacheHttpSession', 'autoStart' =&gt; 1, 'sessionName' =&gt; 'frontend', 'cookieParams' =&gt; array('lifetime' =&gt;'3600', 'path' =&gt; '/', 'domain' =&gt;'.test.com', 'httponly' =&gt; '1'), 'cookieMode' =&gt; 'only', ), // 你可以使用 scriptMap 来配置脚本来自哪里。 // 对于一个生产环境的配置,如下 'clientScript' =&gt; array( 'scriptMap' =&gt; array( 'register.js' =&gt; 'site.min.js', 'login.js' =&gt; 'site.min.js', ), ), // 对于一个开发环境,可以这样做 'clientScript' =&gt; array( 'scriptMap' =&gt; array( 'register.js' =&gt; 'register.js', 'login.js' =&gt; 'login.js', ), ), ), ); $database = require(dirname(__FILE__) .DIRECTORY_SEPARATOR . 'db.php'); if (!empty($database)) { $config['components'] =CMap::mergeArray($config['components'],$database); // Yii::app()-&gt;setComponents($database); } return $config; ///////////////////////////////////////// 数据库配置/////////////////////////////// //db.php return array( 'db'=&gt; array( 'connectionString' =&gt;'mysql:host=192.168.1.240;dbname=tttt', 'emulatePrepare' =&gt; true, 'username' =&gt; 'root', 'password' =&gt; '****', 'charset' =&gt; 'utf8', ), 'card'=&gt; array( 'class' =&gt; 'CDbConnection',// 'connectionString' =&gt;'mysql:host=192.168.1.240;dbname=card', 'emulatePrepare' =&gt; true, 'username' =&gt; 'root', 'password' =&gt; '**', 'charset' =&gt; 'utf8', ), ); ///////////////////////////////////////// 共它组件配置////////////////////////// //params.php return array( 'adminEmail'=&gt;'info@example.com', 'pagesize'=&gt;'100', 'pager'=&gt;array( 'class'=&gt;'PagerWidget', 'maxButtonCount'=&gt;8, 'firstPageLabel'=&gt;'首页', 'lastPageLabel'=&gt;'末页', 'nextPageLabel'=&gt;'下一页', 'prevPageLabel'=&gt;'上一页', 'header'=&gt;'', 'cssFile'=&gt;false, ), ); [/php]