Best way to create/update model and relation

I am using the advanced app, with the default "user" migration. I then create a new table migration for "user_profile" which has a "user_id" column as a relation to back to "user->id".

  • user

    • id
    • username
  • user_profile

    • id
    • user_id <-- relation to user->id
    • firstname

A typical setup.

There are relation getters both ways. User can fetch it’s profile via “$user->profile->firstname”. The reverse works, if you pull up by the profile, you can get the user, “$profile->user->username”.

I am trying to streamline the create and update actions to handle both "user" and "profile" the easiest, cleanest, most elegant way.

I think the easiest way to update them is like so:

UserController.php




    public function actionUpdate($id)

    {

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


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

        {

            if ( $model->save() && $model->profile->save() ) {

                Yii::$app->session->setFlash('success', 'The user account has been updated!');

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

            }

        }


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

            'model' => $model,

        ]);

    }



Note: We can call “load()” on the model (which is User) like normal AND on the relation “$model->profile->load()”. Then call save on both ($model->save() and $model->profile->save()) It works great :) – This streamlined the process, we don’t have to do a separate “Profile::find()”. This is the cleanest way. Anyone else working with this code would be able to see what is going on, and it isn’t in an unnecessary Form model for such a simple step.


However, what is the best way to handle creating a new user and giving them some profile information? IE: create a new user and a profile all in one go.

So far, I know of 2 ways to do this.

  1. Use a form to handle the inputs (both from user and profile), ie: username, email, firstname, lastname, phone



    public function actionCreate()

    {

        $model = new CreateUserForm;


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

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

        }


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

            'model' => $model

        ]);

    }



Inside CreateUserForm:




    public function createUser()

    {

        if ($this->validate())

        {

            $user = new User();

            $user->username = $this->username;

            $user->email = $this->email;

            $user->status = $this->status;

            $user->setPassword($this->password);

            $user->generateAuthKey();


            if ($user->save())

            {

                $profile = new UserProfile;

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

                $profile->firstname = $this->firstname;

                $profile->lastname = $this->lastname;


                return $profile->save() ? $user : null;

            }

        }


        return null;

    }



Note: In this, we manually create the user via “new User” and manually create the profile via “new UserProfile”. Pretty typical stuff. However, I should be able to create a new user and define it’s relation info, without manually calling “new UserProfile” and saving it separately. Yii already knows the relation and that it is related via the “id to user_id” relation…

  1. The same way CreateUserForm works, only inside the create action itself and not neatly tucked inside a form…

So my question is, is there a way to create “user” and it’s related “profile” in one go without adding “$profile = new UserProfile” and filling/saving it separately? Similarly how I was able to update both of them in one go…


PS: I just found the "link()" function Yii2 Doc -> Saving Relations. Basically, I want to do this, ONLY I also need to create the user too. Unfortunately, "link()" needs the user to already exist. In the meantime, I used transactions to create the user and the profile.

Wow, it’s a very enlightening article. It describes very well how to handle relational models in Yii ActiveRecord ORM.

I don’t want that much. Your goal looks overly aggressive or sophisticated to me. :)

Look into http://www.yiiframework.com/doc-2.0/guide-concept-events.html

You can use EVENT_AFTER_INSERT and EVENT_AFTER_UPDATE events to save the relation data.