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

Yii 2.0 進階應用:自定義元件實現全域圖片上傳功能 (元件註冊、模型綁定、視圖渲染)

     編輯:PHP 綜合知識

場景:專案多處需上傳圖片,封裝為元件全域複用

Yii 2 元件機制支援單例、延遲載入、依賴注入。將上傳邏輯封裝為 Upload 元件,在 components 註冊,控制器/模型/視圖任意處呼叫 Yii::$app->imgload。

1. 建立元件類 (backend/components/Upload.php)

namespace backend\components;

use Yii;
use yii\base\Component;
use yii\web\UploadedFile;

class Upload extends Component {
    /**
     * 上傳圖片並可選生成縮圖
     * @param Model   $model      已載入資料的模型實例
     * @param string  $path       相對儲存路徑 (如 'uploads/article/')
     * @param string  $attribute  模型屬性名 (對應 fileInput name)
     * @param bool    $thumb      是否生成縮圖
     * @return string|false       成功返回相對路徑 (含縮圖用 # 分隔),失敗 false
     */
    public function uploadPhoto($model, $path, $attribute, $thumb = false) {
        $root = Yii::getAlias('@webroot') . '/' . $path;
        $file = UploadedFile::getInstance($model, $attribute);

        if (!$file) return false;

        // 驗證圖片類型
        $allowedTypes = ['image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/gif'];
        if (!in_array($file->type, $allowedTypes)) {
            Yii::$app->session->setFlash('error', '僅支援 JPG/PNG/GIF 格式');
            return false;
        }

        // 驗證大小 (2MB)
        if ($file->size > 2 * 1024 * 1024) {
            Yii::$app->session->setFlash('error', '圖片不可超過 2MB');
            return false;
        }

        // 建立日期目錄
        $dir = date('Ymd') . '/';
        if (!is_dir($root . $dir) && !mkdir($root . $dir, 0777, true)) {
            Yii::$app->session->setFlash('error', '建立目錄失敗');
            return false;
        }

        // 唯一檔名
        $filename = mt_rand(1000, 9999) . time() . '.' . $file->extension;
        $filepath = $root . $dir . $filename;

        if (!$file->saveAs($filepath)) {
            Yii::$app->session->setFlash('error', '儲存失敗');
            return false;
        }

        $relativePath = $path . $dir . $filename;

        // 生成縮圖 (需安裝 imagine 或使用 GD)
        if ($thumb) {
            $thumbPath = $this->generateThumb($filepath, $root . $dir . 'thumb_' . $filename);
            if ($thumbPath) $relativePath .= '#' . $path . $dir . 'thumb_' . $filename;
        }

        return $relativePath;
    }

    private function generateThumb($src, $dst, $width = 200, $height = 200) {
        // 這裡簡略,實際建議使用 Yii2-Imagine 擴展
        // return $this->imagineResize($src, $dst, $width, $height);
        return true; // 佔位
    }
}

2. 註冊元件 (backend/config/main.php)

return [
    'components' => [
        // ... 其他元件
        'imgload' => [
            'class' => 'backend\components\Upload',
        ],
    ],
];

3. 控制器使用

namespace backend\controllers;

use backend\models\Article;
use Yii;

class ArticleController extends \yii\web\Controller {
    public function actionCreate() {
        $model = new Article();

        if ($model->load(Yii::$app->request->post())) {
            // 上傳封面圖 (cover 為資料表欄位)
            $imgPath = Yii::$app->imgload->uploadPhoto($model, 'uploads/article/', 'cover', true);

            if ($imgPath) {
                $model->cover = $imgPath;  // 格式: uploads/article/20240115/abc.jpg#uploads/article/20240115/thumb_abc.jpg
                if ($model->save()) {
                    Yii::$app->session->setFlash('success', '新增成功');
                    return $this->redirect(['index']);
                }
                // 存失敗刪除已上傳檔案
                @unlink(Yii::getAlias('@webroot') . '/' . explode('#', $imgPath)[0]);
            }
            Yii::$app->session->setFlash('error', '新增失敗');
        }

        return $this->render('create', ['model' => $model]);
    }
}

4. 視圖渲染上傳欄位

use yii\widgets\ActiveForm;
use yii\helpers\Html;

/* @var $model backend\models\Article */
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>

    

    
    

    
    
        <div class="mt-2">
            <img src="" alt="預覽" style="max-height:100px;">
        </div>
    

    <div class="form-group">
        
    </div>

進階:前後端分離 API 上傳

// 控制器動作回傳 JSON
public function actionUpload() {
    $model = new \yii\base\DynamicModel(['file']);
    $model->addRule('file', 'file', ['extensions' => 'jpg, png, gif', 'maxSize' => 2*1024*1024]);
    $model->file = UploadedFile::getInstance($model, 'file');

    if ($model->validate()) {
        $path = Yii::$app->imgload->uploadPhoto($model, 'uploads/temp/', 'file');
        return ['success' => true, 'url' => Yii::$app->urlManager->baseUrl . '/' . $path];
    }
    return ['success' => false, 'errors' => $model->errors];
}

元件化優勢總結

傳統寫法元件化寫法
各控制器複製上傳邏輯單一定義,全域 Yii::$app->imgload 呼叫
修改需逐個檔案改只改元件類,自動生效
難以單元測試元件可獨立實例化測試
參數硬編碼元件屬性可配置化 (如最大尺寸、允許類型、儲存路徑前綴)

配置化元件屬性 (main.php)

'imgload' => [
    'class' => 'backend\components\Upload',
    'maxSize' => 5 * 1024 * 1024,      // 5MB
    'allowedTypes' => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
    'savePathPrefix' => 'uploads/',
    'thumbWidth' => 300,
    'thumbHeight' => 300,
],

元件類中透過 $this->maxSize 等屬性讀取配置。

掌握 Yii 2 元件機制,將通用業務邏輯 (上傳、匯出、支付、通知等) 封裝為可配置、可測試、全域可用的服務,是構建可維護大型應用的關鍵技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved