Form model to associate 3 different models as cascading array input

I know Yii2 is pretty powerful in associating multiple models as form to accept data from user. I need to make a “SINGLE” form to capture data for 3 Models that is many-one relation in upside down tree format.

For example:

company -> branch -> employee

I know how to do it with 2 models like below

namespace app\models\form;

/**
*@property Company $company
*@property Branch[] $branches
*/

Class OrganizationForm extends Model {

//get & Set for $company $branches

    function save(){
        //some processing code
        if ($this->company->save(false){

           foreach($this->branches as $id => $branch)
             //some processing code
             $branch->company_id = $this->company->id;
             $branch->save();
        }
}

How can I include employee Model in the same saving process as for each branch to have multiple employees…?

So you want to save 3 models from 1 form.
It sounds like you have the view for the form worked out already. (if not, I can answer that too)
I would save in a Transaction.
Transactions are all or nothing - if any of them fail, nothing is saved.

Here is a basic example - you would add functions before validate/save
I threw in a few basic actions and assumed you can figure it out.
(I mixed create and update just so you could see syntax for both)

Let me know if its not clear

updated my code to match your question, inc foreach - not sure what you are doing, be careful with the foreach
Ex: of what not to do in employee - be cautious of multiple queries to the db.
If its just for initial creation then it is fine.


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

    try {

        $company->id = $this->id;

        if (!$company->validate()) {
            throw new Exception('Could not update, validation error on Company ' . $this->company_title);
        }
        if (!$company->save()) {
            throw new Exception('Could not update,  error saving Company ' . $this->company_title);
        }

        $branches = $this->branches;
        
        foreach ($branches as $branch){
            $branch = new Branch();
            $branch = $this->setBranch($this, $branch);
            $branch->company_id = $company->id;
        
            if (!$branch->validate()) {
                throw new Exception('Could not create, validation error on Branch');
            }
            if (!$branch->save()) {
                throw new Exception('Could not create,  error saving on Branch');
            }
        
            if (($employee = Employee::findOne(['code' => $branch->code)) !== null]) {

                if (!$employee->validate()) {
                    throw new Exception('Could not update, validation error on Employee');
                }
                if (!$employee->save()) {
                    throw new Exception('Could not update,  error saving Employee');
                }
                
            }
        }

        $transaction->commit();
        Yii::info('All Models Saved');
        
    } catch(Exception $e) {
        Yii::warning($e->getMessage());
        $transaction->rollback();
        return false;
}

Just thought I would add

Sometimes I will create an additional form / skeleton model that stores all the var for the 3 models.
It is never saved - it only exists to pass data from the form to the models.

Then as I walking though the transaction I will save data back to the skeleton model and then it can be used in any later calls.

So I would set $skeleton = $this
In your example, after saving branch I can add data - $skeleton->branch_id = $branch->id
And use that $employee->branch_id = $skeleton->branch_id
I do this so I can just pass the $skeleton model to other setting functions.

When updating the form it would pull from the 3 models to set the data.