[Solved] Subforms

What is the clean way to implement subforms in Yii2?

I mean, managing two diferent models (from diferent classes) in the same form.

Thanks! :)

Basically the same as it was in yii 1. You can use Model::validateMultiple() if you have an array of models. Check out https://github.com/yiisoft/yii2/issues/3306 for an example. Have not checked the correctness of the code in that issue but the one in the initial post looks right to me to get the idea.

@CeBe I’ve already seen the docs about validating an array of models, but in that case the model Class is the same.

What I need is embed two different Class models in the same form.

The typical example is creating a User and filling the profile in the same form.

What I’m doing right now is something like (not real example):




// Controller

//

public function actionCreate()

{   

    $user = new User;

    $profile = new Profile;


    if ($user->load(Yii::$app->request->post()) && $user->save()) {

        

        $profile->user_id = $user->id;

        $profile->save();

        

        return $this->redirect(['view', 'id' => $user->id]);

    } else {

        return $this->render('create', [

            'user' => $user,

            'profile' => $profile,

        ]);

    }

}


// View

// 

<?= $form->field($profile, 'lastname')->textInput(['maxlength' => 30]) ?>


<?= $form->field($profile, 'firstname')->textInput(['maxlength' => 30]) ?>


<?= $form->field($user, 'email')->textInput(['maxlength' => 255]) ?>

...

// and so on

...



But one of the problems is for example validate the "profile" data before saving the "user"…

Should I use this approach and manually validate both of them before trying to save?

Maybe I am missing something and there is a correct way to do this…

Thanks!




public function actionCreate()

{   

    $user = new User;

    $profile = new Profile;


    if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post()) && Model::validateMultiple([$user, $profile])) {

        

        $user->save(false); // skip validation as model is already validated

        $profile->user_id = $user->id; // no need for validation rule on user_id as you set it yourself

        $profile-save(false); 

        

        return $this->redirect(['view', 'id' => $user->id]);

    } else {

        return $this->render('create', [

            'user' => $user,

            'profile' => $profile,

        ]);

    }

}



You are the man! :)

Thanks. This is useful. I extended this approach for tabular data collection.

is there any update sample code is available for multi model?

This tutorial can maybe help you.

What we could do if it was profiles not a profile. i.e hasToMany. In other words, suppose that it is Invoice -> Items relationship i.e one invoice may has several items?

This tutorial has a missed code:


getItemsToUpdate()

is not defined and there is no any hint about it.

1 Like