Z
Z
ZaurK2018-03-30 19:12:21
Yii
ZaurK, 2018-03-30 19:12:21

How to process two models in one form?

I'm trying to implement something like this , only on the action of adding a product to the database and attaching an image at the same time. I must say that separately adding an entry to the product table and uploading an image file to the server worked, but I decided to combine these models and process them in one form.
Here is the corresponding action from ProductController.php:

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

        if ($model->load(Yii::$app->request->post()) && $uploadForm->load(Yii::$app->request->post()) ) {
            $isValid = $model->validate();
            $isValid = $uploadForm->validate() && $isValid;
      if ($isValid) {
                $model->save(false);
                $uploadForm->save(false);
        return $this->redirect(['view', 'id' => $model->id]);
            }
      
        }

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

models/UploadForm.php:
<?php
namespace backend\models;

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

class UploadForm extends Model
{
    /**
     * @var UploadedFile
     */
    public $imageFile;

    public function rules()
    {
        return [
            [['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
        ];
    }
    
    public function upload()
    {
        if ($this->validate()) {
      $dir = Yii::getAlias('@uploads') . '/images/';
            $this->imageFile->saveAs($dir . $this->imageFile->baseName . '.' . $this->imageFile->extension);
            return true;
        } else {
            return false;
        }
    }
}
?>

models/Product.php:
<?php

namespace backend\models;

use Yii;
use backend\models\Category;
use yii\helpers\ArrayHelper;
/**
 * This is the model class for table "product".
 *
 * @property int $id
 * @property int $cat_id
 * @property string $ptitle
 * @property string $pdescription
 * @property string $img_path
 */
class Product extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'product';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['cat_id', 'ptitle'], 'required'],
            [['cat_id'], 'integer'],
            [['pdescription'], 'string'],
            [['ptitle', 'img_path'], 'string', 'max' => 256],
      [['cat_id'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['cat_id' => 'id']],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'cat_id' => 'Категория',
            'ptitle' => 'Название продукции',
            'pdescription' => 'Описание продукции',
            'img_path' => 'Img Path',
        ];
    }
  
  /**
     * @return \yii\db\ActiveQuery
     */
    public function getCategory()
    {
        return $this->hasOne(Category::className(), ['id' => 'cat_id']);
    }

    public function getCatName()
    {
        // Выбираем 
    $cattitle = Category::find()
        ->select(['id', 'ctitle'])
    ->where(['id' => $this->cat_id])
        ->one();

    return $cattitle ? $cattitle->ctitle : 'hhh';
    }
  
  public static function getCatsList()
{
    // Выбираем 
    $parents = Category::find()
        ->select(['id', 'ctitle'])
        ->all();
 
    return ArrayHelper::map($parents, 'id', 'ctitle');
}
}

views/product/create.php:
<?php

use yii\helpers\Html;


/* @var $this yii\web\View */
/* @var $model backend\models\Product */

$this->title = 'Добавить продукт';
$this->params['breadcrumbs'][] = ['label' => 'Продукция', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="product-create">

    <h1><?= Html::encode($this->title) ?></h1>

    <?= $this->render('_form', [
        'model' => $model,
    'uploadForm' => $uploadForm,
    ]) ?>

</div>

views/product/_form.php:
<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;
use backend\models\Category;

/* @var $this yii\web\View */
/* @var $model backend\models\Product */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="product-form">

     <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data'], 'action' => ['product/create'],]); ?>
  
  <?php
    $categories = ArrayHelper::map(Category::find()->all(), 'id', 'ctitle');
    echo $form->field($model, 'cat_id')->dropDownList($categories, ['prompt' => 'Выберите категорию']);
    ?>

    <?= $form->field($model, 'ptitle')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'pdescription')->textarea(['rows' => 6]) ?>

     <?= $form->field($uploadForm, 'imageFile')->fileInput() ?>
  
  

    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>

    <?php ActiveForm::end(); ?>	
</div>

As a result, when submitting the form with the fields filled in and the selected image, the inscription "file not selected" appears near the file selection field, it is obvious that the presence of the file does not pass validation. I tried to print the $_POST variable - indeed everything is filled in, except for the variable for the file.
Tell me what is wrong and how to implement it correctly?

Answer the question

In order to leave comments, you need to log in

[[+comments_count]] answer(s)
D
Dmitry, 2018-03-30
@slo_nik

Good evening.
First, save the Products model, generate a name for the new file, and pass that name to the UploadForm model.
Create a file name in beforeSave();
Also use transaction. If the file does not load, roll back the transaction.
It turns out that you need to save one model.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question