Yii2: Upload Image Using Kartik/Fileinput Plugin

I want to upload an image via Kartik widget. After submitting the form, the $_FILE['Product'] has the data about the image but getInstance($model, 'images') returns null. Tried with images[], also null. This is what I'm trying to var_dump in the controller:

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

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

And this is my model 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;
        }
    }
}

Tried with rules ['images', 'safe'] also ['images', 'file'] ( think the second one is not right because the attribute is an array, right ? ). The form is <?php $form = ActiveForm::begin(['options' => ['multipart/form-data']]); ?>. Finally my input:

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

Full controller action:

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,
        ]);
    }
9

1 Answer

What looks like you are trying to upload a single image you should remove the [] from the input field name from the ActiveForm field declaration, and from models rules.

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/*' ] ,
            ]) ?>

and from the following line

UploadedFile::getInstance($model, 'images');
Maya Lin-Takahashi

Maya Lin-Takahashi

Consumer Tech & Gadget Reviewer

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.