이 글은 Yii 개발 과정에서 발생하는 사소한 문제에 대한 해결 방법을 기록하기 위한 글이며, 포괄적이지도, 권위적이지도 않으며, 튜토리얼도 아닙니다. 제가 직접 작성했는데, 나중에 문제를 해결할 수도 있을 것 같으니 꼭 기억해두세요.
1. Yii에 Js, Css 파일을 소개합니다.
가장 간단한 질문부터 시작해 보겠습니다. 문제가 아니라 단지 문법입니다. js 파일은 protected와 같은 수준의 js 폴더에 있고, css 파일은 protected와 같은 수준의 css 폴더에 있다고 가정해 보겠습니다. 그러면 사양은 다음과 같습니다. 해당 뷰에 css와 js 함수의 Parameter가 아래와 같이 작성되어 있습니다. (이 때문에 조정하는데 1시간이 걸렸습니다..)
등록된 js 파일의 두 번째 매개변수는 js가 배치되는 위치입니다. 세 가지 옵션이 있습니다. CClientScript::POS_HEAD는 CClientScript::POS_END 부분의 시작 부분에 배치됩니다. 특별한 요구 사항은 없습니다. 등록된 CSS 파일의 두 번째 매개 변수는 미디어입니다. 지금은 기본값을 사용해도 됩니다. ...
Jquery와 같은 js의 경우,registerCoreScript를 사용해도 설명할 수 없는 오류가 발생하지 않습니다...
//注册 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 수정
Yii 모델의 isNewRecord 속성은 매우 유용하며 이 속성을 기반으로 사례별로 논의할 수 있습니다. 그러나 트랜잭션 메커니즘이나 기타 상황을 켜서 데이터를 삽입한 후 롤백하면 레코드는 데이터베이스에 없지만 isNewRecord는 false이므로 더 이상 새 레코드가 아닙니다. 해결 방법은 기본 키를 사용하여 데이터베이스에 액세스하여 새 레코드인지 확인하는 것입니다. 이 속성을 사용하기 전에 먼저 다음과 같이 처리해야 합니다. 다음 모델은 Post이고 기본 키는 id입니다.
if(!$model->isNewRecord) { $db_exist = Post::model()->findByPk($model->id); if($db_exist == NULL) $model->isNewRecord = true; }
3.Yii가 숨겨진 입력 필드를 생성합니다
입력란을 직접 작성하는 것은 쉽지만(단순히 표시:없음이 아니냐) 때로는 Yii의 양식 코드 형식을 따라야 할 때도 있습니다. 어쨌든 한 문장만...
<?php echo $form->hiddenField($model,'name'); ?> <?php if($model->isNewRecord) echo $form->hiddenField($model,'path',array('size'=>60,'maxlength'=>128,'id'=>'path1')); ?>
4. Yii는 드롭다운 메뉴를 생성합니다
양식에 드롭다운 메뉴가 필요할 때가 많습니다. 이때 Chtml의 listdata가 매우 유용합니다. 데이터베이스의 필드에 0과 1 등 몇 가지 가능성만 있는 경우 다음과 같이 작성할 수 있습니다.
echo $form->dropDownList($model,'is_marry',array('0'=>'否','1'=>'是'));
이때 보이는 것은 Yes와 No의 드롭다운 메뉴입니다. 'Yes'를 선택하여 제출하면 이 항목은 1로 채워지고, 'No'는 0이 됩니다. 물론, 모델에 함수를 추가하여 드롭다운 메뉴 배열을 생성한 다음 뷰에서 호출할 수도 있습니다. 이 기능에 대한 데이터는 직접 작성하거나 데이터베이스에서 찾을 수 있습니다. 아래에는 Listdata가 사용되는데, 이는 특히 모델의 ID가 키이고 이름이 값임을 의미합니다.
/* 写在 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 거래 메커니즘 활성화
동시에 여러 레코드를 데이터베이스에 저장할 때 트랜잭션 메커니즘을 활성화해야 할 수도 있습니다. Yii에서는 거래 메커니즘을 활성화하는 것이 쉽습니다. 단 세 문장이면 충분합니다.
/*开启事务机制*/ $transaction = Yii::app()->db->beginTransaction(); try { /* 成功则 commit */ $transaction->commit(); } catch(Exception $e) { $transaction->rollBack(); }
더 완전한 것은 다음과 같습니다:
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(); } }
그런데 제가 원래 이렇게 하는 편인데, 그 혜택을 직접 경험해 보시길...
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. 연결된 테이블의 동일한 필드를 쿼리하는 동안 오류가 발생했습니다.
가끔 두 개의 테이블을 만들지만 두 테이블의 필드가 동일한 경우가 있습니다. CDbCriteria를 사용하여 관련 쿼리 검색을 수행할 때 추가 설정이 없으면 쿼리 오류가 발생하는데 이는 아마도 Mysql 문이 모호하다. 이때는 메인 테이블에 별칭을 설정하고, 관련 필드를 쿼리할 때 이름을 추가하는 것에 주의하면 됩니다.
예를 들어 Post와 User라는 두 모델에 ID가 있습니다.
$criteria=new CDbCriteria; $criteria->alias = "post"; $criteria->with = array('user'); $criteria->compare('post.id',$Post->id,true); $model = Post::model()->find($criteria);
7. 파일 업로드
말하자면 이것은 Yii가 아닙니다. 기본적으로 네이티브 HTML 및 PHP이므로 너무 게으르면 여기에 넣겠습니다.
다음은 HTML이고, 액션은 자신의 URL로 변경되며, id와 이름도 사용자가 정의합니다.
<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>
서버가 파일을 받아 저장하기 위한 코드입니다.
파일이 최종적으로 첨부된 폴더에 저장됩니다.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); } } }
다음은 기존 파일을 old_file 경로에서 attachment/file의 현재 날짜 폴더로 이동하는 것입니다. 여기 모바일은 이름 바꾸기를 사용합니다
/*创建文件夹*/ $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 시나리오 및 보안 분야
현재 모델 장면 보기:
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));