Thursday, April 13, 2017

Cascade create a model and attach it to another model in Controller in a One to Many relationship Yii

Cascade create a model and attach it to another model in Controller in a One to Many relationship Yii


Suppose we have a situation where we a set of users, each of which belong to a particular project. In Yii, we already create two models, namely Project and User. The User model class contains an attribute project_id, which is the id attribute value of the associated Project model. Now a user cannot be created without knowing the project_id it is associated with

Step 1:

In the protected/views/project/view.php, add a link to create user associated with the project:


<?php echo CHtml::link(CHtml::encode(Create user under the project), array(user/create, project_id=>$model->id)); ?>
The project_id allows the UserController (i.e. the controller associated with the User model) to identify the project_id to which the created user should be associated with.

Step 2:

In the protected/controllers/UserController.php, add a private member variable _project:


private $_project = null;

Next in the UserController.php, find the method filters(), and add one line for projectContext filter:


/**
* @return array action filters
*/
public function filters()
{
return array(
accessControl, // perform access control for CRUD operations
projectContext + create index admin, //check to ensure valid event context
);
}

Next in the UserController.php, defines the following methods:


public function filterProjectContext($filterChain)
{
//set the project identifier based on either the GET or POST input
//request variables, since we allow both types for our actions
$project_id = null;
if(isset($_GET[project_id]))
$project_id = $_GET[project_id];
else
if(isset($_POST[project_id]))
$project_id = $_POST[project_id];
$this->loadProject($project_id);
//complete the running of other filters and execute the requested action
$filterChain->run();
}

protected function loadProject($project_id)
{
//if the project property is null, create it based on input id
if($this->_project===null)
{
$this->_project=Project::model()->findbyPk($project_id);
if($this->_project===null)
{
throw new CHttpException(404,The requested project does not exist.);
}
}
return $this->_project;
}
The above method allows Yii code to create and assign the _project with the content from database using the project_id passed in from Step 1. As a result, before the actionCreate() method is invoked, the _project is already properly initialized based project_id attribute passed in. The final step is to assign $user->project_id in the actionCreate() method of the UserController class, as shown below:

public function actionCreate()
{
$model=new User;
$model->project_id=$this->_project->id;

// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);

if(isset($_POST[User]))
{
$model->attributes=$_POST[User];
if($model->save())
$this->redirect(array(view,id=>$model->id));
}

$this->render(create,array(
model=>$model,
));
}