This article is intended to record solutions to minor problems in the Yii development process. It is not comprehensive, not authoritative, and is not a tutorial. I have written it myself, and I think it can solve the problem. It may be used in the future, so just remember it.
1. Introduction of Js and Css files in Yii.
Let’s start with the simplest question. It’s not a problem, it’s just grammar. Assume that our js files are placed in the js folder at the same level as protected, and the css files are placed in the css folder at the same level as protected. Well, the specification is like this... Then we can put it in the corresponding view The interface is written as follows. The parameters of the css and js functions are different... (It took an hour to adjust because of this..)
The second parameter of the registered js file is the location where the js is placed. There are three options: CClientScript::POS_HEAD is placed in the Head part. CClientScript::POS_BEGIN is placed at the beginning of the Body. CClientScript::POS_END is placed at the end of the Body. There are no special requirements. There is no need to fill it out... The second parameter of the registered Css file is media. Interested students can click here. For now, the default is fine...
For js like Jquery, using registerCoreScript will not cause inexplicable errors...
//注册 js 文件 Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl.'/js/project1.js',CClientScript::POS_HEAD); //注册 css 文件 Yii::app()->clientScript->registerCssFile(Yii::app()->baseUrl.'/css/project1.css'); //注册 Jquery 文件 Yii::app()->clientScript->registerCoreScript('jquery');
2. Yii isNewRecord fix
The isNewRecord attribute of Yii’s Model is very useful and can be discussed on a case-by-case basis based on this attribute. However, if we turn on the transaction mechanism or other circumstances, causing the data to be rolled back after being inserted, then the record will not be in the database, but isNewRecord is false, which means it is no longer a new record. The solution is to use the primary key to access the database to determine whether it is a new record. Before using this attribute, we must first process it as follows. The following Model is Post, and the primary key is id:
if(!$model->isNewRecord) { $db_exist = Post::model()->findByPk($model->id); if($db_exist == NULL) $model->isNewRecord = true; }
3.Yii generates hidden input field
Although it is easy to write an input field by yourself (isn’t it just display:none), sometimes you have to follow Yii’s form code format. Anyway, just one sentence...
<?php echo $form->hiddenField($model,'name'); ?> <?php if($model->isNewRecord) echo $form->hiddenField($model,'path',array('size'=>60,'maxlength'=>128,'id'=>'path1')); ?>
4. Yii generates drop-down menu
Many times we need a drop-down menu in a form. At this time, Chtml’s listdata is very useful. If the fields in our database have only a few possibilities, such as 0 and 1, we can write it as follows:
echo $form->dropDownList($model,'is_marry',array('0'=>'否','1'=>'是'));
At this time, what you see is the drop-down menu of Yes and No. When you select 'Yes' to submit, this field will be filled with 1, and 'No' will be 0. Of course, it's often not just that simple. We can add a function to the Model to generate an array of drop-down menus, and then call it in the view. The data for this function can be written by yourself or found in the database. Listdata is used below, which specifically means that the id in the model is the key and the name is the value.
/* 写在 model 里 */ public function getUserOptions() { $models = User::model()->findAll(); $models = User::model()->findAllByAttributes(array('is_regeister'=>'1')); return CHtml::listdata($models, 'id', 'name'); } /* 写在 view 的界面里 */ echo $form->dropDownList($model,'user_id',User::model()->getUserOptions());
5.Yii Enable transaction mechanism
When you save several records to the database at the same time, you may need to enable the transaction mechanism. It is easy to enable the transaction mechanism in Yii, just three sentences are enough.
/*开启事务机制*/ $transaction = Yii::app()->db->beginTransaction(); try { /* 成功则 commit */ $transaction->commit(); } catch(Exception $e) { $transaction->rollBack(); }
A more complete one is like this:
if($_POST['ModelA']) { /*开启事务机制*/ $transaction = Yii::app()->db->beginTransaction(); try { /*此处省略一堆逻辑*/ $modelA->save(); $modelB->save(); /* 成功则 commit */ $transaction->commit(); $this->redirect(array('view','id'=>$model->id)); } catch(Exception $e) { $transaction->rollBack(); } }
But I usually do it like this, please experience the benefits yourself...
if($_POST['ModelA']) { /*开启事务机制*/ $transaction = Yii::app()->db->beginTransaction(); try { $validated = true; /*此处省略一堆逻辑*/ $valid = $modelA->save(); $validated = $valid & $validated; /*此处继续省略一堆逻辑*/ $valid = $modelB->save(); $validated = $valid & $validated; /* 成功则 commit */ if($validated) { $transaction->commit(); $this->redirect(array('view','id'=>$model->id)); } else { /*不成功即回滚 */ $transaction->rollBack(); } } catch(Exception $e) { $transaction->rollBack(); } }
6. An error occurred when querying the same fields in the associated table.
Sometimes we build two tables, but the two tables have the same fields. When using CDbCriteria to perform a with related query search, if no additional settings are made, a query error will occur, which probably means that the Mysql statement is ambiguous. . At this time, we can just set an alias in the main table, and then pay attention to adding the name when querying the relevant fields.
For example: two Models, Post and User, have an id. We can write it like this:
$criteria=new CDbCriteria; $criteria->alias = "post"; $criteria->with = array('user'); $criteria->compare('post.id',$Post->id,true); $model = Post::model()->find($criteria);
7. File upload
Speaking of which, this is not Yii. It is basically native HTML and PHP. If I am too lazy, I will just put it here.
The following is HTML, the action is changed to your own url, and the id and name are also defined by you.
<form action="your url" method='post' enctype="multipart/form-data" id='fileform'> <p style='display:inline-block'>文件上传 </p><input id='file1' name='file1' type='file' ></input> <br /> <input type='submit' value='上传'> </form>
This is the code for the server to receive and save the file. The file is finally saved to the file folder of the attached folder:
if(isset($_FILES['file1'])) { $xlsfile = $_FILES['file1']; $tmp_name = $xlsfile['tmp_name']; /*获取文件名*/ $file_name = basename($xlsfile_name); if($xlsfile['error'] > 0) { echo "文件上传出错!请重试。<br />"; exit; } else { if(file_exists("attached/tmp/".$file_name)) echo "文件已存在!本次不予保存!"; else { if(!is_dir("attached/tmp/")) { /*新建文件夹,默认权限 777, true 意味着可以递归从创建*/ if(!mkdir("attached/tmp/",0777,true)) { echo "找不到 attached/tmp 文件夹,且创建失败!<br />"; exit; } } /*这个函数仅用于上传文件的移动*/ move_uploaded_file($tmp_name,"attached/tmp/".$file_name); } } }
The following is to move the existing files from the old_file path to the current date folder in attached/file. The mobile here uses rename
/*创建文件夹*/ $date = date('Y-m-d',time()); $date = str_replace('-',"",$date); $dir = "attached/file/".$date.'/'; if(!is_dir($dir)) { if(!mkdir($dir,0777,true)) { exit('无法创建文件夹!'); } } /*移动文件*/ $file_name = basename($old_file); $finish = rename($old_file,$dir.$file_name); if(!$finish) { exit('无法移动文件!'); }
8.YIi Scenarios and Security Fields
View the current Model scene:
var_dump($model->scenario);
查看场景的安全字段。安全字段的意思是说这些数据由用户提交的时候不会被 Yii 过滤掉。有次发现网页提交上来的东西有些有有些没,调了很久才知道在那个场景下部分被过滤了。
$arr = $model->getSafeAttributeNames($model->scenario); var_dump($arr);
强制赋值避免 rule 规则过滤字段。用 setAttributes 可以强制取消 Yii 的安全过滤,只要第二个参数赋值为 false 就好。但是这也只能对这个 Model 生成时就拥有的字段生效,如果要对包括自己定义的所有字段不过滤,还是要定义场景然后在 rule 里指定安全字段比较好。
if(isset($_GET['Po'])) $model->setAttributes($_GET['Post'],false);
检查日期格式合法性
有时我们需要检验用户填写的日期是否合法,可以用下面的函数。
function checkDatetime($dateStr, $format = "Y-m-d H:i:s") { $time = strtotime($dateStr); $checkDate = date($format, $time); return $checkDate == $dateStr; }
Yii 渲染多个 model
相信新手都有疑惑,_form 里面的表单都是渲染一个 model 然后提交给 controller 保存数据的,如果想要渲染多个 model 怎么办呢?
下面,我们假设有两个 model 类,分别叫做 Person 和 Addr,我们想要做的是在一个 Person 的 _form 里再渲染几个 Addr 的 model ,意思是一个人可以有几个地址。基本思路其实还是很简单,就是你在 controller 里定义要渲染的 model 然后传给 view 界面,最后依然在 controller 里接收 Post 过来的数据。主要是写法问题而已,我相信下面大家都能看懂,有疑问的童鞋再留言好了。
//在 controller 里面 $model=new Person; /* $addrs 存储 Addr model 的数组,放几个你就看着办吧*/ $addrs = array(); if(isset($_POST['Person'])) { $model->attributes = $_POST['Person']; /*此处省略一堆逻辑*/ foreach($_POST['Addr'] as $one_addr) { $addr = new Addr(); $addr->attributes = $one_addr; /*此处省略另一堆逻辑*/ } } $this->render('create',array( 'model'=>$model, 'addrs' => $addrs, )); //在 view 里面 /*可以循环输出你的多个 model */ $num = count($addrs); for($i = 0;$i < $num;++$i) { echo $form->labelEx($addrs[$i],"[{$i}]postcode"); echo $form->textField($addrs[$i],"[{$i}]postcode",array('size'=>10,'maxlength'=>10)); ...; } /*也可以通过数字指定输出某个 model */ echo $form->labelEx($addrs[0],"[0]postcode"); echo $form->textField($addrs[0],"[0]postcode",array('size'=>10,'maxlength'=>10));