首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Yii 框架開發實戰:常見錯誤解決方案與最佳實踐總結

     編輯:PHP 相關知識

Yii 框架開發實戰:常見錯誤解決方案與最佳實踐總結

本文記錄 Yii 1.x 開發過程中遇到的典型問題及解決方案,非官方教程,僅供參考。涵蓋靜態資源註冊、模型狀態判斷、表單構建、事務處理、關聯查詢、文件上傳、場景驗證等核心場景。

1. JS/CSS 文件正確註冊方式

假設項目結構: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 參數含義不同,切勿混淆。

2. isNewRecord 狀態修復機制

當事務回滾導致數據未真正寫入但 isNewRecord 已變為 false 時,需手動校驗:

if (!$model->isNewRecord) {
    $db_exist = Post::model()->findByPk($model->id);
    if ($db_exist === null) {
        $model->isNewRecord = true;
    }
}

3. 隱藏輸入域與下拉選單生成

// 隱藏域(符合 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());

4. 事務處理最佳實踐

基本結構:

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

5. 關聯表同名字段查詢解決方案

當主表與關聯表存在同名字段(如均有 id)時,需設置別名避免 SQL 模糊:

$criteria = new CDbCriteria;
$criteria->alias = "post";           // 設置主表別名
$criteria->with = array('user');     // 關聯關係名
$criteria->compare('post.id', $Post->id, true);  // 使用 表別名.字段名
$model = Post::model()->find($criteria);

6. 文件上傳完整實現

前端表單(注意 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);

7. 場景與安全屬性控制

// 查看當前場景
var_dump($model->scenario);

// 查看場景安全屬性
$arr = $model->getSafeAttributeNames($model->scenario);
var_dump($arr);

// 強制賦值跳過安全過濾(僅限模型定義字段)
$model->setAttributes($_GET['Post'], false);

8. 日期格式驗證函數

function checkDatetime($dateStr, $format = "Y-m-d H:i:s") {
    $time = strtotime($dateStr);
    $checkDate = date($format, $time);
    return $checkDate == $dateStr;
}

9. 多模型表單渲染(一對多場景)

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));
    // 其他字段...
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved