Yii2:使用Kartik / FileInput插件上传图像

时间:2018-03-21 19:55:01

标签: file-upload yii2 yii2-advanced-app

我想通过Kartik小部件上传图片。提交表单后,$_FILE['Product']包含有关图片的数据,但getInstance($model, 'images')会返回null。试过images[],也是null。 这就是我在控制器中尝试var_dump的原因:

public function actionCreate()
    {
        $model = new Product();

        if ($model->load(Yii::$app->request->post())) {
            var_dump(UploadedFile::getInstance($model, 'images[]'));die;

这是我的模型Product

<?php

namespace app\models;

use backend\models\CActiveRecord;
use Yii;
use omgdef\multilingual\MultilingualQuery;
use omgdef\multilingual\MultilingualBehavior;
use yii\web\UploadedFile;

/**
 * This is the model class for table "product".
 *
 * @property int $id
 * @property int $category_id
 * @property int $quantity
 * @property double $price
 * @property int $sort
 *
 * @property Productlang[] $productlangs
 */
class Product extends CActiveRecord
{
    public $images;

    public static function find()
    {
        return new MultilingualQuery(get_called_class());
    }

    public function behaviors()
    {
        $allLanguages = [];
        foreach (Yii::$app->params['languages'] as $title => $language) {
            $allLanguages[$title] = $language;
        }

        return [
            'ml' => [
                'class' => MultilingualBehavior::className(),
                'languages' => $allLanguages,
                //'languageField' => 'language',
                //'localizedPrefix' => '',
                //'requireTranslations' => false',
                //'dynamicLangClass' => true',
                //'langClassName' => PostLang::className(), // or namespace/for/a/class/PostLang
                'defaultLanguage' => Yii::$app->params['languageDefault'],
                'langForeignKey' => 'product_id',
                'tableName' => "{{%productLang}}",
                'attributes' => [
                    'title',
                    'description',
                    'meta_title',
                    'meta_desc',
                    'url'
                ]
            ],
        ];
    }
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'product';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        $string = $this->multilingualFields(['description', 'url']);
        $string_59 = $this->multilingualFields(['meta_title']);
        $string_255 = $this->multilingualFields(['meta_desc', 'title']);

        $string[] = 'description';
        $string[] = 'url';
        $string_59[] = 'meta_title';
        $string_255[] = 'meta_desc';
        $string_255[] = 'title';

        return [
            [['quantity', 'price', 'title', 'meta_title', 'meta_desc'], 'required'],
            [['category_id', 'quantity', 'sort'], 'integer'],
            [$string, 'string'],
            [$string_59, 'string', 'max' => 59],
            [$string_255, 'string', 'max' => 255],
            [['price'], 'number'],
            ['images', 'file']
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'category_id' => 'Category ID',
            'quantity' => 'Quantity',
            'price' => 'Price',
            'sort' => 'Sort',
        ];
    }

    public function upload()
    {
        if ($this->validate()) {
            foreach ($this->image as $file) {
                $file->saveAs(\Yii::getAlias("@images") . "/products/" . $this->id . "_" . $this->image->baseName . '.' . $this->image->extension);
            }
            return true;
        } else {
            return false;
        }
    }
}

尝试使用规则['images', 'safe']['images', 'file'](认为第二个不正确,因为该属性是一个数组,对吧?)。表格为<?php $form = ActiveForm::begin(['options' => ['multipart/form-data']]); ?>。 最后我的意见是:

<?= $form->field($model, 'images[]')->widget(FileInput::class, [
                'showMessage' => true,
            ]) ?>

完全控制器操作:

public function actionCreate()
    {
        $model = new Product();

        if ($model->load(Yii::$app->request->post())) {

            foreach (Yii::$app->params['languages'] as $language){
                if(Yii::$app->params['languageDefault'] != $language){

                    $title_lang = "title_$language";
                    $model->$title_lang = Yii::$app->request->post('Product')["title_$language"];

                    $description_lang = "description_$language";
                    $model->$description_lang = Yii::$app->request->post('Product')["description_$language"];

                    $meta_title_lang = "meta_title_$language";
                    $model->$meta_title_lang = Yii::$app->request->post('Product')["meta_title_$language"];

                    $meta_desc_lang = "meta_desc_$language";
                    $model->$meta_desc_lang = Yii::$app->request->post('Product')["meta_desc_$language"];

                }
            }

            if($model->save()){

                $model = $this->findModel($model->id, true);

                //Make urls
                foreach (Yii::$app->params['languages'] as $language) {
                    if (Yii::$app->params['languageDefault'] != $language) {
                        $url_lang = "url_$language";
                        $title_lang = "title_$language";
                        $model->$url_lang = $model->constructURL(
                            $model->$title_lang,
                            $model->id
                        );
                    }else{
                        $model->url = $model->constructURL(
                            $model->title,
                            $model->id
                        );
                    }
                }

                //Upload Images
                $model->images = UploadedFile::getInstance($model, 'images');
                if (!($model->upload())) {
                    Yii::$app->session->setFlash('error',  Yii::t('app', 'Some problem with the image uploading occure!'));
                    return $this->redirect(['create']);
                }


                if($model->update() !== false){
                    return $this->redirect(['view', 'id' => $model->id]);
                }else{
                    Yii::$app->session->setFlash('error',  Yii::t('app', 'Something went wrong. Please, try again later!'));
                    return $this->redirect(['create']);
                }
            }
        }

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

1 个答案:

答案 0 :(得分:0)

您尝试上传单个图片时应该从ActiveForm字段声明和模型规则中删除输入字段名称中的[]

Single File

<?= $form->field($model, 'images')->widget(FileInput::class, [
                'showMessage' => true,
                'pluginOptions' => [
                        'showCaption' => false ,
                        'showRemove' => false ,
                        'showUpload' => false ,
                        'showPreview' => false ,
                        'browseClass' => 'btn btn-success btn-block' ,
                        'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
                        'browseLabel' => 'Select Profile Image'
                    ] ,
                    'options' => ['accept' => 'image/*' ] ,
            ]) ?>

并从以下一行

UploadedFile::getInstance($model, 'images');

Multiple Files

对于多个文件,您需要为该字段添加'options' => ['multiple' => true],并将属性名称更改为images[]

<?= $form->field($model, 'images[]')->widget(FileInput::class, [
                'showMessage' => true,
                'pluginOptions' => [
                        'showCaption' => false ,
                        'showRemove' => false ,
                        'showUpload' => false ,
                        'showPreview' => false ,
                        'browseClass' => 'btn btn-success btn-block' ,
                        'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
                        'browseLabel' => 'Select Profile Image'
                    ] ,
                    'options' => ['accept' => 'image/*' ,'multiple'=>true] ,
            ]) ?>

并且为了接收上传的文件,您不应该将属性指定为数组只需将getInstance更改为getInstances,然后尝试打印,它会显示使用foreach()的所有图片保存所有这些。

UploadedFile::getInstances($model, 'images');

我个人更喜欢使用单独的模型进行文件上传,而不是使用ActiveRecord模型。

注意:使用多个文件上传时,您还可以在模型规则中指定'maxFiles'=>1000以限制要上传的文件数

修改

要对代码进行问题排查,您应该从控制器中注释掉actionCreate并替换为我在下面添加的代码

public function actionCreate() {
    $model = new Product();

    if ( $model->load ( Yii::$app->request->post () ) ) {

        foreach ( Yii::$app->params['languages'] as $language ) {
            if ( Yii::$app->params['languageDefault'] != $language ) {

                $title_lang = "title_$language";
                $model->$title_lang = Yii::$app->request->post ( 'Product' )["title_$language"];

                $description_lang = "description_$language";
                $model->$description_lang = Yii::$app->request->post ( 'Product' )["description_$language"];

                $meta_title_lang = "meta_title_$language";
                $model->$meta_title_lang = Yii::$app->request->post ( 'Product' )["meta_title_$language"];

                $meta_desc_lang = "meta_desc_$language";
                $model->$meta_desc_lang = Yii::$app->request->post ( 'Product' )["meta_desc_$language"];
            }
        }

        $transaction = Yii::$app->db->beginTransaction ();

        try {
            if ( !$model->save () ) {
                throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $model->errors , 0 , false ) ) );
            }

            //Make urls
            foreach ( Yii::$app->params['languages'] as $language ) {
                if ( Yii::$app->params['languageDefault'] != $language ) {
                    $url_lang = "url_$language";
                    $title_lang = "title_$language";
                    $model->$url_lang = $model->constructURL (
                            $model->$title_lang , $model->id
                    );
                } else {
                    $model->url = $model->constructURL (
                            $model->title , $model->id
                    );
                }
            }

            //save the new urls
            if ( !$model->save () ) {
                throw new \Exception ( implode ( "<br />" , \yii\helpers\ArrayHelper::getColumn ( $model->errors , 0 , false ) ) );
            }

            //Upload Images
            $model->images = UploadedFile::getInstances ( $model , 'images' );
            $model->upload ();

            //commit the transatction to save the record in the table
            $transaction->commit ();

            Yii::$app->session->setFlash ( 'success' , 'The model saved successfully.' );
            return $this->redirect ( [ 'view' , 'id' => $model->id ] );
        } catch ( \Exception $ex ) {
            $transaction->rollBack ();
            Yii::$app->session->setFlash ( 'error' , Yii::t ( 'app' , $ex->getMessage () ) );
        }
    }

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

并注释掉模型的upload()函数并添加以下函数

public function upload() {
    $skipped = [];
    foreach ( $this->images as $file ) {
        if ( !$file->saveAs ( \Yii::getAlias ( "@images" ) . "/products/" . $this->id . "_" . $this->image->baseName . '.' . $this->image->extension ) ) {
            $skipped[] = "File " . $file->baseName . " was not saved.";
        }
    }
    if ( !empty ( $skipped ) ) {
        Yii::$app->session->setFlash ( 'error' , implode ( "<br>" , $skipped ) );
    }
}

对于ActiveForm,请确保您的输入符合以下

$form->field($model, 'images[]')->widget(FileInput::class, [
            'showMessage' => true,
            'pluginOptions' => [
                    'showCaption' => false ,
                    'showRemove' => false ,
                    'showUpload' => false ,
                    'showPreview' => false ,
                    'browseClass' => 'btn btn-success btn-block' ,
                    'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ' ,
                    'browseLabel' => 'Select Profile Image'
                ] ,
                'options' => ['accept' => 'image/*','multiple'=>true ] ,
]) ;