本文記錄 Yii 1.x 開發過程中遇到的典型問題及解決方案,非官方教程,僅供參考。涵蓋靜態資源註冊、模型狀態判斷、表單構建、事務處理、關聯查詢、文件上傳、場景驗證等核心場景。
假設項目結構:protected 同級目錄下有 js/ 和 css/ 文件夾。在 View 中註冊:
// 註冊 JS 文件,第二參數指定位置
Yii::app()->clientScript->registerScriptFile(
Yii::app()->baseUrl . '/js/project1.js',
CClientScript::POS_HEAD // 可選:POS_HEAD、POS_BEGIN、POS_END
);
// 註冊 CSS 文件,第二參數為 media 類型
Yii::app()->clientScript->registerCssFile(
Yii::app()->baseUrl . '/css/project1.css'
);
// 註冊 jQuery 核心庫(推薦方式)
Yii::app()->clientScript->registerCoreScript('jquery');
注意:registerScriptFile 和 registerCssFile 參數含義不同,切勿混淆。
當事務回滾導致數據未真正寫入但 isNewRecord 已變為 false 時,需手動校驗:
if (!$model->isNewRecord) {
$db_exist = Post::model()->findByPk($model->id);
if ($db_exist === null) {
$model->isNewRecord = true;
}
}
// 隱藏域(符合 Yii 表單規範)
echo $form->hiddenField($model, 'name');
if ($model->isNewRecord) {
echo $form->hiddenField($model, 'path', array('size'=>60, 'maxlength'=>128, 'id'=>'path1'));
}
// 簡單下拉選單(鍵值對直接定義)
echo $form->dropDownList($model, 'is_marry', array('0'=>'否', '1'=>'是'));
// 複雜下拉選單(從 Model 獲取數據)
// Model 中定義:
public function getUserOptions() {
$models = User::model()->findAllByAttributes(array('is_register'=>'1'));
return CHtml::listData($models, 'id', 'name');
}
// View 中調用:
echo $form->dropDownList($model, 'user_id', User::model()->getUserOptions());
基本結構:
$transaction = Yii::app()->db->beginTransaction();
try {
// 業務邏輯
$modelA->save();
$modelB->save();
$transaction->commit();
} catch (Exception $e) {
$transaction->rollBack();
}
進階模式(推薦):逐步驗證,全部成功才提交:
$transaction = Yii::app()->db->beginTransaction();
try {
$validated = true;
$valid = $modelA->save();
$validated = $valid & $validated;
$valid = $modelB->save();
$validated = $valid & $validated;
if ($validated) {
$transaction->commit();
$this->redirect(array('view', 'id'=>$model->id));
} else {
$transaction->rollBack();
}
} catch (Exception $e) {
$transaction->rollBack();
}
當主表與關聯表存在同名字段(如均有 id)時,需設置別名避免 SQL 模糊:
$criteria = new CDbCriteria;
$criteria->alias = "post"; // 設置主表別名
$criteria->with = array('user'); // 關聯關係名
$criteria->compare('post.id', $Post->id, true); // 使用 表別名.字段名
$model = Post::model()->find($criteria);
前端表單(注意 enctype):
<form action="your_url" method="post" enctype="multipart/form-data" id="fileform">
文件上傳 <input id="file1" name="file1" type="file">
<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 "上傳出錯!";
exit;
}
if (!is_dir("attached/tmp/")) {
mkdir("attached/tmp/", 0777, true);
}
if (file_exists("attached/tmp/".$file_name)) {
echo "文件已存在!";
} else {
move_uploaded_file($tmp_name, "attached/tmp/".$file_name);
}
}
按日期歸檔(使用 rename 移動):
$date = str_replace('-', '', date('Y-m-d'));
$dir = "attached/file/{$date}/";
if (!is_dir($dir)) mkdir($dir, 0777, true);
$file_name = basename($old_file);
rename($old_file, $dir.$file_name);
// 查看當前場景 var_dump($model->scenario); // 查看場景安全屬性 $arr = $model->getSafeAttributeNames($model->scenario); var_dump($arr); // 強制賦值跳過安全過濾(僅限模型定義字段) $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;
}
Controller 中準備多模型數據:
$model = new Person;
$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 中循環輸出:
for ($i = 0; $i < count($addrs); ++$i) {
echo $form->labelEx($addrs[$i], "[{$i}]postcode");
echo $form->textField($addrs[$i], "[{$i}]postcode", array('size'=>10, 'maxlength'=>10));
// 其他字段...
}